================ @@ -0,0 +1,419 @@ +//===----------------------------------------------------------------------===// +// +// 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 "UseStructuredBindingCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "../utils/OptionsUtils.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +static constexpr const char *DefaultPairTypes = "std::pair"; +static constexpr llvm::StringLiteral PairDeclName = "PairVarD"; +static constexpr llvm::StringLiteral PairVarTypeName = "PairVarType"; +static constexpr llvm::StringLiteral FirstVarDeclName = "FirstVarDecl"; +static constexpr llvm::StringLiteral SecondVarDeclName = "SecondVarDecl"; +static constexpr llvm::StringLiteral FirstDeclStmtName = "FirstDeclStmt"; +static constexpr llvm::StringLiteral SecondDeclStmtName = "SecondDeclStmt"; +static constexpr llvm::StringLiteral FirstTypeName = "FirstType"; +static constexpr llvm::StringLiteral SecondTypeName = "SecondType"; +static constexpr llvm::StringLiteral ScopeBlockName = "ScopeBlock"; +static constexpr llvm::StringLiteral StdTieAssignStmtName = "StdTieAssign"; +static constexpr llvm::StringLiteral StdTieExprName = "StdTieExpr"; +static constexpr llvm::StringLiteral ForRangeStmtName = "ForRangeStmt"; + +/// Try to match exactly two VarDecl inside two DeclStmts, and set binding for +/// the used DeclStmts. +static bool +matchTwoVarDecl(const DeclStmt *DS1, const DeclStmt *DS2, + ast_matchers::internal::Matcher<VarDecl> InnerMatcher1, + ast_matchers::internal::Matcher<VarDecl> InnerMatcher2, + internal::ASTMatchFinder *Finder, + internal::BoundNodesTreeBuilder *Builder) { + SmallVector<std::pair<const VarDecl *, const DeclStmt *>, 2> Vars; + auto CollectVarsInDeclStmt = [&Vars](const DeclStmt *DS) -> bool { + if (!DS) + return true; + + for (const auto *VD : DS->decls()) { + if (Vars.size() == 2) + return false; + + if (const auto *Var = dyn_cast<VarDecl>(VD)) + Vars.emplace_back(Var, DS); + else + return false; + } + + return true; + }; + + // If we already get two VarDecls, then don't need to collect from DS2. + if (!CollectVarsInDeclStmt(DS1) || + (Vars.size() != 2 && !CollectVarsInDeclStmt(DS2)) || Vars.size() != 2) + return false; + + if (InnerMatcher1.matches(*Vars[0].first, Finder, Builder) && + InnerMatcher2.matches(*Vars[1].first, Finder, Builder)) { + Builder->setBinding(FirstDeclStmtName, + clang::DynTypedNode::create(*Vars[0].second)); + if (Vars[0].second != Vars[1].second) + Builder->setBinding(SecondDeclStmtName, + clang::DynTypedNode::create(*Vars[1].second)); + return true; + } + + return false; +} + +namespace { +/// What qualifiers and specifiers are used to create structured binding +/// declaration, it only supports the following four cases now. +enum TransferType : uint8_t { + TT_ByVal, + TT_ByConstVal, + TT_ByRef, + TT_ByConstRef +}; + +/// Matches a Stmt whose parent is a CompoundStmt, and which is directly +/// following two VarDecls matching the inner matcher, at the same time set +/// binding for the CompoundStmt. +AST_MATCHER_P2(Stmt, hasPreTwoVarDecl, ast_matchers::internal::Matcher<VarDecl>, + InnerMatcher1, ast_matchers::internal::Matcher<VarDecl>, + InnerMatcher2) { + 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(llvm::make_range(C->body_rbegin(), C->body_rend()), &Node); + assert(I != C->body_rend() && "C is parent of Node"); + if ((I + 1) == C->body_rend()) + return false; + + const auto *DS2 = dyn_cast<DeclStmt>(*(I + 1)); + if (!DS2) + return false; + + const DeclStmt *DS1 = (!DS2->isSingleDecl() || ((I + 2) == C->body_rend()) + ? nullptr + : dyn_cast<DeclStmt>(*(I + 2))); + if (DS1 && !DS1->isSingleDecl()) + return false; ---------------- flovent wrote:
``` if (DS1 && !DS1->isSingleDecl()) return false; ``` This code is added in latest commit to avoid: ``` int a, b; XYZ otherV = call(); std::tie(a, b) = ...; // Should not warn ``` Because we should accpet that in other two cases, so i handle it specificly in `hasPreTwoVarDecl`: ``` Pair p = ...; // warn int a = p.first, b = p.second; XYZ otherV = call(); ``` But when i look at these lines of code again, it's a bit complicated indeed, i'll see how to make it more clear. https://github.com/llvm/llvm-project/pull/158462 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits