24static EditGenerator
rewrite(RangeSelector Call, RangeSelector Builder) {
27 return [Call = std::move(Call),
28 Builder = std::move(Builder)](
const MatchFinder::MatchResult &Result)
29 -> Expected<SmallVector<transformer::Edit, 1>> {
30 Expected<CharSourceRange> CallRange = Call(Result);
32 return CallRange.takeError();
33 SourceManager &SM = *Result.SourceManager;
34 const LangOptions &LangOpts = Result.Context->getLangOpts();
35 SourceLocation Begin = CallRange->getBegin();
38 const bool InMacro = CallRange->getBegin().isMacroID();
40 while (SM.isMacroArgExpansion(Begin))
41 Begin = SM.getImmediateExpansionRange(Begin).getBegin();
43 WarnOnly.Kind = EditKind::Range;
44 WarnOnly.Range = CharSourceRange::getCharRange(Begin, Begin);
45 return SmallVector<Edit, 1>({WarnOnly});
50 auto NextToken = [&](std::optional<Token> CurrentToken) {
53 if (CurrentToken->is(clang::tok::eof))
54 return std::optional<Token>();
56 CurrentToken->getLocation(), SM, LangOpts);
58 std::optional<Token> LessToken =
60 while (LessToken && LessToken->getKind() != clang::tok::less)
61 LessToken = NextToken(LessToken);
63 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
67 std::optional<Token> EndToken = NextToken(LessToken);
68 std::optional<Token> GreaterToken = NextToken(EndToken);
69 for (; GreaterToken && GreaterToken->getKind() != clang::tok::greater;
70 GreaterToken = NextToken(GreaterToken)) {
71 EndToken = GreaterToken;
74 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
78 std::optional<Token> ArgStart = NextToken(GreaterToken);
79 if (!ArgStart || ArgStart->getKind() != clang::tok::l_paren) {
80 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
83 std::optional<Token> Arg = NextToken(ArgStart);
85 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
86 "unexpected end of file");
88 const bool HasArgs = Arg->getKind() != clang::tok::r_paren;
90 Expected<CharSourceRange> BuilderRange = Builder(Result);
92 return BuilderRange.takeError();
95 auto GetText = [&](
const CharSourceRange &Range) {
96 return clang::Lexer::getSourceText(Range, SM, LangOpts);
100 Replace.Kind = EditKind::Range;
101 Replace.Range.setBegin(CallRange->getBegin());
102 Replace.Range.setEnd(ArgStart->getEndLoc());
103 const Expr *BuilderExpr = Result.Nodes.getNodeAs<Expr>(
"builder");
104 std::string BuilderText = GetText(*BuilderRange).str();
105 if (BuilderExpr->getType()->isPointerType()) {
106 BuilderText = BuilderExpr->isImplicitCXXThis()
108 : llvm::formatv(
"*{}", BuilderText).str();
110 const StringRef OpType = GetText(CharSourceRange::getTokenRange(
111 LessToken->getEndLoc(), EndToken->getLastLoc()));
112 Replace.Replacement = llvm::formatv(
"{}::create({}{}", OpType, BuilderText,
113 HasArgs ?
", " :
"");
115 return SmallVector<Edit, 1>({Replace});
120 const Stencil Message = cat(
"use 'OpType::create(builder, ...)' instead of "
121 "'builder.create<OpType>(...)'");
123 auto BuilderType = cxxRecordDecl(isSameOrDerivedFrom(
"::mlir::OpBuilder"));
124 const ast_matchers::internal::Matcher<Stmt> Base =
126 on(expr(anyOf(hasType(BuilderType), hasType(pointsTo(BuilderType))))
128 callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()),
133 {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), Base),
134 rewrite(node(
"call"), node(
"builder")), Message),
135 makeRule(Base, noopEdit(node(
"call")), Message)});
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.