diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp')
-rw-r--r-- | contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp new file mode 100644 index 0000000000..7effb8250a --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/abseil/StringFindStartswithCheck.cpp @@ -0,0 +1,143 @@ +//===--- StringFindStartswithCheck.cc - clang-tidy---------------*- C++ -*-===// +// +// 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 "StringFindStartswithCheck.h" + +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::abseil { + +StringFindStartswithCheck::StringFindStartswithCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StringLikeClasses(utils::options::parseStringList( + Options.get("StringLikeClasses", "::std::basic_string"))), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()), + AbseilStringsMatchHeader( + Options.get("AbseilStringsMatchHeader", "absl/strings/match.h")) {} + +void StringFindStartswithCheck::registerMatchers(MatchFinder *Finder) { + auto ZeroLiteral = integerLiteral(equals(0)); + auto StringClassMatcher = cxxRecordDecl(hasAnyName(StringLikeClasses)); + auto StringType = hasUnqualifiedDesugaredType( + recordType(hasDeclaration(StringClassMatcher))); + + auto StringFind = cxxMemberCallExpr( + // .find()-call on a string... + callee(cxxMethodDecl(hasName("find")).bind("findfun")), + on(hasType(StringType)), + // ... with some search expression ... + hasArgument(0, expr().bind("needle")), + // ... and either "0" as second argument or the default argument (also 0). + anyOf(hasArgument(1, ZeroLiteral), hasArgument(1, cxxDefaultArgExpr()))); + + Finder->addMatcher( + // Match [=!]= with a zero on one side and a string.find on the other. + binaryOperator( + hasAnyOperatorName("==", "!="), + hasOperands(ignoringParenImpCasts(ZeroLiteral), + ignoringParenImpCasts(StringFind.bind("findexpr")))) + .bind("expr"), + this); + + auto StringRFind = cxxMemberCallExpr( + // .rfind()-call on a string... + callee(cxxMethodDecl(hasName("rfind")).bind("findfun")), + on(hasType(StringType)), + // ... with some search expression ... + hasArgument(0, expr().bind("needle")), + // ... and "0" as second argument. + hasArgument(1, ZeroLiteral)); + + Finder->addMatcher( + // Match [=!]= with either a zero or npos on one side and a string.rfind + // on the other. + binaryOperator( + hasAnyOperatorName("==", "!="), + hasOperands(ignoringParenImpCasts(ZeroLiteral), + ignoringParenImpCasts(StringRFind.bind("findexpr")))) + .bind("expr"), + this); +} + +void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) { + const ASTContext &Context = *Result.Context; + const SourceManager &Source = Context.getSourceManager(); + + // Extract matching (sub)expressions + const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr"); + assert(ComparisonExpr != nullptr); + const auto *Needle = Result.Nodes.getNodeAs<Expr>("needle"); + assert(Needle != nullptr); + const Expr *Haystack = Result.Nodes.getNodeAs<CXXMemberCallExpr>("findexpr") + ->getImplicitObjectArgument(); + assert(Haystack != nullptr); + const CXXMethodDecl *FindFun = + Result.Nodes.getNodeAs<CXXMethodDecl>("findfun"); + assert(FindFun != nullptr); + + bool Rev = FindFun->getName().contains("rfind"); + + if (ComparisonExpr->getBeginLoc().isMacroID()) + return; + + // Get the source code blocks (as characters) for both the string object + // and the search expression + const StringRef NeedleExprCode = Lexer::getSourceText( + CharSourceRange::getTokenRange(Needle->getSourceRange()), Source, + Context.getLangOpts()); + const StringRef HaystackExprCode = Lexer::getSourceText( + CharSourceRange::getTokenRange(Haystack->getSourceRange()), Source, + Context.getLangOpts()); + + // Create the StartsWith string, negating if comparison was "!=". + bool Neg = ComparisonExpr->getOpcode() == BO_NE; + + // Create the warning message and a FixIt hint replacing the original expr. + auto Diagnostic = + diag(ComparisonExpr->getBeginLoc(), + "use %select{absl::StartsWith|!absl::StartsWith}0 " + "instead of %select{find()|rfind()}1 %select{==|!=}0 0") + << Neg << Rev; + + Diagnostic << FixItHint::CreateReplacement( + ComparisonExpr->getSourceRange(), + ((Neg ? "!absl::StartsWith(" : "absl::StartsWith(") + HaystackExprCode + + ", " + NeedleExprCode + ")") + .str()); + + // Create a preprocessor #include FixIt hint (createIncludeInsertion checks + // whether this already exists). + Diagnostic << IncludeInserter.createIncludeInsertion( + Source.getFileID(ComparisonExpr->getBeginLoc()), + AbseilStringsMatchHeader); +} + +void StringFindStartswithCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void StringFindStartswithCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "StringLikeClasses", + utils::options::serializeStringList(StringLikeClasses)); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); + Options.store(Opts, "AbseilStringsMatchHeader", AbseilStringsMatchHeader); +} + +} // namespace clang::tidy::abseil |