aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
committervitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
downloadydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp')
-rw-r--r--contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp b/contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp
new file mode 100644
index 0000000000..09cddb2208
--- /dev/null
+++ b/contrib/libs/clang14/tools/extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp
@@ -0,0 +1,264 @@
+//===--- IdDependentBackwardBranchCheck.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 "IdDependentBackwardBranchCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace altera {
+
+void IdDependentBackwardBranchCheck::registerMatchers(MatchFinder *Finder) {
+ // Prototype to identify all variables which hold a thread-variant ID.
+ // First Matcher just finds all the direct assignments of either ID call.
+ const auto ThreadID = expr(hasDescendant(callExpr(callee(functionDecl(
+ anyOf(hasName("get_global_id"), hasName("get_local_id")))))));
+
+ const auto RefVarOrField = forEachDescendant(
+ stmt(anyOf(declRefExpr(to(varDecl())).bind("assign_ref_var"),
+ memberExpr(member(fieldDecl())).bind("assign_ref_field"))));
+
+ Finder->addMatcher(
+ compoundStmt(
+ // Bind on actual get_local/global_id calls.
+ forEachDescendant(
+ stmt(
+ anyOf(declStmt(hasDescendant(varDecl(hasInitializer(ThreadID))
+ .bind("tid_dep_var"))),
+ binaryOperator(allOf(
+ isAssignmentOperator(), hasRHS(ThreadID),
+ hasLHS(anyOf(
+ declRefExpr(to(varDecl().bind("tid_dep_var"))),
+ memberExpr(member(
+ fieldDecl().bind("tid_dep_field")))))))))
+ .bind("straight_assignment"))),
+ this);
+
+ // Bind all VarDecls that include an initializer with a variable DeclRefExpr
+ // (in case it is ID-dependent).
+ Finder->addMatcher(
+ stmt(forEachDescendant(
+ varDecl(hasInitializer(RefVarOrField)).bind("pot_tid_var"))),
+ this);
+
+ // Bind all VarDecls that are assigned a value with a variable DeclRefExpr (in
+ // case it is ID-dependent).
+ Finder->addMatcher(
+ stmt(forEachDescendant(binaryOperator(
+ allOf(isAssignmentOperator(), hasRHS(RefVarOrField),
+ hasLHS(anyOf(
+ declRefExpr(to(varDecl().bind("pot_tid_var"))),
+ memberExpr(member(fieldDecl().bind("pot_tid_field"))))))))),
+ this);
+
+ // Second Matcher looks for branch statements inside of loops and bind on the
+ // condition expression IF it either calls an ID function or has a variable
+ // DeclRefExpr. DeclRefExprs are checked later to confirm whether the variable
+ // is ID-dependent.
+ const auto CondExpr =
+ expr(anyOf(hasDescendant(callExpr(callee(functionDecl(
+ anyOf(hasName("get_global_id"),
+ hasName("get_local_id")))))
+ .bind("id_call")),
+ hasDescendant(stmt(anyOf(declRefExpr(to(varDecl())),
+ memberExpr(member(fieldDecl())))))))
+ .bind("cond_expr");
+ Finder->addMatcher(stmt(anyOf(forStmt(hasCondition(CondExpr)),
+ doStmt(hasCondition(CondExpr)),
+ whileStmt(hasCondition(CondExpr))))
+ .bind("backward_branch"),
+ this);
+}
+
+IdDependentBackwardBranchCheck::IdDependencyRecord *
+IdDependentBackwardBranchCheck::hasIdDepVar(const Expr *Expression) {
+ if (const auto *Declaration = dyn_cast<DeclRefExpr>(Expression)) {
+ // It is a DeclRefExpr, so check if it's an ID-dependent variable.
+ const auto *CheckVariable = dyn_cast<VarDecl>(Declaration->getDecl());
+ auto FoundVariable = IdDepVarsMap.find(CheckVariable);
+ if (FoundVariable == IdDepVarsMap.end())
+ return nullptr;
+ return &(FoundVariable->second);
+ }
+ for (const auto *Child : Expression->children())
+ if (const auto *ChildExpression = dyn_cast<Expr>(Child))
+ if (IdDependencyRecord *Result = hasIdDepVar(ChildExpression))
+ return Result;
+ return nullptr;
+}
+
+IdDependentBackwardBranchCheck::IdDependencyRecord *
+IdDependentBackwardBranchCheck::hasIdDepField(const Expr *Expression) {
+ if (const auto *MemberExpression = dyn_cast<MemberExpr>(Expression)) {
+ const auto *CheckField =
+ dyn_cast<FieldDecl>(MemberExpression->getMemberDecl());
+ auto FoundField = IdDepFieldsMap.find(CheckField);
+ if (FoundField == IdDepFieldsMap.end())
+ return nullptr;
+ return &(FoundField->second);
+ }
+ for (const auto *Child : Expression->children())
+ if (const auto *ChildExpression = dyn_cast<Expr>(Child))
+ if (IdDependencyRecord *Result = hasIdDepField(ChildExpression))
+ return Result;
+ return nullptr;
+}
+
+void IdDependentBackwardBranchCheck::saveIdDepVar(const Stmt *Statement,
+ const VarDecl *Variable) {
+ // Record that this variable is thread-dependent.
+ IdDepVarsMap[Variable] =
+ IdDependencyRecord(Variable, Variable->getBeginLoc(),
+ Twine("assignment of ID-dependent variable ") +
+ Variable->getNameAsString());
+}
+
+void IdDependentBackwardBranchCheck::saveIdDepField(const Stmt *Statement,
+ const FieldDecl *Field) {
+ // Record that this field is thread-dependent.
+ IdDepFieldsMap[Field] = IdDependencyRecord(
+ Field, Statement->getBeginLoc(),
+ Twine("assignment of ID-dependent field ") + Field->getNameAsString());
+}
+
+void IdDependentBackwardBranchCheck::saveIdDepVarFromReference(
+ const DeclRefExpr *RefExpr, const MemberExpr *MemExpr,
+ const VarDecl *PotentialVar) {
+ // If the variable is already in IdDepVarsMap, ignore it.
+ if (IdDepVarsMap.find(PotentialVar) != IdDepVarsMap.end())
+ return;
+ std::string Message;
+ llvm::raw_string_ostream StringStream(Message);
+ StringStream << "inferred assignment of ID-dependent value from "
+ "ID-dependent ";
+ if (RefExpr) {
+ const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
+ // If variable isn't ID-dependent, but RefVar is.
+ if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end())
+ StringStream << "variable " << RefVar->getNameAsString();
+ }
+ if (MemExpr) {
+ const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
+ // If variable isn't ID-dependent, but RefField is.
+ if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end())
+ StringStream << "member " << RefField->getNameAsString();
+ }
+ IdDepVarsMap[PotentialVar] =
+ IdDependencyRecord(PotentialVar, PotentialVar->getBeginLoc(), Message);
+}
+
+void IdDependentBackwardBranchCheck::saveIdDepFieldFromReference(
+ const DeclRefExpr *RefExpr, const MemberExpr *MemExpr,
+ const FieldDecl *PotentialField) {
+ // If the field is already in IdDepFieldsMap, ignore it.
+ if (IdDepFieldsMap.find(PotentialField) != IdDepFieldsMap.end())
+ return;
+ std::string Message;
+ llvm::raw_string_ostream StringStream(Message);
+ StringStream << "inferred assignment of ID-dependent member from "
+ "ID-dependent ";
+ if (RefExpr) {
+ const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
+ // If field isn't ID-dependent, but RefVar is.
+ if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end())
+ StringStream << "variable " << RefVar->getNameAsString();
+ }
+ if (MemExpr) {
+ const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
+ if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end())
+ StringStream << "member " << RefField->getNameAsString();
+ }
+ IdDepFieldsMap[PotentialField] = IdDependencyRecord(
+ PotentialField, PotentialField->getBeginLoc(), Message);
+}
+
+IdDependentBackwardBranchCheck::LoopType
+IdDependentBackwardBranchCheck::getLoopType(const Stmt *Loop) {
+ switch (Loop->getStmtClass()) {
+ case Stmt::DoStmtClass:
+ return DoLoop;
+ case Stmt::WhileStmtClass:
+ return WhileLoop;
+ case Stmt::ForStmtClass:
+ return ForLoop;
+ default:
+ return UnknownLoop;
+ }
+}
+
+void IdDependentBackwardBranchCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ // The first half of the callback only deals with identifying and storing
+ // ID-dependency information into the IdDepVars and IdDepFields maps.
+ const auto *Variable = Result.Nodes.getNodeAs<VarDecl>("tid_dep_var");
+ const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("tid_dep_field");
+ const auto *Statement = Result.Nodes.getNodeAs<Stmt>("straight_assignment");
+ const auto *RefExpr = Result.Nodes.getNodeAs<DeclRefExpr>("assign_ref_var");
+ const auto *MemExpr = Result.Nodes.getNodeAs<MemberExpr>("assign_ref_field");
+ const auto *PotentialVar = Result.Nodes.getNodeAs<VarDecl>("pot_tid_var");
+ const auto *PotentialField =
+ Result.Nodes.getNodeAs<FieldDecl>("pot_tid_field");
+
+ // Save variables and fields assigned directly through ID function calls.
+ if (Statement && (Variable || Field)) {
+ if (Variable)
+ saveIdDepVar(Statement, Variable);
+ else if (Field)
+ saveIdDepField(Statement, Field);
+ }
+
+ // Save variables assigned to values of Id-dependent variables and fields.
+ if ((RefExpr || MemExpr) && PotentialVar)
+ saveIdDepVarFromReference(RefExpr, MemExpr, PotentialVar);
+
+ // Save fields assigned to values of ID-dependent variables and fields.
+ if ((RefExpr || MemExpr) && PotentialField)
+ saveIdDepFieldFromReference(RefExpr, MemExpr, PotentialField);
+
+ // The second part of the callback deals with checking if a branch inside a
+ // loop is thread dependent.
+ const auto *CondExpr = Result.Nodes.getNodeAs<Expr>("cond_expr");
+ const auto *IDCall = Result.Nodes.getNodeAs<CallExpr>("id_call");
+ const auto *Loop = Result.Nodes.getNodeAs<Stmt>("backward_branch");
+ if (!Loop)
+ return;
+ LoopType Type = getLoopType(Loop);
+ if (CondExpr) {
+ if (IDCall) { // Conditional expression calls an ID function directly.
+ diag(CondExpr->getBeginLoc(),
+ "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
+ "to ID function call and may cause performance degradation")
+ << Type;
+ return;
+ }
+ // Conditional expression has DeclRefExpr(s), check ID-dependency.
+ IdDependencyRecord *IdDepVar = hasIdDepVar(CondExpr);
+ IdDependencyRecord *IdDepField = hasIdDepField(CondExpr);
+ if (IdDepVar) {
+ // Change one of these to a Note
+ diag(IdDepVar->Location, IdDepVar->Message, DiagnosticIDs::Note);
+ diag(CondExpr->getBeginLoc(),
+ "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
+ "to variable reference to %1 and may cause performance degradation")
+ << Type << IdDepVar->VariableDeclaration;
+ } else if (IdDepField) {
+ diag(IdDepField->Location, IdDepField->Message, DiagnosticIDs::Note);
+ diag(CondExpr->getBeginLoc(),
+ "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
+ "to member reference to %1 and may cause performance degradation")
+ << Type << IdDepField->FieldDeclaration;
+ }
+ }
+}
+
+} // namespace altera
+} // namespace tidy
+} // namespace clang