diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/lib/ASTMatchers | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/ASTMatchers')
7 files changed, 1999 insertions, 215 deletions
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 6ebd736..f6dcb97 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -30,10 +30,21 @@ namespace { typedef MatchFinder::MatchCallback MatchCallback; +// The maximum number of memoization entries to store. +// 10k has been experimentally found to give a good trade-off +// of performance vs. memory consumption by running matcher +// that match on every statement over a very large codebase. +// +// FIXME: Do some performance optimization in general and +// revisit this number; also, put up micro-benchmarks that we can +// optimize this on. +static const unsigned MaxMemoizationEntries = 10000; + // We use memoization to avoid running the same matcher on the same -// AST node twice. This pair is the key for looking up match +// AST node twice. This struct is the key for looking up match // result. It consists of an ID of the MatcherInterface (for -// identifying the matcher) and a pointer to the AST node. +// identifying the matcher), a pointer to the AST node and the +// bound nodes before the matcher was executed. // // We currently only memoize on nodes whose pointers identify the // nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc). @@ -41,12 +52,24 @@ typedef MatchFinder::MatchCallback MatchCallback; // generation of keys for each type. // FIXME: Benchmark whether memoization of non-pointer typed nodes // provides enough benefit for the additional amount of code. -typedef std::pair<uint64_t, const void*> UntypedMatchInput; +struct MatchKey { + uint64_t MatcherID; + ast_type_traits::DynTypedNode Node; + BoundNodesTreeBuilder BoundNodes; + + bool operator<(const MatchKey &Other) const { + if (MatcherID != Other.MatcherID) + return MatcherID < Other.MatcherID; + if (Node != Other.Node) + return Node < Other.Node; + return BoundNodes < Other.BoundNodes; + } +}; // Used to store the result of a match and possibly bound nodes. struct MemoizedMatchResult { bool ResultOfMatch; - BoundNodesTree Nodes; + BoundNodesTreeBuilder Nodes; }; // A RecursiveASTVisitor that traverses all children or all descendants of @@ -103,6 +126,12 @@ public: else if (const TypeLoc *T = DynNode.get<TypeLoc>()) traverse(*T); // FIXME: Add other base types after adding tests. + + // It's OK to always overwrite the bound nodes, as if there was + // no match in this recursive branch, the result set is empty + // anyway. + *Builder = ResultBindings; + return Matches; } @@ -220,18 +249,20 @@ private: return true; } if (Bind != ASTMatchFinder::BK_All) { - if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), - Finder, Builder)) { + BoundNodesTreeBuilder RecursiveBuilder(*Builder); + if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder, + &RecursiveBuilder)) { Matches = true; - return false; // Abort as soon as a match is found. + ResultBindings.addMatch(RecursiveBuilder); + return false; // Abort as soon as a match is found. } } else { - BoundNodesTreeBuilder RecursiveBuilder; - if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), - Finder, &RecursiveBuilder)) { + BoundNodesTreeBuilder RecursiveBuilder(*Builder); + if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder, + &RecursiveBuilder)) { // After the first match the matcher succeeds. Matches = true; - Builder->addMatch(RecursiveBuilder.build()); + ResultBindings.addMatch(RecursiveBuilder); } } return true; @@ -251,6 +282,7 @@ private: const DynTypedMatcher *const Matcher; ASTMatchFinder *const Finder; BoundNodesTreeBuilder *const Builder; + BoundNodesTreeBuilder ResultBindings; int CurrentDepth; const int MaxDepth; const ASTMatchFinder::TraversalKind Traversal; @@ -263,21 +295,31 @@ private: class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, public ASTMatchFinder { public: - MatchASTVisitor(std::vector<std::pair<const internal::DynTypedMatcher*, - MatchCallback*> > *MatcherCallbackPairs) - : MatcherCallbackPairs(MatcherCallbackPairs), - ActiveASTContext(NULL) { - } + MatchASTVisitor( + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > * + MatcherCallbackPairs) + : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(NULL) {} void onStartOfTranslationUnit() { - for (std::vector<std::pair<const internal::DynTypedMatcher*, - MatchCallback*> >::const_iterator - I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end(); + for (std::vector<std::pair<internal::DynTypedMatcher, + MatchCallback *> >::const_iterator + I = MatcherCallbackPairs->begin(), + E = MatcherCallbackPairs->end(); I != E; ++I) { I->second->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(); + } + } + void set_active_ast_context(ASTContext *NewActiveASTContext) { ActiveASTContext = NewActiveASTContext; } @@ -285,7 +327,7 @@ public: // The following Visit*() and Traverse*() functions "override" // methods in RecursiveASTVisitor. - bool VisitTypedefDecl(TypedefDecl *DeclNode) { + bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) { // When we see 'typedef A B', we add name 'B' to the set of names // A's canonical type maps to. This is necessary for implementing // isDerivedFrom(x) properly, where x can be the name of the base @@ -332,25 +374,30 @@ public: const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { - const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData()); - // For AST-nodes that don't have an identity, we can't memoize. - if (!input.second) + if (!Node.getMemoizationData()) return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal, Bind); - std::pair<MemoizationMap::iterator, bool> InsertResult - = ResultCache.insert(std::make_pair(input, MemoizedMatchResult())); - if (InsertResult.second) { - BoundNodesTreeBuilder DescendantBoundNodesBuilder; - InsertResult.first->second.ResultOfMatch = - matchesRecursively(Node, Matcher, &DescendantBoundNodesBuilder, - MaxDepth, Traversal, Bind); - InsertResult.first->second.Nodes = - DescendantBoundNodesBuilder.build(); + MatchKey Key; + Key.MatcherID = Matcher.getID(); + Key.Node = Node; + // Note that we key on the bindings *before* the match. + Key.BoundNodes = *Builder; + + MemoizationMap::iterator I = ResultCache.find(Key); + if (I != ResultCache.end()) { + *Builder = I->second.Nodes; + return I->second.ResultOfMatch; } - InsertResult.first->second.Nodes.copyTo(Builder); - return InsertResult.first->second.ResultOfMatch; + + MemoizedMatchResult Result; + Result.Nodes = *Builder; + Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes, + MaxDepth, Traversal, Bind); + ResultCache[Key] = Result; + *Builder = Result.Nodes; + return Result.ResultOfMatch; } // Matches children or descendants of 'Node' with 'BaseMatcher'. @@ -373,14 +420,18 @@ public: BoundNodesTreeBuilder *Builder, TraversalKind Traversal, BindKind Bind) { - return matchesRecursively(Node, Matcher, Builder, 1, Traversal, - Bind); + if (ResultCache.size() > MaxMemoizationEntries) + ResultCache.clear(); + return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal, + Bind); } // Implements ASTMatchFinder::matchesDescendantOf. virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { + if (ResultCache.size() > MaxMemoizationEntries) + ResultCache.clear(); return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX, TK_AsIs, Bind); } @@ -389,6 +440,10 @@ public: const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { + // Reset the cache outside of the recursive call to make sure we + // don't invalidate any iterators. + if (ResultCache.size() > MaxMemoizationEntries) + ResultCache.clear(); return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode); } @@ -396,15 +451,15 @@ 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<const internal::DynTypedMatcher*, - MatchCallback*> >::const_iterator - I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end(); + 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)) { - BoundNodesTree BoundNodes = Builder.build(); + if (I->first.matches(Node, this, &Builder)) { MatchVisitor Visitor(ActiveASTContext, I->second); - BoundNodes.visitMatches(&Visitor); + Builder.visitMatches(&Visitor); } } } @@ -450,60 +505,71 @@ private: assert(false && "Found node that is not in the parent map."); return false; } - const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData()); - MemoizationMap::iterator I = ResultCache.find(input); - if (I == ResultCache.end()) { - BoundNodesTreeBuilder AncestorBoundNodesBuilder; - bool Matches = false; - if (Parents.size() == 1) { - // Only one parent - do recursive memoization. - const ast_type_traits::DynTypedNode Parent = Parents[0]; - if (Matcher.matches(Parent, this, &AncestorBoundNodesBuilder)) { - Matches = true; - } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { - Matches = memoizedMatchesAncestorOfRecursively( - Parent, Matcher, &AncestorBoundNodesBuilder, MatchMode); + MatchKey Key; + Key.MatcherID = Matcher.getID(); + Key.Node = Node; + Key.BoundNodes = *Builder; + + // Note that we cannot use insert and reuse the iterator, as recursive + // calls to match might invalidate the result cache iterators. + MemoizationMap::iterator I = ResultCache.find(Key); + if (I != ResultCache.end()) { + *Builder = I->second.Nodes; + return I->second.ResultOfMatch; + } + MemoizedMatchResult Result; + Result.ResultOfMatch = false; + Result.Nodes = *Builder; + if (Parents.size() == 1) { + // Only one parent - do recursive memoization. + const ast_type_traits::DynTypedNode Parent = Parents[0]; + if (Matcher.matches(Parent, this, &Result.Nodes)) { + Result.ResultOfMatch = true; + } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { + // Reset the results to not include the bound nodes from the failed + // match above. + Result.Nodes = *Builder; + Result.ResultOfMatch = memoizedMatchesAncestorOfRecursively( + Parent, Matcher, &Result.Nodes, MatchMode); + // Once we get back from the recursive call, the result will be the + // same as the parent's result. + } + } 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()); + while (!Queue.empty()) { + Result.Nodes = *Builder; + if (Matcher.matches(Queue.front(), this, &Result.Nodes)) { + Result.ResultOfMatch = true; + break; } - } 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()); - while (!Queue.empty()) { - if (Matcher.matches(Queue.front(), this, - &AncestorBoundNodesBuilder)) { - Matches = true; - 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) { - // 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 (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) { + // 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); } - Queue.pop_front(); } + Queue.pop_front(); } - - I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult())) - .first; - I->second.Nodes = AncestorBoundNodesBuilder.build(); - I->second.ResultOfMatch = Matches; } - I->second.Nodes.copyTo(Builder); - return I->second.ResultOfMatch; + ResultCache[Key] = Result; + + *Builder = Result.Nodes; + return Result.ResultOfMatch; } // Implements a BoundNodesTree::Visitor that calls a MatchCallback with // the aggregated bound nodes for each match. - class MatchVisitor : public BoundNodesTree::Visitor { + class MatchVisitor : public BoundNodesTreeBuilder::Visitor { public: MatchVisitor(ASTContext* Context, MatchFinder::MatchCallback* Callback) @@ -525,28 +591,74 @@ private: BoundNodesTreeBuilder *Builder) { const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); - const std::set<const TypedefDecl*> &Aliases = TypeAliases[CanonicalType]; - for (std::set<const TypedefDecl*>::const_iterator + const std::set<const TypedefNameDecl *> &Aliases = + TypeAliases[CanonicalType]; + for (std::set<const TypedefNameDecl*>::const_iterator It = Aliases.begin(), End = Aliases.end(); It != End; ++It) { - if (Matcher.matches(**It, this, Builder)) + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(**It, this, &Result)) { + *Builder = Result; return true; + } } return false; } - std::vector<std::pair<const internal::DynTypedMatcher*, - MatchCallback*> > *const MatcherCallbackPairs; + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const + MatcherCallbackPairs; ASTContext *ActiveASTContext; // Maps a canonical type to its TypedefDecls. - llvm::DenseMap<const Type*, std::set<const TypedefDecl*> > TypeAliases; + llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases; // Maps (matcher, node) -> the match result for memoization. - typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap; + typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap; MemoizationMap ResultCache; }; +static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) { + // Type::getAs<...>() drills through typedefs. + if (TypeNode->getAs<DependentNameType>() != NULL || + TypeNode->getAs<DependentTemplateSpecializationType>() != NULL || + TypeNode->getAs<TemplateTypeParmType>() != NULL) + // Dependent names and template TypeNode parameters will be matched when + // the template is instantiated. + return NULL; + TemplateSpecializationType const *TemplateType = + TypeNode->getAs<TemplateSpecializationType>(); + if (TemplateType == NULL) { + return TypeNode->getAsCXXRecordDecl(); + } + if (TemplateType->getTemplateName().isDependent()) + // Dependent template specializations will be matched when the + // template is instantiated. + return NULL; + + // For template specialization types which are specializing a template + // declaration which is an explicit or partial specialization of another + // template declaration, getAsCXXRecordDecl() returns the corresponding + // ClassTemplateSpecializationDecl. + // + // For template specialization types which are specializing a template + // declaration which is neither an explicit nor partial specialization of + // another template declaration, getAsCXXRecordDecl() returns NULL and + // we get the CXXRecordDecl of the templated declaration. + CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl(); + if (SpecializationDecl != NULL) { + return SpecializationDecl; + } + NamedDecl *Templated = + TemplateType->getTemplateName().getAsTemplateDecl()->getTemplatedDecl(); + if (CXXRecordDecl *TemplatedRecord = dyn_cast<CXXRecordDecl>(Templated)) { + return TemplatedRecord; + } + // Now it can still be that we have an alias template. + TypeAliasDecl *AliasDecl = dyn_cast<TypeAliasDecl>(Templated); + assert(AliasDecl); + return getAsCXXRecordDecl(AliasDecl->getUnderlyingType().getTypePtr()); +} + // Returns true if the given class is directly or indirectly derived // from a base type with the given name. A class is not considered to be // derived from itself. @@ -557,58 +669,26 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, return false; typedef CXXRecordDecl::base_class_const_iterator BaseIterator; for (BaseIterator It = Declaration->bases_begin(), - End = Declaration->bases_end(); It != End; ++It) { + End = Declaration->bases_end(); + It != End; ++It) { const Type *TypeNode = It->getType().getTypePtr(); if (typeHasMatchingAlias(TypeNode, Base, Builder)) return true; - // Type::getAs<...>() drills through typedefs. - if (TypeNode->getAs<DependentNameType>() != NULL || - TypeNode->getAs<DependentTemplateSpecializationType>() != NULL || - TypeNode->getAs<TemplateTypeParmType>() != NULL) - // Dependent names and template TypeNode parameters will be matched when - // the template is instantiated. + CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode); + if (ClassDecl == NULL) continue; - CXXRecordDecl *ClassDecl = NULL; - TemplateSpecializationType const *TemplateType = - TypeNode->getAs<TemplateSpecializationType>(); - if (TemplateType != NULL) { - if (TemplateType->getTemplateName().isDependent()) - // Dependent template specializations will be matched when the - // template is instantiated. - continue; - - // For template specialization types which are specializing a template - // declaration which is an explicit or partial specialization of another - // template declaration, getAsCXXRecordDecl() returns the corresponding - // ClassTemplateSpecializationDecl. - // - // For template specialization types which are specializing a template - // declaration which is neither an explicit nor partial specialization of - // another template declaration, getAsCXXRecordDecl() returns NULL and - // we get the CXXRecordDecl of the templated declaration. - CXXRecordDecl *SpecializationDecl = - TemplateType->getAsCXXRecordDecl(); - if (SpecializationDecl != NULL) { - ClassDecl = SpecializationDecl; - } else { - ClassDecl = dyn_cast<CXXRecordDecl>( - TemplateType->getTemplateName() - .getAsTemplateDecl()->getTemplatedDecl()); - } - } else { - ClassDecl = TypeNode->getAsCXXRecordDecl(); - } - assert(ClassDecl != NULL); if (ClassDecl == Declaration) { // This can happen for recursive template definitions; if the // current declaration did not match, we can safely return false. - assert(TemplateType); return false; } - if (Base.matches(*ClassDecl, this, Builder)) + BoundNodesTreeBuilder Result(*Builder); + if (Base.matches(*ClassDecl, this, &Result)) { + *Builder = Result; return true; + } if (classIsDerivedFrom(ClassDecl, Base, Builder)) return true; } @@ -664,25 +744,19 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc( class MatchASTConsumer : public ASTConsumer { public: - MatchASTConsumer( - std::vector<std::pair<const internal::DynTypedMatcher*, - MatchCallback*> > *MatcherCallbackPairs, - MatchFinder::ParsingDoneTestCallback *ParsingDone) - : Visitor(MatcherCallbackPairs), - ParsingDone(ParsingDone) {} + MatchASTConsumer(MatchFinder *Finder, + MatchFinder::ParsingDoneTestCallback *ParsingDone) + : Finder(Finder), ParsingDone(ParsingDone) {} private: virtual void HandleTranslationUnit(ASTContext &Context) { if (ParsingDone != NULL) { ParsingDone->run(); } - Visitor.set_active_ast_context(&Context); - Visitor.onStartOfTranslationUnit(); - Visitor.TraverseDecl(Context.getTranslationUnitDecl()); - Visitor.set_active_ast_context(NULL); + Finder->matchAST(Context); } - MatchASTVisitor Visitor; + MatchFinder *Finder; MatchFinder::ParsingDoneTestCallback *ParsingDone; }; @@ -699,53 +773,64 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} MatchFinder::MatchFinder() : ParsingDone(NULL) {} -MatchFinder::~MatchFinder() { - for (std::vector<std::pair<const internal::DynTypedMatcher*, - MatchCallback*> >::const_iterator - It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end(); - It != End; ++It) { - delete It->first; - } -} +MatchFinder::~MatchFinder() {} void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new internal::Matcher<Decl>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); } void MatchFinder::addMatcher(const TypeMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new internal::Matcher<QualType>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); } void MatchFinder::addMatcher(const StatementMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new internal::Matcher<Stmt>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); } void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new NestedNameSpecifierMatcher(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); } void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new NestedNameSpecifierLocMatcher(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); } void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair( - new TypeLocMatcher(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); +} + +bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action) { + if (NodeMatch.canConvertTo<Decl>()) { + addMatcher(NodeMatch.convertTo<Decl>(), Action); + return true; + } else if (NodeMatch.canConvertTo<QualType>()) { + addMatcher(NodeMatch.convertTo<QualType>(), Action); + return true; + } else if (NodeMatch.canConvertTo<Stmt>()) { + addMatcher(NodeMatch.convertTo<Stmt>(), Action); + return true; + } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) { + addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action); + return true; + } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) { + addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action); + return true; + } else if (NodeMatch.canConvertTo<TypeLoc>()) { + addMatcher(NodeMatch.convertTo<TypeLoc>(), Action); + return true; + } + return false; } ASTConsumer *MatchFinder::newASTConsumer() { - return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); + return new internal::MatchASTConsumer(this, ParsingDone); } void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, @@ -755,6 +840,14 @@ void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, Visitor.match(Node); } +void MatchFinder::matchAST(ASTContext &Context) { + internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + Visitor.set_active_ast_context(&Context); + Visitor.onStartOfTranslationUnit(); + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + Visitor.onEndOfTranslationUnit(); +} + void MatchFinder::registerTestCallbackAfterParsing( MatchFinder::ParsingDoneTestCallback *NewParsingDone) { ParsingDone = NewParsingDone; diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index f1a9ff2..d15eb54 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -18,68 +18,65 @@ namespace clang { namespace ast_matchers { namespace internal { -void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const { - for (IDToNodeMap::const_iterator It = NodeMap.begin(); - It != NodeMap.end(); - ++It) { - Builder->setBinding(It->first, It->second); +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])); } } -void BoundNodesMap::copyTo(BoundNodesMap *Other) const { - for (IDToNodeMap::const_iterator I = NodeMap.begin(), - E = NodeMap.end(); - I != E; ++I) { - Other->NodeMap[I->first] = I->second; - } -} - -BoundNodesTree::BoundNodesTree() {} +DynTypedMatcher::MatcherStorage::~MatcherStorage() {} -BoundNodesTree::BoundNodesTree( - const BoundNodesMap& Bindings, - const std::vector<BoundNodesTree> RecursiveBindings) - : Bindings(Bindings), - RecursiveBindings(RecursiveBindings) {} - -void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const { - Bindings.copyTo(Builder); - for (std::vector<BoundNodesTree>::const_iterator - I = RecursiveBindings.begin(), - E = RecursiveBindings.end(); - I != E; ++I) { - Builder->addMatch(*I); +void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { + for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) { + Bindings.push_back(Other.Bindings[i]); } } -void BoundNodesTree::visitMatches(Visitor* ResultVisitor) { - BoundNodesMap AggregatedBindings; - visitMatchesRecursively(ResultVisitor, AggregatedBindings); +bool AllOfVariadicOperator(const ast_type_traits::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 (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + if (!InnerMatchers[i].matches(DynNode, Finder, Builder)) + return false; + } + return true; } -void BoundNodesTree:: -visitMatchesRecursively(Visitor* ResultVisitor, - const BoundNodesMap& AggregatedBindings) { - BoundNodesMap CombinedBindings(AggregatedBindings); - Bindings.copyTo(&CombinedBindings); - if (RecursiveBindings.empty()) { - ResultVisitor->visitMatch(BoundNodes(CombinedBindings)); - } else { - for (unsigned I = 0; I < RecursiveBindings.size(); ++I) { - RecursiveBindings[I].visitMatchesRecursively(ResultVisitor, - CombinedBindings); +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers) { + BoundNodesTreeBuilder Result; + bool Matched = false; + for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + BoundNodesTreeBuilder BuilderInner(*Builder); + if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) { + Matched = true; + Result.addMatch(BuilderInner); } } + *Builder = Result; + return Matched; } -BoundNodesTreeBuilder::BoundNodesTreeBuilder() {} - -void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) { - RecursiveBindings.push_back(Bindings); -} - -BoundNodesTree BoundNodesTreeBuilder::build() const { - return BoundNodesTree(Bindings, RecursiveBindings); +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) { + BoundNodesTreeBuilder Result = *Builder; + if (InnerMatchers[i].matches(DynNode, Finder, &Result)) { + *Builder = Result; + return true; + } + } + return false; } } // end namespace internal diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp new file mode 100644 index 0000000..da2ed9a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -0,0 +1,220 @@ +//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type, + SourceRange Range) { + ContextStack.push_back(ContextFrame()); + ContextFrame& data = ContextStack.back(); + data.Type = Type; + data.Range = Range; + return ArgStream(&data.Args); +} + +Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error, + StringRef MatcherName, + const SourceRange &MatcherRange) + : Error(Error) { + Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName; +} + +Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error, + StringRef MatcherName, + const SourceRange &MatcherRange, + unsigned ArgNumber) + : Error(Error) { + Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber + << MatcherName; +} + +Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); } + +Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error) + : Error(Error), BeginIndex(Error->Errors.size()) {} + +Diagnostics::OverloadContext::~OverloadContext() { + // Merge all errors that happened while in this context. + if (BeginIndex < Error->Errors.size()) { + Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex]; + for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) { + Dest.Messages.push_back(Error->Errors[i].Messages[0]); + } + Error->Errors.resize(BeginIndex + 1); + } +} + +void Diagnostics::OverloadContext::revertErrors() { + // Revert the errors. + Error->Errors.resize(BeginIndex); +} + +Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) { + Out->push_back(Arg.str()); + return *this; +} + +Diagnostics::ArgStream Diagnostics::addError(const SourceRange &Range, + ErrorType Error) { + Errors.push_back(ErrorContent()); + ErrorContent &Last = Errors.back(); + Last.ContextStack = ContextStack; + Last.Messages.push_back(ErrorContent::Message()); + Last.Messages.back().Range = Range; + Last.Messages.back().Type = Error; + return ArgStream(&Last.Messages.back().Args); +} + +StringRef contextTypeToFormatString(Diagnostics::ContextType Type) { + switch (Type) { + case Diagnostics::CT_MatcherConstruct: + return "Error building matcher $0."; + case Diagnostics::CT_MatcherArg: + return "Error parsing argument $0 for matcher $1."; + } + llvm_unreachable("Unknown ContextType value."); +} + +StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { + switch (Type) { + case Diagnostics::ET_RegistryNotFound: + return "Matcher not found: $0"; + case Diagnostics::ET_RegistryWrongArgCount: + return "Incorrect argument count. (Expected = $0) != (Actual = $1)"; + case Diagnostics::ET_RegistryWrongArgType: + return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)"; + case Diagnostics::ET_RegistryNotBindable: + return "Matcher does not support binding."; + case Diagnostics::ET_RegistryAmbiguousOverload: + // TODO: Add type info about the overload error. + return "Ambiguous matcher overload."; + + case Diagnostics::ET_ParserStringError: + return "Error parsing string token: <$0>"; + case Diagnostics::ET_ParserNoOpenParen: + return "Error parsing matcher. Found token <$0> while looking for '('."; + case Diagnostics::ET_ParserNoCloseParen: + return "Error parsing matcher. Found end-of-code while looking for ')'."; + case Diagnostics::ET_ParserNoComma: + return "Error parsing matcher. Found token <$0> while looking for ','."; + case Diagnostics::ET_ParserNoCode: + return "End of code found while looking for token."; + case Diagnostics::ET_ParserNotAMatcher: + return "Input value is not a matcher expression."; + case Diagnostics::ET_ParserInvalidToken: + return "Invalid token <$0> found when looking for a value."; + case Diagnostics::ET_ParserMalformedBindExpr: + return "Malformed bind() expression."; + case Diagnostics::ET_ParserTrailingCode: + return "Expected end of code."; + case Diagnostics::ET_ParserUnsignedError: + return "Error parsing unsigned token: <$0>"; + case Diagnostics::ET_ParserOverloadedType: + return "Input value has unresolved overloaded type: $0"; + + case Diagnostics::ET_None: + return "<N/A>"; + } + llvm_unreachable("Unknown ErrorType value."); +} + +void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args, + llvm::raw_ostream &OS) { + while (!FormatString.empty()) { + std::pair<StringRef, StringRef> Pieces = FormatString.split("$"); + OS << Pieces.first.str(); + if (Pieces.second.empty()) break; + + const char Next = Pieces.second.front(); + FormatString = Pieces.second.drop_front(); + if (Next >= '0' && Next <= '9') { + const unsigned Index = Next - '0'; + if (Index < Args.size()) { + OS << Args[Index]; + } else { + OS << "<Argument_Not_Provided>"; + } + } + } +} + +static void maybeAddLineAndColumn(const SourceRange &Range, + llvm::raw_ostream &OS) { + if (Range.Start.Line > 0 && Range.Start.Column > 0) { + OS << Range.Start.Line << ":" << Range.Start.Column << ": "; + } +} + +static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame, + llvm::raw_ostream &OS) { + maybeAddLineAndColumn(Frame.Range, OS); + formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS); +} + +static void +printMessageToStream(const Diagnostics::ErrorContent::Message &Message, + const Twine Prefix, llvm::raw_ostream &OS) { + maybeAddLineAndColumn(Message.Range, OS); + OS << Prefix; + formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS); +} + +static void printErrorContentToStream(const Diagnostics::ErrorContent &Content, + llvm::raw_ostream &OS) { + if (Content.Messages.size() == 1) { + printMessageToStream(Content.Messages[0], "", OS); + } else { + for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + printMessageToStream(Content.Messages[i], + "Candidate " + Twine(i + 1) + ": ", OS); + } + } +} + +void Diagnostics::printToStream(llvm::raw_ostream &OS) const { + for (size_t i = 0, e = Errors.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + printErrorContentToStream(Errors[i], OS); + } +} + +std::string Diagnostics::toString() const { + std::string S; + llvm::raw_string_ostream OS(S); + printToStream(OS); + return OS.str(); +} + +void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const { + for (size_t i = 0, e = Errors.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + const ErrorContent &Error = Errors[i]; + for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) { + printContextFrameToStream(Error.ContextStack[i], OS); + OS << "\n"; + } + printErrorContentToStream(Error, OS); + } +} + +std::string Diagnostics::toStringFull() const { + std::string S; + llvm::raw_string_ostream OS(S); + printToStreamFull(OS); + return OS.str(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h new file mode 100644 index 0000000..ae0c300 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -0,0 +1,453 @@ +//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Functions templates and classes to wrap matcher construct functions. +/// +/// A collection of template function and classes that provide a generic +/// marshalling layer on top of matcher construct functions. +/// These are used by the registry to export all marshaller constructors with +/// the same generic interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H + +#include <string> + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/type_traits.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace internal { + +/// \brief Helper template class to just from argument type to the right is/get +/// functions in VariantValue. +/// Used to verify and extract the matcher arguments below. +template <class T> struct ArgTypeTraits; +template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> { +}; + +template <> struct ArgTypeTraits<std::string> { + static StringRef asString() { return "String"; } + static bool is(const VariantValue &Value) { return Value.isString(); } + static const std::string &get(const VariantValue &Value) { + return Value.getString(); + } +}; + +template <> +struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> { +}; + +template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { + static std::string asString() { + return (Twine("Matcher<") + + ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() + + ">").str(); + } + static bool is(const VariantValue &Value) { + return Value.isMatcher() && Value.getMatcher().hasTypedMatcher<T>(); + } + static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { + return Value.getMatcher().getTypedMatcher<T>(); + } +}; + +template <> struct ArgTypeTraits<unsigned> { + static std::string asString() { return "Unsigned"; } + static bool is(const VariantValue &Value) { return Value.isUnsigned(); } + static unsigned get(const VariantValue &Value) { + return Value.getUnsigned(); + } +}; + +/// \brief Generic MatcherCreate interface. +/// +/// Provides a \c run() method that constructs the matcher from the provided +/// arguments. +class MatcherCreateCallback { +public: + virtual ~MatcherCreateCallback() {} + virtual VariantMatcher run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const = 0; +}; + +/// \brief Simple callback implementation. Marshaller and function are provided. +/// +/// This class wraps a function of arbitrary signature and a marshaller +/// function into a MatcherCreateCallback. +/// The marshaller is in charge of taking the VariantValue arguments, checking +/// their types, unpacking them and calling the underlying function. +class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback { +public: + typedef VariantMatcher (*MarshallerType)(void (*Func)(), + StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + /// \param Marshaller Function to unpack the arguments and call \c Func + /// \param Func Matcher construct function. This is the function that + /// compile-time matcher expressions would use to create the matcher. + FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, void (*Func)(), + StringRef MatcherName) + : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName) {} + + VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + return Marshaller(Func, MatcherName, NameRange, Args, Error); + } + +private: + const MarshallerType Marshaller; + void (* const Func)(); + const std::string MatcherName; +}; + +/// \brief Simple callback implementation. Free function is wrapped. +/// +/// This class simply wraps a free function with the right signature to export +/// it as a MatcherCreateCallback. +/// This allows us to have one implementation of the interface for as many free +/// functions as we want, reducing the number of symbols and size of the +/// object file. +class FreeFuncMatcherCreateCallback : public MatcherCreateCallback { +public: + typedef VariantMatcher (*RunFunc)(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName) + : Func(Func), MatcherName(MatcherName.str()) {} + + VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + return Func(MatcherName, NameRange, Args, Error); + } + +private: + const RunFunc Func; + const std::string MatcherName; +}; + +/// \brief Helper macros to check the arguments on all marshaller functions. +#define CHECK_ARG_COUNT(count) \ + if (Args.size() != count) { \ + Error->addError(NameRange, Error->ET_RegistryWrongArgCount) \ + << count << Args.size(); \ + return VariantMatcher(); \ + } + +#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>::asString() \ + << Args[index].Value.getTypeAsString(); \ + return VariantMatcher(); \ + } + +/// \brief Helper methods to extract and merge all possible typed matchers +/// out of the polymorphic object. +template <class PolyMatcher> +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector<DynTypedMatcher> &Out, + ast_matchers::internal::EmptyTypeList) {} + +template <class PolyMatcher, class TypeList> +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector<DynTypedMatcher> &Out, TypeList) { + Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly)); + mergePolyMatchers(Poly, Out, typename TypeList::tail()); +} + +/// \brief Convert the return values of the functions into a VariantMatcher. +/// +/// There are 2 cases right now: The return value is a Matcher<T> or is a +/// 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) { + return VariantMatcher::SingleMatcher(Matcher); +} + +template <typename T> +static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, + typename T::ReturnTypes * = + NULL) { + std::vector<DynTypedMatcher> Matchers; + mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes()); + VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers); + return Out; +} + +/// \brief 0-arg marshaller function. +template <typename ReturnType> +static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + typedef ReturnType (*FuncType)(); + CHECK_ARG_COUNT(0); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)()); +} + +/// \brief 1-arg marshaller function. +template <typename ReturnType, typename ArgType1> +static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + typedef ReturnType (*FuncType)(ArgType1); + CHECK_ARG_COUNT(1); + CHECK_ARG_TYPE(0, ArgType1); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)( + ArgTypeTraits<ArgType1>::get(Args[0].Value))); +} + +/// \brief 2-arg marshaller function. +template <typename ReturnType, typename ArgType1, typename ArgType2> +static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + typedef ReturnType (*FuncType)(ArgType1, ArgType2); + CHECK_ARG_COUNT(2); + CHECK_ARG_TYPE(0, ArgType1); + CHECK_ARG_TYPE(1, ArgType2); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)( + ArgTypeTraits<ArgType1>::get(Args[0].Value), + ArgTypeTraits<ArgType2>::get(Args[1].Value))); +} + +#undef CHECK_ARG_COUNT +#undef CHECK_ARG_TYPE + +/// \brief Variadic marshaller function. +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> +VariantMatcher +variadicMatcherCreateCallback(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, Diagnostics *Error) { + ArgT **InnerArgs = new ArgT *[Args.size()](); + + bool HasError = false; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + typedef ArgTypeTraits<ArgT> ArgTraits; + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!ArgTraits::is(Value)) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << ArgTraits::asString() << Value.getTypeAsString(); + HasError = true; + break; + } + InnerArgs[i] = new ArgT(ArgTraits::get(Value)); + } + + VariantMatcher Out; + if (!HasError) { + Out = outvalueToVariantMatcher( + Func(ArrayRef<const ArgT *>(InnerArgs, Args.size()))); + } + + for (size_t i = 0, e = Args.size(); i != e; ++i) { + delete InnerArgs[i]; + } + delete[] InnerArgs; + return Out; +} + +/// \brief Helper class used to collect all the possible overloads of an +/// argument adaptative matcher function. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +class AdaptativeOverloadCollector { +public: + AdaptativeOverloadCollector(StringRef Name, + std::vector<MatcherCreateCallback *> &Out) + : Name(Name), Out(Out) { + collect(FromTypes()); + } + +private: + typedef ast_matchers::internal::ArgumentAdaptingMatcherFunc< + ArgumentAdapterT, FromTypes, ToTypes> AdaptativeFunc; + + /// \brief End case for the recursion + static void collect(ast_matchers::internal::EmptyTypeList) {} + + /// \brief Recursive case. Get the overload for the head of the list, and + /// recurse to the tail. + template <typename FromTypeList> inline void collect(FromTypeList); + + const StringRef Name; + std::vector<MatcherCreateCallback *> &Out; +}; + +/// \brief MatcherCreateCallback that wraps multiple "overloads" of the same +/// matcher. +/// +/// It will try every overload and generate appropriate errors for when none or +/// more than one overloads match the arguments. +class OverloadedMatcherCreateCallback : public MatcherCreateCallback { +public: + OverloadedMatcherCreateCallback(ArrayRef<MatcherCreateCallback *> Callbacks) + : Overloads(Callbacks) {} + + virtual ~OverloadedMatcherCreateCallback() { + llvm::DeleteContainerPointers(Overloads); + } + + virtual VariantMatcher run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + std::vector<VariantMatcher> Constructed; + Diagnostics::OverloadContext Ctx(Error); + for (size_t i = 0, e = Overloads.size(); i != e; ++i) { + VariantMatcher SubMatcher = Overloads[i]->run(NameRange, Args, Error); + if (!SubMatcher.isNull()) { + Constructed.push_back(SubMatcher); + } + } + + if (Constructed.empty()) return VariantMatcher(); // No overload matched. + // We ignore the errors if any matcher succeeded. + Ctx.revertErrors(); + if (Constructed.size() > 1) { + // More than one constructed. It is ambiguous. + Error->addError(NameRange, Error->ET_RegistryAmbiguousOverload); + return VariantMatcher(); + } + return Constructed[0]; + } + +private: + std::vector<MatcherCreateCallback *> Overloads; +}; + +/// \brief Variadic operator marshaller function. +class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback { +public: + typedef ast_matchers::internal::VariadicOperatorFunction VarFunc; + VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName) + : Func(Func), MatcherName(MatcherName) {} + + virtual VariantMatcher run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + std::vector<VariantMatcher> InnerArgs; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!Value.isMatcher()) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << "Matcher<>" << Value.getTypeAsString(); + return VariantMatcher(); + } + InnerArgs.push_back(Value.getMatcher()); + } + return VariantMatcher::VariadicOperatorMatcher(Func, InnerArgs); + } + +private: + const VarFunc Func; + const StringRef MatcherName; +}; + + +/// Helper functions to select the appropriate marshaller functions. +/// They detect the number of arguments, arguments types and return type. + +/// \brief 0-arg overload +template <typename ReturnType> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(), + StringRef MatcherName) { + return new FixedArgCountMatcherCreateCallback( + matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func), + MatcherName); +} + +/// \brief 1-arg overload +template <typename ReturnType, typename ArgType1> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), + StringRef MatcherName) { + return new FixedArgCountMatcherCreateCallback( + matcherMarshall1<ReturnType, ArgType1>, + reinterpret_cast<void (*)()>(Func), MatcherName); +} + +/// \brief 2-arg overload +template <typename ReturnType, typename ArgType1, typename ArgType2> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, + ArgType2), + StringRef MatcherName) { + return new FixedArgCountMatcherCreateCallback( + matcherMarshall2<ReturnType, ArgType1, ArgType2>, + reinterpret_cast<void (*)()>(Func), MatcherName); +} + +/// \brief Variadic overload. +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> +MatcherCreateCallback * +makeMatcherAutoMarshall(llvm::VariadicFunction<ResultT, ArgT, Func> VarFunc, + StringRef MatcherName) { + return new FreeFuncMatcherCreateCallback( + &variadicMatcherCreateCallback<ResultT, ArgT, Func>, MatcherName); +} + +/// \brief Argument adaptative overload. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +MatcherCreateCallback * +makeMatcherAutoMarshall(ast_matchers::internal::ArgumentAdaptingMatcherFunc< + ArgumentAdapterT, FromTypes, ToTypes>, + StringRef MatcherName) { + std::vector<MatcherCreateCallback *> Overloads; + AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>(MatcherName, + Overloads); + return new OverloadedMatcherCreateCallback(Overloads); +} + +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +template <typename FromTypeList> +inline void +AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>::collect( + FromTypeList) { + Out.push_back(makeMatcherAutoMarshall( + &AdaptativeFunc::template create<typename FromTypeList::head>, Name)); + collect(typename FromTypeList::tail()); +} + +/// \brief Variadic operator overload. +MatcherCreateCallback *makeMatcherAutoMarshall( + ast_matchers::internal::VariadicOperatorMatcherFunc Func, + StringRef MatcherName) { + return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName); +} + +} // namespace internal +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp new file mode 100644 index 0000000..df9596e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp @@ -0,0 +1,420 @@ +//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Recursive parser implementation for the matcher expression grammar. +/// +//===----------------------------------------------------------------------===// + +#include <string> +#include <vector> + +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Simple structure to hold information for one token from the parser. +struct Parser::TokenInfo { + /// \brief Different possible tokens. + enum TokenKind { + TK_Eof = 0, + TK_OpenParen = 1, + TK_CloseParen = 2, + TK_Comma = 3, + TK_Period = 4, + TK_Literal = 5, + TK_Ident = 6, + TK_InvalidChar = 7, + TK_Error = 8 + }; + + /// \brief Some known identifiers. + static const char* const ID_Bind; + + TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {} + + StringRef Text; + TokenKind Kind; + SourceRange Range; + VariantValue Value; +}; + +const char* const Parser::TokenInfo::ID_Bind = "bind"; + +/// \brief Simple tokenizer for the parser. +class Parser::CodeTokenizer { +public: + explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) + : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) { + NextToken = getNextToken(); + } + + /// \brief Returns but doesn't consume the next token. + const TokenInfo &peekNextToken() const { return NextToken; } + + /// \brief Consumes and returns the next token. + TokenInfo consumeNextToken() { + TokenInfo ThisToken = NextToken; + NextToken = getNextToken(); + return ThisToken; + } + + TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; } + +private: + TokenInfo getNextToken() { + consumeWhitespace(); + TokenInfo Result; + Result.Range.Start = currentLocation(); + + if (Code.empty()) { + Result.Kind = TokenInfo::TK_Eof; + Result.Text = ""; + return Result; + } + + switch (Code[0]) { + case ',': + Result.Kind = TokenInfo::TK_Comma; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case '.': + Result.Kind = TokenInfo::TK_Period; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case '(': + Result.Kind = TokenInfo::TK_OpenParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case ')': + Result.Kind = TokenInfo::TK_CloseParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + + case '"': + case '\'': + // Parse a string literal. + consumeStringLiteral(&Result); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // Parse an unsigned literal. + consumeUnsignedLiteral(&Result); + break; + + default: + if (isAlphanumeric(Code[0])) { + // Parse an identifier + size_t TokenLength = 1; + while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength])) + ++TokenLength; + Result.Kind = TokenInfo::TK_Ident; + Result.Text = Code.substr(0, TokenLength); + Code = Code.drop_front(TokenLength); + } else { + Result.Kind = TokenInfo::TK_InvalidChar; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(1); + } + break; + } + + Result.Range.End = currentLocation(); + return Result; + } + + /// \brief Consume an unsigned literal. + void consumeUnsignedLiteral(TokenInfo *Result) { + unsigned Length = 1; + if (Code.size() > 1) { + // Consume the 'x' or 'b' radix modifier, if present. + switch (toLowercase(Code[1])) { + case 'x': case 'b': Length = 2; + } + } + while (Length < Code.size() && isHexDigit(Code[Length])) + ++Length; + + Result->Text = Code.substr(0, Length); + Code = Code.drop_front(Length); + + unsigned Value; + if (!Result->Text.getAsInteger(0, Value)) { + Result->Kind = TokenInfo::TK_Literal; + Result->Value = Value; + } else { + SourceRange Range; + Range.Start = Result->Range.Start; + Range.End = currentLocation(); + Error->addError(Range, Error->ET_ParserUnsignedError) << Result->Text; + Result->Kind = TokenInfo::TK_Error; + } + } + + /// \brief Consume a string literal. + /// + /// \c Code must be positioned at the start of the literal (the opening + /// quote). Consumed until it finds the same closing quote character. + void consumeStringLiteral(TokenInfo *Result) { + bool InEscape = false; + const char Marker = Code[0]; + for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) { + if (InEscape) { + InEscape = false; + continue; + } + if (Code[Length] == '\\') { + InEscape = true; + continue; + } + if (Code[Length] == Marker) { + Result->Kind = TokenInfo::TK_Literal; + Result->Text = Code.substr(0, Length + 1); + Result->Value = Code.substr(1, Length - 1).str(); + Code = Code.drop_front(Length + 1); + return; + } + } + + StringRef ErrorText = Code; + Code = Code.drop_front(Code.size()); + SourceRange Range; + Range.Start = Result->Range.Start; + Range.End = currentLocation(); + Error->addError(Range, Error->ET_ParserStringError) << ErrorText; + Result->Kind = TokenInfo::TK_Error; + } + + /// \brief Consume all leading whitespace from \c Code. + void consumeWhitespace() { + while (!Code.empty() && isWhitespace(Code[0])) { + if (Code[0] == '\n') { + ++Line; + StartOfLine = Code.drop_front(); + } + Code = Code.drop_front(); + } + } + + SourceLocation currentLocation() { + SourceLocation Location; + Location.Line = Line; + Location.Column = Code.data() - StartOfLine.data() + 1; + return Location; + } + + StringRef Code; + StringRef StartOfLine; + unsigned Line; + Diagnostics *Error; + TokenInfo NextToken; +}; + +Parser::Sema::~Sema() {} + +/// \brief Parse and validate a matcher expression. +/// \return \c true on success, in which case \c Value has the matcher parsed. +/// If the input is malformed, or some argument has an error, it +/// returns \c false. +bool Parser::parseMatcherExpressionImpl(VariantValue *Value) { + const TokenInfo NameToken = Tokenizer->consumeNextToken(); + assert(NameToken.Kind == TokenInfo::TK_Ident); + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen) + << OpenToken.Text; + return false; + } + + std::vector<ParserValue> Args; + TokenInfo EndToken; + while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) { + if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) { + // End of args. + EndToken = Tokenizer->consumeNextToken(); + break; + } + if (Args.size() > 0) { + // We must find a , token to continue. + const TokenInfo CommaToken = Tokenizer->consumeNextToken(); + if (CommaToken.Kind != TokenInfo::TK_Comma) { + Error->addError(CommaToken.Range, Error->ET_ParserNoComma) + << CommaToken.Text; + return false; + } + } + + Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error, + NameToken.Text, NameToken.Range, Args.size() + 1); + ParserValue ArgValue; + ArgValue.Text = Tokenizer->peekNextToken().Text; + ArgValue.Range = Tokenizer->peekNextToken().Range; + if (!parseExpressionImpl(&ArgValue.Value)) return false; + + Args.push_back(ArgValue); + } + + if (EndToken.Kind == TokenInfo::TK_Eof) { + Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen); + return false; + } + + std::string BindID; + if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) { + // Parse .bind("foo") + Tokenizer->consumeNextToken(); // consume the period. + const TokenInfo BindToken = Tokenizer->consumeNextToken(); + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + const TokenInfo IDToken = Tokenizer->consumeNextToken(); + const TokenInfo CloseToken = Tokenizer->consumeNextToken(); + + // TODO: We could use different error codes for each/some to be more + // explicit about the syntax error. + if (BindToken.Kind != TokenInfo::TK_Ident || + BindToken.Text != TokenInfo::ID_Bind) { + Error->addError(BindToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) { + Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (CloseToken.Kind != TokenInfo::TK_CloseParen) { + Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + BindID = IDToken.Value.getString(); + } + + // Merge the start and end infos. + Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error, + NameToken.Text, NameToken.Range); + SourceRange MatcherRange = NameToken.Range; + MatcherRange.End = EndToken.Range.End; + VariantMatcher Result = S->actOnMatcherExpression( + NameToken.Text, MatcherRange, BindID, Args, Error); + if (Result.isNull()) return false; + + *Value = Result; + return true; +} + +/// \brief Parse an <Expresssion> +bool Parser::parseExpressionImpl(VariantValue *Value) { + switch (Tokenizer->nextTokenKind()) { + case TokenInfo::TK_Literal: + *Value = Tokenizer->consumeNextToken().Value; + return true; + + case TokenInfo::TK_Ident: + return parseMatcherExpressionImpl(Value); + + case TokenInfo::TK_Eof: + Error->addError(Tokenizer->consumeNextToken().Range, + Error->ET_ParserNoCode); + return false; + + case TokenInfo::TK_Error: + // This error was already reported by the tokenizer. + return false; + + case TokenInfo::TK_OpenParen: + case TokenInfo::TK_CloseParen: + case TokenInfo::TK_Comma: + case TokenInfo::TK_Period: + case TokenInfo::TK_InvalidChar: + const TokenInfo Token = Tokenizer->consumeNextToken(); + Error->addError(Token.Range, Error->ET_ParserInvalidToken) << Token.Text; + return false; + } + + llvm_unreachable("Unknown token kind."); +} + +Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, + Diagnostics *Error) + : Tokenizer(Tokenizer), S(S), Error(Error) {} + +class RegistrySema : public Parser::Sema { +public: + virtual ~RegistrySema() {} + VariantMatcher actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + if (BindID.empty()) { + return Registry::constructMatcher(MatcherName, NameRange, Args, Error); + } else { + return Registry::constructBoundMatcher(MatcherName, NameRange, BindID, + Args, Error); + } + } +}; + +bool Parser::parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + RegistrySema S; + return parseExpression(Code, &S, Value, Error); +} + +bool Parser::parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + CodeTokenizer Tokenizer(Code, Error); + if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false; + if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) { + Error->addError(Tokenizer.peekNextToken().Range, + Error->ET_ParserTrailingCode); + return false; + } + return true; +} + +llvm::Optional<DynTypedMatcher> +Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) { + RegistrySema S; + return parseMatcherExpression(Code, &S, Error); +} + +llvm::Optional<DynTypedMatcher> +Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S, + Diagnostics *Error) { + VariantValue Value; + if (!parseExpression(Code, S, &Value, Error)) + return llvm::Optional<DynTypedMatcher>(); + if (!Value.isMatcher()) { + Error->addError(SourceRange(), Error->ET_ParserNotAMatcher); + return llvm::Optional<DynTypedMatcher>(); + } + llvm::Optional<DynTypedMatcher> Result = + Value.getMatcher().getSingleMatcher(); + if (!Result.hasValue()) { + Error->addError(SourceRange(), Error->ET_ParserOverloadedType) + << Value.getTypeAsString(); + } + return Result; +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp new file mode 100644 index 0000000..70e956e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -0,0 +1,345 @@ +//===--- Registry.cpp - Matcher registry -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===------------------------------------------------------------===// +/// +/// \file +/// \brief Registry map populated at static initialization time. +/// +//===------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Registry.h" + +#include <utility> + +#include "Marshallers.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ManagedStatic.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using internal::MatcherCreateCallback; + +typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap; +class RegistryMaps { +public: + RegistryMaps(); + ~RegistryMaps(); + + const ConstructorMap &constructors() const { return Constructors; } + +private: + void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback); + ConstructorMap Constructors; +}; + +void RegistryMaps::registerMatcher(StringRef MatcherName, + MatcherCreateCallback *Callback) { + assert(Constructors.find(MatcherName) == Constructors.end()); + Constructors[MatcherName] = Callback; +} + +#define REGISTER_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherAutoMarshall( \ + ::clang::ast_matchers::name, #name)); + +#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \ + static_cast< ::clang::ast_matchers::name##_Type##Id>( \ + ::clang::ast_matchers::name) + +#define REGISTER_OVERLOADED_2(name) \ + do { \ + MatcherCreateCallback *Callbacks[] = { \ + internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \ + #name), \ + internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \ + #name) \ + }; \ + registerMatcher(#name, \ + new internal::OverloadedMatcherCreateCallback(Callbacks)); \ + } while (0) + +/// \brief Generate a registry map with all the known matchers. +RegistryMaps::RegistryMaps() { + // TODO: Here is the list of the missing matchers, grouped by reason. + // + // Need Variant/Parser fixes: + // ofKind + // + // Polymorphic + argument overload: + // unless + // findAll + // + // Other: + // loc + // equals + // equalsNode + + REGISTER_OVERLOADED_2(callee); + REGISTER_OVERLOADED_2(hasPrefix); + REGISTER_OVERLOADED_2(hasType); + REGISTER_OVERLOADED_2(isDerivedFrom); + REGISTER_OVERLOADED_2(isSameOrDerivedFrom); + REGISTER_OVERLOADED_2(pointsTo); + REGISTER_OVERLOADED_2(references); + REGISTER_OVERLOADED_2(thisPointerType); + + REGISTER_MATCHER(accessSpecDecl); + REGISTER_MATCHER(alignOfExpr); + REGISTER_MATCHER(allOf); + REGISTER_MATCHER(anyOf); + REGISTER_MATCHER(anything); + REGISTER_MATCHER(argumentCountIs); + REGISTER_MATCHER(arraySubscriptExpr); + REGISTER_MATCHER(arrayType); + REGISTER_MATCHER(asString); + REGISTER_MATCHER(asmStmt); + REGISTER_MATCHER(atomicType); + REGISTER_MATCHER(autoType); + REGISTER_MATCHER(binaryOperator); + REGISTER_MATCHER(bindTemporaryExpr); + REGISTER_MATCHER(blockPointerType); + REGISTER_MATCHER(boolLiteral); + REGISTER_MATCHER(breakStmt); + REGISTER_MATCHER(builtinType); + REGISTER_MATCHER(cStyleCastExpr); + REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(castExpr); + REGISTER_MATCHER(catchStmt); + REGISTER_MATCHER(characterLiteral); + REGISTER_MATCHER(classTemplateDecl); + REGISTER_MATCHER(classTemplateSpecializationDecl); + REGISTER_MATCHER(complexType); + REGISTER_MATCHER(compoundLiteralExpr); + REGISTER_MATCHER(compoundStmt); + REGISTER_MATCHER(conditionalOperator); + REGISTER_MATCHER(constCastExpr); + REGISTER_MATCHER(constantArrayType); + REGISTER_MATCHER(constructExpr); + REGISTER_MATCHER(constructorDecl); + REGISTER_MATCHER(containsDeclaration); + REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(ctorInitializer); + REGISTER_MATCHER(decl); + REGISTER_MATCHER(declCountIs); + REGISTER_MATCHER(declRefExpr); + REGISTER_MATCHER(declStmt); + REGISTER_MATCHER(defaultArgExpr); + REGISTER_MATCHER(deleteExpr); + REGISTER_MATCHER(dependentSizedArrayType); + REGISTER_MATCHER(destructorDecl); + REGISTER_MATCHER(doStmt); + REGISTER_MATCHER(dynamicCastExpr); + REGISTER_MATCHER(eachOf); + REGISTER_MATCHER(elaboratedType); + REGISTER_MATCHER(enumConstantDecl); + REGISTER_MATCHER(enumDecl); + REGISTER_MATCHER(explicitCastExpr); + REGISTER_MATCHER(expr); + REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(floatLiteral); + REGISTER_MATCHER(forEach); + REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forField); + REGISTER_MATCHER(forRangeStmt); + REGISTER_MATCHER(forStmt); + REGISTER_MATCHER(functionDecl); + REGISTER_MATCHER(functionTemplateDecl); + REGISTER_MATCHER(functionType); + REGISTER_MATCHER(functionalCastExpr); + REGISTER_MATCHER(gotoStmt); + REGISTER_MATCHER(has); + REGISTER_MATCHER(hasAncestor); + REGISTER_MATCHER(hasAnyArgument); + REGISTER_MATCHER(hasAnyConstructorInitializer); + REGISTER_MATCHER(hasAnyParameter); + REGISTER_MATCHER(hasAnySubstatement); + REGISTER_MATCHER(hasAnyTemplateArgument); + REGISTER_MATCHER(hasAnyUsingShadowDecl); + REGISTER_MATCHER(hasArgument); + REGISTER_MATCHER(hasArgumentOfType); + REGISTER_MATCHER(hasBase); + REGISTER_MATCHER(hasBody); + REGISTER_MATCHER(hasCanonicalType); + REGISTER_MATCHER(hasCondition); + REGISTER_MATCHER(hasConditionVariableStatement); + REGISTER_MATCHER(hasDeclContext); + REGISTER_MATCHER(hasDeclaration); + REGISTER_MATCHER(hasDeducedType); + REGISTER_MATCHER(hasDescendant); + REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasEitherOperand); + REGISTER_MATCHER(hasElementType); + REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasImplicitDestinationType); + REGISTER_MATCHER(hasIncrement); + REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasLHS); + REGISTER_MATCHER(hasLocalQualifiers); + REGISTER_MATCHER(hasLoopInit); + REGISTER_MATCHER(hasMethod); + REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasOperatorName); + REGISTER_MATCHER(hasOverloadedOperatorName); + REGISTER_MATCHER(hasParameter); + REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasQualifier); + REGISTER_MATCHER(hasRHS); + REGISTER_MATCHER(hasSingleDecl); + REGISTER_MATCHER(hasSize); + REGISTER_MATCHER(hasSizeExpr); + REGISTER_MATCHER(hasSourceExpression); + REGISTER_MATCHER(hasTargetDecl); + REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasTrueExpression); + REGISTER_MATCHER(hasUnaryOperand); + REGISTER_MATCHER(hasValueType); + REGISTER_MATCHER(ifStmt); + REGISTER_MATCHER(ignoringImpCasts); + REGISTER_MATCHER(ignoringParenCasts); + REGISTER_MATCHER(ignoringParenImpCasts); + REGISTER_MATCHER(implicitCastExpr); + REGISTER_MATCHER(incompleteArrayType); + REGISTER_MATCHER(initListExpr); + REGISTER_MATCHER(innerType); + REGISTER_MATCHER(integerLiteral); + REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isConstQualified); + REGISTER_MATCHER(isDefinition); + REGISTER_MATCHER(isExplicitTemplateSpecialization); + REGISTER_MATCHER(isExternC); + REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(isInteger); + REGISTER_MATCHER(isOverride); + REGISTER_MATCHER(isPrivate); + REGISTER_MATCHER(isProtected); + REGISTER_MATCHER(isPublic); + REGISTER_MATCHER(isTemplateInstantiation); + REGISTER_MATCHER(isVirtual); + REGISTER_MATCHER(isWritten); + REGISTER_MATCHER(lValueReferenceType); + REGISTER_MATCHER(labelStmt); + REGISTER_MATCHER(lambdaExpr); + REGISTER_MATCHER(matchesName); + REGISTER_MATCHER(materializeTemporaryExpr); + REGISTER_MATCHER(member); + REGISTER_MATCHER(memberCallExpr); + REGISTER_MATCHER(memberExpr); + REGISTER_MATCHER(memberPointerType); + REGISTER_MATCHER(methodDecl); + REGISTER_MATCHER(namedDecl); + REGISTER_MATCHER(namesType); + REGISTER_MATCHER(namespaceDecl); + REGISTER_MATCHER(nestedNameSpecifier); + REGISTER_MATCHER(nestedNameSpecifierLoc); + REGISTER_MATCHER(newExpr); + REGISTER_MATCHER(nullPtrLiteralExpr); + REGISTER_MATCHER(nullStmt); + REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(on); + REGISTER_MATCHER(onImplicitObjectArgument); + REGISTER_MATCHER(operatorCallExpr); + REGISTER_MATCHER(parameterCountIs); + REGISTER_MATCHER(parenType); + 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(refersToType); + REGISTER_MATCHER(reinterpretCastExpr); + REGISTER_MATCHER(returnStmt); + REGISTER_MATCHER(returns); + REGISTER_MATCHER(sizeOfExpr); + REGISTER_MATCHER(specifiesNamespace); + REGISTER_MATCHER(specifiesType); + REGISTER_MATCHER(specifiesTypeLoc); + REGISTER_MATCHER(statementCountIs); + REGISTER_MATCHER(staticCastExpr); + REGISTER_MATCHER(stmt); + REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(switchCase); + REGISTER_MATCHER(switchStmt); + REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(thisExpr); + REGISTER_MATCHER(throughUsingDecl); + REGISTER_MATCHER(throwExpr); + REGISTER_MATCHER(to); + REGISTER_MATCHER(tryStmt); + REGISTER_MATCHER(type); + REGISTER_MATCHER(typeLoc); + REGISTER_MATCHER(typedefType); + REGISTER_MATCHER(unaryExprOrTypeTraitExpr); + REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(userDefinedLiteral); + REGISTER_MATCHER(usingDecl); + REGISTER_MATCHER(varDecl); + REGISTER_MATCHER(variableArrayType); + REGISTER_MATCHER(whileStmt); + REGISTER_MATCHER(withInitializer); +} + +RegistryMaps::~RegistryMaps() { + for (ConstructorMap::iterator it = Constructors.begin(), + end = Constructors.end(); + it != end; ++it) { + delete it->second; + } +} + +static llvm::ManagedStatic<RegistryMaps> RegistryData; + +} // anonymous namespace + +// static +VariantMatcher Registry::constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + ConstructorMap::const_iterator it = + RegistryData->constructors().find(MatcherName); + if (it == RegistryData->constructors().end()) { + Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName; + return VariantMatcher(); + } + + return it->second->run(NameRange, Args, Error); +} + +// static +VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error); + if (Out.isNull()) return Out; + + llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher(); + if (Result.hasValue()) { + llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID); + if (Bound.hasValue()) { + return VariantMatcher::SingleMatcher(*Bound); + } + } + Error->addError(NameRange, Error->ET_RegistryNotBindable); + return VariantMatcher(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 0000000..3e49e1b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -0,0 +1,256 @@ +//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +VariantMatcher::MatcherOps::~MatcherOps() {} +VariantMatcher::Payload::~Payload() {} + +class VariantMatcher::SinglePayload : public VariantMatcher::Payload { +public: + SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} + + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + return Matcher; + } + + virtual std::string getTypeAsString() const { + return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") + .str(); + } + + virtual void makeTypedMatcher(MatcherOps &Ops) const { + if (Ops.canConstructFrom(Matcher)) + Ops.constructFrom(Matcher); + } + +private: + const DynTypedMatcher Matcher; +}; + +class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { +public: + PolymorphicPayload(ArrayRef<DynTypedMatcher> MatchersIn) + : Matchers(MatchersIn) {} + + virtual ~PolymorphicPayload() {} + + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + if (Matchers.size() != 1) + return llvm::Optional<DynTypedMatcher>(); + return Matchers[0]; + } + + virtual std::string getTypeAsString() const { + std::string Inner; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + if (i != 0) + Inner += "|"; + Inner += Matchers[i].getSupportedKind().asStringRef(); + } + return (Twine("Matcher<") + Inner + ">").str(); + } + + virtual void makeTypedMatcher(MatcherOps &Ops) const { + const DynTypedMatcher *Found = NULL; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + if (Ops.canConstructFrom(Matchers[i])) { + if (Found) + return; + Found = &Matchers[i]; + } + } + if (Found) + Ops.constructFrom(*Found); + } + + const std::vector<DynTypedMatcher> Matchers; +}; + +class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { +public: + VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef<VariantMatcher> Args) + : Func(Func), Args(Args) {} + + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + return llvm::Optional<DynTypedMatcher>(); + } + + virtual std::string getTypeAsString() const { + std::string Inner; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + if (i != 0) + Inner += "&"; + Inner += Args[i].getTypeAsString(); + } + return Inner; + } + + virtual void makeTypedMatcher(MatcherOps &Ops) const { + Ops.constructVariadicOperator(Func, Args); + } + +private: + const ast_matchers::internal::VariadicOperatorFunction Func; + const std::vector<VariantMatcher> Args; +}; + +VariantMatcher::VariantMatcher() {} + +VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { + return VariantMatcher(new SinglePayload(Matcher)); +} + +VariantMatcher +VariantMatcher::PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers) { + return VariantMatcher(new PolymorphicPayload(Matchers)); +} + +VariantMatcher VariantMatcher::VariadicOperatorMatcher( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef<VariantMatcher> Args) { + return VariantMatcher(new VariadicOpPayload(Func, Args)); +} + +llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { + return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>(); +} + +void VariantMatcher::reset() { Value.reset(); } + +std::string VariantMatcher::getTypeAsString() const { + if (Value) return Value->getTypeAsString(); + return "<Nothing>"; +} + +VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { + *this = Other; +} + +VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { + setUnsigned(Unsigned); +} + +VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { + setString(String); +} + +VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { + setMatcher(Matcher); +} + +VariantValue::~VariantValue() { reset(); } + +VariantValue &VariantValue::operator=(const VariantValue &Other) { + if (this == &Other) return *this; + reset(); + switch (Other.Type) { + case VT_Unsigned: + setUnsigned(Other.getUnsigned()); + break; + case VT_String: + setString(Other.getString()); + break; + case VT_Matcher: + setMatcher(Other.getMatcher()); + break; + case VT_Nothing: + Type = VT_Nothing; + break; + } + return *this; +} + +void VariantValue::reset() { + switch (Type) { + case VT_String: + delete Value.String; + break; + case VT_Matcher: + delete Value.Matcher; + break; + // Cases that do nothing. + case VT_Unsigned: + case VT_Nothing: + break; + } + Type = VT_Nothing; +} + +bool VariantValue::isUnsigned() const { + return Type == VT_Unsigned; +} + +unsigned VariantValue::getUnsigned() const { + assert(isUnsigned()); + return Value.Unsigned; +} + +void VariantValue::setUnsigned(unsigned NewValue) { + reset(); + Type = VT_Unsigned; + Value.Unsigned = NewValue; +} + +bool VariantValue::isString() const { + return Type == VT_String; +} + +const std::string &VariantValue::getString() const { + assert(isString()); + return *Value.String; +} + +void VariantValue::setString(const std::string &NewValue) { + reset(); + Type = VT_String; + Value.String = new std::string(NewValue); +} + +bool VariantValue::isMatcher() const { + return Type == VT_Matcher; +} + +const VariantMatcher &VariantValue::getMatcher() const { + assert(isMatcher()); + return *Value.Matcher; +} + +void VariantValue::setMatcher(const VariantMatcher &NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = new VariantMatcher(NewValue); +} + +std::string VariantValue::getTypeAsString() const { + switch (Type) { + case VT_String: return "String"; + case VT_Matcher: return getMatcher().getTypeAsString(); + case VT_Unsigned: return "Unsigned"; + case VT_Nothing: return "Nothing"; + } + llvm_unreachable("Invalid Type"); +} + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang |