diff options
author | dim <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
commit | c86b984ea8ecb3e944dc3de48539f4c1f65851ea (patch) | |
tree | 3eb853da77d46cc77c4b017525a422f9ddb1385b /lib/ASTMatchers | |
parent | c696171ff15f0ee60dea4abfd99a135473c95656 (diff) | |
download | FreeBSD-src-c86b984ea8ecb3e944dc3de48539f4c1f65851ea.zip FreeBSD-src-c86b984ea8ecb3e944dc3de48539f4c1f65851ea.tar.gz |
Vendor import of clang RELEASE_360/rc1 tag r226102 (effectively, 3.6.0 RC1):
https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_360/rc1@226102
Diffstat (limited to 'lib/ASTMatchers')
-rw-r--r-- | lib/ASTMatchers/ASTMatchFinder.cpp | 289 | ||||
-rw-r--r-- | lib/ASTMatchers/ASTMatchersInternal.cpp | 268 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Marshallers.h | 105 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Parser.cpp | 105 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Registry.cpp | 171 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/VariantValue.cpp | 164 |
6 files changed, 817 insertions, 285 deletions
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 23708e2..fa7968a 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -20,7 +20,11 @@ #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 { @@ -53,7 +57,7 @@ static const unsigned MaxMemoizationEntries = 10000; // FIXME: Benchmark whether memoization of non-pointer typed nodes // provides enough benefit for the additional amount of code. struct MatchKey { - uint64_t MatcherID; + DynTypedMatcher::MatcherIDType MatcherID; ast_type_traits::DynTypedNode Node; BoundNodesTreeBuilder BoundNodes; @@ -292,28 +296,33 @@ private: class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, public ASTMatchFinder { public: - MatchASTVisitor( - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > * - MatcherCallbackPairs) - : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(nullptr) {} + MatchASTVisitor(const MatchFinder::MatchersByType *Matchers, + const MatchFinder::MatchFinderOptions &Options) + : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {} + + ~MatchASTVisitor() { + if (Options.CheckProfiling) { + Options.CheckProfiling->Records = std::move(TimeByBucket); + } + } void onStartOfTranslationUnit() { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - I->second->onStartOfTranslationUnit(); + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (MatchCallback *MC : Matchers->AllCallbacks) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MC->getID()]); + MC->onStartOfTranslationUnit(); } } void onEndOfTranslationUnit() { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - I->second->onEndOfTranslationUnit(); + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (MatchCallback *MC : Matchers->AllCallbacks) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MC->getID()]); + MC->onEndOfTranslationUnit(); } } @@ -372,7 +381,7 @@ public: BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { // For AST-nodes that don't have an identity, we can't memoize. - if (!Node.getMemoizationData()) + if (!Node.getMemoizationData() || !Builder->isComparable()) return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal, Bind); @@ -392,9 +401,12 @@ public: Result.Nodes = *Builder; Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Traversal, Bind); - ResultCache[Key] = Result; - *Builder = Result.Nodes; - return Result.ResultOfMatch; + + MemoizedMatchResult &CachedResult = ResultCache[Key]; + CachedResult = std::move(Result); + + *Builder = CachedResult.Nodes; + return CachedResult.ResultOfMatch; } // Matches children or descendants of 'Node' with 'BaseMatcher'. @@ -447,22 +459,27 @@ 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) { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - BoundNodesTreeBuilder Builder; - if (I->first.matches(Node, this, &Builder)) { - MatchVisitor Visitor(ActiveASTContext, I->second); - Builder.visitMatches(&Visitor); - } + void match(const ast_type_traits::DynTypedNode &Node) { + // FIXME: Improve this with a switch or a visitor pattern. + if (auto *N = Node.get<Decl>()) { + match(*N); + } else if (auto *N = Node.get<Stmt>()) { + match(*N); + } else if (auto *N = Node.get<Type>()) { + match(*N); + } else if (auto *N = Node.get<QualType>()) { + match(*N); + } else if (auto *N = Node.get<NestedNameSpecifier>()) { + match(*N); + } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) { + match(*N); + } else if (auto *N = Node.get<TypeLoc>()) { + match(*N); } } template <typename T> void match(const T &Node) { - match(ast_type_traits::DynTypedNode::create(Node)); + matchDispatch(&Node); } // Implements ASTMatchFinder::getASTContext. @@ -475,6 +492,116 @@ public: bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; } private: + class TimeBucketRegion { + public: + TimeBucketRegion() : Bucket(nullptr) {} + ~TimeBucketRegion() { setBucket(nullptr); } + + /// \brief Start timing for \p NewBucket. + /// + /// If there was a bucket already set, it will finish the timing for that + /// other bucket. + /// \p NewBucket will be timed until the next call to \c setBucket() or + /// until the \c TimeBucketRegion is destroyed. + /// If \p NewBucket is the same as the currently timed bucket, this call + /// does nothing. + void setBucket(llvm::TimeRecord *NewBucket) { + if (Bucket != NewBucket) { + auto Now = llvm::TimeRecord::getCurrentTime(true); + if (Bucket) + *Bucket += Now; + if (NewBucket) + *NewBucket -= Now; + Bucket = NewBucket; + } + } + + private: + llvm::TimeRecord *Bucket; + }; + + /// \brief Runs all the \p Matchers on \p Node. + /// + /// Used by \c matchDispatch() below. + template <typename T, typename MC> + void matchWithoutFilter(const T &Node, const MC &Matchers) { + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (const auto &MP : Matchers) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MP.second->getID()]); + BoundNodesTreeBuilder Builder; + if (MP.first.matches(Node, this, &Builder)) { + MatchVisitor Visitor(ActiveASTContext, MP.second); + Builder.visitMatches(&Visitor); + } + } + } + + void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) { + auto Kind = DynNode.getNodeKind(); + auto it = MatcherFiltersMap.find(Kind); + const auto &Filter = + it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind); + + if (Filter.empty()) + return; + + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + auto &Matchers = this->Matchers->DeclOrStmt; + for (unsigned short I : Filter) { + auto &MP = Matchers[I]; + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MP.second->getID()]); + BoundNodesTreeBuilder Builder; + if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) { + MatchVisitor Visitor(ActiveASTContext, MP.second); + Builder.visitMatches(&Visitor); + } + } + } + + const std::vector<unsigned short> & + getFilterForKind(ast_type_traits::ASTNodeKind Kind) { + auto &Filter = MatcherFiltersMap[Kind]; + auto &Matchers = this->Matchers->DeclOrStmt; + assert((Matchers.size() < USHRT_MAX) && "Too many matchers."); + for (unsigned I = 0, E = Matchers.size(); I != E; ++I) { + if (Matchers[I].first.canMatchNodesOfKind(Kind)) { + Filter.push_back(I); + } + } + return Filter; + } + + /// @{ + /// \brief Overloads to pair the different node types to their matchers. + void matchDispatch(const Decl *Node) { + return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + } + void matchDispatch(const Stmt *Node) { + return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + } + + void matchDispatch(const Type *Node) { + matchWithoutFilter(QualType(Node, 0), Matchers->Type); + } + void matchDispatch(const TypeLoc *Node) { + matchWithoutFilter(*Node, Matchers->TypeLoc); + } + void matchDispatch(const QualType *Node) { + matchWithoutFilter(*Node, Matchers->Type); + } + void matchDispatch(const NestedNameSpecifier *Node) { + matchWithoutFilter(*Node, Matchers->NestedNameSpecifier); + } + void matchDispatch(const NestedNameSpecifierLoc *Node) { + matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc); + } + void matchDispatch(const void *) { /* Do nothing. */ } + /// @} + // Returns whether an ancestor of \p Node matches \p Matcher. // // The order of matching ((which can lead to different nodes being bound in @@ -497,11 +624,7 @@ private: assert(Node.getMemoizationData() && "Invariant broken: only nodes that support memoization may be " "used in the parent map."); - ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node); - if (Parents.empty()) { - assert(false && "Found node that is not in the parent map."); - return false; - } + MatchKey Key; Key.MatcherID = Matcher.getID(); Key.Node = Node; @@ -514,9 +637,13 @@ private: *Builder = I->second.Nodes; return I->second.ResultOfMatch; } + MemoizedMatchResult Result; Result.ResultOfMatch = false; Result.Nodes = *Builder; + + const auto &Parents = ActiveASTContext->getParents(Node); + assert(!Parents.empty() && "Found node that is not in the parent map."); if (Parents.size() == 1) { // Only one parent - do recursive memoization. const ast_type_traits::DynTypedNode Parent = Parents[0]; @@ -543,25 +670,24 @@ private: break; } if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { - ASTContext::ParentVector Ancestors = - ActiveASTContext->getParents(Queue.front()); - for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(), - E = Ancestors.end(); - I != E; ++I) { + for (const auto &Parent : + ActiveASTContext->getParents(Queue.front())) { // Make sure we do not visit the same node twice. // Otherwise, we'll visit the common ancestors as often as there // are splits on the way down. - if (Visited.insert(I->getMemoizationData()).second) - Queue.push_back(*I); + if (Visited.insert(Parent.getMemoizationData()).second) + Queue.push_back(Parent); } } Queue.pop_front(); } } - ResultCache[Key] = Result; - *Builder = Result.Nodes; - return Result.ResultOfMatch; + MemoizedMatchResult &CachedResult = ResultCache[Key]; + CachedResult = std::move(Result); + + *Builder = CachedResult.Nodes; + return CachedResult.ResultOfMatch; } // Implements a BoundNodesTree::Visitor that calls a MatchCallback with @@ -588,22 +714,35 @@ private: BoundNodesTreeBuilder *Builder) { const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); - const std::set<const TypedefNameDecl *> &Aliases = - TypeAliases[CanonicalType]; - for (std::set<const TypedefNameDecl*>::const_iterator - It = Aliases.begin(), End = Aliases.end(); - It != End; ++It) { + for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) { BoundNodesTreeBuilder Result(*Builder); - if (Matcher.matches(**It, this, &Result)) { - *Builder = Result; + if (Matcher.matches(*Alias, this, &Result)) { + *Builder = std::move(Result); return true; } } return false; } - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const - MatcherCallbackPairs; + /// \brief Bucket to record map. + /// + /// Used to get the appropriate bucket for each matcher. + llvm::StringMap<llvm::TimeRecord> TimeByBucket; + + const MatchFinder::MatchersByType *Matchers; + + /// \brief Filtered list of matcher indices for each matcher kind. + /// + /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node + /// 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. + /// This also allows us to skip the restrict check at matching time. See + /// use \c matchesNoKindCheck() above. + llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>> + MatcherFiltersMap; + + const MatchFinder::MatchFinderOptions &Options; ASTContext *ActiveASTContext; // Maps a canonical type to its TypedefDecls. @@ -680,7 +819,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, } BoundNodesTreeBuilder Result(*Builder); if (Base.matches(*ClassDecl, this, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } if (classIsDerivedFrom(ClassDecl, Base, Builder)) @@ -731,7 +870,8 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc( match(NNS); // We only match the nested name specifier here (as opposed to traversing it) // because the traversal is already done in the parallel "Loc"-hierarchy. - match(*NNS.getNestedNameSpecifier()); + if (NNS.hasQualifier()) + match(*NNS.getNestedNameSpecifier()); return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS); } @@ -765,38 +905,45 @@ MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes, MatchFinder::MatchCallback::~MatchCallback() {} MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} -MatchFinder::MatchFinder() : ParsingDone(nullptr) {} +MatchFinder::MatchFinder(MatchFinderOptions Options) + : Options(std::move(Options)), ParsingDone(nullptr) {} MatchFinder::~MatchFinder() {} void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const TypeMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.Type.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const StatementMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.NestedNameSpecifier.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.NestedNameSpecifierLoc.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.TypeLoc.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, @@ -823,19 +970,19 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, return false; } -ASTConsumer *MatchFinder::newASTConsumer() { - return new internal::MatchASTConsumer(this, ParsingDone); +std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() { + return llvm::make_unique<internal::MatchASTConsumer>(this, ParsingDone); } void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, ASTContext &Context) { - internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + internal::MatchASTVisitor Visitor(&Matchers, Options); Visitor.set_active_ast_context(&Context); Visitor.match(Node); } void MatchFinder::matchAST(ASTContext &Context) { - internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + internal::MatchASTVisitor Visitor(&Matchers, Options); Visitor.set_active_ast_context(&Context); Visitor.onStartOfTranslationUnit(); Visitor.TraverseDecl(Context.getTranslationUnitDecl()); @@ -847,5 +994,7 @@ void MatchFinder::registerTestCallbackAfterParsing( ParsingDone = NewParsingDone; } +StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; } + } // end namespace ast_matchers } // end namespace clang diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index 47b8b6d..2c482e3 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -13,25 +13,219 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ManagedStatic.h" namespace clang { namespace ast_matchers { namespace internal { +bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + + void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); - for (unsigned i = 0, e = Bindings.size(); i != e; ++i) { - ResultVisitor->visitMatch(BoundNodes(Bindings[i])); + for (BoundNodesMap &Binding : Bindings) { + ResultVisitor->visitMatch(BoundNodes(Binding)); } } -DynTypedMatcher::MatcherStorage::~MatcherStorage() {} +namespace { -void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { - for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) { - Bindings.push_back(Other.Bindings[i]); +typedef bool (*VariadicOperatorFunction)( + const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); + +template <VariadicOperatorFunction Func> +class VariadicMatcher : public DynMatcherInterface { +public: + VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers) + : InnerMatchers(std::move(InnerMatchers)) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Func(DynNode, Finder, Builder, InnerMatchers); + } + +private: + std::vector<DynTypedMatcher> InnerMatchers; +}; + +class IdDynMatcher : public DynMatcherInterface { + public: + IdDynMatcher(StringRef ID, + const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher) + : ID(ID), InnerMatcher(InnerMatcher) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); + if (Result) Builder->setBinding(ID, DynNode); + return Result; + } + + private: + const std::string ID; + const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + +/// \brief A matcher that always returns true. +/// +/// We only ever need one instance of this matcher, so we create a global one +/// and reuse it to reduce the overhead of the matcher and increase the chance +/// of cache hits. +class TrueMatcherImpl : public DynMatcherInterface { +public: + TrueMatcherImpl() { + Retain(); // Reference count will never become zero. + } + bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *, + BoundNodesTreeBuilder *) const override { + return true; + } +}; +static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance; + +} // namespace + +DynTypedMatcher DynTypedMatcher::constructVariadic( + DynTypedMatcher::VariadicOperator Op, + std::vector<DynTypedMatcher> InnerMatchers) { + assert(InnerMatchers.size() > 0 && "Array must not be empty."); + assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(), + [&InnerMatchers](const DynTypedMatcher &M) { + return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind); + }) && + "SupportedKind must match!"); + + auto SupportedKind = InnerMatchers[0].SupportedKind; + // We must relax the restrict kind here. + // The different operators might deal differently with a mismatch. + // Make it the same as SupportedKind, since that is the broadest type we are + // allowed to accept. + auto RestrictKind = SupportedKind; + + switch (Op) { + case VO_AllOf: + // In the case of allOf() we must pass all the checks, so making + // RestrictKind the most restrictive can save us time. This way we reject + // 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); + } + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<AllOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_AnyOf: + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<AnyOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_EachOf: + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_UnaryNot: + // FIXME: Implement the Not operator to take a single matcher instead of a + // vector. + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<NotUnaryOperator>(std::move(InnerMatchers))); } + llvm_unreachable("Invalid Op value."); +} + +DynTypedMatcher DynTypedMatcher::trueMatcher( + ast_type_traits::ASTNodeKind NodeKind) { + return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); +} + +bool DynTypedMatcher::canMatchNodesOfKind( + ast_type_traits::ASTNodeKind Kind) const { + return RestrictKind.isBaseOf(Kind); +} + +DynTypedMatcher DynTypedMatcher::dynCastTo( + const ast_type_traits::ASTNodeKind Kind) const { + auto Copy = *this; + Copy.SupportedKind = Kind; + Copy.RestrictKind = + ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind); + return Copy; +} + +bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + if (RestrictKind.isBaseOf(DynNode.getNodeKind()) && + Implementation->dynMatches(DynNode, Finder, Builder)) { + return true; + } + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + Builder->removeBindings([](const BoundNodesMap &) { return true; }); + return false; +} + +bool DynTypedMatcher::matchesNoKindCheck( + const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + assert(RestrictKind.isBaseOf(DynNode.getNodeKind())); + if (Implementation->dynMatches(DynNode, Finder, Builder)) { + return true; + } + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + Builder->removeBindings([](const BoundNodesMap &) { return true; }); + return false; +} + +llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const { + if (!AllowBind) return llvm::None; + auto Result = *this; + Result.Implementation = new IdDynMatcher(ID, Result.Implementation); + return Result; +} + +bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { + const auto From = getSupportedKind(); + auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(); + auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>(); + /// Mimic the implicit conversions of Matcher<>. + /// - From Matcher<Type> to Matcher<QualType> + if (From.isSame(TypeKind) && To.isSame(QualKind)) return true; + /// - From Matcher<Base> to Matcher<Derived> + return From.isBaseOf(To); +} + +void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { + Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, @@ -61,8 +255,8 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, // 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 (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - if (!InnerMatchers[i].matches(DynNode, Finder, Builder)) + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { + if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder)) return false; } return true; @@ -74,14 +268,14 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ArrayRef<DynTypedMatcher> InnerMatchers) { BoundNodesTreeBuilder Result; bool Matched = false; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder BuilderInner(*Builder); - if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) { + if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) { Matched = true; Result.addMatch(BuilderInner); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -89,16 +283,62 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder Result = *Builder; - if (InnerMatchers[i].matches(DynNode, Finder, &Result)) { - *Builder = Result; + if (InnerMatcher.matches(DynNode, Finder, &Result)) { + *Builder = std::move(Result); return true; } } return false; } +HasNameMatcher::HasNameMatcher(StringRef NameRef) + : UseUnqualifiedMatch(NameRef.find("::") == NameRef.npos), Name(NameRef) { + assert(!Name.empty()); +} + +bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const { + assert(UseUnqualifiedMatch); + if (Node.getIdentifier()) { + // Simple name. + return Name == Node.getName(); + } + if (Node.getDeclName()) { + // Name needs to be constructed. + llvm::SmallString<128> NodeName; + llvm::raw_svector_ostream OS(NodeName); + Node.printName(OS); + return Name == OS.str(); + } + return false; +} + +bool HasNameMatcher::matchesNodeFull(const NamedDecl &Node) const { + llvm::SmallString<128> NodeName = StringRef("::"); + llvm::raw_svector_ostream OS(NodeName); + Node.printQualifiedName(OS); + const StringRef FullName = OS.str(); + const StringRef Pattern = Name; + + if (Pattern.startswith("::")) + return FullName == Pattern; + + return FullName.endswith(Pattern) && + FullName.drop_back(Pattern.size()).endswith("::"); +} + +bool HasNameMatcher::matchesNode(const NamedDecl &Node) const { + // FIXME: There is still room for improvement, but it would require copying a + // lot of the logic from NamedDecl::printQualifiedName(). The benchmarks do + // not show like that extra complexity is needed right now. + if (UseUnqualifiedMatch) { + assert(matchesNodeUnqualified(Node) == matchesNodeFull(Node)); + return matchesNodeUnqualified(Node); + } + return matchesNodeFull(Node); +} + } // end namespace internal } // end namespace ast_matchers } // end namespace clang diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index 6e144cd..b78bc03 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -17,8 +17,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#ifndef LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/Dynamic/Diagnostics.h" @@ -30,48 +30,8 @@ namespace clang { namespace ast_matchers { namespace dynamic { - namespace internal { -struct ArgKind { - enum Kind { - AK_Matcher, - AK_Unsigned, - AK_String - }; - ArgKind(Kind K) - : K(K) {} - ArgKind(ast_type_traits::ASTNodeKind MatcherKind) - : K(AK_Matcher), MatcherKind(MatcherKind) {} - - std::string asString() const { - switch (getArgKind()) { - case AK_Matcher: - return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); - case AK_Unsigned: - return "unsigned"; - case AK_String: - return "string"; - } - llvm_unreachable("unhandled ArgKind"); - } - - Kind getArgKind() const { return K; } - ast_type_traits::ASTNodeKind getMatcherKind() const { - assert(K == AK_Matcher); - return MatcherKind; - } - - bool operator<(const ArgKind &Other) const { - if (K == AK_Matcher && Other.K == AK_Matcher) - return MatcherKind < Other.MatcherKind; - return K < Other.K; - } - -private: - Kind K; - ast_type_traits::ASTNodeKind MatcherKind; -}; /// \brief Helper template class to just from argument type to the right is/get /// functions in VariantValue. @@ -116,6 +76,27 @@ template <> struct ArgTypeTraits<unsigned> { } }; +template <> struct ArgTypeTraits<attr::Kind> { +private: + static attr::Kind getAttrKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<attr::Kind>(AttrKind) +#define ATTR(X) .Case("attr::" #X, attr:: X) +#include "clang/Basic/AttrList.inc" + .Default(attr::Kind(-1)); + } +public: + static bool is(const VariantValue &Value) { + return Value.isString() && + getAttrKind(Value.getString()) != attr::Kind(-1); + } + static attr::Kind get(const VariantValue &Value) { + return getAttrKind(Value.getString()); + } + static ArgKind getKind() { + return ArgKind(ArgKind::AK_String); + } +}; + /// \brief Matcher descriptor interface. /// /// Provides a \c create() method that constructs the matcher from the provided @@ -161,16 +142,10 @@ inline bool isRetKindConvertibleTo( ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, ast_type_traits::ASTNodeKind *LeastDerivedKind) { - for (ArrayRef<ast_type_traits::ASTNodeKind>::const_iterator - i = RetKinds.begin(), - e = RetKinds.end(); - i != e; ++i) { - unsigned Distance; - if (i->isBaseOf(Kind, &Distance)) { - if (Specificity) - *Specificity = 100 - Distance; + for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) { + if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) { if (LeastDerivedKind) - *LeastDerivedKind = *i; + *LeastDerivedKind = NodeKind; return true; } } @@ -322,8 +297,8 @@ variadicMatcherDescriptor(StringRef MatcherName, const SourceRange &NameRange, VariantMatcher Out; if (!HasError) { - Out = outvalueToVariantMatcher( - Func(ArrayRef<const ArgT *>(InnerArgs, Args.size()))); + Out = outvalueToVariantMatcher(Func(llvm::makeArrayRef(InnerArgs, + Args.size()))); } for (size_t i = 0, e = Args.size(); i != e; ++i) { @@ -498,7 +473,7 @@ private: template <typename FromTypeList> inline void collect(FromTypeList); - const StringRef Name; + StringRef Name; std::vector<MatcherDescriptor *> &Out; }; @@ -581,15 +556,15 @@ private: /// \brief Variadic operator marshaller function. class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { public: - typedef ast_matchers::internal::VariadicOperatorFunction VarFunc; + typedef DynTypedMatcher::VariadicOperator VarOp; VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount, - VarFunc Func, StringRef MatcherName) - : MinCount(MinCount), MaxCount(MaxCount), Func(Func), + VarOp Op, StringRef MatcherName) + : MinCount(MinCount), MaxCount(MaxCount), Op(Op), MatcherName(MatcherName) {} virtual VariantMatcher create(const SourceRange &NameRange, ArrayRef<ParserValue> Args, - Diagnostics *Error) const { + Diagnostics *Error) const override { if (Args.size() < MinCount || MaxCount < Args.size()) { const std::string MaxStr = (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str(); @@ -609,17 +584,17 @@ public: } InnerArgs.push_back(Value.getMatcher()); } - return VariantMatcher::VariadicOperatorMatcher(Func, std::move(InnerArgs)); + return VariantMatcher::VariadicOperatorMatcher(Op, std::move(InnerArgs)); } - bool isVariadic() const { return true; } - unsigned getNumArgs() const { return 0; } + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, - std::vector<ArgKind> &Kinds) const { + 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 { + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { if (Specificity) *Specificity = 1; if (LeastDerivedKind) @@ -631,7 +606,7 @@ public: private: const unsigned MinCount; const unsigned MaxCount; - const VarFunc Func; + const VarOp Op; const StringRef MatcherName; }; @@ -724,7 +699,7 @@ MatcherDescriptor * makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc< MinCount, MaxCount> Func, StringRef MatcherName) { - return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Func, + return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Op, MatcherName); } diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 25629d9..9930c53 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/CharInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ManagedStatic.h" #include <string> #include <vector> @@ -258,8 +259,14 @@ private: Parser::Sema::~Sema() {} -VariantValue Parser::Sema::getNamedValue(StringRef Name) { - return VariantValue(); +std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return std::vector<ArgKind>(); +} + +std::vector<MatcherCompletion> +Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) { + return std::vector<MatcherCompletion>(); } struct Parser::ScopedContextEntry { @@ -288,7 +295,9 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) { if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) { // Parse as a named value. - if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) { + if (const VariantValue NamedValue = + NamedValues ? NamedValues->lookup(NameToken.Text) + : VariantValue()) { *Value = NamedValue; return true; } @@ -379,7 +388,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, Tokenizer->consumeNextToken(); // consume the period. const TokenInfo BindToken = Tokenizer->consumeNextToken(); if (BindToken.Kind == TokenInfo::TK_CodeCompletion) { - addCompletion(BindToken, "bind(\"", "bind"); + addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1)); return false; } @@ -427,13 +436,28 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, // If the prefix of this completion matches the completion token, add it to // Completions minus the prefix. -void Parser::addCompletion(const TokenInfo &CompToken, StringRef TypedText, - StringRef Decl) { - if (TypedText.size() >= CompToken.Text.size() && - TypedText.substr(0, CompToken.Text.size()) == CompToken.Text) { - Completions.push_back( - MatcherCompletion(TypedText.substr(CompToken.Text.size()), Decl)); +void Parser::addCompletion(const TokenInfo &CompToken, + const MatcherCompletion& Completion) { + if (StringRef(Completion.TypedText).startswith(CompToken.Text) && + Completion.Specificity > 0) { + Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()), + Completion.MatcherDecl, Completion.Specificity); + } +} + +std::vector<MatcherCompletion> Parser::getNamedValueCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + if (!NamedValues) return std::vector<MatcherCompletion>(); + std::vector<MatcherCompletion> Result; + for (const auto &Entry : *NamedValues) { + unsigned Specificity; + if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) { + std::string Decl = + (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str(); + Result.emplace_back(Entry.getKey(), Decl, Specificity); + } } + return Result; } void Parser::addExpressionCompletions() { @@ -449,12 +473,13 @@ void Parser::addExpressionCompletions() { return; } - std::vector<MatcherCompletion> RegCompletions = - Registry::getCompletions(ContextStack); - for (std::vector<MatcherCompletion>::iterator I = RegCompletions.begin(), - E = RegCompletions.end(); - I != E; ++I) { - addCompletion(CompToken, I->TypedText, I->MatcherDecl); + auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack); + for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); + } + + for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); } } @@ -494,9 +519,12 @@ bool Parser::parseExpressionImpl(VariantValue *Value) { llvm_unreachable("Unknown token kind."); } +static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema; + Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, - Diagnostics *Error) - : Tokenizer(Tokenizer), S(S), Error(Error) {} + const NamedValueMap *NamedValues, Diagnostics *Error) + : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema), + NamedValues(NamedValues), Error(Error) {} Parser::RegistrySema::~RegistrySema() {} @@ -516,16 +544,22 @@ VariantMatcher Parser::RegistrySema::actOnMatcherExpression( } } -bool Parser::parseExpression(StringRef Code, VariantValue *Value, - Diagnostics *Error) { - RegistrySema S; - return parseExpression(Code, &S, Value, Error); +std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return Registry::getAcceptedCompletionTypes(Context); +} + +std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + return Registry::getMatcherCompletions(AcceptedTypes); } bool Parser::parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error) { CodeTokenizer Tokenizer(Code, Error); - if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false; + if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value)) + return false; if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) { Error->addError(Tokenizer.peekNextToken().Range, Error->ET_ParserTrailingCode); @@ -535,28 +569,31 @@ bool Parser::parseExpression(StringRef Code, Sema *S, } std::vector<MatcherCompletion> -Parser::completeExpression(StringRef Code, unsigned CompletionOffset) { +Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues) { Diagnostics Error; CodeTokenizer Tokenizer(Code, &Error, CompletionOffset); - RegistrySema S; - Parser P(&Tokenizer, &S, &Error); + Parser P(&Tokenizer, S, NamedValues, &Error); VariantValue Dummy; P.parseExpressionImpl(&Dummy); - return P.Completions; -} + // Sort by specificity, then by name. + std::sort(P.Completions.begin(), P.Completions.end(), + [](const MatcherCompletion &A, const MatcherCompletion &B) { + if (A.Specificity != B.Specificity) + return A.Specificity > B.Specificity; + return A.TypedText < B.TypedText; + }); -llvm::Optional<DynTypedMatcher> -Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) { - RegistrySema S; - return parseMatcherExpression(Code, &S, Error); + return P.Completions; } llvm::Optional<DynTypedMatcher> -Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S, +Parser::parseMatcherExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, Diagnostics *Error) { VariantValue Value; - if (!parseExpression(Code, S, &Value, Error)) + if (!parseExpression(Code, S, NamedValues, &Value, Error)) return llvm::Optional<DynTypedMatcher>(); if (!Value.isMatcher()) { Error->addError(SourceRange(), Error->ET_ParserNotAMatcher); diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 4bc50a0..d550a89 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -101,8 +101,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(argumentCountIs); REGISTER_MATCHER(arraySubscriptExpr); REGISTER_MATCHER(arrayType); - REGISTER_MATCHER(asString); REGISTER_MATCHER(asmStmt); + REGISTER_MATCHER(asString); REGISTER_MATCHER(atomicType); REGISTER_MATCHER(autoType); REGISTER_MATCHER(binaryOperator); @@ -111,7 +111,6 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(boolLiteral); REGISTER_MATCHER(breakStmt); REGISTER_MATCHER(builtinType); - REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(callExpr); REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); @@ -123,18 +122,20 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(compoundLiteralExpr); REGISTER_MATCHER(compoundStmt); REGISTER_MATCHER(conditionalOperator); - REGISTER_MATCHER(constCastExpr); REGISTER_MATCHER(constantArrayType); + REGISTER_MATCHER(constCastExpr); REGISTER_MATCHER(constructExpr); REGISTER_MATCHER(constructorDecl); REGISTER_MATCHER(containsDeclaration); REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(ctorInitializer); + REGISTER_MATCHER(CUDAKernelCallExpr); REGISTER_MATCHER(decl); + REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(declCountIs); REGISTER_MATCHER(declRefExpr); REGISTER_MATCHER(declStmt); - REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(defaultArgExpr); REGISTER_MATCHER(defaultStmt); REGISTER_MATCHER(deleteExpr); @@ -147,6 +148,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(equalsBoundNode); + REGISTER_MATCHER(equalsIntegralValue); REGISTER_MATCHER(explicitCastExpr); REGISTER_MATCHER(expr); REGISTER_MATCHER(exprWithCleanups); @@ -160,10 +162,10 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forRangeStmt); REGISTER_MATCHER(forStmt); REGISTER_MATCHER(friendDecl); + REGISTER_MATCHER(functionalCastExpr); REGISTER_MATCHER(functionDecl); REGISTER_MATCHER(functionTemplateDecl); REGISTER_MATCHER(functionType); - REGISTER_MATCHER(functionalCastExpr); REGISTER_MATCHER(gotoStmt); REGISTER_MATCHER(has); REGISTER_MATCHER(hasAncestor); @@ -175,19 +177,21 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnyUsingShadowDecl); REGISTER_MATCHER(hasArgument); REGISTER_MATCHER(hasArgumentOfType); + REGISTER_MATCHER(hasAttr); REGISTER_MATCHER(hasBase); REGISTER_MATCHER(hasBody); REGISTER_MATCHER(hasCanonicalType); REGISTER_MATCHER(hasCaseConstant); REGISTER_MATCHER(hasCondition); REGISTER_MATCHER(hasConditionVariableStatement); - REGISTER_MATCHER(hasDeclContext); REGISTER_MATCHER(hasDeclaration); + REGISTER_MATCHER(hasDeclContext); REGISTER_MATCHER(hasDeducedType); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); + REGISTER_MATCHER(hasElse); REGISTER_MATCHER(hasFalseExpression); REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); @@ -198,6 +202,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasLocalQualifiers); REGISTER_MATCHER(hasLocalStorage); REGISTER_MATCHER(hasLoopInit); + REGISTER_MATCHER(hasLoopVariable); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); REGISTER_MATCHER(hasObjectExpression); @@ -206,6 +211,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); REGISTER_MATCHER(hasQualifier); + REGISTER_MATCHER(hasRangeInit); REGISTER_MATCHER(hasRHS); REGISTER_MATCHER(hasSingleDecl); REGISTER_MATCHER(hasSize); @@ -213,6 +219,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasSourceExpression); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasThen); REGISTER_MATCHER(hasTrueExpression); REGISTER_MATCHER(hasTypeLoc); REGISTER_MATCHER(hasUnaryOperand); @@ -230,22 +237,30 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isDefinition); + REGISTER_MATCHER(isDeleted); REGISTER_MATCHER(isExplicitTemplateSpecialization); REGISTER_MATCHER(isExpr); REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(isExpansionInFileMatching); + REGISTER_MATCHER(isExpansionInMainFile); + REGISTER_MATCHER(isInstantiated); + REGISTER_MATCHER(isExpansionInSystemHeader); REGISTER_MATCHER(isInteger); + REGISTER_MATCHER(isIntegral); + REGISTER_MATCHER(isInTemplateInstantiation); REGISTER_MATCHER(isListInitialization); REGISTER_MATCHER(isOverride); REGISTER_MATCHER(isPrivate); REGISTER_MATCHER(isProtected); REGISTER_MATCHER(isPublic); + REGISTER_MATCHER(isPure); REGISTER_MATCHER(isTemplateInstantiation); REGISTER_MATCHER(isVirtual); REGISTER_MATCHER(isWritten); - REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(labelStmt); REGISTER_MATCHER(lambdaExpr); + REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(matchesName); REGISTER_MATCHER(materializeTemporaryExpr); REGISTER_MATCHER(member); @@ -254,8 +269,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(memberPointerType); REGISTER_MATCHER(methodDecl); REGISTER_MATCHER(namedDecl); - REGISTER_MATCHER(namesType); REGISTER_MATCHER(namespaceDecl); + REGISTER_MATCHER(namesType); REGISTER_MATCHER(nestedNameSpecifier); REGISTER_MATCHER(nestedNameSpecifierLoc); REGISTER_MATCHER(newExpr); @@ -271,15 +286,16 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(pointee); REGISTER_MATCHER(pointerType); REGISTER_MATCHER(qualType); - REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(recordDecl); REGISTER_MATCHER(recordType); REGISTER_MATCHER(referenceType); REGISTER_MATCHER(refersToDeclaration); + REGISTER_MATCHER(refersToIntegralType); REGISTER_MATCHER(refersToType); REGISTER_MATCHER(reinterpretCastExpr); - REGISTER_MATCHER(returnStmt); REGISTER_MATCHER(returns); + REGISTER_MATCHER(returnStmt); + REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(sizeOfExpr); REGISTER_MATCHER(specifiesNamespace); REGISTER_MATCHER(specifiesType); @@ -288,8 +304,11 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(staticCastExpr); REGISTER_MATCHER(stmt); REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(substNonTypeTemplateParmExpr); REGISTER_MATCHER(switchCase); REGISTER_MATCHER(switchStmt); + REGISTER_MATCHER(templateArgument); + REGISTER_MATCHER(templateArgumentCountIs); REGISTER_MATCHER(templateSpecializationType); REGISTER_MATCHER(temporaryObjectExpr); REGISTER_MATCHER(thisExpr); @@ -298,8 +317,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(to); REGISTER_MATCHER(tryStmt); REGISTER_MATCHER(type); - REGISTER_MATCHER(typeLoc); + REGISTER_MATCHER(typedefDecl); REGISTER_MATCHER(typedefType); + REGISTER_MATCHER(typeLoc); REGISTER_MATCHER(unaryExprOrTypeTraitExpr); REGISTER_MATCHER(unaryOperator); REGISTER_MATCHER(unaryTransformType); @@ -308,8 +328,11 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(unresolvedUsingValueDecl); REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usingDecl); + REGISTER_MATCHER(usingDirectiveDecl); + REGISTER_MATCHER(valueDecl); REGISTER_MATCHER(varDecl); REGISTER_MATCHER(variableArrayType); + REGISTER_MATCHER(voidType); REGISTER_MATCHER(whileStmt); REGISTER_MATCHER(withInitializer); } @@ -353,77 +376,63 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } -struct ReverseSpecificityThenName { - bool operator()(const std::pair<unsigned, std::string> &A, - const std::pair<unsigned, std::string> &B) const { - return A.first > B.first || (A.first == B.first && A.second < B.second); - } -}; - -} +} // namespace -std::vector<MatcherCompletion> Registry::getCompletions( - ArrayRef<std::pair<MatcherCtor, unsigned> > Context) { +std::vector<ArgKind> Registry::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { ASTNodeKind InitialTypes[] = { - ASTNodeKind::getFromNodeKind<Decl>(), - ASTNodeKind::getFromNodeKind<QualType>(), - ASTNodeKind::getFromNodeKind<Type>(), - ASTNodeKind::getFromNodeKind<Stmt>(), - ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), - ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), - ASTNodeKind::getFromNodeKind<TypeLoc>() - }; - ArrayRef<ASTNodeKind> InitialTypesRef(InitialTypes); + ASTNodeKind::getFromNodeKind<Decl>(), + ASTNodeKind::getFromNodeKind<QualType>(), + ASTNodeKind::getFromNodeKind<Type>(), + ASTNodeKind::getFromNodeKind<Stmt>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), + ASTNodeKind::getFromNodeKind<TypeLoc>()}; // Starting with the above seed of acceptable top-level matcher types, compute // the acceptable type set for the argument indicated by each context element. - std::set<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end()); - for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator - CtxI = Context.begin(), - CtxE = Context.end(); - CtxI != CtxE; ++CtxI) { - std::vector<internal::ArgKind> NextTypeSet; - for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end(); - I != E; ++I) { - if (CtxI->first->isConvertibleTo(*I) && - (CtxI->first->isVariadic() || - CtxI->second < CtxI->first->getNumArgs())) - CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet); + std::set<ArgKind> TypeSet(std::begin(InitialTypes), std::end(InitialTypes)); + for (const auto &CtxEntry : Context) { + MatcherCtor Ctor = CtxEntry.first; + unsigned ArgNumber = CtxEntry.second; + std::vector<ArgKind> NextTypeSet; + for (const ArgKind &Kind : TypeSet) { + if (Kind.getArgKind() == Kind.AK_Matcher && + Ctor->isConvertibleTo(Kind.getMatcherKind()) && + (Ctor->isVariadic() || ArgNumber < Ctor->getNumArgs())) + Ctor->getArgKinds(Kind.getMatcherKind(), ArgNumber, NextTypeSet); } TypeSet.clear(); - for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(), - E = NextTypeSet.end(); - I != E; ++I) { - if (I->getArgKind() == internal::ArgKind::AK_Matcher) - TypeSet.insert(I->getMatcherKind()); - } + TypeSet.insert(NextTypeSet.begin(), NextTypeSet.end()); } + return std::vector<ArgKind>(TypeSet.begin(), TypeSet.end()); +} - typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion, - ReverseSpecificityThenName> CompletionsTy; - CompletionsTy Completions; +std::vector<MatcherCompletion> +Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) { + std::vector<MatcherCompletion> Completions; - // TypeSet now contains the list of acceptable types for the argument we are - // completing. Search the registry for acceptable matchers. + // Search the registry for acceptable matchers. for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(), E = RegistryData->constructors().end(); I != E; ++I) { std::set<ASTNodeKind> RetKinds; unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs(); bool IsPolymorphic = I->second->isPolymorphic(); - std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs); + std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs); unsigned MaxSpecificity = 0; - for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(), - TE = TypeSet.end(); - TI != TE; ++TI) { + for (const ArgKind& Kind : AcceptedTypes) { + if (Kind.getArgKind() != Kind.AK_Matcher) + continue; unsigned Specificity; ASTNodeKind LeastDerivedKind; - if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) { + if (I->second->isConvertibleTo(Kind.getMatcherKind(), &Specificity, + &LeastDerivedKind)) { if (MaxSpecificity < Specificity) MaxSpecificity = Specificity; RetKinds.insert(LeastDerivedKind); for (unsigned Arg = 0; Arg != NumArgs; ++Arg) - I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]); + I->second->getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]); if (IsPolymorphic) break; } @@ -437,24 +446,25 @@ std::vector<MatcherCompletion> Registry::getCompletions( OS << "Matcher<T> " << I->first() << "(Matcher<T>"; } else { OS << "Matcher<" << RetKinds << "> " << I->first() << "("; - for (std::vector<std::vector<internal::ArgKind> >::iterator - KI = ArgsKinds.begin(), - KE = ArgsKinds.end(); - KI != KE; ++KI) { - if (KI != ArgsKinds.begin()) + for (const std::vector<ArgKind> &Arg : ArgsKinds) { + if (&Arg != &ArgsKinds[0]) OS << ", "; - // This currently assumes that a matcher may not overload a - // non-matcher, and all non-matcher overloads have identical - // arguments. - if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) { - std::set<ASTNodeKind> MatcherKinds; - std::transform( - KI->begin(), KI->end(), - std::inserter(MatcherKinds, MatcherKinds.end()), - std::mem_fun_ref(&internal::ArgKind::getMatcherKind)); + + bool FirstArgKind = true; + std::set<ASTNodeKind> MatcherKinds; + // Two steps. First all non-matchers, then matchers only. + for (const ArgKind &AK : Arg) { + if (AK.getArgKind() == ArgKind::AK_Matcher) { + MatcherKinds.insert(AK.getMatcherKind()); + } else { + if (!FirstArgKind) OS << "|"; + FirstArgKind = false; + OS << AK.asString(); + } + } + if (!MatcherKinds.empty()) { + if (!FirstArgKind) OS << "|"; OS << "Matcher<" << MatcherKinds << ">"; - } else { - OS << (*KI)[0].asString(); } } } @@ -466,19 +476,14 @@ std::vector<MatcherCompletion> Registry::getCompletions( TypedText += "("; if (ArgsKinds.empty()) TypedText += ")"; - else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String) + else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String) TypedText += "\""; - Completions[std::make_pair(MaxSpecificity, I->first())] = - MatcherCompletion(TypedText, OS.str()); + Completions.emplace_back(TypedText, OS.str(), MaxSpecificity); } } - std::vector<MatcherCompletion> RetVal; - for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end(); - I != E; ++I) - RetVal.push_back(I->second); - return RetVal; + return Completions; } // static diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index 18c9894..a88b707 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -20,26 +20,88 @@ namespace clang { namespace ast_matchers { namespace dynamic { -VariantMatcher::MatcherOps::~MatcherOps() {} +std::string ArgKind::asString() const { + switch (getArgKind()) { + case AK_Matcher: + return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); + case AK_Unsigned: + return "unsigned"; + case AK_String: + return "string"; + } + llvm_unreachable("unhandled ArgKind"); +} + +bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const { + if (K != To.K) + return false; + if (K != AK_Matcher) { + if (Specificity) + *Specificity = 1; + return true; + } + unsigned Distance; + if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance)) + return false; + + if (Specificity) + *Specificity = 100 - Distance; + return true; +} + +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); + return Matcher.canConvertTo(NodeKind); +} + +llvm::Optional<DynTypedMatcher> +VariantMatcher::MatcherOps::constructVariadicOperator( + DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const { + std::vector<DynTypedMatcher> DynMatchers; + for (const auto &InnerMatcher : InnerMatchers) { + // Abort if any of the inner matchers can't be converted to + // Matcher<T>. + if (!InnerMatcher.Value) + return llvm::None; + llvm::Optional<DynTypedMatcher> Inner = + InnerMatcher.Value->getTypedMatcher(*this); + if (!Inner) + return llvm::None; + DynMatchers.push_back(*Inner); + } + return DynTypedMatcher::constructVariadic(Op, DynMatchers); +} + VariantMatcher::Payload::~Payload() {} class VariantMatcher::SinglePayload : public VariantMatcher::Payload { public: SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { return Matcher; } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") .str(); } - virtual void makeTypedMatcher(MatcherOps &Ops) const { + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { bool Ignore; if (Ops.canConstructFrom(Matcher, Ignore)) - Ops.constructFrom(Matcher); + return Matcher; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + return ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, Specificity); } private: @@ -51,15 +113,15 @@ public: PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn) : Matchers(std::move(MatchersIn)) {} - virtual ~PolymorphicPayload() {} + ~PolymorphicPayload() override {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { if (Matchers.size() != 1) return llvm::Optional<DynTypedMatcher>(); return Matchers[0]; } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { std::string Inner; for (size_t i = 0, e = Matchers.size(); i != e; ++i) { if (i != 0) @@ -69,7 +131,8 @@ public: return (Twine("Matcher<") + Inner + ">").str(); } - virtual void makeTypedMatcher(MatcherOps &Ops) const { + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { bool FoundIsExact = false; const DynTypedMatcher *Found = nullptr; int NumFound = 0; @@ -89,7 +152,23 @@ public: } // We only succeed if we found exactly one, or if we found an exact match. if (Found && (FoundIsExact || NumFound == 1)) - Ops.constructFrom(*Found); + return *Found; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + unsigned MaxSpecificity = 0; + for (const DynTypedMatcher &Matcher : Matchers) { + unsigned ThisSpecificity; + if (ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, &ThisSpecificity)) { + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + } + if (Specificity) + *Specificity = MaxSpecificity; + return MaxSpecificity > 0; } const std::vector<DynTypedMatcher> Matchers; @@ -97,15 +176,15 @@ public: class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { public: - VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func, + VariadicOpPayload(DynTypedMatcher::VariadicOperator Op, std::vector<VariantMatcher> Args) - : Func(Func), Args(std::move(Args)) {} + : Op(Op), Args(std::move(Args)) {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { return llvm::Optional<DynTypedMatcher>(); } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { std::string Inner; for (size_t i = 0, e = Args.size(); i != e; ++i) { if (i != 0) @@ -115,12 +194,22 @@ public: return Inner; } - virtual void makeTypedMatcher(MatcherOps &Ops) const { - Ops.constructVariadicOperator(Func, Args); + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + return Ops.constructVariadicOperator(Op, Args); + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + for (const VariantMatcher &Matcher : Args) { + if (!Matcher.isConvertibleTo(Kind, Specificity)) + return false; + } + return true; } private: - const ast_matchers::internal::VariadicOperatorFunction Func; + const DynTypedMatcher::VariadicOperator Op; const std::vector<VariantMatcher> Args; }; @@ -136,9 +225,9 @@ VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { } VariantMatcher VariantMatcher::VariadicOperatorMatcher( - ast_matchers::internal::VariadicOperatorFunction Func, + DynTypedMatcher::VariadicOperator Op, std::vector<VariantMatcher> Args) { - return VariantMatcher(new VariadicOpPayload(Func, std::move(Args))); + return VariantMatcher(new VariadicOpPayload(Op, std::move(Args))); } llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { @@ -251,6 +340,43 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) { Value.Matcher = new VariantMatcher(NewValue); } +bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { + switch (Kind.getArgKind()) { + case ArgKind::AK_Unsigned: + if (!isUnsigned()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_String: + if (!isString()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_Matcher: + if (!isMatcher()) + return false; + return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity); + } + llvm_unreachable("Invalid Type"); +} + +bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds, + unsigned *Specificity) const { + unsigned MaxSpecificity = 0; + for (const ArgKind& Kind : Kinds) { + unsigned ThisSpecificity; + if (!isConvertibleTo(Kind, &ThisSpecificity)) + continue; + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + if (Specificity && MaxSpecificity > 0) { + *Specificity = MaxSpecificity; + } + return MaxSpecificity > 0; +} + std::string VariantValue::getTypeAsString() const { switch (Type) { case VT_String: return "String"; |