17cfdff7bSTom Lokovic //===--- StringFindStrContainsCheck.cc - clang-tidy------------------------===// 27cfdff7bSTom Lokovic // 37cfdff7bSTom Lokovic // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47cfdff7bSTom Lokovic // See https://llvm.org/LICENSE.txt for license information. 57cfdff7bSTom Lokovic // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67cfdff7bSTom Lokovic // 77cfdff7bSTom Lokovic //===----------------------------------------------------------------------===// 87cfdff7bSTom Lokovic 97cfdff7bSTom Lokovic #include "StringFindStrContainsCheck.h" 107cfdff7bSTom Lokovic 117cfdff7bSTom Lokovic #include "../utils/OptionsUtils.h" 127cfdff7bSTom Lokovic #include "clang/AST/ASTContext.h" 137cfdff7bSTom Lokovic #include "clang/ASTMatchers/ASTMatchers.h" 147cfdff7bSTom Lokovic #include "clang/Frontend/CompilerInstance.h" 157cfdff7bSTom Lokovic #include "clang/Tooling/Transformer/RewriteRule.h" 167cfdff7bSTom Lokovic #include "clang/Tooling/Transformer/Stencil.h" 177cfdff7bSTom Lokovic 1823063296SNathan James // FixItHint - Hint to check documentation script to mark this check as 1923063296SNathan James // providing a FixIt. 2023063296SNathan James 217cfdff7bSTom Lokovic using namespace clang::ast_matchers; 227cfdff7bSTom Lokovic 237cfdff7bSTom Lokovic namespace clang { 247cfdff7bSTom Lokovic namespace tidy { 257cfdff7bSTom Lokovic namespace abseil { 267cfdff7bSTom Lokovic 279eb2284fSYitzhak Mandelbaum using ::clang::transformer::addInclude; 287cfdff7bSTom Lokovic using ::clang::transformer::applyFirst; 297cfdff7bSTom Lokovic using ::clang::transformer::cat; 309eb2284fSYitzhak Mandelbaum using ::clang::transformer::changeTo; 317cfdff7bSTom Lokovic using ::clang::transformer::makeRule; 327cfdff7bSTom Lokovic using ::clang::transformer::node; 33fdff677aSYitzhak Mandelbaum using ::clang::transformer::RewriteRule; 347cfdff7bSTom Lokovic 3516622d53SChris Kennelly AST_MATCHER(Type, isCharType) { return Node.isCharType(); } 3616622d53SChris Kennelly 377cfdff7bSTom Lokovic static const char DefaultStringLikeClasses[] = "::std::basic_string;" 387cfdff7bSTom Lokovic "::std::basic_string_view;" 397cfdff7bSTom Lokovic "::absl::string_view"; 407cfdff7bSTom Lokovic static const char DefaultAbseilStringsMatchHeader[] = "absl/strings/match.h"; 417cfdff7bSTom Lokovic 429eb2284fSYitzhak Mandelbaum static transformer::RewriteRule 439eb2284fSYitzhak Mandelbaum makeRewriteRule(const std::vector<std::string> &StringLikeClassNames, 449eb2284fSYitzhak Mandelbaum StringRef AbseilStringsMatchHeader) { 457cfdff7bSTom Lokovic auto StringLikeClass = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>( 467cfdff7bSTom Lokovic StringLikeClassNames.begin(), StringLikeClassNames.end()))); 477cfdff7bSTom Lokovic auto StringType = 487cfdff7bSTom Lokovic hasUnqualifiedDesugaredType(recordType(hasDeclaration(StringLikeClass))); 497cfdff7bSTom Lokovic auto CharStarType = 507cfdff7bSTom Lokovic hasUnqualifiedDesugaredType(pointerType(pointee(isAnyCharacter()))); 5116622d53SChris Kennelly auto CharType = hasUnqualifiedDesugaredType(isCharType()); 527cfdff7bSTom Lokovic auto StringNpos = declRefExpr( 537cfdff7bSTom Lokovic to(varDecl(hasName("npos"), hasDeclContext(StringLikeClass)))); 547cfdff7bSTom Lokovic auto StringFind = cxxMemberCallExpr( 557cfdff7bSTom Lokovic callee(cxxMethodDecl( 56*1fdb3e36STom Lokovic hasName("find"), parameterCountIs(2), 5716622d53SChris Kennelly hasParameter( 5816622d53SChris Kennelly 0, parmVarDecl(anyOf(hasType(StringType), hasType(CharStarType), 5916622d53SChris Kennelly hasType(CharType)))))), 607cfdff7bSTom Lokovic on(hasType(StringType)), hasArgument(0, expr().bind("parameter_to_find")), 617cfdff7bSTom Lokovic anyOf(hasArgument(1, integerLiteral(equals(0))), 627cfdff7bSTom Lokovic hasArgument(1, cxxDefaultArgExpr())), 637cfdff7bSTom Lokovic onImplicitObjectArgument(expr().bind("string_being_searched"))); 647cfdff7bSTom Lokovic 65ab2d3ce4SAlexander Kornienko RewriteRule Rule = applyFirst( 669eb2284fSYitzhak Mandelbaum {makeRule( 679eb2284fSYitzhak Mandelbaum binaryOperator(hasOperatorName("=="), 687cfdff7bSTom Lokovic hasOperands(ignoringParenImpCasts(StringNpos), 697cfdff7bSTom Lokovic ignoringParenImpCasts(StringFind))), 709eb2284fSYitzhak Mandelbaum {changeTo(cat("!absl::StrContains(", node("string_being_searched"), 717cfdff7bSTom Lokovic ", ", node("parameter_to_find"), ")")), 729eb2284fSYitzhak Mandelbaum addInclude(AbseilStringsMatchHeader)}, 737cfdff7bSTom Lokovic cat("use !absl::StrContains instead of find() == npos")), 749eb2284fSYitzhak Mandelbaum makeRule( 759eb2284fSYitzhak Mandelbaum binaryOperator(hasOperatorName("!="), 767cfdff7bSTom Lokovic hasOperands(ignoringParenImpCasts(StringNpos), 777cfdff7bSTom Lokovic ignoringParenImpCasts(StringFind))), 789eb2284fSYitzhak Mandelbaum {changeTo(cat("absl::StrContains(", node("string_being_searched"), 797cfdff7bSTom Lokovic ", ", node("parameter_to_find"), ")")), 809eb2284fSYitzhak Mandelbaum addInclude(AbseilStringsMatchHeader)}, 819eb2284fSYitzhak Mandelbaum cat("use absl::StrContains instead " 829eb2284fSYitzhak Mandelbaum "of find() != npos"))}); 83ab2d3ce4SAlexander Kornienko return Rule; 847cfdff7bSTom Lokovic } 857cfdff7bSTom Lokovic 867cfdff7bSTom Lokovic StringFindStrContainsCheck::StringFindStrContainsCheck( 877cfdff7bSTom Lokovic StringRef Name, ClangTidyContext *Context) 889eb2284fSYitzhak Mandelbaum : TransformerClangTidyCheck(Name, Context), 897cfdff7bSTom Lokovic StringLikeClassesOption(utils::options::parseStringList( 907cfdff7bSTom Lokovic Options.get("StringLikeClasses", DefaultStringLikeClasses))), 917cfdff7bSTom Lokovic AbseilStringsMatchHeaderOption(Options.get( 929eb2284fSYitzhak Mandelbaum "AbseilStringsMatchHeader", DefaultAbseilStringsMatchHeader)) { 939eb2284fSYitzhak Mandelbaum setRule( 949eb2284fSYitzhak Mandelbaum makeRewriteRule(StringLikeClassesOption, AbseilStringsMatchHeaderOption)); 959eb2284fSYitzhak Mandelbaum } 967cfdff7bSTom Lokovic 977cfdff7bSTom Lokovic bool StringFindStrContainsCheck::isLanguageVersionSupported( 987cfdff7bSTom Lokovic const LangOptions &LangOpts) const { 997cfdff7bSTom Lokovic return LangOpts.CPlusPlus11; 1007cfdff7bSTom Lokovic } 1017cfdff7bSTom Lokovic 1027cfdff7bSTom Lokovic void StringFindStrContainsCheck::storeOptions( 1037cfdff7bSTom Lokovic ClangTidyOptions::OptionMap &Opts) { 1047cfdff7bSTom Lokovic TransformerClangTidyCheck::storeOptions(Opts); 1057cfdff7bSTom Lokovic Options.store(Opts, "StringLikeClasses", 1067cfdff7bSTom Lokovic utils::options::serializeStringList(StringLikeClassesOption)); 1077cfdff7bSTom Lokovic Options.store(Opts, "AbseilStringsMatchHeader", 1087cfdff7bSTom Lokovic AbseilStringsMatchHeaderOption); 1097cfdff7bSTom Lokovic } 1107cfdff7bSTom Lokovic 1117cfdff7bSTom Lokovic } // namespace abseil 1127cfdff7bSTom Lokovic } // namespace tidy 1137cfdff7bSTom Lokovic } // namespace clang 114