diff options
Diffstat (limited to 'include/clang/ASTMatchers/ASTMatchers.h')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 337 |
1 files changed, 304 insertions, 33 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 1ff4ab367fd5..f002cb9cbaba 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 |