clang-tools 22.0.0git
StringFindStrContainsCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
14#include "clang/Tooling/Transformer/RewriteRule.h"
15#include "clang/Tooling/Transformer/Stencil.h"
16
17// FixItHint - Hint to check documentation script to mark this check as
18// providing a FixIt.
19
20using namespace clang::ast_matchers;
21
22namespace clang::tidy::abseil {
23
24using ::clang::transformer::addInclude;
25using ::clang::transformer::applyFirst;
26using ::clang::transformer::cat;
27using ::clang::transformer::changeTo;
28using ::clang::transformer::makeRule;
29using ::clang::transformer::node;
30using ::clang::transformer::RewriteRuleWith;
31
32namespace {
33AST_MATCHER(Type, isCharType) { return Node.isCharType(); }
34} // namespace
35
36static constexpr char DefaultStringLikeClasses[] = "::std::basic_string;"
37 "::std::basic_string_view;"
38 "::absl::string_view";
39static constexpr char DefaultAbseilStringsMatchHeader[] =
40 "absl/strings/match.h";
41
42static transformer::RewriteRuleWith<std::string>
43makeRewriteRule(ArrayRef<StringRef> StringLikeClassNames,
44 StringRef AbseilStringsMatchHeader) {
45 auto StringLikeClass = cxxRecordDecl(hasAnyName(StringLikeClassNames));
46 auto StringType =
47 hasUnqualifiedDesugaredType(recordType(hasDeclaration(StringLikeClass)));
48 auto CharStarType =
49 hasUnqualifiedDesugaredType(pointerType(pointee(isAnyCharacter())));
50 auto CharType = hasUnqualifiedDesugaredType(isCharType());
51 auto StringNpos = declRefExpr(
52 to(varDecl(hasName("npos"), hasDeclContext(StringLikeClass))));
53 auto StringFind = cxxMemberCallExpr(
54 callee(cxxMethodDecl(
55 hasName("find"), parameterCountIs(2),
56 hasParameter(
57 0, parmVarDecl(anyOf(hasType(StringType), hasType(CharStarType),
58 hasType(CharType)))))),
59 on(hasType(StringType)), hasArgument(0, expr().bind("parameter_to_find")),
60 anyOf(hasArgument(1, integerLiteral(equals(0))),
61 hasArgument(1, cxxDefaultArgExpr())),
62 onImplicitObjectArgument(expr().bind("string_being_searched")));
63
64 RewriteRuleWith<std::string> Rule = applyFirst(
65 {makeRule(
66 binaryOperator(hasOperatorName("=="),
67 hasOperands(ignoringParenImpCasts(StringNpos),
68 ignoringParenImpCasts(StringFind))),
69 {changeTo(cat("!absl::StrContains(", node("string_being_searched"),
70 ", ", node("parameter_to_find"), ")")),
71 addInclude(AbseilStringsMatchHeader)},
72 cat("use !absl::StrContains instead of find() == npos")),
73 makeRule(
74 binaryOperator(hasOperatorName("!="),
75 hasOperands(ignoringParenImpCasts(StringNpos),
76 ignoringParenImpCasts(StringFind))),
77 {changeTo(cat("absl::StrContains(", node("string_being_searched"),
78 ", ", node("parameter_to_find"), ")")),
79 addInclude(AbseilStringsMatchHeader)},
80 cat("use absl::StrContains instead "
81 "of find() != npos"))});
82 return Rule;
83}
84
86 StringRef Name, ClangTidyContext *Context)
87 : TransformerClangTidyCheck(Name, Context),
88 StringLikeClassesOption(utils::options::parseStringList(
89 Options.get("StringLikeClasses", DefaultStringLikeClasses))),
90 AbseilStringsMatchHeaderOption(Options.get(
91 "AbseilStringsMatchHeader", DefaultAbseilStringsMatchHeader)) {
92 setRule(
93 makeRewriteRule(StringLikeClassesOption, AbseilStringsMatchHeaderOption));
94}
95
97 const LangOptions &LangOpts) const {
98 return LangOpts.CPlusPlus11;
99}
100
103 TransformerClangTidyCheck::storeOptions(Opts);
104 Options.store(Opts, "StringLikeClasses",
105 utils::options::serializeStringList(StringLikeClassesOption));
106 Options.store(Opts, "AbseilStringsMatchHeader",
107 AbseilStringsMatchHeaderOption);
108}
109
110} // namespace clang::tidy::abseil
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
StringFindStrContainsCheck(StringRef Name, ClangTidyContext *Context)
void setRule(transformer::RewriteRuleWith< std::string > R)
Set the rule that this check implements.
TransformerClangTidyCheck(StringRef Name, ClangTidyContext *Context)
static transformer::RewriteRuleWith< std::string > makeRewriteRule(ArrayRef< StringRef > StringLikeClassNames, StringRef AbseilStringsMatchHeader)
static constexpr char DefaultAbseilStringsMatchHeader[]
AST_MATCHER(BinaryOperator, isRelationalOperator)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap