================ @@ -0,0 +1,409 @@ +//===----------------------------------------------------------------------===// +// +// 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 "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +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 BeginDeclStmtName = "BeginDeclStmt"; +static constexpr llvm::StringLiteral EndDeclStmtName = "EndDeclStmt"; +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"; +static constexpr llvm::StringLiteral InitExprName = "init_expr"; + +/// Matches a sequence of VarDecls matching the inner matchers, starting from +/// the \p Iter to \p EndIter and set bindings for the first DeclStmt and the +/// last DeclStmt if matched. +/// +/// \p Backwards indicates whether to match the VarDecls in reverse order. +template <typename Iterator> +static bool matchNVarDeclStartingWith( + Iterator Iter, Iterator EndIter, + ArrayRef<ast_matchers::internal::Matcher<VarDecl>> InnerMatchers, + ast_matchers::internal::ASTMatchFinder *Finder, + ast_matchers::internal::BoundNodesTreeBuilder *Builder, + bool Backwards = false) { + const DeclStmt *BeginDS = nullptr; + const DeclStmt *EndDS = nullptr; + size_t N = InnerMatchers.size(); + size_t Count = 0; + for (; Iter != EndIter; ++Iter) { + EndDS = dyn_cast<DeclStmt>(*Iter); + if (!EndDS) + break; + + if (!BeginDS) + BeginDS = EndDS; + + auto Matches = [&](const Decl *VD) { + // We don't want redundant decls in DeclStmt. + if (Count == N) + return false; + + if (const auto *Var = dyn_cast<VarDecl>(VD); + Var && InnerMatchers[Backwards ? N - Count - 1 : Count].matches( + *Var, Finder, Builder)) { + ++Count; + return true; + } + + return false; + }; + + if (Backwards) { + for (const auto *VD : llvm::reverse(EndDS->decls())) { + if (!Matches(VD)) + return false; + } + } else { + for (const auto *VD : EndDS->decls()) { + if (!Matches(VD)) + return false; + } + } + + // All the matchers is satisfied in those DeclStmts. + if (Count == N) { + Builder->setBinding( + BeginDeclStmtName, + clang::DynTypedNode::create(Backwards ? *EndDS : *BeginDS)); + Builder->setBinding(EndDeclStmtName, clang::DynTypedNode::create( + Backwards ? *BeginDS : *EndDS)); + 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. +AST_MATCHER_P(Stmt, hasPreTwoVarDecl, + llvm::SmallVector<ast_matchers::internal::Matcher<VarDecl>>, + InnerMatchers) { + const DynTypedNodeList Parents = Finder->getASTContext().getParents(Node); + if (Parents.size() != 1) + return false; + + const auto *C = Parents[0].get<CompoundStmt>(); + if (!C) + return false; + + const auto I = llvm::find(llvm::reverse(C->body()), &Node); + assert(I != C->body_rend() && "C is parent of Node"); + return matchNVarDeclStartingWith(I + 1, C->body_rend(), InnerMatchers, Finder, + Builder, true); +} + +/// Matches a Stmt whose parent is a CompoundStmt, and which is directly +/// followed by two VarDecls matching the inner matcher. +AST_MATCHER_P(Stmt, hasNextTwoVarDecl, + llvm::SmallVector<ast_matchers::internal::Matcher<VarDecl>>, + InnerMatchers) { + const DynTypedNodeList Parents = Finder->getASTContext().getParents(Node); + if (Parents.size() != 1) + return false; + + const 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"); + return matchNVarDeclStartingWith(I + 1, C->body_end(), InnerMatchers, Finder, + Builder); +} + +/// Matches a CompoundStmt which has two VarDecls matching the inner matcher in +/// the beginning. +AST_MATCHER_P(CompoundStmt, hasFirstTwoVarDecl, + llvm::SmallVector<ast_matchers::internal::Matcher<VarDecl>>, + InnerMatchers) { + return matchNVarDeclStartingWith(Node.body_begin(), Node.body_end(), + InnerMatchers, Finder, Builder); +} + +/// It's not very common to have specifiers for variables used to decompose a +/// pair, so we ignore these cases. +AST_MATCHER(VarDecl, hasAnySpecifiersShouldBeIgnored) { + return Node.isStaticLocal() || Node.isConstexpr() || Node.hasAttrs() || + Node.isInlineSpecified(); +} + +// Ignore nodes inside macros. +AST_POLYMORPHIC_MATCHER(isInMarco, + AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl)) { + return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID(); +} + +AST_MATCHER_P(Expr, ignoringCopyCtorAndImplicitCast, + ast_matchers::internal::Matcher<Expr>, InnerMatcher) { + if (const auto *CtorE = dyn_cast<CXXConstructExpr>(&Node)) { + if (const auto *CtorD = CtorE->getConstructor(); ---------------- vbvictor wrote:
```suggestion if (const /*PlaceRealTypePlease*/ *CtorD = CtorE->getConstructor(); ``` 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