================
@@ -0,0 +1,252 @@
+//===--- MinMaxUseInitializerListCheck.cpp - clang-tidy 
-------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinMaxUseInitializerListCheck.h"
+#include "../utils/ASTUtils.h"
+#include "../utils/LexerUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+
+namespace {
+
+struct FindArgsResult {
+  const Expr *First;
+  const Expr *Last;
+  const Expr *Compare;
+  std::vector<const clang::Expr *> Args;
+};
+
+} // anonymous namespace
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+static FindArgsResult findArgs(const CallExpr *Call) {
+  FindArgsResult Result;
+  Result.First = nullptr;
+  Result.Last = nullptr;
+  Result.Compare = nullptr;
+
+  if (Call->getNumArgs() == 3) {
+    auto ArgIterator = Call->arguments().begin();
+    std::advance(ArgIterator, 2);
+    Result.Compare = *ArgIterator;
+  } else {
+    auto ArgIterator = Call->arguments().begin();
+
+    if (const auto *InitListExpr =
+            dyn_cast<CXXStdInitializerListExpr>(*ArgIterator)) {
+      if (const auto *InitList = dyn_cast<clang::InitListExpr>(
+              InitListExpr->getSubExpr()->IgnoreImplicit())) {
+        Result.Args.insert(Result.Args.begin(), InitList->inits().begin(),
+                           InitList->inits().end());
+
+        Result.First = *ArgIterator;
+        Result.Last = *ArgIterator;
+
+        std::advance(ArgIterator, 1);
+        if (ArgIterator != Call->arguments().end()) {
+          Result.Compare = *ArgIterator;
+        }
+        return Result;
+      }
+    }
+  }
+
+  for (const Expr *Arg : Call->arguments()) {
+    if (!Result.First)
+      Result.First = Arg;
+
+    if (Arg == Result.Compare)
+      continue;
+
+    Result.Args.push_back(Arg);
+    Result.Last = Arg;
+  }
+
+  return Result;
+}
+
+static std::vector<FixItHint>
+generateReplacement(const MatchFinder::MatchResult &Match,
+                    const CallExpr *TopCall, const FindArgsResult &Result) {
+  std::vector<FixItHint> FixItHints;
+
+  const QualType ResultType = TopCall->getDirectCallee()
+                                  ->getReturnType()
+                                  .getNonReferenceType()
+                                  .getUnqualifiedType()
+                                  .getCanonicalType();
+  const bool IsInitializerList = Result.First == Result.Last;
+
+  if (!IsInitializerList)
+    FixItHints.push_back(
+        FixItHint::CreateInsertion(Result.First->getBeginLoc(), "{"));
+
+  for (const Expr *Arg : Result.Args) {
+    if (const auto *InnerCall =
+            dyn_cast<CallExpr>(Arg->IgnoreParenImpCasts())) {
+      const FindArgsResult InnerResult = findArgs(InnerCall);
+      const std::vector<FixItHint> InnerReplacements =
+          generateReplacement(Match, InnerCall, InnerResult);
+      if (InnerCall->getDirectCallee()->getQualifiedNameAsString() ==
+              TopCall->getDirectCallee()->getQualifiedNameAsString() &&
+          ((!Result.Compare && !InnerResult.Compare) ||
+           utils::areStatementsIdentical(Result.Compare, InnerResult.Compare,
+                                         *Match.Context))) {
+
+        FixItHints.push_back(
+            FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+                InnerCall->getCallee()->getSourceRange())));
+
+        const auto LParen = utils::lexer::findNextTokenSkippingComments(
+            InnerCall->getCallee()->getEndLoc(), *Match.SourceManager,
+            Match.Context->getLangOpts());
+        if (LParen && LParen->getKind() == tok::l_paren)
+          FixItHints.push_back(
+              FixItHint::CreateRemoval(SourceRange(LParen->getLocation())));
+
+        FixItHints.push_back(
+            FixItHint::CreateRemoval(SourceRange(InnerCall->getRParenLoc())));
+
+        if (InnerResult.First == InnerResult.Last) {
+          FixItHints.insert(FixItHints.end(), InnerReplacements.begin(),
+                            InnerReplacements.end());
+
+          FixItHints.push_back(
+              FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+                  InnerResult.First->getBeginLoc())));
+          FixItHints.push_back(FixItHint::CreateRemoval(
+              CharSourceRange::getTokenRange(InnerResult.First->getEndLoc())));
+        } else
+          FixItHints.insert(FixItHints.end(), InnerReplacements.begin() + 1,
+                            InnerReplacements.end() - 1);
+
+        if (InnerResult.Compare) {
+          const auto Comma = utils::lexer::findNextTokenSkippingComments(
+              InnerResult.Last->getEndLoc(), *Match.SourceManager,
+              Match.Context->getLangOpts());
+          if (Comma && Comma->getKind() == tok::comma)
+            FixItHints.push_back(
+                FixItHint::CreateRemoval(SourceRange(Comma->getLocation())));
+
+          if (utils::lexer::getPreviousToken(
+                  InnerResult.Compare->getExprLoc(), *Match.SourceManager,
+                  Match.Context->getLangOpts(), false)
+                  .getLocation() == Comma->getLocation())
+            FixItHints.push_back(
+                FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+                    Comma->getLocation(), InnerResult.Compare->getEndLoc())));
+          else {
+            FixItHints.push_back(
+                FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+                    InnerResult.Compare->getSourceRange())));
+          }
+        }
+      }
+      continue;
+    }
+
+    const QualType ArgType = Arg->IgnoreParenImpCasts()
+                                 ->getType()
+                                 .getUnqualifiedType()
+                                 .getCanonicalType();
+
+    if (ArgType != ResultType) {
+      const std::string ArgText =
+          Lexer::getSourceText(
+              CharSourceRange::getTokenRange(Arg->getSourceRange()),
+              *Match.SourceManager, Match.Context->getLangOpts())
+              .str();
+
+      FixItHints.push_back(FixItHint::CreateReplacement(
+          Arg->getSourceRange(),
+          "static_cast<" + ResultType.getAsString() + ">(" + ArgText + ")"));
+    }
----------------
PiotrZSL wrote:

move this code at the begining of for with:
```
const auto *InnerCall =   dyn_cast<CallExpr>(Arg->IgnoreParenImpCasts()));
if (nullptr == InnerCall) {
// that code
continue;
}
```

https://github.com/llvm/llvm-project/pull/85572
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to