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/readability/UseAnyOfAllOfCheck.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/readability/UseAnyOfAllOfCheck.cpp')
-rw-r--r-- | contrib/libs/clang16/tools/extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp new file mode 100644 index 0000000000..7cf0e0853f --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp @@ -0,0 +1,107 @@ +//===--- UseAnyOfAllOfCheck.cpp - 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 "UseAnyOfAllOfCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" +#include "clang/Frontend/CompilerInstance.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace { +/// Matches a Stmt whose parent is a CompoundStmt, and which is directly +/// followed by a Stmt matching the inner matcher. +AST_MATCHER_P(Stmt, nextStmt, ast_matchers::internal::Matcher<Stmt>, + InnerMatcher) { + DynTypedNodeList Parents = Finder->getASTContext().getParents(Node); + if (Parents.size() != 1) + return false; + + auto *C = Parents[0].get<CompoundStmt>(); + if (!C) + return false; + + const auto *I = llvm::find(C->body(), &Node); + assert(I != C->body_end() && "C is parent of Node"); + if (++I == C->body_end()) + return false; // Node is last statement. + + return InnerMatcher.matches(**I, Finder, Builder); +} +} // namespace + +namespace tidy::readability { + +void UseAnyOfAllOfCheck::registerMatchers(MatchFinder *Finder) { + auto Returns = [](bool V) { + return returnStmt(hasReturnValue(cxxBoolLiteral(equals(V)))); + }; + + auto ReturnsButNotTrue = + returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(true))))); + auto ReturnsButNotFalse = + returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(false))))); + + Finder->addMatcher( + cxxForRangeStmt( + nextStmt(Returns(false).bind("final_return")), + hasBody(allOf(hasDescendant(Returns(true)), + unless(anyOf(hasDescendant(breakStmt()), + hasDescendant(gotoStmt()), + hasDescendant(ReturnsButNotTrue)))))) + .bind("any_of_loop"), + this); + + Finder->addMatcher( + cxxForRangeStmt( + nextStmt(Returns(true).bind("final_return")), + hasBody(allOf(hasDescendant(Returns(false)), + unless(anyOf(hasDescendant(breakStmt()), + hasDescendant(gotoStmt()), + hasDescendant(ReturnsButNotFalse)))))) + .bind("all_of_loop"), + this); +} + +static bool isViableLoop(const CXXForRangeStmt &S, ASTContext &Context) { + + ExprMutationAnalyzer Mutations(*S.getBody(), Context); + if (Mutations.isMutated(S.getLoopVariable())) + return false; + const auto Matches = + match(findAll(declRefExpr().bind("decl_ref")), *S.getBody(), Context); + + return llvm::none_of(Matches, [&Mutations](auto &DeclRef) { + // TODO: allow modifications of loop-local variables + return Mutations.isMutated( + DeclRef.template getNodeAs<DeclRefExpr>("decl_ref")->getDecl()); + }); +} + +void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) { + + if (const auto *S = Result.Nodes.getNodeAs<CXXForRangeStmt>("any_of_loop")) { + if (!isViableLoop(*S, *Result.Context)) + return; + + diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::any_of()'") + << getLangOpts().CPlusPlus20; + } else if (const auto *S = + Result.Nodes.getNodeAs<CXXForRangeStmt>("all_of_loop")) { + if (!isViableLoop(*S, *Result.Context)) + return; + + diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::all_of()'") + << getLangOpts().CPlusPlus20; + } +} + +} // namespace tidy::readability +} // namespace clang |