11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/Frontend/CompilerInstance.h" 24 StringFindStartswithCheck::StringFindStartswithCheck(StringRef
Name,
28 Options.get(
"StringLikeClasses",
"::std::basic_string"))),
29 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
30 Options.getLocalOrGlobal(
"IncludeStyle",
"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 anyOf(hasOperatorName(
"=="), hasOperatorName(
"!=")),
54 hasEitherOperand(ignoringParenImpCasts(ZeroLiteral)),
55 hasEitherOperand(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(
80 Context.getLangOpts());
81 const StringRef HaystackExprCode = Lexer::getSourceText(
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")
101 Diagnostic << FixItHint::CreateReplacement(
102 ComparisonExpr->getSourceRange(),
103 (StartswithStr +
"(" + HaystackExprCode +
", " + NeedleExprCode +
")")
108 auto IncludeHint = IncludeInserter->CreateIncludeInsertion(
109 Source.getFileID(ComparisonExpr->getBeginLoc()), AbseilStringsMatchHeader,
112 Diagnostic << *IncludeHint;
117 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
118 IncludeInserter = llvm::make_unique<utils::IncludeInserter>(SM,
getLangOpts(),
120 PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks());
129 Options.
store(Opts,
"AbseilStringsMatchHeader", AbseilStringsMatchHeader);
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.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
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.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
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.