-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[clang-tidy] Add MLIR check for old op builder usage. #149148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
b404f53
[clang-tidy] Add MLIR check for old op builder usage.
jpienaar 34b2a3a
Move into LLVM module as this seems better spot given lack of other p…
jpienaar dc85637
Fix formatting
jpienaar a74232f
Address review comments
jpienaar 4fe574a
Address missed review comments
jpienaar a25b8af
Fix wrong type
jpienaar 9a86c0f
Address clang-tidy warnings except in mlir_op_builder.cpp which is fo…
jpienaar 46ca80b
Update clang-tools-extra/clang-tidy/llvm/MLIROpBuilderCheck.cpp
jpienaar 01f5fbb
Renamings & extra tests
jpienaar 4d104f4
Update clang-tools-extra/docs/clang-tidy/checks/llvm/use-new-mlir-op-…
jpienaar e4f78d0
Switch to EditGenerator so that macros are at least warned about
jpienaar 9e3f973
Use formatv to make easier to see concat
jpienaar 30609a3
Merge branch 'main' into clangtidy-mlir
jpienaar de7c822
Update clang-tools-extra/clang-tidy/llvm/MLIROpBuilderCheck.cpp
jpienaar cd50bdb
Update to UseNewMLIROpBuilderCheck more uniformly
jpienaar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
//===--- UseNewMLIROpBuilderCheck.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 "UseNewMLIROpBuilderCheck.h" | ||
#include "clang/ASTMatchers/ASTMatchers.h" | ||
#include "clang/Basic/LLVM.h" | ||
#include "clang/Lex/Lexer.h" | ||
#include "clang/Tooling/Transformer/RangeSelector.h" | ||
#include "clang/Tooling/Transformer/RewriteRule.h" | ||
#include "clang/Tooling/Transformer/SourceCode.h" | ||
#include "clang/Tooling/Transformer/Stencil.h" | ||
#include "llvm/Support/Error.h" | ||
#include "llvm/Support/FormatVariadic.h" | ||
|
||
namespace clang::tidy::llvm_check { | ||
namespace { | ||
|
||
using namespace ::clang::ast_matchers; | ||
using namespace ::clang::transformer; | ||
|
||
EditGenerator rewrite(RangeSelector Call, RangeSelector Builder, | ||
RangeSelector CallArgs) { | ||
// 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) | ||
-> Expected<SmallVector<transformer::Edit, 1>> { | ||
Expected<CharSourceRange> CallRange = Call(Result); | ||
if (!CallRange) | ||
return CallRange.takeError(); | ||
SourceManager &SM = *Result.SourceManager; | ||
const LangOptions &LangOpts = Result.Context->getLangOpts(); | ||
SourceLocation Begin = CallRange->getBegin(); | ||
|
||
// This will result in just a warning and no edit. | ||
bool InMacro = CallRange->getBegin().isMacroID(); | ||
if (InMacro) { | ||
while (SM.isMacroArgExpansion(Begin)) | ||
Begin = SM.getImmediateExpansionRange(Begin).getBegin(); | ||
Edit WarnOnly; | ||
WarnOnly.Kind = EditKind::Range; | ||
WarnOnly.Range = CharSourceRange::getCharRange(Begin, Begin); | ||
return SmallVector<Edit, 1>({WarnOnly}); | ||
} | ||
|
||
// This will try to extract the template argument as written so that the | ||
// rewritten code looks closest to original. | ||
auto NextToken = [&](std::optional<Token> CurrentToken) { | ||
if (!CurrentToken) | ||
return CurrentToken; | ||
if (CurrentToken->getEndLoc() >= CallRange->getEnd()) | ||
return std::optional<Token>(); | ||
return clang::Lexer::findNextToken(CurrentToken->getLocation(), SM, | ||
LangOpts); | ||
}; | ||
std::optional<Token> LessToken = | ||
clang::Lexer::findNextToken(Begin, SM, LangOpts); | ||
while (LessToken && LessToken->getKind() != clang::tok::less) { | ||
LessToken = NextToken(LessToken); | ||
} | ||
if (!LessToken) { | ||
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; | ||
GreaterToken = NextToken(GreaterToken)) { | ||
EndToken = GreaterToken; | ||
} | ||
if (!EndToken) { | ||
return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, | ||
"missing '>' token"); | ||
} | ||
|
||
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) { | ||
return clang::Lexer::getSourceText(Range, SM, LangOpts); | ||
}; | ||
|
||
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.Replacement = | ||
llvm::formatv("{}::create({}{})", | ||
GetText(CharSourceRange::getTokenRange( | ||
LessToken->getEndLoc(), EndToken->getLastLoc())), | ||
GetText(*BuilderRange), CallArgsStr); | ||
|
||
return SmallVector<Edit, 1>({Replace}); | ||
}; | ||
} | ||
|
||
RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { | ||
return makeRule( | ||
cxxMemberCallExpr( | ||
on(expr(hasType( | ||
cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder")))) | ||
.bind("builder")), | ||
callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))), | ||
callee(cxxMethodDecl(hasName("create")))) | ||
.bind("call"), | ||
rewrite(node("call"), node("builder"), callArgs("call")), | ||
cat("use 'OpType::create(builder, ...)' instead of " | ||
"'builder.create<OpType>(...)'")); | ||
} | ||
} // namespace | ||
|
||
UseNewMlirOpBuilderCheck::UseNewMlirOpBuilderCheck(StringRef Name, | ||
ClangTidyContext *Context) | ||
: TransformerClangTidyCheck(useNewMlirOpBuilderCheckRule(), Name, Context) { | ||
} | ||
|
||
} // namespace clang::tidy::llvm_check |
29 changes: 29 additions & 0 deletions
29
clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//===--- UseNewMLIROpBuilderCheck.h - clang-tidy ----------------*- C++ -*-===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H | ||
|
||
#include "../utils/TransformerClangTidyCheck.h" | ||
|
||
namespace clang::tidy::llvm_check { | ||
|
||
/// Checks for uses of MLIR's old/to be deprecated `OpBuilder::create<T>` form | ||
/// and suggests using `T::create` instead. | ||
class UseNewMlirOpBuilderCheck : public utils::TransformerClangTidyCheck { | ||
public: | ||
UseNewMlirOpBuilderCheck(StringRef Name, ClangTidyContext *Context); | ||
|
||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||
return getLangOpts().CPlusPlus; | ||
} | ||
}; | ||
|
||
} // namespace clang::tidy::llvm_check | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
clang-tools-extra/docs/clang-tidy/checks/llvm/use-new-mlir-op-builder.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
.. title:: clang-tidy - llvm-mlir-op-builder | ||
|
||
llvm-mlir-op-builder | ||
==================== | ||
|
||
Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form | ||
and suggests using ``T::create`` instead. | ||
|
||
Example | ||
------- | ||
|
||
.. code-block:: c++ | ||
|
||
builder.create<FooOp>(builder.getUnknownLoc(), "baz"); | ||
|
||
|
||
Transforms to: | ||
|
||
.. code-block:: c++ | ||
|
||
FooOp::create(builder, builder.getUnknownLoc(), "baz"); |
72 changes: 72 additions & 0 deletions
72
clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// RUN: %check_clang_tidy --match-partial-fixes %s llvm-use-new-mlir-op-builder %t | ||
|
||
namespace mlir { | ||
class Location {}; | ||
class OpBuilder { | ||
public: | ||
template <typename OpTy, typename... Args> | ||
OpTy create(Location location, Args &&...args) { | ||
return OpTy(args...); | ||
} | ||
Location getUnknownLoc() { return Location(); } | ||
}; | ||
class ImplicitLocOpBuilder : public OpBuilder { | ||
public: | ||
template <typename OpTy, typename... Args> | ||
OpTy create(Args &&...args) { | ||
return OpTy(args...); | ||
} | ||
}; | ||
struct ModuleOp { | ||
ModuleOp() {} | ||
static ModuleOp create(OpBuilder &builder, Location location) { | ||
return ModuleOp(); | ||
} | ||
}; | ||
struct NamedOp { | ||
NamedOp(const char* name) {} | ||
static NamedOp create(OpBuilder &builder, Location location, const char* name) { | ||
return NamedOp(name); | ||
} | ||
}; | ||
} // namespace mlir | ||
|
||
#define ASSIGN(A, B, C, D) C A = B.create<C>(B.getUnknownLoc(), D) | ||
|
||
template <typename T> | ||
void g(mlir::OpBuilder &b) { | ||
// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] | ||
// CHECK-FIXES: T::create(b, b.getUnknownLoc(), "gaz") | ||
b.create<T>(b.getUnknownLoc(), "gaz"); | ||
} | ||
|
||
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] | ||
// CHECK-FIXES: mlir:: ModuleOp::create(builder, builder.getUnknownLoc()) | ||
builder.create<mlir:: ModuleOp>(builder.getUnknownLoc()); | ||
|
||
using mlir::NamedOp; | ||
// 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"); | ||
|
||
// CHECK-MESSAGES: :[[@LINE+4]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] | ||
// CHECK-FIXES: NamedOp::create(builder, | ||
// CHECK-FIXES: builder.getUnknownLoc(), | ||
// CHECK-FIXES: "caz") | ||
builder. | ||
create<NamedOp>( | ||
builder.getUnknownLoc(), | ||
"caz"); | ||
|
||
// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] | ||
ASSIGN(op, builder, NamedOp, "daz"); | ||
|
||
g<NamedOp>(builder); | ||
|
||
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) | ||
ib.create<mlir::ModuleOp>( ); | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.