diff options
Diffstat (limited to 'clang/lib/ASTMatchers')
-rw-r--r-- | clang/lib/ASTMatchers/ASTMatchFinder.cpp | 128 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 282 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp | 4 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Marshallers.cpp | 172 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Marshallers.h | 264 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Registry.cpp | 33 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/Dynamic/VariantValue.cpp | 11 | ||||
-rw-r--r-- | clang/lib/ASTMatchers/GtestMatchers.cpp | 104 |
8 files changed, 780 insertions, 218 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 0d1f713db8d30..e88da16dd3d40 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -43,6 +43,13 @@ typedef MatchFinder::MatchCallback MatchCallback; // optimize this on. static const unsigned MaxMemoizationEntries = 10000; +enum class MatchType { + Ancestors, + + Descendants, + Child, +}; + // We use memoization to avoid running the same matcher on the same // AST node twice. This struct is the key for looking up match // result. It consists of an ID of the MatcherInterface (for @@ -57,14 +64,15 @@ static const unsigned MaxMemoizationEntries = 10000; // provides enough benefit for the additional amount of code. struct MatchKey { DynTypedMatcher::MatcherIDType MatcherID; - ast_type_traits::DynTypedNode Node; + DynTypedNode Node; BoundNodesTreeBuilder BoundNodes; - ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs; + TraversalKind Traversal = TK_AsIs; + MatchType Type; bool operator<(const MatchKey &Other) const { - return std::tie(MatcherID, Node, BoundNodes, Traversal) < - std::tie(Other.MatcherID, Other.Node, Other.BoundNodes, - Other.Traversal); + return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) < + std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node, + Other.BoundNodes); } }; @@ -87,8 +95,7 @@ public: // matching the descendants. MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, int MaxDepth, - ast_type_traits::TraversalKind Traversal, - ASTMatchFinder::BindKind Bind) + TraversalKind Traversal, ASTMatchFinder::BindKind Bind) : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0), MaxDepth(MaxDepth), Traversal(Traversal), Bind(Bind), Matches(false) {} @@ -103,7 +110,7 @@ public: // Traverse*(c) for each child c of 'node'. // - Traverse*(c) in turn calls Traverse(c), completing the // recursion. - bool findMatch(const ast_type_traits::DynTypedNode &DynNode) { + bool findMatch(const DynTypedNode &DynNode) { reset(); if (const Decl *D = DynNode.get<Decl>()) traverse(*D); @@ -143,14 +150,16 @@ public: Stmt *StmtToTraverse = StmtNode; if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) { auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode); - if (LambdaNode && Finder->getASTContext().getTraversalKind() == - ast_type_traits::TK_IgnoreUnlessSpelledInSource) + if (LambdaNode && + Finder->getASTContext().getParentMapContext().getTraversalKind() == + TK_IgnoreUnlessSpelledInSource) StmtToTraverse = LambdaNode; else - StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode); + StmtToTraverse = + Finder->getASTContext().getParentMapContext().traverseIgnored( + ExprNode); } - if (Traversal == - ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) { + if (Traversal == TraversalKind::TK_IgnoreImplicitCastsAndParentheses) { if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) StmtToTraverse = ExprNode->IgnoreParenImpCasts(); } @@ -216,8 +225,8 @@ public: return traverse(*CtorInit); } bool TraverseLambdaExpr(LambdaExpr *Node) { - if (Finder->getASTContext().getTraversalKind() != - ast_type_traits::TK_IgnoreUnlessSpelledInSource) + if (Finder->getASTContext().getParentMapContext().getTraversalKind() != + TK_IgnoreUnlessSpelledInSource) return VisitorBase::TraverseLambdaExpr(Node); if (!Node) return true; @@ -308,7 +317,7 @@ private: } if (Bind != ASTMatchFinder::BK_All) { BoundNodesTreeBuilder RecursiveBuilder(*Builder); - if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder, + if (Matcher->matches(DynTypedNode::create(Node), Finder, &RecursiveBuilder)) { Matches = true; ResultBindings.addMatch(RecursiveBuilder); @@ -316,7 +325,7 @@ private: } } else { BoundNodesTreeBuilder RecursiveBuilder(*Builder); - if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder, + if (Matcher->matches(DynTypedNode::create(Node), Finder, &RecursiveBuilder)) { // After the first match the matcher succeeds. Matches = true; @@ -343,7 +352,7 @@ private: BoundNodesTreeBuilder ResultBindings; int CurrentDepth; const int MaxDepth; - const ast_type_traits::TraversalKind Traversal; + const TraversalKind Traversal; const ASTMatchFinder::BindKind Bind; bool Matches; }; @@ -440,12 +449,10 @@ public: bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit); // Matches children or descendants of 'Node' with 'BaseMatcher'. - bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node, - ASTContext &Ctx, + bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, - ast_type_traits::TraversalKind Traversal, - BindKind Bind) { + TraversalKind Traversal, BindKind Bind) { // For AST-nodes that don't have an identity, we can't memoize. if (!Node.getMemoizationData() || !Builder->isComparable()) return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal, @@ -456,8 +463,9 @@ public: Key.Node = Node; // Note that we key on the bindings *before* the match. Key.BoundNodes = *Builder; - Key.Traversal = Ctx.getTraversalKind(); - + Key.Traversal = Ctx.getParentMapContext().getTraversalKind(); + // Memoize result even doing a single-level match, it might be expensive. + Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants; MemoizationMap::iterator I = ResultCache.find(Key); if (I != ResultCache.end()) { *Builder = I->second.Nodes; @@ -477,11 +485,10 @@ public: } // Matches children or descendants of 'Node' with 'BaseMatcher'. - bool matchesRecursively(const ast_type_traits::DynTypedNode &Node, + bool matchesRecursively(const DynTypedNode &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, - ast_type_traits::TraversalKind Traversal, - BindKind Bind) { + TraversalKind Traversal, BindKind Bind) { MatchChildASTVisitor Visitor( &Matcher, this, Builder, MaxDepth, Traversal, Bind); return Visitor.findMatch(Node); @@ -498,10 +505,9 @@ public: bool Directly) override; // Implements ASTMatchFinder::matchesChildOf. - bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, - ASTContext &Ctx, const DynTypedMatcher &Matcher, - BoundNodesTreeBuilder *Builder, - ast_type_traits::TraversalKind Traversal, + bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, TraversalKind Traversal, BindKind Bind) override { if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); @@ -509,19 +515,18 @@ public: Bind); } // Implements ASTMatchFinder::matchesDescendantOf. - bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node, - ASTContext &Ctx, const DynTypedMatcher &Matcher, + bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) override { if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX, - ast_type_traits::TraversalKind::TK_AsIs, - Bind); + TraversalKind::TK_AsIs, Bind); } // Implements ASTMatchFinder::matchesAncestorOf. - bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node, - ASTContext &Ctx, const DynTypedMatcher &Matcher, + bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) override { // Reset the cache outside of the recursive call to make sure we @@ -534,7 +539,7 @@ public: // Matches all registered matchers on the given node and calls the // result callback for every node that matches. - void match(const ast_type_traits::DynTypedNode &Node) { + void match(const DynTypedNode &Node) { // FIXME: Improve this with a switch or a visitor pattern. if (auto *N = Node.get<Decl>()) { match(*N); @@ -612,7 +617,7 @@ private: } } - void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) { + void matchWithFilter(const DynTypedNode &DynNode) { auto Kind = DynNode.getNodeKind(); auto it = MatcherFiltersMap.find(Kind); const auto &Filter = @@ -636,8 +641,7 @@ private: } } - const std::vector<unsigned short> & - getFilterForKind(ast_type_traits::ASTNodeKind Kind) { + const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) { auto &Filter = MatcherFiltersMap[Kind]; auto &Matchers = this->Matchers->DeclOrStmt; assert((Matchers.size() < USHRT_MAX) && "Too many matchers."); @@ -652,10 +656,10 @@ private: /// @{ /// Overloads to pair the different node types to their matchers. void matchDispatch(const Decl *Node) { - return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + return matchWithFilter(DynTypedNode::create(*Node)); } void matchDispatch(const Stmt *Node) { - return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + return matchWithFilter(DynTypedNode::create(*Node)); } void matchDispatch(const Type *Node) { @@ -692,12 +696,16 @@ private: // Once there are multiple parents, the breadth first search order does not // allow simple memoization on the ancestors. Thus, we only memoize as long // as there is a single parent. - bool memoizedMatchesAncestorOfRecursively( - const ast_type_traits::DynTypedNode &Node, ASTContext &Ctx, - const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, - AncestorMatchMode MatchMode) { + bool memoizedMatchesAncestorOfRecursively(const DynTypedNode &Node, + ASTContext &Ctx, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) { // For AST-nodes that don't have an identity, we can't memoize. - if (!Builder->isComparable()) + // When doing a single-level match, we don't need to memoize because + // ParentMap (in ASTContext) already memoizes the result. + if (!Builder->isComparable() || + MatchMode == AncestorMatchMode::AMM_ParentOnly) return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder, MatchMode); @@ -705,7 +713,8 @@ private: Key.MatcherID = Matcher.getID(); Key.Node = Node; Key.BoundNodes = *Builder; - Key.Traversal = Ctx.getTraversalKind(); + Key.Traversal = Ctx.getParentMapContext().getTraversalKind(); + Key.Type = MatchType::Ancestors; // Note that we cannot use insert and reuse the iterator, as recursive // calls to match might invalidate the result cache iterators. @@ -727,8 +736,7 @@ private: return CachedResult.ResultOfMatch; } - bool matchesAncestorOfRecursively(const ast_type_traits::DynTypedNode &Node, - ASTContext &Ctx, + bool matchesAncestorOfRecursively(const DynTypedNode &Node, ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { @@ -747,7 +755,7 @@ private: return D->getKind() == Decl::TranslationUnit; })) { llvm::errs() << "Tried to match orphan node:\n"; - Node.dump(llvm::errs(), ActiveASTContext->getSourceManager()); + Node.dump(llvm::errs(), *ActiveASTContext); llvm_unreachable("Parent map should be complete!"); } #endif @@ -755,7 +763,7 @@ private: } if (Parents.size() == 1) { // Only one parent - do recursive memoization. - const ast_type_traits::DynTypedNode Parent = Parents[0]; + const DynTypedNode Parent = Parents[0]; BoundNodesTreeBuilder BuilderCopy = *Builder; if (Matcher.matches(Parent, this, &BuilderCopy)) { *Builder = std::move(BuilderCopy); @@ -770,8 +778,7 @@ private: } else { // Multiple parents - BFS over the rest of the nodes. llvm::DenseSet<const void *> Visited; - std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(), - Parents.end()); + std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end()); while (!Queue.empty()) { BoundNodesTreeBuilder BuilderCopy = *Builder; if (Matcher.matches(Queue.front(), this, &BuilderCopy)) { @@ -861,8 +868,7 @@ private: /// kind (and derived kinds) so it is a waste to try every matcher on every /// node. /// We precalculate a list of matchers that pass the toplevel restrict check. - llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>> - MatcherFiltersMap; + llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap; const MatchFinder::MatchFinderOptions &Options; ASTContext *ActiveASTContext; @@ -923,9 +929,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, if (!ClassDecl) continue; if (ClassDecl == Declaration) { - // This can happen for recursive template definitions; if the - // current declaration did not match, we can safely return false. - return false; + // This can happen for recursive template definitions. + continue; } BoundNodesTreeBuilder Result(*Builder); if (Base.matches(*ClassDecl, this, &Result)) { @@ -1137,8 +1142,7 @@ std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() { return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone); } -void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, - ASTContext &Context) { +void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) { internal::MatchASTVisitor Visitor(&Matchers, Options); Visitor.set_active_ast_context(&Context); Visitor.match(Node); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 199a6d839e2eb..4b9baf7a0e751 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -15,9 +15,11 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/PrettyPrinter.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/LLVM.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/None.h" @@ -27,6 +29,8 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -40,39 +44,56 @@ namespace ast_matchers { AST_MATCHER_P(ObjCMessageExpr, hasAnySelectorMatcher, std::vector<std::string>, Matches) { - std::string SelString = Node.getSelector().getAsString(); - for (const std::string &S : Matches) - if (S == SelString) - return true; - return false; + return llvm::is_contained(Matches, Node.getSelector().getAsString()); } namespace internal { -bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, +bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, +bool OptionallyVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); +bool matchesAnyBase(const CXXRecordDecl &Node, + const Matcher<CXXBaseSpecifier> &BaseSpecMatcher, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) { + if (!Node.hasDefinition()) + return false; + + CXXBasePaths Paths; + Paths.setOrigin(&Node); + + const auto basePredicate = + [Finder, Builder, &BaseSpecMatcher](const CXXBaseSpecifier *BaseSpec, + CXXBasePath &IgnoredParam) { + BoundNodesTreeBuilder Result(*Builder); + if (BaseSpecMatcher.matches(*BaseSpec, Finder, Builder)) { + *Builder = std::move(Result); + return true; + } + return false; + }; + + return Node.lookupInBases(basePredicate, Paths, + /*LookupInDependent =*/true); +} + void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); @@ -84,7 +105,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { namespace { using VariadicOperatorFunction = bool (*)( - const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, + const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); template <VariadicOperatorFunction Func> @@ -93,8 +114,7 @@ public: VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers) : InnerMatchers(std::move(InnerMatchers)) {} - bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, + bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return Func(DynNode, Finder, Builder, InnerMatchers); } @@ -109,16 +129,14 @@ public: IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher) : ID(ID), InnerMatcher(std::move(InnerMatcher)) {} - bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, + bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); if (Result) Builder->setBinding(ID, DynNode); return Result; } - llvm::Optional<ast_type_traits::TraversalKind> - TraversalKind() const override { + llvm::Optional<clang::TraversalKind> TraversalKind() const override { return InnerMatcher->TraversalKind(); } @@ -138,20 +156,45 @@ public: Retain(); // Reference count will never become zero. } - bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *, + bool dynMatches(const DynTypedNode &, ASTMatchFinder *, BoundNodesTreeBuilder *) const override { return true; } }; +/// A matcher that specifies a particular \c TraversalKind. +/// +/// The kind provided to the constructor overrides any kind that may be +/// specified by the `InnerMatcher`. +class DynTraversalMatcherImpl : public DynMatcherInterface { +public: + explicit DynTraversalMatcherImpl( + clang::TraversalKind TK, + IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher) + : TK(TK), InnerMatcher(std::move(InnerMatcher)) {} + + bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + llvm::Optional<clang::TraversalKind> TraversalKind() const override { + return TK; + } + +private: + clang::TraversalKind TK; + IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + } // namespace static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance; -DynTypedMatcher DynTypedMatcher::constructVariadic( - DynTypedMatcher::VariadicOperator Op, - ast_type_traits::ASTNodeKind SupportedKind, - std::vector<DynTypedMatcher> InnerMatchers) { +DynTypedMatcher +DynTypedMatcher::constructVariadic(DynTypedMatcher::VariadicOperator Op, + ASTNodeKind SupportedKind, + std::vector<DynTypedMatcher> InnerMatchers) { assert(!InnerMatchers.empty() && "Array must not be empty."); assert(llvm::all_of(InnerMatchers, [SupportedKind](const DynTypedMatcher &M) { @@ -172,8 +215,8 @@ DynTypedMatcher DynTypedMatcher::constructVariadic( // invalid types earlier and we can elide the kind checks inside the // matcher. for (auto &IM : InnerMatchers) { - RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType( - RestrictKind, IM.RestrictKind); + RestrictKind = + ASTNodeKind::getMostDerivedType(RestrictKind, IM.RestrictKind); } return DynTypedMatcher( SupportedKind, RestrictKind, @@ -204,40 +247,45 @@ DynTypedMatcher DynTypedMatcher::constructVariadic( llvm_unreachable("Invalid Op value."); } -DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper( - const DynTypedMatcher &InnerMatcher, - ast_type_traits::ASTNodeKind RestrictKind) { +DynTypedMatcher +DynTypedMatcher::constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher, + ASTNodeKind RestrictKind) { DynTypedMatcher Copy = InnerMatcher; Copy.RestrictKind = RestrictKind; return Copy; } -DynTypedMatcher DynTypedMatcher::trueMatcher( - ast_type_traits::ASTNodeKind NodeKind) { +DynTypedMatcher +DynTypedMatcher::withTraversalKind(ast_type_traits::TraversalKind TK) { + auto Copy = *this; + Copy.Implementation = + new DynTraversalMatcherImpl(TK, std::move(Copy.Implementation)); + return Copy; +} + +DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } -bool DynTypedMatcher::canMatchNodesOfKind( - ast_type_traits::ASTNodeKind Kind) const { +bool DynTypedMatcher::canMatchNodesOfKind(ASTNodeKind Kind) const { return RestrictKind.isBaseOf(Kind); } -DynTypedMatcher DynTypedMatcher::dynCastTo( - const ast_type_traits::ASTNodeKind Kind) const { +DynTypedMatcher DynTypedMatcher::dynCastTo(const ASTNodeKind Kind) const { auto Copy = *this; Copy.SupportedKind = Kind; - Copy.RestrictKind = - ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind); + Copy.RestrictKind = ASTNodeKind::getMostDerivedType(Kind, RestrictKind); return Copy; } -bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, +bool DynTypedMatcher::matches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { TraversalKindScope RAII(Finder->getASTContext(), Implementation->TraversalKind()); - auto N = Finder->getASTContext().traverseIgnored(DynNode); + auto N = + Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); if (RestrictKind.isBaseOf(N.getNodeKind()) && Implementation->dynMatches(N, Finder, Builder)) { @@ -250,13 +298,14 @@ bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, return false; } -bool DynTypedMatcher::matchesNoKindCheck( - const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { +bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { TraversalKindScope raii(Finder->getASTContext(), Implementation->TraversalKind()); - auto N = Finder->getASTContext().traverseIgnored(DynNode); + auto N = + Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); assert(RestrictKind.isBaseOf(N.getNodeKind())); if (Implementation->dynMatches(N, Finder, Builder)) { @@ -277,10 +326,10 @@ llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const { return std::move(Result); } -bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { +bool DynTypedMatcher::canConvertTo(ASTNodeKind To) const { const auto From = getSupportedKind(); - auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(); - auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>(); + auto QualKind = ASTNodeKind::getFromNodeKind<QualType>(); + auto TypeKind = ASTNodeKind::getFromNodeKind<Type>(); /// Mimic the implicit conversions of Matcher<>. /// - From Matcher<Type> to Matcher<QualType> if (From.isSame(TypeKind) && To.isSame(QualKind)) return true; @@ -292,8 +341,8 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } -bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, +bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { if (InnerMatchers.size() != 1) return false; @@ -312,22 +361,18 @@ bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, return !InnerMatchers[0].matches(DynNode, Finder, &Discard); } -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { // allOf leads to one matcher for each alternative in the first // matcher combined with each alternative in the second matcher. // Thus, we can reuse the same Builder. - for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { - if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder)) - return false; - } - return true; + return llvm::all_of(InnerMatchers, [&](const DynTypedMatcher &InnerMatcher) { + return InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder); + }); } -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { BoundNodesTreeBuilder Result; @@ -343,8 +388,7 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, return Matched; } -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, - ASTMatchFinder *Finder, +bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { @@ -357,31 +401,31 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, return false; } -bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, +bool OptionallyVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { - BoundNodesTreeBuilder Result; - for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { - BoundNodesTreeBuilder BuilderInner(*Builder); - if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) - Result.addMatch(BuilderInner); - } - *Builder = std::move(Result); + if (InnerMatchers.size() != 1) + return false; + + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatchers[0].matches(DynNode, Finder, &Result)) + *Builder = std::move(Result); return true; } inline static std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) { std::vector<std::string> Names; + Names.reserve(NameRefs.size()); for (auto *Name : NameRefs) Names.emplace_back(*Name); return Names; } Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) { - std::vector<std::string> Names = vectorFromRefs(NameRefs); - return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Names)); + return internal::Matcher<NamedDecl>( + new internal::HasNameMatcher(vectorFromRefs(NameRefs))); } Matcher<ObjCMessageExpr> hasAnySelectorFunc( @@ -389,10 +433,18 @@ Matcher<ObjCMessageExpr> hasAnySelectorFunc( return hasAnySelectorMatcher(vectorFromRefs(NameRefs)); } +HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) { + return HasOpNameMatcher(vectorFromRefs(NameRefs)); +} + +HasOverloadOpNameMatcher +hasAnyOverloadedOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) { + return HasOverloadOpNameMatcher(vectorFromRefs(NameRefs)); +} + HasNameMatcher::HasNameMatcher(std::vector<std::string> N) - : UseUnqualifiedMatch(std::all_of( - N.begin(), N.end(), - [](StringRef Name) { return Name.find("::") == Name.npos; })), + : UseUnqualifiedMatch(llvm::all_of( + N, [](StringRef Name) { return Name.find("::") == Name.npos; })), Names(std::move(N)) { #ifndef NDEBUG for (StringRef Name : Names) @@ -450,6 +502,7 @@ namespace { class PatternSet { public: PatternSet(ArrayRef<std::string> Names) { + Patterns.reserve(Names.size()); for (StringRef Name : Names) Patterns.push_back({Name, Name.startswith("::")}); } @@ -474,10 +527,10 @@ public: /// A match will be a pattern that was fully consumed, that also matches the /// 'fully qualified' requirement. bool foundMatch(bool AllowFullyQualified) const { - for (auto& P: Patterns) - if (P.P.empty() && (AllowFullyQualified || !P.IsFullyQualified)) - return true; - return false; + return llvm::any_of(Patterns, [&](const Pattern &Pattern) { + return Pattern.P.empty() && + (AllowFullyQualified || !Pattern.IsFullyQualified); + }); } private: @@ -523,7 +576,13 @@ bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const { if (Ctx->isFunctionOrMethod()) return Patterns.foundMatch(/*AllowFullyQualified=*/false); - for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) { + for (; Ctx; Ctx = Ctx->getParent()) { + // Linkage Spec can just be ignored + // FIXME: Any other DeclContext kinds that can be safely disregarded + if (isa<LinkageSpecDecl>(Ctx)) + continue; + if (!isa<NamedDecl>(Ctx)) + break; if (Patterns.foundMatch(/*AllowFullyQualified=*/false)) return true; @@ -592,6 +651,52 @@ bool HasNameMatcher::matchesNode(const NamedDecl &Node) const { return matchesNodeFullFast(Node); } +// Checks whether \p Loc points to a token with source text of \p TokenText. +static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts, + StringRef Text, SourceLocation Loc) { + llvm::SmallString<16> Buffer; + bool Invalid = false; + // Since `Loc` may point into an expansion buffer, which has no corresponding + // source, we need to look at the spelling location to read the actual source. + StringRef TokenText = Lexer::getSpelling(SM.getSpellingLoc(Loc), Buffer, SM, + LangOpts, &Invalid); + return !Invalid && Text == TokenText; +} + +llvm::Optional<SourceLocation> +getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc, + const ASTContext &Context) { + auto &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + while (Loc.isMacroID()) { + SrcMgr::ExpansionInfo Expansion = + SM.getSLocEntry(SM.getFileID(Loc)).getExpansion(); + if (Expansion.isMacroArgExpansion()) + // Check macro argument for an expansion of the given macro. For example, + // `F(G(3))`, where `MacroName` is `G`. + if (llvm::Optional<SourceLocation> ArgLoc = getExpansionLocOfMacro( + MacroName, Expansion.getSpellingLoc(), Context)) + return ArgLoc; + Loc = Expansion.getExpansionLocStart(); + if (isTokenAtLoc(SM, LangOpts, MacroName, Loc)) + return Loc; + } + return llvm::None; +} + +std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex, + llvm::Regex::RegexFlags Flags, + StringRef MatcherID) { + assert(!Regex.empty() && "Empty regex string"); + auto SharedRegex = std::make_shared<llvm::Regex>(Regex, Flags); + std::string Error; + if (!SharedRegex->isValid(Error)) { + llvm::WithColor::error() + << "building matcher '" << MatcherID << "': " << Error << "\n"; + llvm::WithColor::note() << " input was '" << Regex << "'\n"; + } + return SharedRegex; +} } // end namespace internal const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAutoreleasePoolStmt> @@ -647,6 +752,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl> const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; const internal::VariadicDynCastAllOfMatcher<Decl, EnumConstantDecl> enumConstantDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TagDecl> tagDecl; const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> cxxConversionDecl; @@ -727,6 +833,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, MaterializeTemporaryExpr> materializeTemporaryExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr> + cxxNoexceptExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, ArraySubscriptExpr> arraySubscriptExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr> @@ -768,6 +876,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, IntegerLiteral> integerLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, FloatingLiteral> floatLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, ImaginaryLiteral> imaginaryLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, FixedPointLiteral> + fixedPointLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral> userDefinedLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr> @@ -821,12 +931,18 @@ const internal::VariadicOperatorMatcherFunc< const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits<unsigned>::max()> allOf = {internal::DynTypedMatcher::VO_AllOf}; -const internal::VariadicOperatorMatcherFunc< - 1, std::numeric_limits<unsigned>::max()> - optionally = {internal::DynTypedMatcher::VO_Optionally}; +const internal::VariadicOperatorMatcherFunc<1, 1> optionally = { + internal::DynTypedMatcher::VO_Optionally}; const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, internal::hasAnyNameFunc> hasAnyName = {}; + +const internal::VariadicFunction<internal::HasOpNameMatcher, StringRef, + internal::hasAnyOperatorNameFunc> + hasAnyOperatorName = {}; +const internal::VariadicFunction<internal::HasOverloadOpNameMatcher, StringRef, + internal::hasAnyOverloadedOperatorNameFunc> + hasAnyOverloadedOperatorName = {}; const internal::VariadicFunction<internal::Matcher<ObjCMessageExpr>, StringRef, internal::hasAnySelectorFunc> hasAnySelector = {}; @@ -858,6 +974,8 @@ const AstTypeMatcher<BuiltinType> builtinType; const AstTypeMatcher<ArrayType> arrayType; const AstTypeMatcher<ComplexType> complexType; const AstTypeMatcher<ConstantArrayType> constantArrayType; +const AstTypeMatcher<DeducedTemplateSpecializationType> + deducedTemplateSpecializationType; const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType; const AstTypeMatcher<IncompleteArrayType> incompleteArrayType; const AstTypeMatcher<VariableArrayType> variableArrayType; diff --git a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp index 8656bca870ec5..88c2279afb2e3 100644 --- a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -1,4 +1,4 @@ -//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===// +//===--- Diagnostics.cpp - Helper class for error diagnostics ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -98,6 +98,8 @@ static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { return "Ambiguous matcher overload."; case Diagnostics::ET_RegistryValueNotFound: return "Value not found: $0"; + case Diagnostics::ET_RegistryUnknownEnumWithReplace: + return "Unknown value '$1' for arg $0; did you mean '$2'"; case Diagnostics::ET_ParserStringError: return "Error parsing string token: <$0>"; diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp new file mode 100644 index 0000000000000..989ee0fa75cdd --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp @@ -0,0 +1,172 @@ +//===--- Marshallers.cpp ----------------------------------------*- 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 "Marshallers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include <string> + +static llvm::Optional<std::string> +getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed, + llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) { + if (MaxEditDistance != ~0U) + ++MaxEditDistance; + llvm::StringRef Res; + for (const llvm::StringRef &Item : Allowed) { + if (Item.equals_lower(Search)) { + assert(!Item.equals(Search) && "This should be handled earlier on."); + MaxEditDistance = 1; + Res = Item; + continue; + } + unsigned Distance = Item.edit_distance(Search); + if (Distance < MaxEditDistance) { + MaxEditDistance = Distance; + Res = Item; + } + } + if (!Res.empty()) + return Res.str(); + if (!DropPrefix.empty()) { + --MaxEditDistance; // Treat dropping the prefix as 1 edit + for (const llvm::StringRef &Item : Allowed) { + auto NoPrefix = Item; + if (!NoPrefix.consume_front(DropPrefix)) + continue; + if (NoPrefix.equals_lower(Search)) { + if (NoPrefix.equals(Search)) + return Item.str(); + MaxEditDistance = 1; + Res = Item; + continue; + } + unsigned Distance = NoPrefix.edit_distance(Search); + if (Distance < MaxEditDistance) { + MaxEditDistance = Distance; + Res = Item; + } + } + if (!Res.empty()) + return Res.str(); + } + return llvm::None; +} + +llvm::Optional<std::string> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + clang::attr::Kind>::getBestGuess(const VariantValue &Value) { + static constexpr llvm::StringRef Allowed[] = { +#define ATTR(X) "attr::" #X, +#include "clang/Basic/AttrList.inc" + }; + if (Value.isString()) + return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), + "attr::"); + return llvm::None; +} + +llvm::Optional<std::string> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + clang::CastKind>::getBestGuess(const VariantValue &Value) { + static constexpr llvm::StringRef Allowed[] = { +#define CAST_OPERATION(Name) "CK_" #Name, +#include "clang/AST/OperationKinds.def" + }; + if (Value.isString()) + return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), + "CK_"); + return llvm::None; +} + +llvm::Optional<std::string> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) { + static constexpr llvm::StringRef Allowed[] = { +#define OMP_CLAUSE_CLASS(Enum, Str, Class) #Enum, +#include "llvm/Frontend/OpenMP/OMPKinds.def" + }; + if (Value.isString()) + return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), + "OMPC_"); + return llvm::None; +} + +llvm::Optional<std::string> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) { + static constexpr llvm::StringRef Allowed[] = { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, +#include "clang/Basic/TokenKinds.def" + }; + if (Value.isString()) + return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), + "UETT_"); + return llvm::None; +} + +static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags> + RegexMap[] = { + {"NoFlags", llvm::Regex::RegexFlags::NoFlags}, + {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase}, + {"Newline", llvm::Regex::RegexFlags::Newline}, + {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex}, +}; + +llvm::Optional<llvm::Regex::RegexFlags> getRegexFlag(llvm::StringRef Flag) { + for (const auto &StringFlag : RegexMap) { + if (Flag == StringFlag.first) + return StringFlag.second; + } + return llvm::None; +} + +llvm::Optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) { + for (const auto &StringFlag : RegexMap) { + if (Flag.edit_distance(StringFlag.first) < 3) + return StringFlag.first; + } + return llvm::None; +} + +llvm::Optional<llvm::Regex::RegexFlags> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) { + llvm::Optional<llvm::Regex::RegexFlags> Flag; + SmallVector<StringRef, 4> Split; + Flags.split(Split, '|', -1, false); + for (StringRef OrFlag : Split) { + if (llvm::Optional<llvm::Regex::RegexFlags> NextFlag = + getRegexFlag(OrFlag.trim())) + Flag = Flag.getValueOr(llvm::Regex::NoFlags) | *NextFlag; + else + return None; + } + return Flag; +} + +llvm::Optional<std::string> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) { + if (!Value.isString()) + return llvm::None; + SmallVector<StringRef, 4> Split; + llvm::StringRef(Value.getString()).split(Split, '|', -1, false); + for (llvm::StringRef &Flag : Split) { + if (llvm::Optional<llvm::StringRef> BestGuess = + getCloseRegexMatch(Flag.trim())) + Flag = *BestGuess; + else + return None; + } + if (Split.empty()) + return None; + return llvm::join(Split, " | "); +} diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h index 9f46108d1848d..33f6d1e4155cb 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -27,12 +27,15 @@ #include "clang/Basic/AttrKinds.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TypeTraits.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" #include <cassert> #include <cstddef> #include <iterator> @@ -64,6 +67,10 @@ template <> struct ArgTypeTraits<std::string> { static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &) { + return llvm::None; + } }; template <> @@ -80,7 +87,11 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> { } static ArgKind getKind() { - return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + return ArgKind(ASTNodeKind::getFromNodeKind<T>()); + } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &) { + return llvm::None; } }; @@ -94,6 +105,10 @@ template <> struct ArgTypeTraits<bool> { static ArgKind getKind() { return ArgKind(ArgKind::AK_Boolean); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &) { + return llvm::None; + } }; template <> struct ArgTypeTraits<double> { @@ -106,6 +121,10 @@ template <> struct ArgTypeTraits<double> { static ArgKind getKind() { return ArgKind(ArgKind::AK_Double); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &) { + return llvm::None; + } }; template <> struct ArgTypeTraits<unsigned> { @@ -118,6 +137,10 @@ template <> struct ArgTypeTraits<unsigned> { static ArgKind getKind() { return ArgKind(ArgKind::AK_Unsigned); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &) { + return llvm::None; + } }; template <> struct ArgTypeTraits<attr::Kind> { @@ -141,13 +164,15 @@ public: static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits<CastKind> { private: static Optional<CastKind> getCastKind(llvm::StringRef AttrKind) { return llvm::StringSwitch<Optional<CastKind>>(AttrKind) -#define CAST_OPERATION(Name) .Case( #Name, CK_##Name) +#define CAST_OPERATION(Name) .Case("CK_" #Name, CK_##Name) #include "clang/AST/OperationKinds.def" .Default(llvm::None); } @@ -164,15 +189,34 @@ public: static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); +}; + +template <> struct ArgTypeTraits<llvm::Regex::RegexFlags> { +private: + static Optional<llvm::Regex::RegexFlags> getFlags(llvm::StringRef Flags); + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getFlags(Value.getString()); + } + + static llvm::Regex::RegexFlags get(const VariantValue &Value) { + return *getFlags(Value.getString()); + } + + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits<OpenMPClauseKind> { private: static Optional<OpenMPClauseKind> getClauseKind(llvm::StringRef ClauseKind) { return llvm::StringSwitch<Optional<OpenMPClauseKind>>(ClauseKind) -#define OPENMP_CLAUSE(TextualSpelling, Class) \ - .Case("OMPC_" #TextualSpelling, OMPC_##TextualSpelling) -#include "clang/Basic/OpenMPKinds.def" +#define OMP_CLAUSE_CLASS(Enum, Str, Class) .Case(#Enum, llvm::omp::Clause::Enum) +#include "llvm/Frontend/OpenMP/OMPKinds.def" .Default(llvm::None); } @@ -186,6 +230,35 @@ public: } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); +}; + +template <> struct ArgTypeTraits<UnaryExprOrTypeTrait> { +private: + static Optional<UnaryExprOrTypeTrait> + getUnaryOrTypeTraitKind(llvm::StringRef ClauseKind) { + return llvm::StringSwitch<Optional<UnaryExprOrTypeTrait>>(ClauseKind) +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ + .Case("UETT_" #Name, UETT_##Name) +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ + .Case("UETT_" #Name, UETT_##Name) +#include "clang/Basic/TokenKinds.def" + .Default(llvm::None); + } + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getUnaryOrTypeTraitKind(Value.getString()); + } + + static UnaryExprOrTypeTrait get(const VariantValue &Value) { + return *getUnaryOrTypeTraitKind(Value.getString()); + } + + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); }; /// Matcher descriptor interface. @@ -211,7 +284,7 @@ public: /// set of argument types accepted for argument \p ArgNo to \p ArgKinds. // FIXME: We should provide the ability to constrain the output of this // function based on the types of other matcher arguments. - virtual void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + virtual void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &ArgKinds) const = 0; /// Returns whether this matcher is convertible to the given type. If it is @@ -221,20 +294,19 @@ public: /// same matcher overload. Zero specificity indicates that this conversion /// would produce a trivial matcher that will either always or never match. /// Such matchers are excluded from code completion results. - virtual bool isConvertibleTo( - ast_type_traits::ASTNodeKind Kind, unsigned *Specificity = nullptr, - ast_type_traits::ASTNodeKind *LeastDerivedKind = nullptr) const = 0; + virtual bool + isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity = nullptr, + ASTNodeKind *LeastDerivedKind = nullptr) const = 0; /// Returns whether the matcher will, given a matcher of any type T, yield a /// matcher of type T. virtual bool isPolymorphic() const { return false; } }; -inline bool isRetKindConvertibleTo( - ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, - ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) { - for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) { +inline bool isRetKindConvertibleTo(ArrayRef<ASTNodeKind> RetKinds, + ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) { + for (const ASTNodeKind &NodeKind : RetKinds) { if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) { if (LeastDerivedKind) *LeastDerivedKind = NodeKind; @@ -264,10 +336,10 @@ public: /// \param RetKinds The list of matcher types to which the matcher is /// convertible. /// \param ArgKinds The types of the arguments this matcher takes. - FixedArgCountMatcherDescriptor( - MarshallerType Marshaller, void (*Func)(), StringRef MatcherName, - ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, - ArrayRef<ArgKind> ArgKinds) + FixedArgCountMatcherDescriptor(MarshallerType Marshaller, void (*Func)(), + StringRef MatcherName, + ArrayRef<ASTNodeKind> RetKinds, + ArrayRef<ArgKind> ArgKinds) : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName), RetKinds(RetKinds.begin(), RetKinds.end()), ArgKinds(ArgKinds.begin(), ArgKinds.end()) {} @@ -281,14 +353,13 @@ public: bool isVariadic() const override { return false; } unsigned getNumArgs() const override { return ArgKinds.size(); } - void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ArgKinds[ArgNo]); } - bool isConvertibleTo( - ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } @@ -297,7 +368,7 @@ private: const MarshallerType Marshaller; void (* const Func)(); const std::string MatcherName; - const std::vector<ast_type_traits::ASTNodeKind> RetKinds; + const std::vector<ASTNodeKind> RetKinds; const std::vector<ArgKind> ArgKinds; }; @@ -321,7 +392,7 @@ static void mergePolyMatchers(const PolyMatcher &Poly, /// polymorphic matcher. For the former, we just construct the VariantMatcher. /// For the latter, we instantiate all the possible Matcher<T> of the poly /// matcher. -static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) { +inline VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) { return VariantMatcher::SingleMatcher(Matcher); } @@ -336,36 +407,35 @@ static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, } template <typename T> -inline void buildReturnTypeVectorFromTypeList( - std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { - RetTypes.push_back( - ast_type_traits::ASTNodeKind::getFromNodeKind<typename T::head>()); +inline void +buildReturnTypeVectorFromTypeList(std::vector<ASTNodeKind> &RetTypes) { + RetTypes.push_back(ASTNodeKind::getFromNodeKind<typename T::head>()); buildReturnTypeVectorFromTypeList<typename T::tail>(RetTypes); } template <> inline void buildReturnTypeVectorFromTypeList<ast_matchers::internal::EmptyTypeList>( - std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {} + std::vector<ASTNodeKind> &RetTypes) {} template <typename T> struct BuildReturnTypeVector { - static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { + static void build(std::vector<ASTNodeKind> &RetTypes) { buildReturnTypeVectorFromTypeList<typename T::ReturnTypes>(RetTypes); } }; template <typename T> struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T>> { - static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { - RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + static void build(std::vector<ASTNodeKind> &RetTypes) { + RetTypes.push_back(ASTNodeKind::getFromNodeKind<T>()); } }; template <typename T> struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T>> { - static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { - RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + static void build(std::vector<ASTNodeKind> &RetTypes) { + RetTypes.push_back(ASTNodeKind::getFromNodeKind<T>()); } }; @@ -439,14 +509,13 @@ public: bool isVariadic() const override { return true; } unsigned getNumArgs() const override { return 0; } - void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ArgsKind); } - bool isConvertibleTo( - ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } @@ -454,7 +523,7 @@ public: private: const RunFunc Func; const std::string MatcherName; - std::vector<ast_type_traits::ASTNodeKind> RetKinds; + std::vector<ASTNodeKind> RetKinds; const ArgKind ArgsKind; }; @@ -466,12 +535,10 @@ public: ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> Func, StringRef MatcherName) : VariadicFuncMatcherDescriptor(Func, MatcherName), - DerivedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<DerivedT>()) { - } + DerivedKind(ASTNodeKind::getFromNodeKind<DerivedT>()) {} - bool - isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { // If Kind is not a base of DerivedKind, either DerivedKind is a base of // Kind (in which case the match will always succeed) or Kind and // DerivedKind are unrelated (in which case it will always fail), so set @@ -489,7 +556,7 @@ public: } private: - const ast_type_traits::ASTNodeKind DerivedKind; + const ASTNodeKind DerivedKind; }; /// Helper macros to check the arguments on all marshaller functions. @@ -502,9 +569,16 @@ private: #define CHECK_ARG_TYPE(index, type) \ if (!ArgTypeTraits<type>::is(Args[index].Value)) { \ - Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ - << (index + 1) << ArgTypeTraits<type>::getKind().asString() \ - << Args[index].Value.getTypeAsString(); \ + if (llvm::Optional<std::string> BestGuess = \ + ArgTypeTraits<type>::getBestGuess(Args[index].Value)) { \ + Error->addError(Args[index].Range, \ + Error->ET_RegistryUnknownEnumWithReplace) \ + << index + 1 << Args[index].Value.getString() << *BestGuess; \ + } else { \ + Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ + << (index + 1) << ArgTypeTraits<type>::getKind().asString() \ + << Args[index].Value.getTypeAsString(); \ + } \ return VariantMatcher(); \ } @@ -635,7 +709,7 @@ public: return Overload0NumArgs; } - void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { for (const auto &O : Overloads) { if (O->isConvertibleTo(ThisKind)) @@ -643,9 +717,8 @@ public: } } - bool isConvertibleTo( - ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { for (const auto &O : Overloads) { if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind)) return true; @@ -657,6 +730,71 @@ private: std::vector<std::unique_ptr<MatcherDescriptor>> Overloads; }; +template <typename ReturnType> +class RegexMatcherDescriptor : public MatcherDescriptor { +public: + RegexMatcherDescriptor(ReturnType (*WithFlags)(StringRef, + llvm::Regex::RegexFlags), + ReturnType (*NoFlags)(StringRef), + ArrayRef<ASTNodeKind> RetKinds) + : WithFlags(WithFlags), NoFlags(NoFlags), + RetKinds(RetKinds.begin(), RetKinds.end()) {} + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } + + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + assert(ArgNo < 2); + Kinds.push_back(ArgKind::AK_String); + } + + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { + return isRetKindConvertibleTo(RetKinds, Kind, Specificity, + LeastDerivedKind); + } + + VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + if (Args.size() < 1 || Args.size() > 2) { + Error->addError(NameRange, Diagnostics::ET_RegistryWrongArgCount) + << "1 or 2" << Args.size(); + return VariantMatcher(); + } + if (!ArgTypeTraits<StringRef>::is(Args[0].Value)) { + Error->addError(Args[0].Range, Error->ET_RegistryWrongArgType) + << 1 << ArgTypeTraits<StringRef>::getKind().asString() + << Args[0].Value.getTypeAsString(); + return VariantMatcher(); + } + if (Args.size() == 1) { + return outvalueToVariantMatcher( + NoFlags(ArgTypeTraits<StringRef>::get(Args[0].Value))); + } + if (!ArgTypeTraits<llvm::Regex::RegexFlags>::is(Args[1].Value)) { + if (llvm::Optional<std::string> BestGuess = + ArgTypeTraits<llvm::Regex::RegexFlags>::getBestGuess( + Args[1].Value)) { + Error->addError(Args[1].Range, Error->ET_RegistryUnknownEnumWithReplace) + << 2 << Args[1].Value.getString() << *BestGuess; + } else { + Error->addError(Args[1].Range, Error->ET_RegistryWrongArgType) + << 2 << ArgTypeTraits<llvm::Regex::RegexFlags>::getKind().asString() + << Args[1].Value.getTypeAsString(); + } + return VariantMatcher(); + } + return outvalueToVariantMatcher( + WithFlags(ArgTypeTraits<StringRef>::get(Args[0].Value), + ArgTypeTraits<llvm::Regex::RegexFlags>::get(Args[1].Value))); + } + +private: + ReturnType (*const WithFlags)(StringRef, llvm::Regex::RegexFlags); + ReturnType (*const NoFlags)(StringRef); + const std::vector<ASTNodeKind> RetKinds; +}; + /// Variadic operator marshaller function. class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { public: @@ -697,13 +835,13 @@ public: bool isVariadic() const override { return true; } unsigned getNumArgs() const override { return 0; } - void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ThisKind); } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { if (Specificity) *Specificity = 1; if (LeastDerivedKind) @@ -727,7 +865,7 @@ private: template <typename ReturnType> std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) { - std::vector<ast_type_traits::ASTNodeKind> RetTypes; + std::vector<ASTNodeKind> RetTypes; BuildReturnTypeVector<ReturnType>::build(RetTypes); return std::make_unique<FixedArgCountMatcherDescriptor>( matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func), @@ -738,7 +876,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) { template <typename ReturnType, typename ArgType1> std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), StringRef MatcherName) { - std::vector<ast_type_traits::ASTNodeKind> RetTypes; + std::vector<ASTNodeKind> RetTypes; BuildReturnTypeVector<ReturnType>::build(RetTypes); ArgKind AK = ArgTypeTraits<ArgType1>::getKind(); return std::make_unique<FixedArgCountMatcherDescriptor>( @@ -751,7 +889,7 @@ template <typename ReturnType, typename ArgType1, typename ArgType2> std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2), StringRef MatcherName) { - std::vector<ast_type_traits::ASTNodeKind> RetTypes; + std::vector<ASTNodeKind> RetTypes; BuildReturnTypeVector<ReturnType>::build(RetTypes); ArgKind AKs[] = { ArgTypeTraits<ArgType1>::getKind(), ArgTypeTraits<ArgType2>::getKind() }; @@ -760,6 +898,16 @@ makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2), reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs); } +template <typename ReturnType> +std::unique_ptr<MatcherDescriptor> makeMatcherRegexMarshall( + ReturnType (*FuncFlags)(llvm::StringRef, llvm::Regex::RegexFlags), + ReturnType (*Func)(llvm::StringRef)) { + std::vector<ASTNodeKind> RetTypes; + BuildReturnTypeVector<ReturnType>::build(RetTypes); + return std::make_unique<RegexMatcherDescriptor<ReturnType>>(FuncFlags, Func, + RetTypes); +} + /// Variadic overload. template <typename ResultT, typename ArgT, ResultT (*Func)(ArrayRef<const ArgT *>)> diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 1c0930c5983a1..ec2215804c098 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -90,14 +90,14 @@ void RegistryMaps::registerMatcher( REGISTER_MATCHER_OVERLOAD(name); \ } while (false) +#define REGISTER_REGEX_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherRegexMarshall(name, name)) + /// Generate a registry map with all the known matchers. /// Please keep sorted alphabetically! RegistryMaps::RegistryMaps() { // TODO: Here is the list of the missing matchers, grouped by reason. // - // Need Variant/Parser fixes: - // ofKind - // // Polymorphic + argument overload: // findAll // @@ -124,6 +124,10 @@ RegistryMaps::RegistryMaps() { }; REGISTER_MATCHER_OVERLOAD(equals); + REGISTER_REGEX_MATCHER(isExpansionInFileMatching); + REGISTER_REGEX_MATCHER(matchesName); + REGISTER_REGEX_MATCHER(matchesSelector); + REGISTER_MATCHER(accessSpecDecl); REGISTER_MATCHER(addrLabelExpr); REGISTER_MATCHER(alignOfExpr); @@ -154,6 +158,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(characterLiteral); REGISTER_MATCHER(chooseExpr); REGISTER_MATCHER(classTemplateDecl); + REGISTER_MATCHER(classTemplatePartialSpecializationDecl); REGISTER_MATCHER(classTemplateSpecializationDecl); REGISTER_MATCHER(complexType); REGISTER_MATCHER(compoundLiteralExpr); @@ -183,6 +188,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(cxxMemberCallExpr); REGISTER_MATCHER(cxxMethodDecl); REGISTER_MATCHER(cxxNewExpr); + REGISTER_MATCHER(cxxNoexceptExpr); REGISTER_MATCHER(cxxNullPtrLiteralExpr); REGISTER_MATCHER(cxxOperatorCallExpr); REGISTER_MATCHER(cxxRecordDecl); @@ -201,6 +207,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(declStmt); REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(decltypeType); + REGISTER_MATCHER(deducedTemplateSpecializationType); REGISTER_MATCHER(defaultStmt); REGISTER_MATCHER(dependentSizedArrayType); REGISTER_MATCHER(designatedInitExpr); @@ -237,11 +244,15 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(has); REGISTER_MATCHER(hasAncestor); REGISTER_MATCHER(hasAnyArgument); + REGISTER_MATCHER(hasAnyBase); REGISTER_MATCHER(hasAnyClause); REGISTER_MATCHER(hasAnyConstructorInitializer); REGISTER_MATCHER(hasAnyDeclaration); REGISTER_MATCHER(hasAnyName); + REGISTER_MATCHER(hasAnyOperatorName); + REGISTER_MATCHER(hasAnyOverloadedOperatorName); REGISTER_MATCHER(hasAnyParameter); + REGISTER_MATCHER(hasAnyPlacementArg); REGISTER_MATCHER(hasAnySelector); REGISTER_MATCHER(hasAnySubstatement); REGISTER_MATCHER(hasAnyTemplateArgument); @@ -267,6 +278,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasDefinition); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasDirectBase); REGISTER_MATCHER(hasDynamicExceptionSpec); REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); @@ -292,6 +304,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasName); REGISTER_MATCHER(hasNullSelector); REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasOperands); REGISTER_MATCHER(hasOperatorName); REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); @@ -303,6 +316,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasReceiverType); REGISTER_MATCHER(hasReplacementType); REGISTER_MATCHER(hasReturnValue); + REGISTER_MATCHER(hasPlacementArg); REGISTER_MATCHER(hasSelector); REGISTER_MATCHER(hasSingleDecl); REGISTER_MATCHER(hasSize); @@ -347,12 +361,14 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isArray); REGISTER_MATCHER(isArrow); REGISTER_MATCHER(isAssignmentOperator); + REGISTER_MATCHER(isAtPosition); REGISTER_MATCHER(isBaseInitializer); REGISTER_MATCHER(isBitField); REGISTER_MATCHER(isCatchAll); REGISTER_MATCHER(isClass); REGISTER_MATCHER(isClassMessage); REGISTER_MATCHER(isClassMethod); + REGISTER_MATCHER(isComparisonOperator); REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isConstexpr); @@ -363,8 +379,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isDefinition); REGISTER_MATCHER(isDelegatingConstructor); REGISTER_MATCHER(isDeleted); + REGISTER_MATCHER(isEnum); REGISTER_MATCHER(isExceptionVariable); - REGISTER_MATCHER(isExpansionInFileMatching); + REGISTER_MATCHER(isExpandedFromMacro); REGISTER_MATCHER(isExpansionInMainFile); REGISTER_MATCHER(isExpansionInSystemHeader); REGISTER_MATCHER(isExplicit); @@ -372,6 +389,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isExpr); REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isFinal); + REGISTER_MATCHER(isFirstPrivateKind); REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isInStdNamespace); REGISTER_MATCHER(isInTemplateInstantiation); @@ -391,7 +409,6 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isNoReturn); REGISTER_MATCHER(isNoThrow); REGISTER_MATCHER(isNoneKind); - REGISTER_MATCHER(isOMPStructuredBlock); REGISTER_MATCHER(isOverride); REGISTER_MATCHER(isPrivate); REGISTER_MATCHER(isProtected); @@ -420,8 +437,6 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(labelStmt); REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(linkageSpecDecl); - REGISTER_MATCHER(matchesName); - REGISTER_MATCHER(matchesSelector); REGISTER_MATCHER(materializeTemporaryExpr); REGISTER_MATCHER(member); REGISTER_MATCHER(memberExpr); @@ -452,6 +467,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(objcThrowStmt); REGISTER_MATCHER(objcTryStmt); REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(ofKind); REGISTER_MATCHER(ompDefaultClause); REGISTER_MATCHER(ompExecutableDirective); REGISTER_MATCHER(on); @@ -492,6 +508,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(substTemplateTypeParmType); REGISTER_MATCHER(switchCase); REGISTER_MATCHER(switchStmt); + REGISTER_MATCHER(tagDecl); REGISTER_MATCHER(tagType); REGISTER_MATCHER(templateArgument); REGISTER_MATCHER(templateArgumentCountIs); @@ -652,7 +669,7 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) { OS << "..."; OS << ")"; - std::string TypedText = Name; + std::string TypedText = std::string(Name); TypedText += "("; if (ArgsKinds.empty()) TypedText += ")"; diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp index 118ca2a41cb18..866e2d0e3491a 100644 --- a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -1,4 +1,4 @@ -//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ +//===--- VariantValue.cpp - Polymorphic value type --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -101,8 +101,7 @@ public: return llvm::None; } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, - unsigned *Specificity) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override { return ArgKind(Matcher.getSupportedKind()) .isConvertibleTo(Kind, Specificity); } @@ -159,8 +158,7 @@ public: return llvm::None; } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, - unsigned *Specificity) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override { unsigned MaxSpecificity = 0; for (const DynTypedMatcher &Matcher : Matchers) { unsigned ThisSpecificity; @@ -202,8 +200,7 @@ public: return Ops.constructVariadicOperator(Op, Args); } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, - unsigned *Specificity) const override { + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override { for (const VariantMatcher &Matcher : Args) { if (!Matcher.isConvertibleTo(Kind, Specificity)) return false; diff --git a/clang/lib/ASTMatchers/GtestMatchers.cpp b/clang/lib/ASTMatchers/GtestMatchers.cpp new file mode 100644 index 0000000000000..c99fdf6c0fcd6 --- /dev/null +++ b/clang/lib/ASTMatchers/GtestMatchers.cpp @@ -0,0 +1,104 @@ +//===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- 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 "clang/ASTMatchers/GtestMatchers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Timer.h" +#include <deque> +#include <memory> +#include <set> + +namespace clang { +namespace ast_matchers { + +static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) { + switch (Cmp) { + case GtestCmp::Eq: + return cxxMethodDecl(hasName("Compare"), + ofClass(cxxRecordDecl(isSameOrDerivedFrom( + hasName("::testing::internal::EqHelper"))))); + case GtestCmp::Ne: + return functionDecl(hasName("::testing::internal::CmpHelperNE")); + case GtestCmp::Ge: + return functionDecl(hasName("::testing::internal::CmpHelperGE")); + case GtestCmp::Gt: + return functionDecl(hasName("::testing::internal::CmpHelperGT")); + case GtestCmp::Le: + return functionDecl(hasName("::testing::internal::CmpHelperLE")); + case GtestCmp::Lt: + return functionDecl(hasName("::testing::internal::CmpHelperLT")); + } + llvm_unreachable("Unhandled GtestCmp enum"); +} + +static llvm::StringRef getAssertMacro(GtestCmp Cmp) { + switch (Cmp) { + case GtestCmp::Eq: + return "ASSERT_EQ"; + case GtestCmp::Ne: + return "ASSERT_NE"; + case GtestCmp::Ge: + return "ASSERT_GE"; + case GtestCmp::Gt: + return "ASSERT_GT"; + case GtestCmp::Le: + return "ASSERT_LE"; + case GtestCmp::Lt: + return "ASSERT_LT"; + } + llvm_unreachable("Unhandled GtestCmp enum"); +} + +static llvm::StringRef getExpectMacro(GtestCmp Cmp) { + switch (Cmp) { + case GtestCmp::Eq: + return "EXPECT_EQ"; + case GtestCmp::Ne: + return "EXPECT_NE"; + case GtestCmp::Ge: + return "EXPECT_GE"; + case GtestCmp::Gt: + return "EXPECT_GT"; + case GtestCmp::Le: + return "EXPECT_LE"; + case GtestCmp::Lt: + return "EXPECT_LT"; + } + llvm_unreachable("Unhandled GtestCmp enum"); +} + +// In general, AST matchers cannot match calls to macros. However, we can +// simulate such matches if the macro definition has identifiable elements that +// themselves can be matched. In that case, we can match on those elements and +// then check that the match occurs within an expansion of the desired +// macro. The more uncommon the identified elements, the more efficient this +// process will be. +// +// We use this approach to implement the derived matchers gtestAssert and +// gtestExpect. +internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left, + StatementMatcher Right) { + return callExpr(callee(getComparisonDecl(Cmp)), + isExpandedFromMacro(getAssertMacro(Cmp)), + hasArgument(2, Left), hasArgument(3, Right)); +} + +internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left, + StatementMatcher Right) { + return callExpr(callee(getComparisonDecl(Cmp)), + isExpandedFromMacro(getExpectMacro(Cmp)), + hasArgument(2, Left), hasArgument(3, Right)); +} + +} // end namespace ast_matchers +} // end namespace clang |