diff options
Diffstat (limited to 'include/clang/ASTMatchers')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchFinder.h | 69 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 337 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersInternal.h | 636 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersMacros.h | 17 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Diagnostics.h | 4 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Parser.h | 130 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Registry.h | 51 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/VariantValue.h | 184 |
8 files changed, 951 insertions, 477 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 8af0546..ce2674e 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -38,10 +38,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H #include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Timer.h" namespace clang { @@ -102,6 +104,12 @@ public: /// /// Optionally override to do per translation unit tasks. virtual void onEndOfTranslationUnit() {} + + /// \brief An id used to group the matchers. + /// + /// This id is used, for example, for the profiling output. + /// It defaults to "<unknown>". + virtual StringRef getID() const; }; /// \brief Called when parsing is finished. Intended for testing only. @@ -111,7 +119,22 @@ public: virtual void run() = 0; }; - MatchFinder(); + struct MatchFinderOptions { + struct Profiling { + Profiling(llvm::StringMap<llvm::TimeRecord> &Records) + : Records(Records) {} + + /// \brief Per bucket timing information. + llvm::StringMap<llvm::TimeRecord> &Records; + }; + + /// \brief Enables per-check timers. + /// + /// It prints a report after match. + llvm::Optional<Profiling> CheckProfiling; + }; + + MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); ~MatchFinder(); /// \brief Adds a matcher to execute when running over the AST. @@ -148,7 +171,7 @@ public: MatchCallback *Action); /// \brief Creates a clang ASTConsumer that finds all matches. - clang::ASTConsumer *newASTConsumer(); + std::unique_ptr<clang::ASTConsumer> newASTConsumer(); /// \brief Calls the registered callbacks on all matches on the given \p Node. /// @@ -173,11 +196,25 @@ public: /// Each call to FindAll(...) will call the closure once. void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone); -private: - /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called + /// \brief For each \c Matcher<> a \c MatchCallback that will be called /// when it matches. - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > - MatcherCallbackPairs; + struct MatchersByType { + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>> + DeclOrStmt; + std::vector<std::pair<TypeMatcher, MatchCallback *>> Type; + std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>> + NestedNameSpecifier; + std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>> + NestedNameSpecifierLoc; + std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc; + /// \brief All the callbacks in one container to simplify iteration. + std::vector<MatchCallback *> AllCallbacks; + }; + +private: + MatchersByType Matchers; + + MatchFinderOptions Options; /// \brief Called when parsing is done. ParsingDoneTestCallback *ParsingDone; @@ -210,16 +247,14 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, /// /// This is useful in combanation with \c match(): /// \code -/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), -/// Node, Context)); +/// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), +/// Node, Context)); /// \endcode template <typename NodeT> -NodeT * +const NodeT * selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { - for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(), - E = Results.end(); - I != E; ++I) { - if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo)) + for (const BoundNodes &N : Results) { + if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo)) return Node; } return nullptr; @@ -243,7 +278,7 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, MatchFinder Finder; Finder.addMatcher(Matcher, &Callback); Finder.match(Node, Context); - return Callback.Nodes; + return std::move(Callback.Nodes); } template <typename MatcherT, typename NodeT> @@ -255,4 +290,4 @@ match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 1ff4ab3..f002cb9 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -42,9 +42,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" @@ -140,9 +141,97 @@ typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher; /// \endcode /// /// Usable as: Any Matcher -inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher> -anything() { - return internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>(); +inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } + +/// \brief Matches typedef declarations. +/// +/// Given +/// \code +/// typedef int X; +/// \endcode +/// typedefDecl() +/// matches "typedef int X" +const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; + +/// \brief Matches AST nodes that were expanded within the main-file. +/// +/// Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile()) +/// \code +/// #include <Y.h> +/// class X {}; +/// \endcode +/// Y.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + return SourceManager.isInMainFile( + SourceManager.getExpansionLoc(Node.getLocStart())); +} + +/// \brief Matches AST nodes that were expanded within system-header-files. +/// +/// Example matches Y but not X +/// (matcher = recordDecl(isExpansionInSystemHeader()) +/// \code +/// #include <SystemHeader.h> +/// class X {}; +/// \endcode +/// SystemHeader.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + return SourceManager.isInSystemHeader(ExpansionLoc); +} + +/// \brief Matches AST nodes that were expanded within files whose name is +/// partially matching a given regex. +/// +/// Example matches Y but not X +/// (matcher = recordDecl(isExpansionInFileMatching("AST.*")) +/// \code +/// #include "ASTMatcher.h" +/// class X {}; +/// \endcode +/// ASTMatcher.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc), + std::string, RegExp) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + auto FileEntry = + SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc)); + if (!FileEntry) { + return false; + } + + auto Filename = FileEntry->getName(); + llvm::Regex RE(RegExp); + return RE.match(Filename); } /// \brief Matches declarations. @@ -156,6 +245,17 @@ anything() { /// \endcode const internal::VariadicAllOfMatcher<Decl> decl; +/// \brief Matches a declaration of a linkage specification. +/// +/// Given +/// \code +/// extern "C" {} +/// \endcode +/// linkageSpecDecl() +/// matches "extern "C" {}" +const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> + linkageSpecDecl; + /// \brief Matches a declaration of anything that could have a name. /// /// Example matches \c X, \c S, the anonymous union type, \c i, and \c U; @@ -263,6 +363,17 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer; +/// \brief Matches template arguments. +/// +/// Given +/// \code +/// template <typename T> struct C {}; +/// C<int> c; +/// \endcode +/// templateArgument() +/// matches 'int' in C<int>. +const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; + /// \brief Matches public C++ declarations. /// /// Given @@ -441,6 +552,23 @@ AST_POLYMORPHIC_MATCHER_P2( return InnerMatcher.matches(List[N], Finder, Builder); } +/// \brief Matches if the number of template arguments equals \p N. +/// +/// Given +/// \code +/// template<typename T> struct C {}; +/// C<int> c; +/// \endcode +/// classTemplateSpecializationDecl(templateArgumentCountIs(1)) +/// matches C<int>. +AST_POLYMORPHIC_MATCHER_P( + templateArgumentCountIs, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl, + TemplateSpecializationType), + unsigned, N) { + return internal::getTemplateSpecializationArgs(Node).size() == N; +} + /// \brief Matches a TemplateArgument that refers to a certain type. /// /// Given @@ -497,6 +625,68 @@ AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) { return false; } +/// \brief Matches a TemplateArgument that is an integral value. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(isIntegral())) +/// matches the implicit instantiation of C in C<42> +/// with isIntegral() matching 42. +AST_MATCHER(TemplateArgument, isIntegral) { + return Node.getKind() == TemplateArgument::Integral; +} + +/// \brief Matches a TemplateArgument that referes to an integral type. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(refersToIntegralType(asString("int")))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, refersToIntegralType, + internal::Matcher<QualType>, InnerMatcher) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return InnerMatcher.matches(Node.getIntegralType(), Finder, Builder); +} + +/// \brief Matches a TemplateArgument of integral type with a given value. +/// +/// Note that 'Value' is a string as the template argument's value is +/// an arbitrary precision integer. 'Value' must be euqal to the canonical +/// representation of that integral value in base 10. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(equalsIntegralValue("42"))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, equalsIntegralValue, + std::string, Value) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return Node.getAsIntegral().toString(10) == Value; +} + +/// \brief Matches any value declaration. +/// +/// Example matches A, B, C and F +/// \code +/// enum X { A, B, C }; +/// void F(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; + /// \brief Matches C++ constructor declarations. /// /// Example matches Foo::Foo() and Foo::Foo(int) @@ -1414,21 +1604,21 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { - internal::EachOfVariadicOperator + internal::DynTypedMatcher::VO_EachOf }; /// \brief Matches if any of the given matchers matches. /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = { - internal::AnyOfVariadicOperator + internal::DynTypedMatcher::VO_AnyOf }; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { - internal::AllOfVariadicOperator + internal::DynTypedMatcher::VO_AllOf }; /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) @@ -1502,16 +1692,8 @@ inline internal::Matcher<Stmt> sizeOfExpr( /// \code /// namespace a { namespace b { class X; } } /// \endcode -AST_MATCHER_P(NamedDecl, hasName, std::string, Name) { - assert(!Name.empty()); - const std::string FullNameString = "::" + Node.getQualifiedNameAsString(); - const StringRef FullName = FullNameString; - const StringRef Pattern = Name; - if (Pattern.startswith("::")) { - return FullName == Pattern; - } else { - return FullName.endswith(("::" + Pattern).str()); - } +inline internal::Matcher<NamedDecl> hasName(const std::string &Name) { + return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name)); } /// \brief Matches NamedDecl nodes whose fully qualified names contain @@ -1558,7 +1740,7 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { inline internal::PolymorphicMatcherWithParam1< internal::HasOverloadedOperatorNameMatcher, StringRef, AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)> -hasOverloadedOperatorName(const StringRef Name) { +hasOverloadedOperatorName(StringRef Name) { return internal::PolymorphicMatcherWithParam1< internal::HasOverloadedOperatorNameMatcher, StringRef, AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>( @@ -1592,7 +1774,7 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, } /// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). -AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) { assert(!BaseName.empty()); return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -1607,8 +1789,8 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, /// \brief Overloaded method as shortcut for /// \c isSameOrDerivedFrom(hasName(...)). -AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName, - 1) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string, + BaseName, 1) { assert(!BaseName.empty()); return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -1768,7 +1950,7 @@ const internal::ArgumentAdaptingMatcherFunc< /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<1, 1> unless = { - internal::NotUnaryOperator + internal::DynTypedMatcher::VO_UnaryNot }; /// \brief Matches a node if the declaration associated with that node @@ -1844,7 +2026,7 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>, /// Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x"))))) /// \code /// class Y { public: void x(); }; -/// void z() { Y y; y.x(); +/// void z() { Y y; y.x(); } /// \endcode AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, 1) { @@ -1952,6 +2134,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, /// void a(X b) { /// X &x = b; /// const X &y = b; +/// } /// }; /// \endcode AST_MATCHER_P(QualType, references, internal::Matcher<QualType>, @@ -2280,11 +2463,10 @@ AST_MATCHER(CXXCtorInitializer, isWritten) { AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2( CallExpr, CXXConstructExpr), internal::Matcher<Expr>, InnerMatcher) { - for (unsigned I = 0; I < Node.getNumArgs(); ++I) { + for (const Expr *Arg : Node.arguments()) { BoundNodesTreeBuilder Result(*Builder); - if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder, - &Result)) { - *Builder = Result; + if (InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, &Result)) { + *Builder = std::move(Result); return true; } } @@ -2372,6 +2554,19 @@ AST_MATCHER(FunctionDecl, isExternC) { return Node.isExternC(); } +/// \brief Matches deleted function declarations. +/// +/// Given: +/// \code +/// void Func(); +/// void DeletedFunc() = delete; +/// \endcode +/// functionDecl(isDeleted()) +/// matches the declaration of DeletedFunc, but not Func. +AST_MATCHER(FunctionDecl, isDeleted) { + return Node.isDeleted(); +} + /// \brief Matches the condition expression of an if statement, for loop, /// or conditional operator. /// @@ -2953,6 +3148,43 @@ AST_POLYMORPHIC_MATCHER( TSK_ExplicitInstantiationDefinition); } +/// \brief Matches declarations that are template instantiations or are inside +/// template instantiations. +/// +/// Given +/// \code +/// template<typename T> void A(T t) { T i; } +/// A(0); +/// A(0U); +/// \endcode +/// functionDecl(isInstantiated()) +/// matches 'A(int) {...};' and 'A(unsigned) {...}'. +AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) { + auto IsInstantiation = decl(anyOf(recordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))); + return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation))); +} + +/// \brief Matches statements inside of a template instantiation. +/// +/// Given +/// \code +/// int j; +/// template<typename T> void A(T t) { T i; j += 42;} +/// A(0); +/// A(0U); +/// \endcode +/// declStmt(isInTemplateInstantiation()) +/// matches 'int i;' and 'unsigned i'. +/// unless(stmt(isInTemplateInstantiation())) +/// will NOT match j += 42; as it's shared between the template definition and +/// instantiation. +AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) { + return stmt( + hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))))); +} + /// \brief Matches explicit template specializations of function, class, or /// static member variable template instantiations. /// @@ -2979,6 +3211,18 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc, new internal::TypeLocTypeMatcher(InnerMatcher)); } +/// \brief Matches type \c void. +/// +/// Given +/// \code +/// struct S { void func(); }; +/// \endcode +/// functionDecl(returns(voidType())) +/// matches "void func();" +AST_MATCHER(Type, voidType) { + return Node.isVoidType(); +} + /// \brief Matches builtin Types. /// /// Given @@ -3094,6 +3338,7 @@ AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType); /// int a[] = { 2, 3 } /// int b[42]; /// int c[a[0]]; +/// } /// \endcode /// variableArrayType() /// matches "int c[a[0]]" @@ -3432,8 +3677,9 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, /// \c recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the /// declaration of \c class \c D. AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) { - return InnerMatcher.matches(*Decl::castFromDeclContext(Node.getDeclContext()), - Finder, Builder); + const DeclContext *DC = Node.getDeclContext(); + if (!DC) return false; + return InnerMatcher.matches(*Decl::castFromDeclContext(DC), Finder, Builder); } /// \brief Matches nested name specifiers. @@ -3599,7 +3845,7 @@ AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>, Result.addMatch(CaseBuilder); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -3622,7 +3868,7 @@ AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer, Result.addMatch(InitBuilder); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -3643,7 +3889,32 @@ AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>, return InnerMatcher.matches(*Node.getLHS(), Finder, Builder); } +/// \brief Matches declaration that has a given attribute. +/// +/// Given +/// \code +/// __attribute__((device)) void f() { ... } +/// \endcode +/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of +/// f. +AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) { + for (const auto *Attr : Node.attrs()) { + if (Attr->getKind() == AttrKind) + return true; + } + return false; +} + +/// \brief Matches CUDA kernel call expression. +/// +/// Example matches, +/// \code +/// kernel<<<i,j>>>(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr> + CUDAKernelCallExpr; + } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 94435fd..ebe5cdd 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -32,8 +32,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" @@ -44,6 +44,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/VariadicFunction.h" +#include "llvm/Support/ManagedStatic.h" #include <map> #include <string> #include <vector> @@ -61,9 +62,8 @@ public: /// \brief Adds \c Node to the map with key \c ID. /// /// The node's base type should be in NodeBaseType or it will be unaccessible. - template <typename T> - void addNode(StringRef ID, const T* Node) { - NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node); + void addNode(StringRef ID, const ast_type_traits::DynTypedNode& DynNode) { + NodeMap[ID] = DynNode; } /// \brief Returns the AST node bound to \c ID. @@ -103,6 +103,16 @@ public: return NodeMap; } + /// \brief Returns \c true if this \c BoundNodesMap can be compared, i.e. all + /// stored nodes have memoization data. + bool isComparable() const { + for (const auto &IDAndNode : NodeMap) { + if (!IDAndNode.second.getMemoizationData()) + return false; + } + return true; + } + private: IDToNodeMap NodeMap; }; @@ -126,11 +136,12 @@ public: }; /// \brief Add a binding from an id to a node. - template <typename T> void setBinding(const std::string &Id, const T *Node) { + void setBinding(const std::string &Id, + const ast_type_traits::DynTypedNode &DynNode) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); - for (unsigned i = 0, e = Bindings.size(); i != e; ++i) - Bindings[i].addNode(Id, Node); + for (BoundNodesMap &Binding : Bindings) + Binding.addNode(Id, DynNode); } /// \brief Adds a branch in the tree. @@ -153,12 +164,38 @@ public: return Bindings < Other.Bindings; } + /// \brief Returns \c true if this \c BoundNodesTreeBuilder can be compared, + /// i.e. all stored node maps have memoization data. + bool isComparable() const { + for (const BoundNodesMap &NodesMap : Bindings) { + if (!NodesMap.isComparable()) + return false; + } + return true; + } + private: SmallVector<BoundNodesMap, 16> Bindings; }; class ASTMatchFinder; +/// \brief Generic interface for all matchers. +/// +/// Used by the implementation of Matcher<T> and DynTypedMatcher. +/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T> +/// instead. +class DynMatcherInterface : public RefCountedBaseVPTR { +public: + /// \brief Returns true if \p DynNode can be matched. + /// + /// May bind \p DynNode to an ID via \p Builder, or recurse into + /// the AST via \p Finder. + virtual bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const = 0; +}; + /// \brief Generic interface for matchers on an AST node of type T. /// /// Implement this if your matcher may need to inspect the children or @@ -167,7 +204,7 @@ class ASTMatchFinder; /// current node and doesn't care about its children or descendants, /// implement SingleNodeMatcherInterface instead. template <typename T> -class MatcherInterface : public RefCountedBaseVPTR { +class MatcherInterface : public DynMatcherInterface { public: virtual ~MatcherInterface() {} @@ -178,6 +215,12 @@ public: virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const = 0; + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return matches(DynNode.getUnchecked<T>(), Finder, Builder); + } }; /// \brief Interface for matchers that only evaluate properties on a single @@ -199,6 +242,145 @@ private: } }; +template <typename> class Matcher; + +/// \brief Matcher that works on a \c DynTypedNode. +/// +/// It is constructed from a \c Matcher<T> object and redirects most calls to +/// underlying matcher. +/// It checks whether the \c DynTypedNode is convertible into the type of the +/// underlying matcher and then do the actual match on the actual node, or +/// return false if it is not convertible. +class DynTypedMatcher { +public: + /// \brief Takes ownership of the provided implementation pointer. + template <typename T> + DynTypedMatcher(MatcherInterface<T> *Implementation) + : AllowBind(false), + SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), + RestrictKind(SupportedKind), Implementation(Implementation) {} + + /// \brief Construct from a variadic function. + enum VariadicOperator { + /// \brief Matches nodes for which all provided matchers match. + VO_AllOf, + /// \brief Matches nodes for which at least one of the provided matchers + /// matches. + VO_AnyOf, + /// \brief Matches nodes for which at least one of the provided matchers + /// matches, but doesn't stop at the first match. + VO_EachOf, + /// \brief Matches nodes that do not match the provided matcher. + /// + /// Uses the variadic matcher interface, but fails if + /// InnerMatchers.size() != 1. + VO_UnaryNot + }; + static DynTypedMatcher + constructVariadic(VariadicOperator Op, + std::vector<DynTypedMatcher> InnerMatchers); + + /// \brief Get a "true" matcher for \p NodeKind. + /// + /// It only checks that the node is of the right kind. + static DynTypedMatcher trueMatcher(ast_type_traits::ASTNodeKind NodeKind); + + void setAllowBind(bool AB) { AllowBind = AB; } + + /// \brief Check whether this matcher could ever match a node of kind \p Kind. + /// \return \c false if this matcher will never match such a node. Otherwise, + /// return \c true. + bool canMatchNodesOfKind(ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Return a matcher that points to the same implementation, but + /// restricts the node types for \p Kind. + DynTypedMatcher dynCastTo(const ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Returns true if the matcher matches the given \c DynNode. + bool matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; + + /// \brief Same as matches(), but skips the kind check. + /// + /// It is faster, but the caller must ensure the node is valid for the + /// kind of this matcher. + bool matchesNoKindCheck(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const; + + /// \brief Bind the specified \p ID to the matcher. + /// \return A new matcher with the \p ID bound to it if this matcher supports + /// binding. Otherwise, returns an empty \c Optional<>. + llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const; + + /// \brief Returns a unique \p ID for the matcher. + /// + /// Casting a Matcher<T> to Matcher<U> creates a matcher that has the + /// same \c Implementation pointer, but different \c RestrictKind. We need to + /// include both in the ID to make it unique. + /// + /// \c MatcherIDType supports operator< and provides strict weak ordering. + typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType; + MatcherIDType getID() const { + /// FIXME: Document the requirements this imposes on matcher + /// implementations (no new() implementation_ during a Matches()). + return std::make_pair(RestrictKind, + reinterpret_cast<uint64_t>(Implementation.get())); + } + + /// \brief Returns the type this matcher works on. + /// + /// \c matches() will always return false unless the node passed is of this + /// or a derived type. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return SupportedKind; + } + + /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted + /// to a \c Matcher<T>. + /// + /// This method verifies that the underlying matcher in \c Other can process + /// nodes of types T. + template <typename T> bool canConvertTo() const { + return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } + bool canConvertTo(ast_type_traits::ASTNodeKind To) const; + + /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. + /// + /// This method asserts that \c canConvertTo() is \c true. Callers + /// should call \c canConvertTo() first to make sure that \c this is + /// compatible with T. + template <typename T> Matcher<T> convertTo() const { + assert(canConvertTo<T>()); + return unconditionalConvertTo<T>(); + } + + /// \brief Same as \c convertTo(), but does not check that the underlying + /// matcher can handle a value of T. + /// + /// If it is not compatible, then this matcher will never match anything. + template <typename T> Matcher<T> unconditionalConvertTo() const; + +private: + DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind, + ast_type_traits::ASTNodeKind RestrictKind, + IntrusiveRefCntPtr<DynMatcherInterface> Implementation) + : AllowBind(false), + SupportedKind(SupportedKind), + RestrictKind(RestrictKind), + Implementation(std::move(Implementation)) {} + + bool AllowBind; + ast_type_traits::ASTNodeKind SupportedKind; + /// \brief A potentially stricter node kind. + /// + /// It allows to perform implicit and dynamic cast of matchers without + /// needing to change \c Implementation. + ast_type_traits::ASTNodeKind RestrictKind; + IntrusiveRefCntPtr<DynMatcherInterface> Implementation; +}; + /// \brief Wrapper of a MatcherInterface<T> *that allows copying. /// /// A Matcher<Base> can be used anywhere a Matcher<Derived> is @@ -221,7 +403,10 @@ public: Matcher(const Matcher<From> &Other, typename std::enable_if<std::is_base_of<From, T>::value && !std::is_same<From, T>::value>::type * = 0) - : Implementation(new ImplicitCastMatcher<From>(Other)) {} + : Implementation(restrictMatcher(Other.Implementation)) { + assert(Implementation.getSupportedKind().isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } /// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>. /// @@ -233,26 +418,34 @@ public: std::is_same<TypeT, Type>::value>::type* = 0) : Implementation(new TypeToQualType<TypeT>(Other)) {} + /// \brief Convert \c this into a \c Matcher<T> by applying dyn_cast<> to the + /// argument. + /// \c To must be a base class of \c T. + template <typename To> + Matcher<To> dynCastTo() const { + static_assert(std::is_base_of<To, T>::value, "Invalid dynCast call."); + return Matcher<To>(Implementation); + } + /// \brief Forwards the call to the underlying MatcherInterface<T> pointer. bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - if (Implementation->matches(Node, 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 = BoundNodesTreeBuilder(); - return false; + return Implementation.matches(ast_type_traits::DynTypedNode::create(Node), + Finder, Builder); } /// \brief Returns an ID that uniquely identifies the matcher. - uint64_t getID() const { - /// FIXME: Document the requirements this imposes on matcher - /// implementations (no new() implementation_ during a Matches()). - return reinterpret_cast<uint64_t>(Implementation.get()); + DynTypedMatcher::MatcherIDType getID() const { + return Implementation.getID(); } + /// \brief Extract the dynamic matcher. + /// + /// The returned matcher keeps the same restrictions as \c this and remembers + /// that it is meant to support nodes of type \c T. + operator DynTypedMatcher() const { return Implementation; } + /// \brief Allows the conversion of a \c Matcher<Type> to a \c /// Matcher<QualType>. /// @@ -276,24 +469,22 @@ public: }; private: - /// \brief Allows conversion from Matcher<Base> to Matcher<T> if T - /// is derived from Base. - template <typename Base> - class ImplicitCastMatcher : public MatcherInterface<T> { - public: - explicit ImplicitCastMatcher(const Matcher<Base> &From) - : From(From) {} + // For Matcher<T> <=> Matcher<U> conversions. + template <typename U> friend class Matcher; + // For DynTypedMatcher::unconditionalConvertTo<T>. + friend class DynTypedMatcher; - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - return From.matches(Node, Finder, Builder); - } + static DynTypedMatcher restrictMatcher(const DynTypedMatcher &Other) { + return Other.dynCastTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } - private: - const Matcher<Base> From; - }; + explicit Matcher(const DynTypedMatcher &Implementation) + : Implementation(restrictMatcher(Implementation)) { + assert(this->Implementation.getSupportedKind() + .isSame(ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } - IntrusiveRefCntPtr< MatcherInterface<T> > Implementation; + DynTypedMatcher Implementation; }; // class Matcher /// \brief A convenient helper for creating a Matcher<T> without specifying @@ -303,153 +494,10 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) { return Matcher<T>(Implementation); } -template <typename T> class BindableMatcher; - -/// \brief Matcher that works on a \c DynTypedNode. -/// -/// It is constructed from a \c Matcher<T> object and redirects most calls to -/// underlying matcher. -/// It checks whether the \c DynTypedNode is convertible into the type of the -/// underlying matcher and then do the actual match on the actual node, or -/// return false if it is not convertible. -class DynTypedMatcher { -public: - /// \brief Construct from a \c Matcher<T>. Copies the matcher. - template <typename T> inline DynTypedMatcher(const Matcher<T> &M); - - /// \brief Construct from a bindable \c Matcher<T>. Copies the matcher. - /// - /// This version enables \c tryBind() on the \c DynTypedMatcher. - template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M); - - /// \brief Returns true if the matcher matches the given \c DynNode. - bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return Storage->matches(DynNode, Finder, Builder); - } - - /// \brief Bind the specified \p ID to the matcher. - /// \return A new matcher with the \p ID bound to it if this matcher supports - /// binding. Otherwise, returns an empty \c Optional<>. - llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const { - return Storage->tryBind(ID); - } - - /// \brief Returns a unique \p ID for the matcher. - uint64_t getID() const { return Storage->getID(); } - - /// \brief Returns the type this matcher works on. - /// - /// \c matches() will always return false unless the node passed is of this - /// or a derived type. - ast_type_traits::ASTNodeKind getSupportedKind() const { - return Storage->getSupportedKind(); - } - - /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted - /// to a \c Matcher<T>. - /// - /// This method verifies that the underlying matcher in \c Other can process - /// nodes of types T. - template <typename T> bool canConvertTo() const { - return getSupportedKind().isBaseOf( - ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); - } - - /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. - /// - /// This method asserts that \c canConvertTo() is \c true. Callers - /// should call \c canConvertTo() first to make sure that \c this is - /// compatible with T. - template <typename T> Matcher<T> convertTo() const { - assert(canConvertTo<T>()); - return unconditionalConvertTo<T>(); - } - - /// \brief Same as \c convertTo(), but does not check that the underlying - /// matcher can handle a value of T. - /// - /// If it is not compatible, then this matcher will never match anything. - template <typename T> Matcher<T> unconditionalConvertTo() const; - -private: - class MatcherStorage : public RefCountedBaseVPTR { - public: - MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID) - : SupportedKind(SupportedKind), ID(ID) {} - virtual ~MatcherStorage(); - - virtual bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const = 0; - - virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0; - - ast_type_traits::ASTNodeKind getSupportedKind() const { - return SupportedKind; - } - - uint64_t getID() const { return ID; } - - private: - const ast_type_traits::ASTNodeKind SupportedKind; - const uint64_t ID; - }; - - /// \brief Typed implementation of \c MatcherStorage. - template <typename T> class TypedMatcherStorage; - - IntrusiveRefCntPtr<const MatcherStorage> Storage; -}; - -template <typename T> -class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage { -public: - TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind) - : MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(), - Other.getID()), - InnerMatcher(Other), AllowBind(AllowBind) {} - - bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - if (const T *Node = DynNode.get<T>()) { - return InnerMatcher.matches(*Node, Finder, Builder); - } - return false; - } - - llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const override { - if (!AllowBind) - return llvm::Optional<DynTypedMatcher>(); - return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID)); - } - -private: - const Matcher<T> InnerMatcher; - const bool AllowBind; -}; - -template <typename T> -inline DynTypedMatcher::DynTypedMatcher(const Matcher<T> &M) - : Storage(new TypedMatcherStorage<T>(M, false)) {} - -template <typename T> -inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M) - : Storage(new TypedMatcherStorage<T>(M, true)) {} - /// \brief Specialization of the conversion functions for QualType. /// -/// These specializations provide the Matcher<Type>->Matcher<QualType> +/// This specialization provides the Matcher<Type>->Matcher<QualType> /// conversion that the static API does. -template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const { - const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); - return SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) || - SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>()); -} - template <> inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const { assert(canConvertTo<QualType>()); @@ -470,7 +518,7 @@ bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(*I, Finder, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } } @@ -486,7 +534,7 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(**I, Finder, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } } @@ -549,6 +597,33 @@ private: std::string Name; }; +/// \brief Matches named declarations with a specific name. +/// +/// See \c hasName() in ASTMatchers.h for details. +class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> { + public: + explicit HasNameMatcher(StringRef Name); + + bool matchesNode(const NamedDecl &Node) const override; + + private: + /// \brief Unqualified match routine. + /// + /// It is much faster than the full match, but it only works for unqualified + /// matches. + bool matchesNodeUnqualified(const NamedDecl &Node) const; + + /// \brief Full match routine + /// + /// It generates the fully qualified name of the declaration (which is + /// expensive) before trying to match. + /// It is slower but simple and works on all cases. + bool matchesNodeFull(const NamedDecl &Node) const; + + const bool UseUnqualifiedMatch; + const std::string Name; +}; + /// \brief Matches declarations for QualType and CallExpr. /// /// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but @@ -973,46 +1048,16 @@ private: /// /// This is useful when a matcher syntactically requires a child matcher, /// but the context doesn't care. See for example: anything(). -/// -/// FIXME: Alternatively we could also create a IsAMatcher or something -/// that checks that a dyn_cast is possible. This is purely needed for the -/// difference between calling for example: -/// record() -/// and -/// record(SomeMatcher) -/// In the second case we need the correct type we were dyn_cast'ed to in order -/// to get the right type for the inner matcher. In the first case we don't need -/// that, but we use the type conversion anyway and insert a TrueMatcher. -template <typename T> -class TrueMatcher : public SingleNodeMatcherInterface<T> { -public: - bool matchesNode(const T &Node) const override { - return true; - } -}; - -/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node -/// to an ID if the inner matcher matches on the node. -template <typename T> -class IdMatcher : public MatcherInterface<T> { -public: - /// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches - /// the node. - IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher) - : ID(ID), InnerMatcher(InnerMatcher) {} +class TrueMatcher { + public: + typedef AllNodeBaseTypes ReturnTypes; - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - bool Result = InnerMatcher.matches(Node, Finder, Builder); - if (Result) { - Builder->setBinding(ID, &Node); - } - return Result; + template <typename T> + operator Matcher<T>() const { + return DynTypedMatcher::trueMatcher( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) + .template unconditionalConvertTo<T>(); } - -private: - const std::string ID; - const Matcher<T> InnerMatcher; }; /// \brief A Matcher that allows binding the node it matches to an id. @@ -1031,7 +1076,17 @@ public: /// The returned matcher is equivalent to this matcher, but will /// bind the matched node on a match. Matcher<T> bind(StringRef ID) const { - return Matcher<T>(new IdMatcher<T>(ID, *this)); + return DynTypedMatcher(*this) + .tryBind(ID) + ->template unconditionalConvertTo<T>(); + } + + /// \brief Same as Matcher<T>'s conversion operator, but enables binding on + /// the returned matcher. + operator DynTypedMatcher() const { + DynTypedMatcher Result = static_cast<const Matcher<T>&>(*this); + Result.setAllowBind(true); + return Result; } }; @@ -1089,36 +1144,11 @@ private: /// \brief VariadicOperatorMatcher related types. /// @{ -/// \brief Function signature for any variadic operator. It takes the inner -/// matchers as an array of DynTypedMatcher. -typedef bool (*VariadicOperatorFunction)( - const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief \c MatcherInterface<T> implementation for an variadic operator. -template <typename T> -class VariadicOperatorMatcherInterface : public MatcherInterface<T> { -public: - VariadicOperatorMatcherInterface(VariadicOperatorFunction Func, - std::vector<DynTypedMatcher> InnerMatchers) - : Func(Func), InnerMatchers(std::move(InnerMatchers)) {} - - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder, - InnerMatchers); - } - -private: - const VariadicOperatorFunction Func; - const std::vector<DynTypedMatcher> InnerMatchers; -}; - /// \brief "No argument" placeholder to use as template paratemers. struct VariadicOperatorNoArg {}; -/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction -/// operator. +/// \brief Polymorphic matcher object that uses a \c +/// DynTypedMatcher::VariadicOperator operator. /// /// Input matchers can have any type (including other polymorphic matcher /// types), and the actual Matcher<T> is generated on demand with an implicit @@ -1133,7 +1163,8 @@ template <typename P1, typename P2 = VariadicOperatorNoArg, typename P9 = VariadicOperatorNoArg> class VariadicOperatorMatcher { public: - VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1, + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + const P1 &Param1, const P2 &Param2 = VariadicOperatorNoArg(), const P3 &Param3 = VariadicOperatorNoArg(), const P4 &Param4 = VariadicOperatorNoArg(), @@ -1142,7 +1173,7 @@ public: const P7 &Param7 = VariadicOperatorNoArg(), const P8 &Param8 = VariadicOperatorNoArg(), const P9 &Param9 = VariadicOperatorNoArg()) - : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3), + : Op(Op), Param1(Param1), Param2(Param2), Param3(Param3), Param4(Param4), Param5(Param5), Param6(Param6), Param7(Param7), Param8(Param8), Param9(Param9) {} @@ -1157,8 +1188,8 @@ public: addMatcher<T>(Param7, Matchers); addMatcher<T>(Param8, Matchers); addMatcher<T>(Param9, Matchers); - return Matcher<T>( - new VariadicOperatorMatcherInterface<T>(Func, std::move(Matchers))); + return DynTypedMatcher::constructVariadic(Op, std::move(Matchers)) + .template unconditionalConvertTo<T>(); } private: @@ -1173,7 +1204,7 @@ private: static void addMatcher(VariadicOperatorNoArg, std::vector<DynTypedMatcher> &Matchers) {} - const VariadicOperatorFunction Func; + const DynTypedMatcher::VariadicOperator Op; const P1 Param1; const P2 Param2; const P3 Param3; @@ -1191,7 +1222,7 @@ private: /// It supports 1-9 argument overloaded operator(). More can be added if needed. template <unsigned MinCount, unsigned MaxCount> struct VariadicOperatorMatcherFunc { - VariadicOperatorFunction Func; + DynTypedMatcher::VariadicOperator Op; template <unsigned Count, typename T> struct EnableIfValidArity @@ -1200,30 +1231,29 @@ struct VariadicOperatorMatcherFunc { template <typename M1> typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type operator()(const M1 &P1) const { - return VariadicOperatorMatcher<M1>(Func, P1); + return VariadicOperatorMatcher<M1>(Op, P1); } template <typename M1, typename M2> typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type operator()(const M1 &P1, const M2 &P2) const { - return VariadicOperatorMatcher<M1, M2>(Func, P1, P2); + return VariadicOperatorMatcher<M1, M2>(Op, P1, P2); } template <typename M1, typename M2, typename M3> typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3) const { - return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3); + return VariadicOperatorMatcher<M1, M2, M3>(Op, P1, P2, P3); } template <typename M1, typename M2, typename M3, typename M4> typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const { - return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4); + return VariadicOperatorMatcher<M1, M2, M3, M4>(Op, P1, P2, P3, P4); } template <typename M1, typename M2, typename M3, typename M4, typename M5> typename EnableIfValidArity< 5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) const { - return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4, - P5); + return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Op, P1, P2, P3, P4, P5); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6> @@ -1232,7 +1262,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6>( - Func, P1, P2, P3, P4, P5, P6); + Op, P1, P2, P3, P4, P5, P6); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7> @@ -1241,7 +1271,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6, const M7 &P7) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7>( - Func, P1, P2, P3, P4, P5, P6, P7); + Op, P1, P2, P3, P4, P5, P6, P7); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7, typename M8> @@ -1250,7 +1280,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8>( - Func, P1, P2, P3, P4, P5, P6, P7, P8); + Op, P1, P2, P3, P4, P5, P6, P7, P8); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7, typename M8, typename M9> @@ -1260,55 +1290,40 @@ struct VariadicOperatorMatcherFunc { const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8, const M9 &P9) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9>( - Func, P1, P2, P3, P4, P5, P6, P7, P8, P9); + Op, P1, P2, P3, P4, P5, P6, P7, P8, P9); } }; /// @} -/// \brief Matches nodes that do not match the provided matcher. -/// -/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1. -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which all provided matchers match. -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which at least one of the provided matchers -/// matches, but doesn't stop at the first match. -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which at least one of the provided matchers -/// matches. -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - template <typename T> inline Matcher<T> DynTypedMatcher::unconditionalConvertTo() const { - return Matcher<T>(new VariadicOperatorMatcherInterface<T>( - AllOfVariadicOperator, llvm::makeArrayRef(*this))); + return Matcher<T>(*this); } /// \brief Creates a Matcher<T> that matches if all inner matchers match. template<typename T> BindableMatcher<T> makeAllOfComposite( ArrayRef<const Matcher<T> *> InnerMatchers) { - std::vector<DynTypedMatcher> DynMatchers; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - DynMatchers.push_back(*InnerMatchers[i]); + // For the size() == 0 case, we return a "true" matcher. + if (InnerMatchers.size() == 0) { + return BindableMatcher<T>(TrueMatcher()); + } + // For the size() == 1 case, we simply return that one matcher. + // No need to wrap it in a variadic operation. + if (InnerMatchers.size() == 1) { + return BindableMatcher<T>(*InnerMatchers[0]); } - return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>( - AllOfVariadicOperator, std::move(DynMatchers))); + + std::vector<DynTypedMatcher> DynMatchers; + DynMatchers.reserve(InnerMatchers.size()); + for (const auto *InnerMatcher : InnerMatchers) { + DynMatchers.push_back(*InnerMatcher); + } + return BindableMatcher<T>( + DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, + std::move(DynMatchers)) + .template unconditionalConvertTo<T>()); } /// \brief Creates a Matcher<T> that matches if @@ -1320,8 +1335,8 @@ BindableMatcher<T> makeAllOfComposite( template<typename T, typename InnerT> BindableMatcher<T> makeDynCastAllOfComposite( ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers)) - .unconditionalConvertTo<T>()); + return BindableMatcher<T>( + makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); } /// \brief Matches nodes of type T that have at least one descendant node of @@ -1606,6 +1621,23 @@ private: const Matcher<InnerTBase> InnerMatcher; }; +/// \brief A simple memoizer of T(*)() functions. +/// +/// It will call the passed 'Func' template parameter at most once. +/// Used to support AST_MATCHER_FUNCTION() macro. +template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher { + struct Wrapper { + Wrapper() : M(Func()) {} + Matcher M; + }; + +public: + static const Matcher &getInstance() { + static llvm::ManagedStatic<Wrapper> Instance; + return Instance->M; + } +}; + // Define the create() method out of line to silence a GCC warning about // the struct "Func" having greater visibility than its base, which comes from // using the flag -fvisibility-inlines-hidden. @@ -1627,7 +1659,7 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) { inline ArrayRef<TemplateArgument> getTemplateSpecializationArgs(const TemplateSpecializationType &T) { - return ArrayRef<TemplateArgument>(T.getArgs(), T.getNumArgs()); + return llvm::makeArrayRef(T.getArgs(), T.getNumArgs()); } struct NotEqualsBoundNodePredicate { @@ -1642,4 +1674,4 @@ struct NotEqualsBoundNodePredicate { } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h index 563372a..b7888be 100644 --- a/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -34,8 +34,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H + +/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { +/// defines a zero parameter function named DefineMatcher() that returns a +/// ReturnType object. +#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \ + inline ReturnType DefineMatcher##_getInstance(); \ + inline ReturnType DefineMatcher() { \ + return internal::MemoizedMatcher< \ + ReturnType, DefineMatcher##_getInstance>::getInstance(); \ + } \ + inline ReturnType DefineMatcher##_getInstance() /// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) { /// defines a single-parameter function named DefineMatcher() that returns a @@ -352,4 +363,4 @@ internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \ AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF) -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H +#endif diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h index 82a14f1..ef93ac5 100644 --- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/LLVM.h" diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h index 4045f57..bd006b6 100644 --- a/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -31,8 +31,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/Registry.h" @@ -63,17 +63,6 @@ public: public: virtual ~Sema(); - /// \brief Lookup a value by name. - /// - /// This can be used in the Sema layer to declare known constants or to - /// allow to split an expression in pieces. - /// - /// \param Name The name of the value to lookup. - /// - /// \return The named value. It could be any type that VariantValue - /// supports. An empty value means that the name is not recognized. - virtual VariantValue getNamedValue(StringRef Name); - /// \brief Process a matcher expression. /// /// All the arguments passed here have already been processed. @@ -105,6 +94,29 @@ public: /// found. virtual llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) = 0; + + /// \brief Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + virtual std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + virtual std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes); }; /// \brief Sema implementation that uses the matcher registry to process the @@ -121,58 +133,91 @@ public: StringRef BindID, ArrayRef<ParserValue> Args, Diagnostics *Error) override; + + std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override; + + std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; }; - /// \brief Parse a matcher expression, creating matchers from the registry. - /// - /// This overload creates matchers calling directly into the registry. If the - /// caller needs more control over how the matchers are created, then it can - /// use the overload below that takes a Sema. - /// - /// \param MatcherCode The matcher expression to parse. - /// - /// \return The matcher object constructed, or an empty Optional if an error - /// occurred. - /// In that case, \c Error will contain a description of the error. - /// The caller takes ownership of the DynTypedMatcher object returned. - static llvm::Optional<DynTypedMatcher> - parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error); + typedef llvm::StringMap<VariantValue> NamedValueMap; /// \brief Parse a matcher expression. /// /// \param MatcherCode The matcher expression to parse. /// /// \param S The Sema instance that will help the parser - /// construct the matchers. + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// /// \return The matcher object constructed by the processor, or an empty /// Optional if an error occurred. In that case, \c Error will contain a /// description of the error. /// The caller takes ownership of the DynTypedMatcher object returned. static llvm::Optional<DynTypedMatcher> - parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error); - - /// \brief Parse an expression, creating matchers from the registry. - /// - /// Parses any expression supported by this parser. In general, the - /// \c parseMatcherExpression function is a better approach to get a matcher - /// object. - static bool parseExpression(StringRef Code, VariantValue *Value, - Diagnostics *Error); + parseMatcherExpression(StringRef MatcherCode, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, S, nullptr, Error); + } + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, nullptr, Error); + } /// \brief Parse an expression. /// /// Parses any expression supported by this parser. In general, the /// \c parseMatcherExpression function is a better approach to get a matcher /// object. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. static bool parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error); + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + return parseExpression(Code, S, nullptr, Value, Error); + } + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + return parseExpression(Code, nullptr, Value, Error); + } /// \brief Complete an expression at the given offset. /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// /// \return The list of completions, which may be empty if there are no /// available completions or if an error occurred. static std::vector<MatcherCompletion> - completeExpression(StringRef Code, unsigned CompletionOffset); + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues); + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) { + return completeExpression(Code, CompletionOffset, S, nullptr); + } + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset) { + return completeExpression(Code, CompletionOffset, nullptr); + } private: class CodeTokenizer; @@ -180,6 +225,7 @@ private: struct TokenInfo; Parser(CodeTokenizer *Tokenizer, Sema *S, + const NamedValueMap *NamedValues, Diagnostics *Error); bool parseExpressionImpl(VariantValue *Value); @@ -187,12 +233,16 @@ private: VariantValue *Value); bool parseIdentifierPrefixImpl(VariantValue *Value); - void addCompletion(const TokenInfo &CompToken, StringRef TypedText, - StringRef Decl); + void addCompletion(const TokenInfo &CompToken, + const MatcherCompletion &Completion); void addExpressionCompletions(); + std::vector<MatcherCompletion> + getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes); + CodeTokenizer *const Tokenizer; Sema *const S; + const NamedValueMap *const NamedValues; Diagnostics *const Error; typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy; diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h index faa9254..ad24a8d 100644 --- a/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -14,8 +14,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" @@ -36,8 +36,10 @@ typedef const internal::MatcherDescriptor *MatcherCtor; struct MatcherCompletion { MatcherCompletion() {} - MatcherCompletion(StringRef TypedText, StringRef MatcherDecl) - : TypedText(TypedText), MatcherDecl(MatcherDecl) {} + MatcherCompletion(StringRef TypedText, StringRef MatcherDecl, + unsigned Specificity) + : TypedText(TypedText), MatcherDecl(MatcherDecl), + Specificity(Specificity) {} /// \brief The text to type to select this matcher. std::string TypedText; @@ -45,6 +47,13 @@ struct MatcherCompletion { /// \brief The "declaration" of the matcher, with type information. std::string MatcherDecl; + /// \brief Value corresponding to the "specificity" of the converted matcher. + /// + /// Zero specificity indicates that this conversion would produce a trivial + /// matcher that will either always or never match. + /// Such matchers are excluded from code completion results. + unsigned Specificity; + bool operator==(const MatcherCompletion &Other) const { return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl; } @@ -58,28 +67,28 @@ public: /// constructor, or Optional<MatcherCtor>() if not found. static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName); - /// \brief Compute the list of completions for \p Context. + /// \brief Compute the list of completion types for \p Context. /// /// Each element of \p Context represents a matcher invocation, going from - /// outermost to innermost. Elements are pairs consisting of a reference to the - /// matcher constructor and the index of the next element in the argument list - /// of that matcher (or for the last element, the index of the completion - /// point in the argument list). An empty list requests completion for the - /// root matcher. + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + static std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. /// - /// The completions are ordered first by decreasing relevance, then - /// alphabetically. Relevance is determined by how closely the matcher's - /// type matches that of the context. For example, if the innermost matcher - /// takes a FunctionDecl matcher, the FunctionDecl matchers are returned - /// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then - /// polymorphic matchers. + /// \param AcceptedTypes All types accepted for this completion. /// - /// Matchers which are technically convertible to the innermost context but - /// which would match either all or no nodes are excluded. For example, - /// namedDecl and varDecl are excluded in a FunctionDecl context, because - /// those matchers would match respectively all or no nodes in such a context. + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. static std::vector<MatcherCompletion> - getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context); + getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes); /// \brief Construct a matcher from the registry. /// diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index b25267b..a9bd3d5 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -14,8 +14,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" @@ -29,6 +29,51 @@ namespace clang { namespace ast_matchers { namespace dynamic { +/// \brief Kind identifier. +/// +/// It supports all types that VariantValue can contain. +class ArgKind { + public: + enum Kind { + AK_Matcher, + AK_Unsigned, + AK_String + }; + /// \brief Constructor for non-matcher types. + ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); } + + /// \brief Constructor for matcher types. + ArgKind(ast_type_traits::ASTNodeKind MatcherKind) + : K(AK_Matcher), MatcherKind(MatcherKind) {} + + Kind getArgKind() const { return K; } + ast_type_traits::ASTNodeKind getMatcherKind() const { + assert(K == AK_Matcher); + return MatcherKind; + } + + /// \brief Determines if this type can be converted to \p To. + /// + /// \param To the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind To, unsigned *Specificity) const; + + bool operator<(const ArgKind &Other) const { + if (K == AK_Matcher && Other.K == AK_Matcher) + return MatcherKind < Other.MatcherKind; + return K < Other.K; + } + + /// \brief String representation of the type. + std::string asString() const; + +private: + Kind K; + ast_type_traits::ASTNodeKind MatcherKind; +}; + using ast_matchers::internal::DynTypedMatcher; /// \brief A variant matcher object. @@ -48,13 +93,28 @@ class VariantMatcher { /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. class MatcherOps { public: - virtual ~MatcherOps(); - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const = 0; - virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; - virtual void constructVariadicOperator( - ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef<VariantMatcher> InnerMatchers) = 0; + MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + + /// \brief Convert \p Matcher the destination type and return it as a new + /// DynTypedMatcher. + virtual DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const = 0; + + /// \brief Constructs a variadic typed matcher from \p InnerMatchers. + /// Will try to convert each inner matcher to the destination type and + /// return llvm::None if it fails to do so. + llvm::Optional<DynTypedMatcher> + constructVariadicOperator(DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const; + + protected: + ~MatcherOps() {} + + private: + ast_type_traits::ASTNodeKind NodeKind; }; /// \brief Payload interface to be specialized by each matcher type. @@ -65,7 +125,10 @@ class VariantMatcher { virtual ~Payload(); virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0; virtual std::string getTypeAsString() const = 0; - virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; + virtual llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const = 0; + virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const = 0; }; public: @@ -84,9 +147,9 @@ public: /// \brief Creates a 'variadic' operator matcher. /// /// It will bind to the appropriate type on getTypedMatcher<T>(). - static VariantMatcher VariadicOperatorMatcher( - ast_matchers::internal::VariadicOperatorFunction Func, - std::vector<VariantMatcher> Args); + static VariantMatcher + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args); /// \brief Makes the matcher the "null" matcher. void reset(); @@ -111,9 +174,21 @@ public: /// that can, the result would be ambiguous and false is returned. template <class T> bool hasTypedMatcher() const { - TypedMatcherOps<T> Ops; - if (Value) Value->makeTypedMatcher(Ops); - return Ops.hasMatcher(); + if (!Value) return false; + return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue(); + } + + /// \brief Determines if the contained matcher can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const { + if (Value) + return Value->isConvertibleTo(Kind, Specificity); + return false; } /// \brief Return this matcher as a \c Matcher<T>. @@ -122,10 +197,9 @@ public: /// Asserts that \c hasTypedMatcher<T>() is true. template <class T> ast_matchers::internal::Matcher<T> getTypedMatcher() const { - TypedMatcherOps<T> Ops; - Value->makeTypedMatcher(Ops); - assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false"); - return Ops.matcher(); + assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false"); + return Value->getTypedMatcher(TypedMatcherOps<T>()) + ->template convertTo<T>(); } /// \brief String representation of the type of the value. @@ -137,51 +211,25 @@ public: private: explicit VariantMatcher(Payload *Value) : Value(Value) {} + template <typename T> struct TypedMatcherOps; + class SinglePayload; class PolymorphicPayload; class VariadicOpPayload; - template <typename T> - class TypedMatcherOps : public MatcherOps { - public: - typedef ast_matchers::internal::Matcher<T> MatcherT; - - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const { - IsExactMatch = Matcher.getSupportedKind().isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); - return Matcher.canConvertTo<T>(); - } - - virtual void constructFrom(const DynTypedMatcher& Matcher) { - Out.reset(new MatcherT(Matcher.convertTo<T>())); - } - - virtual void constructVariadicOperator( - ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef<VariantMatcher> InnerMatchers) { - std::vector<DynTypedMatcher> DynMatchers; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - // Abort if any of the inner matchers can't be converted to - // Matcher<T>. - if (!InnerMatchers[i].hasTypedMatcher<T>()) { - return; - } - DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>()); - } - Out.reset(new MatcherT( - new ast_matchers::internal::VariadicOperatorMatcherInterface<T>( - Func, DynMatchers))); - } - - bool hasMatcher() const { return Out.get() != nullptr; } - const MatcherT &matcher() const { return *Out; } + IntrusiveRefCntPtr<const Payload> Value; +}; - private: - std::unique_ptr<MatcherT> Out; - }; +template <typename T> +struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {} + typedef ast_matchers::internal::Matcher<T> MatcherT; - IntrusiveRefCntPtr<const Payload> Value; + DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const override { + return DynTypedMatcher(Matcher.convertTo<T>()); + } }; /// \brief Variant value class. @@ -228,6 +276,24 @@ public: const VariantMatcher &getMatcher() const; void setMatcher(const VariantMatcher &Matcher); + /// \brief Determines if the contained value can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const; + + /// \brief Determines if the contained value can be converted to any kind + /// in \p Kinds. + /// + /// \param Kinds the requested destination types. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. It is the maximum specificity of all the possible + /// conversions. + bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const; + /// \brief String representation of the type of the value. std::string getTypeAsString() const; |