11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Frontend/CompilerInstance.h"
15 #include "clang/Lex/Lexer.h"
16 #include "clang/Lex/Preprocessor.h"
24 StringFindStartswithCheck::StringFindStartswithCheck(StringRef
Name,
28 Options.get(
"StringLikeClasses",
"::std::basic_string"))),
29 IncludeStyle(Options.getLocalOrGlobal(
"IncludeStyle",
30 utils::IncludeSorter::IS_LLVM)),
31 AbseilStringsMatchHeader(
32 Options.get(
"AbseilStringsMatchHeader",
"absl/strings/match.h")) {}
35 auto ZeroLiteral = integerLiteral(equals(0));
36 auto StringClassMatcher = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>(
37 StringLikeClasses.begin(), StringLikeClasses.end())));
38 auto StringType = hasUnqualifiedDesugaredType(
39 recordType(hasDeclaration(StringClassMatcher)));
41 auto StringFind = cxxMemberCallExpr(
43 callee(cxxMethodDecl(hasName(
"find"))),
44 on(hasType(StringType)),
46 hasArgument(0, expr().bind(
"needle")),
48 anyOf(hasArgument(1, ZeroLiteral), hasArgument(1, cxxDefaultArgExpr())));
53 hasAnyOperatorName(
"==",
"!="),
54 hasOperands(ignoringParenImpCasts(ZeroLiteral),
55 ignoringParenImpCasts(StringFind.bind(
"findexpr"))))
61 const ASTContext &Context = *Result.Context;
62 const SourceManager &Source = Context.getSourceManager();
65 const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>(
"expr");
66 assert(ComparisonExpr !=
nullptr);
67 const auto *Needle = Result.Nodes.getNodeAs<Expr>(
"needle");
68 assert(Needle !=
nullptr);
69 const Expr *Haystack = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"findexpr")
70 ->getImplicitObjectArgument();
71 assert(Haystack !=
nullptr);
73 if (ComparisonExpr->getBeginLoc().isMacroID())
78 const StringRef NeedleExprCode = Lexer::getSourceText(
79 CharSourceRange::getTokenRange(Needle->getSourceRange()), Source,
80 Context.getLangOpts());
81 const StringRef HaystackExprCode = Lexer::getSourceText(
82 CharSourceRange::getTokenRange(Haystack->getSourceRange()), Source,
83 Context.getLangOpts());
86 bool Neg = ComparisonExpr->getOpcodeStr() ==
"!=";
87 StringRef StartswithStr;
89 StartswithStr =
"!absl::StartsWith";
91 StartswithStr =
"absl::StartsWith";
96 diag(ComparisonExpr->getBeginLoc(),
97 (StringRef(
"use ") + StartswithStr +
" instead of find() " +
98 ComparisonExpr->getOpcodeStr() +
" 0")
102 ComparisonExpr->getSourceRange(),
103 (StartswithStr +
"(" + HaystackExprCode +
", " + NeedleExprCode +
")")
108 Diagnostic << IncludeInserter->CreateIncludeInsertion(
109 Source.getFileID(ComparisonExpr->getBeginLoc()), AbseilStringsMatchHeader,
114 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
115 IncludeInserter = std::make_unique<utils::IncludeInserter>(SM,
getLangOpts(),
117 PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks());
125 Options.
store(Opts,
"AbseilStringsMatchHeader", AbseilStringsMatchHeader);