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::RewriteRuleWith; 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::RewriteRuleWith<std::string> 43 makeRewriteRule(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 85 StringFindStrContainsCheck::StringFindStrContainsCheck( 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 96 bool StringFindStrContainsCheck::isLanguageVersionSupported( 97 const LangOptions &LangOpts) const { 98 return LangOpts.CPlusPlus11; 99 } 100 101 void StringFindStrContainsCheck::storeOptions( 102 ClangTidyOptions::OptionMap &Opts) { 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 abseil 111 } // namespace tidy 112 } // namespace clang 113