https://github.com/jpienaar updated 
https://github.com/llvm/llvm-project/pull/159423

>From f23c42bea591a122ab366a749c4959e44b405d50 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Wed, 17 Sep 2025 18:53:01 +0000
Subject: [PATCH 1/6] [clang-tidy][mlir] Expand to cover pointer of builder

Previously this only checked for OpBuilder usage, but it could also be
invoked via pointer. Also change how call range is calculated to avoid
false overlaps which limits rewriting builder calls inside arguments of
builder calls.
---
 .../llvm/UseNewMLIROpBuilderCheck.cpp         | 71 ++++++++++---------
 .../checkers/llvm/use-new-mlir-op-builder.cpp | 38 +++++++++-
 2 files changed, 75 insertions(+), 34 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
index 0d81b9a9e38ca..8705c10f5c646 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
@@ -23,13 +23,11 @@ namespace {
 using namespace ::clang::ast_matchers;
 using namespace ::clang::transformer;
 
-EditGenerator rewrite(RangeSelector Call, RangeSelector Builder,
-                      RangeSelector CallArgs) {
+EditGenerator rewrite(RangeSelector Call, RangeSelector Builder) {
   // This is using an EditGenerator rather than ASTEdit as we want to warn even
   // if in macro.
-  return [Call = std::move(Call), Builder = std::move(Builder),
-          CallArgs =
-              std::move(CallArgs)](const MatchFinder::MatchResult &Result)
+  return [Call = std::move(Call),
+          Builder = std::move(Builder)](const MatchFinder::MatchResult &Result)
              -> Expected<SmallVector<transformer::Edit, 1>> {
     Expected<CharSourceRange> CallRange = Call(Result);
     if (!CallRange)
@@ -54,7 +52,7 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder,
     auto NextToken = [&](std::optional<Token> CurrentToken) {
       if (!CurrentToken)
         return CurrentToken;
-      if (CurrentToken->getEndLoc() >= CallRange->getEnd())
+      if (CurrentToken->is(clang::tok::eof))
         return std::optional<Token>();
       return clang::Lexer::findNextToken(CurrentToken->getLocation(), SM,
                                          LangOpts);
@@ -68,9 +66,10 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder,
       return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
                                                  "missing '<' token");
     }
+
     std::optional<Token> EndToken = NextToken(LessToken);
-    for (std::optional<Token> GreaterToken = NextToken(EndToken);
-         GreaterToken && GreaterToken->getKind() != clang::tok::greater;
+    std::optional<Token> GreaterToken = NextToken(EndToken);
+    for (; GreaterToken && GreaterToken->getKind() != clang::tok::greater;
          GreaterToken = NextToken(GreaterToken)) {
       EndToken = GreaterToken;
     }
@@ -79,12 +78,21 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder,
                                                  "missing '>' token");
     }
 
+    std::optional<Token> ArgStart = NextToken(GreaterToken);
+    if (!ArgStart || ArgStart->getKind() != clang::tok::l_paren) {
+      return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+                                                 "missing '(' token");
+    }
+    std::optional<Token> Arg = NextToken(ArgStart);
+    if (!Arg) {
+      return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+                                                 "unexpected end of file");
+    }
+    bool hasArgs = Arg->getKind() != clang::tok::r_paren;
+
     Expected<CharSourceRange> BuilderRange = Builder(Result);
     if (!BuilderRange)
       return BuilderRange.takeError();
-    Expected<CharSourceRange> CallArgsRange = CallArgs(Result);
-    if (!CallArgsRange)
-      return CallArgsRange.takeError();
 
     // Helper for concatting below.
     auto GetText = [&](const CharSourceRange &Range) {
@@ -93,18 +101,19 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder,
 
     Edit Replace;
     Replace.Kind = EditKind::Range;
-    Replace.Range = *CallRange;
-    std::string CallArgsStr;
-    // Only emit args if there are any.
-    if (auto CallArgsText = GetText(*CallArgsRange).ltrim();
-        !CallArgsText.rtrim().empty()) {
-      CallArgsStr = llvm::formatv(", {}", CallArgsText);
+    Replace.Range.setBegin(CallRange->getBegin());
+    Replace.Range.setEnd(ArgStart->getEndLoc());
+    const Expr *BuilderExpr = Result.Nodes.getNodeAs<Expr>("builder");
+    std::string BuilderText = GetText(*BuilderRange).str();
+    if (BuilderExpr->getType()->isPointerType()) {
+      BuilderText = BuilderExpr->isImplicitCXXThis()
+                        ? "*this"
+                        : llvm::formatv("*{}", BuilderText).str();
     }
-    Replace.Replacement =
-        llvm::formatv("{}::create({}{})",
-                      GetText(CharSourceRange::getTokenRange(
-                          LessToken->getEndLoc(), EndToken->getLastLoc())),
-                      GetText(*BuilderRange), CallArgsStr);
+    StringRef OpType = GetText(CharSourceRange::getTokenRange(
+        LessToken->getEndLoc(), EndToken->getLastLoc()));
+    Replace.Replacement = llvm::formatv("{}::create({}{}", OpType, BuilderText,
+                                        hasArgs ? ", " : "");
 
     return SmallVector<Edit, 1>({Replace});
   };
@@ -114,19 +123,17 @@ RewriteRuleWith<std::string> 
useNewMlirOpBuilderCheckRule() {
   Stencil message = cat("use 'OpType::create(builder, ...)' instead of "
                         "'builder.create<OpType>(...)'");
   // Match a create call on an OpBuilder.
-  ast_matchers::internal::Matcher<Stmt> base =
-      cxxMemberCallExpr(
-          on(expr(hasType(
-                      cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder"))))
-                 .bind("builder")),
-          callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))),
-          callee(cxxMethodDecl(hasName("create"))))
-          .bind("call");
+  auto BuilderType = cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder"));
+  ast_matchers::internal::Matcher<Stmt> base = cxxMemberCallExpr(
+      on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
+             .bind("builder")),
+      callee(expr().bind("call")),
+      callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))),
+      callee(cxxMethodDecl(hasName("create"))));
   return applyFirst(
       //  Attempt rewrite given an lvalue builder, else just warn.
       {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base),
-                rewrite(node("call"), node("builder"), callArgs("call")),
-                message),
+                rewrite(node("call"), node("builder")), message),
        makeRule(base, noopEdit(node("call")), message)});
 }
 } // namespace
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
index 0971a1611e3cb..1fbbf0a76c42a 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
@@ -2,6 +2,7 @@
 
 namespace mlir {
 class Location {};
+class Value {};
 class OpBuilder {
 public:
   template <typename OpTy, typename... Args>
@@ -28,6 +29,13 @@ struct NamedOp {
   static NamedOp create(OpBuilder &builder, Location location, const char* 
name) {
     return NamedOp(name);
   }
+  Value getResult() { return Value(); }
+};
+struct OperandOp {
+  OperandOp(Value val) {}
+  static OperandOp create(OpBuilder &builder, Location location, Value val) {
+    return OperandOp(val);
+  }
 };
 } // namespace mlir
 
@@ -40,6 +48,15 @@ void g(mlir::OpBuilder &b) {
   b.create<T>(b.getUnknownLoc(), "gaz");
 }
 
+class CustomBuilder : public mlir::ImplicitLocOpBuilder {
+public:
+  mlir::NamedOp f(const char *name) {
+    // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: use 'OpType::create(builder, 
...)'
+    // CHECK-FIXES: NamedOp::create(*this, name);
+    return create<mlir::NamedOp>(name);
+  }
+};
+
 void f() {
   mlir::OpBuilder builder;
   // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
@@ -47,6 +64,8 @@ void f() {
   builder.create<mlir::  ModuleOp>(builder.getUnknownLoc());
 
   using mlir::NamedOp;
+  using mlir::OperandOp;
+
   // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
   // CHECK-FIXES: NamedOp::create(builder, builder.getUnknownLoc(), "baz")
   builder.create<NamedOp>(builder.getUnknownLoc(), "baz");
@@ -56,7 +75,7 @@ void f() {
   // CHECK-FIXES:   builder.getUnknownLoc(),
   // CHECK-FIXES:   "caz")
   builder.
-   create<NamedOp>(
+   create<NamedOp>  (
      builder.getUnknownLoc(),
      "caz");
 
@@ -67,10 +86,25 @@ void f() {
 
   mlir::ImplicitLocOpBuilder ib;
   // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
-  // CHECK-FIXES: mlir::ModuleOp::create(ib)
+  // CHECK-FIXES: mlir::ModuleOp::create(ib   )
   ib.create<mlir::ModuleOp>(   );
 
   // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
   // CHECK-FIXES: 
mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc());
   mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc());
+
+  auto *p = &builder;
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, 
...)'
+  // CHECK-FIXES: NamedOp::create(*p, builder.getUnknownLoc(), "eaz")
+  p->create<NamedOp>(builder.getUnknownLoc(), "eaz");
+
+  CustomBuilder cb;
+  cb.f("faz");
+
+  // CHECK-MESSAGES: :[[@LINE+4]]:3: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
+  // CHECK-FIXES: OperandOp::create(builder, builder.getUnknownLoc(),
+  // CHECK-MESSAGES: :[[@LINE+3]]:5: warning: use 'OpType::create(builder, 
...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder]
+  // CHECK-FIXES: NamedOp::create(builder,
+  builder.create<OperandOp>(builder.getUnknownLoc(),
+    builder.create<NamedOp>(builder.getUnknownLoc(), "gaz").getResult());
 }

>From b2fb3e853c93e49cf6f6a51a6bb4a1fddbc37cac Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Thu, 18 Sep 2025 20:48:40 -0700
Subject: [PATCH 2/6] Apply suggestions from code review

Co-authored-by: EugeneZelenko <[email protected]>
---
 .../clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp              | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
index 8705c10f5c646..1b4360207b53b 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
@@ -88,7 +88,7 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder) {
       return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
                                                  "unexpected end of file");
     }
-    bool hasArgs = Arg->getKind() != clang::tok::r_paren;
+    const bool hasArgs = Arg->getKind() != clang::tok::r_paren;
 
     Expected<CharSourceRange> BuilderRange = Builder(Result);
     if (!BuilderRange)
@@ -110,7 +110,7 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder) {
                         ? "*this"
                         : llvm::formatv("*{}", BuilderText).str();
     }
-    StringRef OpType = GetText(CharSourceRange::getTokenRange(
+    const StringRef OpType = GetText(CharSourceRange::getTokenRange(
         LessToken->getEndLoc(), EndToken->getLastLoc()));
     Replace.Replacement = llvm::formatv("{}::create({}{}", OpType, BuilderText,
                                         hasArgs ? ", " : "");

>From 540e4af4df871e0d7ce06357fd8a942e6824b4ce Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Tue, 23 Sep 2025 13:46:24 +0200
Subject: [PATCH 3/6] Update
 clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp

Co-authored-by: Victor Chernyakin <[email protected]>
---
 .../test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
index 1fbbf0a76c42a..ea58a6c93e324 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
@@ -52,7 +52,7 @@ class CustomBuilder : public mlir::ImplicitLocOpBuilder {
 public:
   mlir::NamedOp f(const char *name) {
     // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: use 'OpType::create(builder, 
...)'
-    // CHECK-FIXES: NamedOp::create(*this, name);
+    // CHECK-FIXES: mlir::NamedOp::create(*this, name);
     return create<mlir::NamedOp>(name);
   }
 };

>From 87fc9c02176ac538a17ef6a6faba4eddfdb515b8 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Tue, 23 Sep 2025 14:03:37 +0200
Subject: [PATCH 4/6] Merge two cxxMethodDecl checks

---
 .../clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp              | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
index 1b4360207b53b..09530ff69e404 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
@@ -128,8 +128,8 @@ RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() 
{
       on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
              .bind("builder")),
       callee(expr().bind("call")),
-      callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))),
-      callee(cxxMethodDecl(hasName("create"))));
+      callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()),
+                           hasName("create"))));
   return applyFirst(
       //  Attempt rewrite given an lvalue builder, else just warn.
       {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base),

>From 0ce25d1b77a4dfa4588355a18cd54f0aa99b1819 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Tue, 23 Sep 2025 14:05:26 +0200
Subject: [PATCH 5/6] Fix clang-tidy flags

---
 .../clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp       | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
index 09530ff69e404..2dc2a7b971f09 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
@@ -88,7 +88,7 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder) {
       return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
                                                  "unexpected end of file");
     }
-    const bool hasArgs = Arg->getKind() != clang::tok::r_paren;
+    const bool HasArgs = Arg->getKind() != clang::tok::r_paren;
 
     Expected<CharSourceRange> BuilderRange = Builder(Result);
     if (!BuilderRange)
@@ -113,7 +113,7 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector 
Builder) {
     const StringRef OpType = GetText(CharSourceRange::getTokenRange(
         LessToken->getEndLoc(), EndToken->getLastLoc()));
     Replace.Replacement = llvm::formatv("{}::create({}{}", OpType, BuilderText,
-                                        hasArgs ? ", " : "");
+                                        HasArgs ? ", " : "");
 
     return SmallVector<Edit, 1>({Replace});
   };
@@ -124,7 +124,7 @@ RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() 
{
                         "'builder.create<OpType>(...)'");
   // Match a create call on an OpBuilder.
   auto BuilderType = cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder"));
-  ast_matchers::internal::Matcher<Stmt> base = cxxMemberCallExpr(
+  ast_matchers::internal::Matcher<Stmt> Base = cxxMemberCallExpr(
       on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
              .bind("builder")),
       callee(expr().bind("call")),
@@ -132,9 +132,9 @@ RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() 
{
                            hasName("create"))));
   return applyFirst(
       //  Attempt rewrite given an lvalue builder, else just warn.
-      {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base),
+      {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), Base),
                 rewrite(node("call"), node("builder")), message),
-       makeRule(base, noopEdit(node("call")), message)});
+       makeRule(Base, noopEdit(node("call")), message)});
 }
 } // namespace
 

>From 01d0e6f0288eb0e43dd4654b2d9ac66c671fb04e Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <[email protected]>
Date: Wed, 24 Sep 2025 09:10:55 +0200
Subject: [PATCH 6/6] Change bind to allow one callee descend.

---
 .../clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp    | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
index 2dc2a7b971f09..edc7322c4e7ab 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
@@ -124,12 +124,13 @@ RewriteRuleWith<std::string> 
useNewMlirOpBuilderCheckRule() {
                         "'builder.create<OpType>(...)'");
   // Match a create call on an OpBuilder.
   auto BuilderType = cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder"));
-  ast_matchers::internal::Matcher<Stmt> Base = cxxMemberCallExpr(
-      on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
-             .bind("builder")),
-      callee(expr().bind("call")),
-      callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()),
-                           hasName("create"))));
+  ast_matchers::internal::Matcher<Stmt> Base = =
+      cxxMemberCallExpr(
+          on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
+                 .bind("builder")),
+          callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()),
+                               hasName("create"))))
+          .bind("call");
   return applyFirst(
       //  Attempt rewrite given an lvalue builder, else just warn.
       {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), Base),

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to