12 #include "../utils/OptionsUtils.h" 13 #include "clang/AST/ASTContext.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/Frontend/CompilerInstance.h" 25 StringFindStartswithCheck::StringFindStartswithCheck(StringRef
Name,
29 Options.get(
"StringLikeClasses",
"::std::basic_string"))),
30 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
31 Options.getLocalOrGlobal(
"IncludeStyle",
"llvm"))),
32 AbseilStringsMatchHeader(
33 Options.get(
"AbseilStringsMatchHeader",
"absl/strings/match.h")) {}
36 auto ZeroLiteral = integerLiteral(equals(0));
37 auto StringClassMatcher = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>(
38 StringLikeClasses.begin(), StringLikeClasses.end())));
39 auto StringType = hasUnqualifiedDesugaredType(
40 recordType(hasDeclaration(StringClassMatcher)));
42 auto StringFind = cxxMemberCallExpr(
44 callee(cxxMethodDecl(hasName(
"find"))),
45 on(hasType(StringType)),
47 hasArgument(0, expr().bind(
"needle")),
49 anyOf(hasArgument(1, ZeroLiteral), hasArgument(1, cxxDefaultArgExpr())));
54 anyOf(hasOperatorName(
"=="), hasOperatorName(
"!=")),
55 hasEitherOperand(ignoringParenImpCasts(ZeroLiteral)),
56 hasEitherOperand(ignoringParenImpCasts(StringFind.bind(
"findexpr"))))
62 const ASTContext &Context = *Result.Context;
63 const SourceManager &Source = Context.getSourceManager();
66 const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>(
"expr");
67 assert(ComparisonExpr !=
nullptr);
68 const auto *Needle = Result.Nodes.getNodeAs<Expr>(
"needle");
69 assert(Needle !=
nullptr);
70 const Expr *Haystack = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"findexpr")
71 ->getImplicitObjectArgument();
72 assert(Haystack !=
nullptr);
74 if (ComparisonExpr->getBeginLoc().isMacroID())
79 const StringRef NeedleExprCode = Lexer::getSourceText(
80 CharSourceRange::getTokenRange(Needle->getSourceRange()), Source,
81 Context.getLangOpts());
82 const StringRef HaystackExprCode = Lexer::getSourceText(
83 CharSourceRange::getTokenRange(Haystack->getSourceRange()), Source,
84 Context.getLangOpts());
87 bool Neg = ComparisonExpr->getOpcodeStr() ==
"!=";
88 StringRef StartswithStr;
90 StartswithStr =
"!absl::StartsWith";
92 StartswithStr =
"absl::StartsWith";
97 diag(ComparisonExpr->getBeginLoc(),
98 (StringRef(
"use ") + StartswithStr +
" instead of find() " +
99 ComparisonExpr->getOpcodeStr() +
" 0")
102 Diagnostic << FixItHint::CreateReplacement(
103 ComparisonExpr->getSourceRange(),
104 (StartswithStr +
"(" + HaystackExprCode +
", " + NeedleExprCode +
")")
109 auto IncludeHint = IncludeInserter->CreateIncludeInsertion(
110 Source.getFileID(ComparisonExpr->getBeginLoc()), AbseilStringsMatchHeader,
113 Diagnostic << *IncludeHint;
118 CompilerInstance &Compiler) {
119 IncludeInserter = llvm::make_unique<clang::tidy::utils::IncludeInserter>(
120 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
121 Compiler.getPreprocessor().addPPCallbacks(
122 IncludeInserter->CreatePPCallbacks());
131 Options.
store(Opts,
"AbseilStringsMatchHeader", AbseilStringsMatchHeader);
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
static StringRef toString(IncludeStyle Style)
Converts IncludeStyle to string representation.
Base class for all clang-tidy checks.
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.