xref: /llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStrContainsCheck.cpp (revision 11a411a49b62c129bba551df4587dd446fcdc660)
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 
237d2ea6c4SCarlos Galvez namespace clang::tidy::abseil {
247cfdff7bSTom Lokovic 
259eb2284fSYitzhak Mandelbaum using ::clang::transformer::addInclude;
267cfdff7bSTom Lokovic using ::clang::transformer::applyFirst;
277cfdff7bSTom Lokovic using ::clang::transformer::cat;
289eb2284fSYitzhak Mandelbaum using ::clang::transformer::changeTo;
297cfdff7bSTom Lokovic using ::clang::transformer::makeRule;
307cfdff7bSTom Lokovic using ::clang::transformer::node;
319edeceaeSEric Li using ::clang::transformer::RewriteRuleWith;
327cfdff7bSTom Lokovic 
AST_MATCHER(Type,isCharType)33b6f6be4bSPiotr Zegar AST_MATCHER(Type, isCharType) { return Node.isCharType(); }
34b6f6be4bSPiotr Zegar 
35*11a411a4SPiotr Zegar static const char DefaultStringLikeClasses[] = "::std::basic_string;"
367cfdff7bSTom Lokovic                                                "::std::basic_string_view;"
377cfdff7bSTom Lokovic                                                "::absl::string_view";
38*11a411a4SPiotr Zegar static const char DefaultAbseilStringsMatchHeader[] = "absl/strings/match.h";
397cfdff7bSTom Lokovic 
409edeceaeSEric Li static transformer::RewriteRuleWith<std::string>
makeRewriteRule(ArrayRef<StringRef> StringLikeClassNames,StringRef AbseilStringsMatchHeader)4112cb5405SNathan James makeRewriteRule(ArrayRef<StringRef> StringLikeClassNames,
429eb2284fSYitzhak Mandelbaum                 StringRef AbseilStringsMatchHeader) {
4312cb5405SNathan James   auto StringLikeClass = cxxRecordDecl(hasAnyName(StringLikeClassNames));
447cfdff7bSTom Lokovic   auto StringType =
457cfdff7bSTom Lokovic       hasUnqualifiedDesugaredType(recordType(hasDeclaration(StringLikeClass)));
467cfdff7bSTom Lokovic   auto CharStarType =
477cfdff7bSTom Lokovic       hasUnqualifiedDesugaredType(pointerType(pointee(isAnyCharacter())));
4816622d53SChris Kennelly   auto CharType = hasUnqualifiedDesugaredType(isCharType());
497cfdff7bSTom Lokovic   auto StringNpos = declRefExpr(
507cfdff7bSTom Lokovic       to(varDecl(hasName("npos"), hasDeclContext(StringLikeClass))));
517cfdff7bSTom Lokovic   auto StringFind = cxxMemberCallExpr(
527cfdff7bSTom Lokovic       callee(cxxMethodDecl(
531fdb3e36STom Lokovic           hasName("find"), parameterCountIs(2),
5416622d53SChris Kennelly           hasParameter(
5516622d53SChris Kennelly               0, parmVarDecl(anyOf(hasType(StringType), hasType(CharStarType),
5616622d53SChris Kennelly                                    hasType(CharType)))))),
577cfdff7bSTom Lokovic       on(hasType(StringType)), hasArgument(0, expr().bind("parameter_to_find")),
587cfdff7bSTom Lokovic       anyOf(hasArgument(1, integerLiteral(equals(0))),
597cfdff7bSTom Lokovic             hasArgument(1, cxxDefaultArgExpr())),
607cfdff7bSTom Lokovic       onImplicitObjectArgument(expr().bind("string_being_searched")));
617cfdff7bSTom Lokovic 
629edeceaeSEric Li   RewriteRuleWith<std::string> Rule = applyFirst(
639eb2284fSYitzhak Mandelbaum       {makeRule(
649eb2284fSYitzhak Mandelbaum            binaryOperator(hasOperatorName("=="),
657cfdff7bSTom Lokovic                           hasOperands(ignoringParenImpCasts(StringNpos),
667cfdff7bSTom Lokovic                                       ignoringParenImpCasts(StringFind))),
679eb2284fSYitzhak Mandelbaum            {changeTo(cat("!absl::StrContains(", node("string_being_searched"),
687cfdff7bSTom Lokovic                          ", ", node("parameter_to_find"), ")")),
699eb2284fSYitzhak Mandelbaum             addInclude(AbseilStringsMatchHeader)},
707cfdff7bSTom Lokovic            cat("use !absl::StrContains instead of find() == npos")),
719eb2284fSYitzhak Mandelbaum        makeRule(
729eb2284fSYitzhak Mandelbaum            binaryOperator(hasOperatorName("!="),
737cfdff7bSTom Lokovic                           hasOperands(ignoringParenImpCasts(StringNpos),
747cfdff7bSTom Lokovic                                       ignoringParenImpCasts(StringFind))),
759eb2284fSYitzhak Mandelbaum            {changeTo(cat("absl::StrContains(", node("string_being_searched"),
767cfdff7bSTom Lokovic                          ", ", node("parameter_to_find"), ")")),
779eb2284fSYitzhak Mandelbaum             addInclude(AbseilStringsMatchHeader)},
789eb2284fSYitzhak Mandelbaum            cat("use absl::StrContains instead "
799eb2284fSYitzhak Mandelbaum                "of find() != npos"))});
80ab2d3ce4SAlexander Kornienko   return Rule;
817cfdff7bSTom Lokovic }
827cfdff7bSTom Lokovic 
StringFindStrContainsCheck(StringRef Name,ClangTidyContext * Context)837cfdff7bSTom Lokovic StringFindStrContainsCheck::StringFindStrContainsCheck(
847cfdff7bSTom Lokovic     StringRef Name, ClangTidyContext *Context)
859eb2284fSYitzhak Mandelbaum     : TransformerClangTidyCheck(Name, Context),
867cfdff7bSTom Lokovic       StringLikeClassesOption(utils::options::parseStringList(
87*11a411a4SPiotr Zegar           Options.get("StringLikeClasses", DefaultStringLikeClasses))),
887cfdff7bSTom Lokovic       AbseilStringsMatchHeaderOption(Options.get(
89*11a411a4SPiotr Zegar           "AbseilStringsMatchHeader", DefaultAbseilStringsMatchHeader)) {
909eb2284fSYitzhak Mandelbaum   setRule(
919eb2284fSYitzhak Mandelbaum       makeRewriteRule(StringLikeClassesOption, AbseilStringsMatchHeaderOption));
929eb2284fSYitzhak Mandelbaum }
937cfdff7bSTom Lokovic 
isLanguageVersionSupported(const LangOptions & LangOpts) const947cfdff7bSTom Lokovic bool StringFindStrContainsCheck::isLanguageVersionSupported(
957cfdff7bSTom Lokovic     const LangOptions &LangOpts) const {
967cfdff7bSTom Lokovic   return LangOpts.CPlusPlus11;
977cfdff7bSTom Lokovic }
987cfdff7bSTom Lokovic 
storeOptions(ClangTidyOptions::OptionMap & Opts)997cfdff7bSTom Lokovic void StringFindStrContainsCheck::storeOptions(
1007cfdff7bSTom Lokovic     ClangTidyOptions::OptionMap &Opts) {
1017cfdff7bSTom Lokovic   TransformerClangTidyCheck::storeOptions(Opts);
1027cfdff7bSTom Lokovic   Options.store(Opts, "StringLikeClasses",
1037cfdff7bSTom Lokovic                 utils::options::serializeStringList(StringLikeClassesOption));
1047cfdff7bSTom Lokovic   Options.store(Opts, "AbseilStringsMatchHeader",
1057cfdff7bSTom Lokovic                 AbseilStringsMatchHeaderOption);
1067cfdff7bSTom Lokovic }
1077cfdff7bSTom Lokovic 
1087d2ea6c4SCarlos Galvez } // namespace clang::tidy::abseil
109