| //===--- StringFindStrContainsCheck.cc - clang-tidy------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "StringFindStrContainsCheck.h" |
| |
| #include "../utils/OptionsUtils.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/ASTMatchers/ASTMatchers.h" |
| #include "clang/Frontend/CompilerInstance.h" |
| #include "clang/Tooling/Transformer/RewriteRule.h" |
| #include "clang/Tooling/Transformer/Stencil.h" |
| |
| // FixItHint - Hint to check documentation script to mark this check as |
| // providing a FixIt. |
| |
| using namespace clang::ast_matchers; |
| |
| namespace clang { |
| namespace tidy { |
| namespace abseil { |
| |
| using ::clang::transformer::addInclude; |
| using ::clang::transformer::applyFirst; |
| using ::clang::transformer::cat; |
| using ::clang::transformer::changeTo; |
| using ::clang::transformer::makeRule; |
| using ::clang::transformer::node; |
| using ::clang::transformer::RewriteRule; |
| |
| AST_MATCHER(Type, isCharType) { return Node.isCharType(); } |
| |
| static const char DefaultStringLikeClasses[] = "::std::basic_string;" |
| "::std::basic_string_view;" |
| "::absl::string_view"; |
| static const char DefaultAbseilStringsMatchHeader[] = "absl/strings/match.h"; |
| |
| static transformer::RewriteRule |
| makeRewriteRule(const std::vector<std::string> &StringLikeClassNames, |
| StringRef AbseilStringsMatchHeader) { |
| auto StringLikeClass = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>( |
| StringLikeClassNames.begin(), StringLikeClassNames.end()))); |
| auto StringType = |
| hasUnqualifiedDesugaredType(recordType(hasDeclaration(StringLikeClass))); |
| auto CharStarType = |
| hasUnqualifiedDesugaredType(pointerType(pointee(isAnyCharacter()))); |
| auto CharType = hasUnqualifiedDesugaredType(isCharType()); |
| auto StringNpos = declRefExpr( |
| to(varDecl(hasName("npos"), hasDeclContext(StringLikeClass)))); |
| auto StringFind = cxxMemberCallExpr( |
| callee(cxxMethodDecl( |
| hasName("find"), parameterCountIs(2), |
| hasParameter( |
| 0, parmVarDecl(anyOf(hasType(StringType), hasType(CharStarType), |
| hasType(CharType)))))), |
| on(hasType(StringType)), hasArgument(0, expr().bind("parameter_to_find")), |
| anyOf(hasArgument(1, integerLiteral(equals(0))), |
| hasArgument(1, cxxDefaultArgExpr())), |
| onImplicitObjectArgument(expr().bind("string_being_searched"))); |
| |
| RewriteRule Rule = applyFirst( |
| {makeRule( |
| binaryOperator(hasOperatorName("=="), |
| hasOperands(ignoringParenImpCasts(StringNpos), |
| ignoringParenImpCasts(StringFind))), |
| {changeTo(cat("!absl::StrContains(", node("string_being_searched"), |
| ", ", node("parameter_to_find"), ")")), |
| addInclude(AbseilStringsMatchHeader)}, |
| cat("use !absl::StrContains instead of find() == npos")), |
| makeRule( |
| binaryOperator(hasOperatorName("!="), |
| hasOperands(ignoringParenImpCasts(StringNpos), |
| ignoringParenImpCasts(StringFind))), |
| {changeTo(cat("absl::StrContains(", node("string_being_searched"), |
| ", ", node("parameter_to_find"), ")")), |
| addInclude(AbseilStringsMatchHeader)}, |
| cat("use absl::StrContains instead " |
| "of find() != npos"))}); |
| return Rule; |
| } |
| |
| StringFindStrContainsCheck::StringFindStrContainsCheck( |
| StringRef Name, ClangTidyContext *Context) |
| : TransformerClangTidyCheck(Name, Context), |
| StringLikeClassesOption(utils::options::parseStringList( |
| Options.get("StringLikeClasses", DefaultStringLikeClasses))), |
| AbseilStringsMatchHeaderOption(Options.get( |
| "AbseilStringsMatchHeader", DefaultAbseilStringsMatchHeader)) { |
| setRule( |
| makeRewriteRule(StringLikeClassesOption, AbseilStringsMatchHeaderOption)); |
| } |
| |
| bool StringFindStrContainsCheck::isLanguageVersionSupported( |
| const LangOptions &LangOpts) const { |
| return LangOpts.CPlusPlus11; |
| } |
| |
| void StringFindStrContainsCheck::storeOptions( |
| ClangTidyOptions::OptionMap &Opts) { |
| TransformerClangTidyCheck::storeOptions(Opts); |
| Options.store(Opts, "StringLikeClasses", |
| utils::options::serializeStringList(StringLikeClassesOption)); |
| Options.store(Opts, "AbseilStringsMatchHeader", |
| AbseilStringsMatchHeaderOption); |
| } |
| |
| } // namespace abseil |
| } // namespace tidy |
| } // namespace clang |