25static EditGenerator
rewrite(RangeSelector Call, RangeSelector Builder) {
28 return [Call = std::move(Call),
29 Builder = std::move(Builder)](
const MatchFinder::MatchResult &Result)
30 -> Expected<SmallVector<transformer::Edit, 1>> {
31 Expected<CharSourceRange> CallRange = Call(Result);
33 return CallRange.takeError();
34 SourceManager &SM = *Result.SourceManager;
35 const LangOptions &LangOpts = Result.Context->getLangOpts();
36 SourceLocation Begin = CallRange->getBegin();
39 const bool InMacro = CallRange->getBegin().isMacroID();
41 while (SM.isMacroArgExpansion(Begin))
42 Begin = SM.getImmediateExpansionRange(Begin).getBegin();
44 WarnOnly.Kind = EditKind::Range;
45 WarnOnly.Range = CharSourceRange::getCharRange(Begin, Begin);
46 return SmallVector<Edit, 1>({WarnOnly});
51 auto NextToken = [&](std::optional<Token> CurrentToken) {
54 if (CurrentToken->is(clang::tok::eof))
55 return std::optional<Token>();
56 return clang::Lexer::findNextToken(CurrentToken->getLocation(), SM,
59 std::optional<Token> LessToken =
60 clang::Lexer::findNextToken(Begin, SM, LangOpts);
61 while (LessToken && LessToken->getKind() != clang::tok::less) {
62 LessToken = NextToken(LessToken);
65 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
69 std::optional<Token> EndToken = NextToken(LessToken);
70 std::optional<Token> GreaterToken = NextToken(EndToken);
71 for (; GreaterToken && GreaterToken->getKind() != clang::tok::greater;
72 GreaterToken = NextToken(GreaterToken)) {
73 EndToken = GreaterToken;
76 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
80 std::optional<Token> ArgStart = NextToken(GreaterToken);
81 if (!ArgStart || ArgStart->getKind() != clang::tok::l_paren) {
82 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
85 std::optional<Token> Arg = NextToken(ArgStart);
87 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
88 "unexpected end of file");
90 const bool HasArgs = Arg->getKind() != clang::tok::r_paren;
92 Expected<CharSourceRange> BuilderRange = Builder(Result);
94 return BuilderRange.takeError();
97 auto GetText = [&](
const CharSourceRange &Range) {
98 return clang::Lexer::getSourceText(Range, SM, LangOpts);
102 Replace.Kind = EditKind::Range;
103 Replace.Range.setBegin(CallRange->getBegin());
104 Replace.Range.setEnd(ArgStart->getEndLoc());
105 const Expr *BuilderExpr = Result.Nodes.getNodeAs<Expr>(
"builder");
106 std::string BuilderText = GetText(*BuilderRange).str();
107 if (BuilderExpr->getType()->isPointerType()) {
108 BuilderText = BuilderExpr->isImplicitCXXThis()
110 : llvm::formatv(
"*{}", BuilderText).str();
112 const StringRef OpType = GetText(CharSourceRange::getTokenRange(
113 LessToken->getEndLoc(), EndToken->getLastLoc()));
114 Replace.Replacement = llvm::formatv(
"{}::create({}{}", OpType, BuilderText,
115 HasArgs ?
", " :
"");
117 return SmallVector<Edit, 1>({Replace});
122 const Stencil Message = cat(
"use 'OpType::create(builder, ...)' instead of "
123 "'builder.create<OpType>(...)'");
125 auto BuilderType = cxxRecordDecl(isSameOrDerivedFrom(
"::mlir::OpBuilder"));
126 const ast_matchers::internal::Matcher<Stmt> Base =
128 on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
130 callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()),
135 {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), Base),
136 rewrite(node(
"call"), node(
"builder")), Message),
137 makeRule(Base, noopEdit(node(
"call")), Message)});
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.