1 //===--- StringFindStrContainsCheck.cc - clang-tidy------------------------===// 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 9 #include "StringFindStrContainsCheck.h" 10 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/Tooling/Transformer/RewriteRule.h" 16 #include "clang/Tooling/Transformer/Stencil.h" 17 18 // FixItHint - Hint to check documentation script to mark this check as 19 // providing a FixIt. 20 21 using namespace clang::ast_matchers; 22 23 namespace clang { 24 namespace tidy { 25 namespace abseil { 26 27 using ::clang::transformer::addInclude; 28 using ::clang::transformer::applyFirst; 29 using ::clang::transformer::cat; 30 using ::clang::transformer::changeTo; 31 using ::clang::transformer::makeRule; 32 using ::clang::transformer::node; 33 using ::clang::transformer::RewriteRule; 34 35 AST_MATCHER(Type, isCharType) { return Node.isCharType(); } 36 37 static const char DefaultStringLikeClasses[] = "::std::basic_string;" 38 "::std::basic_string_view;" 39 "::absl::string_view"; 40 static const char DefaultAbseilStringsMatchHeader[] = "absl/strings/match.h"; 41 42 static transformer::RewriteRule 43 makeRewriteRule(const std::vector<std::string> &StringLikeClassNames, 44 StringRef AbseilStringsMatchHeader) { 45 auto StringLikeClass = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>( 46 StringLikeClassNames.begin(), StringLikeClassNames.end()))); 47 auto StringType = 48 hasUnqualifiedDesugaredType(recordType(hasDeclaration(StringLikeClass))); 49 auto CharStarType = 50 hasUnqualifiedDesugaredType(pointerType(pointee(isAnyCharacter()))); 51 auto CharType = hasUnqualifiedDesugaredType(isCharType()); 52 auto StringNpos = declRefExpr( 53 to(varDecl(hasName("npos"), hasDeclContext(StringLikeClass)))); 54 auto StringFind = cxxMemberCallExpr( 55 callee(cxxMethodDecl( 56 hasName("find"), parameterCountIs(2), 57 hasParameter( 58 0, parmVarDecl(anyOf(hasType(StringType), hasType(CharStarType), 59 hasType(CharType)))))), 60 on(hasType(StringType)), hasArgument(0, expr().bind("parameter_to_find")), 61 anyOf(hasArgument(1, integerLiteral(equals(0))), 62 hasArgument(1, cxxDefaultArgExpr())), 63 onImplicitObjectArgument(expr().bind("string_being_searched"))); 64 65 RewriteRule Rule = applyFirst( 66 {makeRule( 67 binaryOperator(hasOperatorName("=="), 68 hasOperands(ignoringParenImpCasts(StringNpos), 69 ignoringParenImpCasts(StringFind))), 70 {changeTo(cat("!absl::StrContains(", node("string_being_searched"), 71 ", ", node("parameter_to_find"), ")")), 72 addInclude(AbseilStringsMatchHeader)}, 73 cat("use !absl::StrContains instead of find() == npos")), 74 makeRule( 75 binaryOperator(hasOperatorName("!="), 76 hasOperands(ignoringParenImpCasts(StringNpos), 77 ignoringParenImpCasts(StringFind))), 78 {changeTo(cat("absl::StrContains(", node("string_being_searched"), 79 ", ", node("parameter_to_find"), ")")), 80 addInclude(AbseilStringsMatchHeader)}, 81 cat("use absl::StrContains instead " 82 "of find() != npos"))}); 83 return Rule; 84 } 85 86 StringFindStrContainsCheck::StringFindStrContainsCheck( 87 StringRef Name, ClangTidyContext *Context) 88 : TransformerClangTidyCheck(Name, Context), 89 StringLikeClassesOption(utils::options::parseStringList( 90 Options.get("StringLikeClasses", DefaultStringLikeClasses))), 91 AbseilStringsMatchHeaderOption(Options.get( 92 "AbseilStringsMatchHeader", DefaultAbseilStringsMatchHeader)) { 93 setRule( 94 makeRewriteRule(StringLikeClassesOption, AbseilStringsMatchHeaderOption)); 95 } 96 97 bool StringFindStrContainsCheck::isLanguageVersionSupported( 98 const LangOptions &LangOpts) const { 99 return LangOpts.CPlusPlus11; 100 } 101 102 void StringFindStrContainsCheck::storeOptions( 103 ClangTidyOptions::OptionMap &Opts) { 104 TransformerClangTidyCheck::storeOptions(Opts); 105 Options.store(Opts, "StringLikeClasses", 106 utils::options::serializeStringList(StringLikeClassesOption)); 107 Options.store(Opts, "AbseilStringsMatchHeader", 108 AbseilStringsMatchHeaderOption); 109 } 110 111 } // namespace abseil 112 } // namespace tidy 113 } // namespace clang 114