StringFindStrContainsCheck.cpp 4.6 KB

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