Support Attr in DynTypedNode and ASTMatchers.
Differential Revision: https://reviews.llvm.org/D89743
This commit is contained in:
parent
9ed7416aaf
commit
a4bdcdadc6
|
@ -442,7 +442,7 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||||
hasDeclaration(DeclMatcher),
|
hasDeclaration(DeclMatcher),
|
||||||
unless(templateSpecializationType()))))),
|
unless(templateSpecializationType()))))),
|
||||||
hasParent(nestedNameSpecifierLoc()),
|
hasParent(nestedNameSpecifierLoc()),
|
||||||
hasAncestor(isImplicit()),
|
hasAncestor(decl(isImplicit())),
|
||||||
hasAncestor(UsingShadowDeclInClass),
|
hasAncestor(UsingShadowDeclInClass),
|
||||||
hasAncestor(functionDecl(isDefaulted())))),
|
hasAncestor(functionDecl(isDefaulted())))),
|
||||||
hasAncestor(decl().bind("dc")))
|
hasAncestor(decl().bind("dc")))
|
||||||
|
@ -466,7 +466,7 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||||
hasAncestor(decl(IsInMovedNs).bind("dc")),
|
hasAncestor(decl(IsInMovedNs).bind("dc")),
|
||||||
loc(nestedNameSpecifier(
|
loc(nestedNameSpecifier(
|
||||||
specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
|
specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
|
||||||
unless(anyOf(hasAncestor(isImplicit()),
|
unless(anyOf(hasAncestor(decl(isImplicit())),
|
||||||
hasAncestor(UsingShadowDeclInClass),
|
hasAncestor(UsingShadowDeclInClass),
|
||||||
hasAncestor(functionDecl(isDefaulted())),
|
hasAncestor(functionDecl(isDefaulted())),
|
||||||
hasAncestor(typeLoc(loc(qualType(hasDeclaration(
|
hasAncestor(typeLoc(loc(qualType(hasDeclaration(
|
||||||
|
@ -495,7 +495,7 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||||
hasAncestor(cxxRecordDecl()))),
|
hasAncestor(cxxRecordDecl()))),
|
||||||
hasParent(namespaceDecl()));
|
hasParent(namespaceDecl()));
|
||||||
Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
|
Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
|
||||||
unless(hasAncestor(isImplicit())),
|
unless(hasAncestor(decl(isImplicit()))),
|
||||||
anyOf(callExpr(callee(FuncMatcher)).bind("call"),
|
anyOf(callExpr(callee(FuncMatcher)).bind("call"),
|
||||||
declRefExpr(to(FuncMatcher.bind("func_decl")))
|
declRefExpr(to(FuncMatcher.bind("func_decl")))
|
||||||
.bind("func_ref"))),
|
.bind("func_ref"))),
|
||||||
|
|
|
@ -38,10 +38,10 @@ void ProBoundsConstantArrayIndexCheck::registerPPCallbacks(
|
||||||
void ProBoundsConstantArrayIndexCheck::registerMatchers(MatchFinder *Finder) {
|
void ProBoundsConstantArrayIndexCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
// Note: if a struct contains an array member, the compiler-generated
|
// Note: if a struct contains an array member, the compiler-generated
|
||||||
// constructor has an arraySubscriptExpr.
|
// constructor has an arraySubscriptExpr.
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(arraySubscriptExpr(hasBase(ignoringImpCasts(hasType(
|
||||||
arraySubscriptExpr(
|
constantArrayType().bind("type")))),
|
||||||
hasBase(ignoringImpCasts(hasType(constantArrayType().bind("type")))),
|
hasIndex(expr().bind("index")),
|
||||||
hasIndex(expr().bind("index")), unless(hasAncestor(isImplicit())))
|
unless(hasAncestor(decl(isImplicit()))))
|
||||||
.bind("expr"),
|
.bind("expr"),
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
|
|
@ -582,6 +582,24 @@ Examples matches public virtual B.
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>></td><td class="name" onclick="toggle('attr0')"><a name="attr0Anchor">attr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>>...</td></tr>
|
||||||
|
<tr><td colspan="4" class="doc" id="attr0"><pre>Matches attributes.
|
||||||
|
Attributes may be attached with a variety of different syntaxes (including
|
||||||
|
keywords, C++11 attributes, GNU ``__attribute``` and MSVC `__declspec``,
|
||||||
|
and ``#pragma``s). They may also be implicit.
|
||||||
|
|
||||||
|
Given
|
||||||
|
struct [[nodiscard]] Foo{};
|
||||||
|
void bar(int * __attribute__((nonnull)) );
|
||||||
|
__declspec(noinline) void baz();
|
||||||
|
|
||||||
|
#pragma omp declare simd
|
||||||
|
int min();
|
||||||
|
attr()
|
||||||
|
matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line.
|
||||||
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr>
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr>
|
||||||
<tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers.
|
<tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers.
|
||||||
|
|
||||||
|
@ -2744,6 +2762,12 @@ Usable as: Any Matcher
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>></td><td class="name" onclick="toggle('isImplicit1')"><a name="isImplicit1Anchor">isImplicit</a></td><td></td></tr>
|
||||||
|
<tr><td colspan="4" class="doc" id="isImplicit1"><pre>Matches an entity that has been implicitly added by the compiler (e.g.
|
||||||
|
implicit default/copy constructors).
|
||||||
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasAnyOperatorName0')"><a name="hasAnyOperatorName0Anchor">hasAnyOperatorName</a></td><td>StringRef, ..., StringRef</td></tr>
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasAnyOperatorName0')"><a name="hasAnyOperatorName0Anchor">hasAnyOperatorName</a></td><td>StringRef, ..., StringRef</td></tr>
|
||||||
<tr><td colspan="4" class="doc" id="hasAnyOperatorName0"><pre>Matches operator expressions (binary or unary) that have any of the
|
<tr><td colspan="4" class="doc" id="hasAnyOperatorName0"><pre>Matches operator expressions (binary or unary) that have any of the
|
||||||
specified names.
|
specified names.
|
||||||
|
@ -3808,8 +3832,8 @@ Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl
|
||||||
|
|
||||||
|
|
||||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
|
||||||
<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches a declaration that has been implicitly added
|
<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches an entity that has been implicitly added by the compiler (e.g.
|
||||||
by the compiler (eg. implicit default/copy constructors).
|
implicit default/copy constructors).
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ class OMPClause;
|
||||||
#define GEN_CLANG_CLAUSE_CLASS
|
#define GEN_CLANG_CLAUSE_CLASS
|
||||||
#define CLAUSE_CLASS(Enum, Str, Class) class Class;
|
#define CLAUSE_CLASS(Enum, Str, Class) class Class;
|
||||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||||
|
class Attr;
|
||||||
|
#define ATTR(A) class A##Attr;
|
||||||
|
#include "clang/Basic/AttrList.inc"
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,8 @@
|
||||||
#include "llvm/Support/AlignOf.h"
|
#include "llvm/Support/AlignOf.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
|
} // namespace llvm
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
|
@ -66,6 +64,7 @@ public:
|
||||||
static ASTNodeKind getFromNode(const Stmt &S);
|
static ASTNodeKind getFromNode(const Stmt &S);
|
||||||
static ASTNodeKind getFromNode(const Type &T);
|
static ASTNodeKind getFromNode(const Type &T);
|
||||||
static ASTNodeKind getFromNode(const OMPClause &C);
|
static ASTNodeKind getFromNode(const OMPClause &C);
|
||||||
|
static ASTNodeKind getFromNode(const Attr &A);
|
||||||
/// \}
|
/// \}
|
||||||
|
|
||||||
/// Returns \c true if \c this and \c Other represent the same kind.
|
/// Returns \c true if \c this and \c Other represent the same kind.
|
||||||
|
@ -152,6 +151,9 @@ private:
|
||||||
#define GEN_CLANG_CLAUSE_CLASS
|
#define GEN_CLANG_CLAUSE_CLASS
|
||||||
#define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class,
|
#define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class,
|
||||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||||
|
NKI_Attr,
|
||||||
|
#define ATTR(A) NKI_##A##Attr,
|
||||||
|
#include "clang/Basic/AttrList.inc"
|
||||||
NKI_NumberOfKinds
|
NKI_NumberOfKinds
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,6 +203,7 @@ KIND_TO_KIND_ID(Decl)
|
||||||
KIND_TO_KIND_ID(Stmt)
|
KIND_TO_KIND_ID(Stmt)
|
||||||
KIND_TO_KIND_ID(Type)
|
KIND_TO_KIND_ID(Type)
|
||||||
KIND_TO_KIND_ID(OMPClause)
|
KIND_TO_KIND_ID(OMPClause)
|
||||||
|
KIND_TO_KIND_ID(Attr)
|
||||||
KIND_TO_KIND_ID(CXXBaseSpecifier)
|
KIND_TO_KIND_ID(CXXBaseSpecifier)
|
||||||
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
|
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
|
||||||
#include "clang/AST/DeclNodes.inc"
|
#include "clang/AST/DeclNodes.inc"
|
||||||
|
@ -211,6 +214,8 @@ KIND_TO_KIND_ID(CXXBaseSpecifier)
|
||||||
#define GEN_CLANG_CLAUSE_CLASS
|
#define GEN_CLANG_CLAUSE_CLASS
|
||||||
#define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class)
|
#define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class)
|
||||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||||
|
#define ATTR(A) KIND_TO_KIND_ID(A##Attr)
|
||||||
|
#include "clang/Basic/AttrList.inc"
|
||||||
#undef KIND_TO_KIND_ID
|
#undef KIND_TO_KIND_ID
|
||||||
|
|
||||||
inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
|
inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
|
||||||
|
@ -486,6 +491,11 @@ struct DynTypedNode::BaseConverter<
|
||||||
T, std::enable_if_t<std::is_base_of<OMPClause, T>::value>>
|
T, std::enable_if_t<std::is_base_of<OMPClause, T>::value>>
|
||||||
: public DynCastPtrConverter<T, OMPClause> {};
|
: public DynCastPtrConverter<T, OMPClause> {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct DynTypedNode::BaseConverter<
|
||||||
|
T, std::enable_if_t<std::is_base_of<Attr, T>::value>>
|
||||||
|
: public DynCastPtrConverter<T, Attr> {};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct DynTypedNode::BaseConverter<
|
struct DynTypedNode::BaseConverter<
|
||||||
NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
|
NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
|
||||||
|
|
|
@ -167,6 +167,7 @@ public:
|
||||||
MatchCallback *Action);
|
MatchCallback *Action);
|
||||||
void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
|
void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
|
||||||
MatchCallback *Action);
|
MatchCallback *Action);
|
||||||
|
void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// Adds a matcher to execute when running over the AST.
|
/// Adds a matcher to execute when running over the AST.
|
||||||
|
@ -219,6 +220,7 @@ public:
|
||||||
std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
|
std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
|
||||||
std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
|
std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
|
||||||
TemplateArgumentLoc;
|
TemplateArgumentLoc;
|
||||||
|
std::vector<std::pair<AttrMatcher, MatchCallback *>> Attr;
|
||||||
/// All the callbacks in one container to simplify iteration.
|
/// All the callbacks in one container to simplify iteration.
|
||||||
llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
|
llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
|
||||||
};
|
};
|
||||||
|
|
|
@ -148,6 +148,7 @@ using CXXBaseSpecifierMatcher = internal::Matcher<CXXBaseSpecifier>;
|
||||||
using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>;
|
using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>;
|
||||||
using TemplateArgumentMatcher = internal::Matcher<TemplateArgument>;
|
using TemplateArgumentMatcher = internal::Matcher<TemplateArgument>;
|
||||||
using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>;
|
using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>;
|
||||||
|
using AttrMatcher = internal::Matcher<Attr>;
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// Matches any node.
|
/// Matches any node.
|
||||||
|
@ -752,9 +753,10 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate,
|
||||||
InnerMatcher.matches(*Decl, Finder, Builder));
|
InnerMatcher.matches(*Decl, Finder, Builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a declaration that has been implicitly added
|
/// Matches an entity that has been implicitly added by the compiler (e.g.
|
||||||
/// by the compiler (eg. implicit default/copy constructors).
|
/// implicit default/copy constructors).
|
||||||
AST_MATCHER(Decl, isImplicit) {
|
AST_POLYMORPHIC_MATCHER(isImplicit,
|
||||||
|
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr)) {
|
||||||
return Node.isImplicit();
|
return Node.isImplicit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3489,8 +3491,8 @@ internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) {
|
||||||
/// Usable as: Any Matcher
|
/// Usable as: Any Matcher
|
||||||
extern const internal::ArgumentAdaptingMatcherFunc<
|
extern const internal::ArgumentAdaptingMatcherFunc<
|
||||||
internal::HasParentMatcher,
|
internal::HasParentMatcher,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>,
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>>
|
||||||
hasParent;
|
hasParent;
|
||||||
|
|
||||||
/// Matches AST nodes that have an ancestor that matches the provided
|
/// Matches AST nodes that have an ancestor that matches the provided
|
||||||
|
@ -3506,8 +3508,8 @@ extern const internal::ArgumentAdaptingMatcherFunc<
|
||||||
/// Usable as: Any Matcher
|
/// Usable as: Any Matcher
|
||||||
extern const internal::ArgumentAdaptingMatcherFunc<
|
extern const internal::ArgumentAdaptingMatcherFunc<
|
||||||
internal::HasAncestorMatcher,
|
internal::HasAncestorMatcher,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>,
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>>
|
||||||
hasAncestor;
|
hasAncestor;
|
||||||
|
|
||||||
/// Matches if the provided matcher does not match.
|
/// Matches if the provided matcher does not match.
|
||||||
|
@ -7133,6 +7135,24 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
|
||||||
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
|
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches attributes.
|
||||||
|
/// Attributes may be attached with a variety of different syntaxes (including
|
||||||
|
/// keywords, C++11 attributes, GNU ``__attribute``` and MSVC `__declspec``,
|
||||||
|
/// and ``#pragma``s). They may also be implicit.
|
||||||
|
///
|
||||||
|
/// Given
|
||||||
|
/// \code
|
||||||
|
/// struct [[nodiscard]] Foo{};
|
||||||
|
/// void bar(int * __attribute__((nonnull)) );
|
||||||
|
/// __declspec(noinline) void baz();
|
||||||
|
///
|
||||||
|
/// #pragma omp declare simd
|
||||||
|
/// int min();
|
||||||
|
/// \endcode
|
||||||
|
/// attr()
|
||||||
|
/// matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line.
|
||||||
|
extern const internal::VariadicAllOfMatcher<Attr> attr;
|
||||||
|
|
||||||
/// Overloads for the \c equalsNode matcher.
|
/// Overloads for the \c equalsNode matcher.
|
||||||
/// FIXME: Implement for other node types.
|
/// FIXME: Implement for other node types.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
|
@ -757,7 +757,8 @@ public:
|
||||||
std::is_base_of<NestedNameSpecifier, T>::value ||
|
std::is_base_of<NestedNameSpecifier, T>::value ||
|
||||||
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||||
std::is_base_of<TypeLoc, T>::value ||
|
std::is_base_of<TypeLoc, T>::value ||
|
||||||
std::is_base_of<QualType, T>::value,
|
std::is_base_of<QualType, T>::value ||
|
||||||
|
std::is_base_of<Attr, T>::value,
|
||||||
"unsupported type for recursive matching");
|
"unsupported type for recursive matching");
|
||||||
return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher,
|
return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher,
|
||||||
Builder, Bind);
|
Builder, Bind);
|
||||||
|
@ -771,7 +772,8 @@ public:
|
||||||
std::is_base_of<NestedNameSpecifier, T>::value ||
|
std::is_base_of<NestedNameSpecifier, T>::value ||
|
||||||
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||||
std::is_base_of<TypeLoc, T>::value ||
|
std::is_base_of<TypeLoc, T>::value ||
|
||||||
std::is_base_of<QualType, T>::value,
|
std::is_base_of<QualType, T>::value ||
|
||||||
|
std::is_base_of<Attr, T>::value,
|
||||||
"unsupported type for recursive matching");
|
"unsupported type for recursive matching");
|
||||||
return matchesDescendantOf(DynTypedNode::create(Node), getASTContext(),
|
return matchesDescendantOf(DynTypedNode::create(Node), getASTContext(),
|
||||||
Matcher, Builder, Bind);
|
Matcher, Builder, Bind);
|
||||||
|
@ -785,7 +787,8 @@ public:
|
||||||
static_assert(std::is_base_of<Decl, T>::value ||
|
static_assert(std::is_base_of<Decl, T>::value ||
|
||||||
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||||
std::is_base_of<Stmt, T>::value ||
|
std::is_base_of<Stmt, T>::value ||
|
||||||
std::is_base_of<TypeLoc, T>::value,
|
std::is_base_of<TypeLoc, T>::value ||
|
||||||
|
std::is_base_of<Attr, T>::value,
|
||||||
"type not allowed for recursive matching");
|
"type not allowed for recursive matching");
|
||||||
return matchesAncestorOf(DynTypedNode::create(Node), getASTContext(),
|
return matchesAncestorOf(DynTypedNode::create(Node), getASTContext(),
|
||||||
Matcher, Builder, MatchMode);
|
Matcher, Builder, MatchMode);
|
||||||
|
@ -1175,7 +1178,8 @@ struct IsBaseType {
|
||||||
std::is_same<T, NestedNameSpecifier>::value ||
|
std::is_same<T, NestedNameSpecifier>::value ||
|
||||||
std::is_same<T, NestedNameSpecifierLoc>::value ||
|
std::is_same<T, NestedNameSpecifierLoc>::value ||
|
||||||
std::is_same<T, CXXCtorInitializer>::value ||
|
std::is_same<T, CXXCtorInitializer>::value ||
|
||||||
std::is_same<T, TemplateArgumentLoc>::value;
|
std::is_same<T, TemplateArgumentLoc>::value ||
|
||||||
|
std::is_same<T, Attr>::value;
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const bool IsBaseType<T>::value;
|
const bool IsBaseType<T>::value;
|
||||||
|
@ -1185,7 +1189,7 @@ const bool IsBaseType<T>::value;
|
||||||
/// Useful for matchers like \c anything and \c unless.
|
/// Useful for matchers like \c anything and \c unless.
|
||||||
using AllNodeBaseTypes =
|
using AllNodeBaseTypes =
|
||||||
TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, QualType,
|
TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, QualType,
|
||||||
Type, TypeLoc, CXXCtorInitializer>;
|
Type, TypeLoc, CXXCtorInitializer, Attr>;
|
||||||
|
|
||||||
/// Helper meta-function to extract the argument out of a function of
|
/// Helper meta-function to extract the argument out of a function of
|
||||||
/// type void(Arg).
|
/// type void(Arg).
|
||||||
|
@ -1212,7 +1216,7 @@ template <class T, class Tuple> constexpr T *new_from_tuple(Tuple &&t) {
|
||||||
using AdaptativeDefaultFromTypes = AllNodeBaseTypes;
|
using AdaptativeDefaultFromTypes = AllNodeBaseTypes;
|
||||||
using AdaptativeDefaultToTypes =
|
using AdaptativeDefaultToTypes =
|
||||||
TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, TypeLoc,
|
TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, TypeLoc,
|
||||||
QualType>;
|
QualType, Attr>;
|
||||||
|
|
||||||
/// All types that are supported by HasDeclarationMatcher above.
|
/// All types that are supported by HasDeclarationMatcher above.
|
||||||
using HasDeclarationSupportedTypes =
|
using HasDeclarationSupportedTypes =
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "clang/AST/ASTTypeTraits.h"
|
#include "clang/AST/ASTTypeTraits.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/AST/OpenMPClause.h"
|
#include "clang/AST/OpenMPClause.h"
|
||||||
|
@ -44,6 +45,9 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
|
||||||
#define GEN_CLANG_CLAUSE_CLASS
|
#define GEN_CLANG_CLAUSE_CLASS
|
||||||
#define CLAUSE_CLASS(Enum, Str, Class) {NKI_OMPClause, #Class},
|
#define CLAUSE_CLASS(Enum, Str, Class) {NKI_OMPClause, #Class},
|
||||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||||
|
{NKI_None, "Attr"},
|
||||||
|
#define ATTR(A) {NKI_Attr, #A "Attr"},
|
||||||
|
#include "clang/Basic/AttrList.inc"
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
|
bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
|
||||||
|
@ -134,7 +138,17 @@ ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
|
||||||
llvm_unreachable("unexpected OpenMP clause kind");
|
llvm_unreachable("unexpected OpenMP clause kind");
|
||||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||||
}
|
}
|
||||||
llvm_unreachable("invalid stmt kind");
|
llvm_unreachable("invalid omp clause kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNodeKind ASTNodeKind::getFromNode(const Attr &A) {
|
||||||
|
switch (A.getKind()) {
|
||||||
|
#define ATTR(A) \
|
||||||
|
case attr::A: \
|
||||||
|
return ASTNodeKind(NKI_##A##Attr);
|
||||||
|
#include "clang/Basic/AttrList.inc"
|
||||||
|
}
|
||||||
|
llvm_unreachable("invalid attr kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynTypedNode::print(llvm::raw_ostream &OS,
|
void DynTypedNode::print(llvm::raw_ostream &OS,
|
||||||
|
@ -162,6 +176,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
|
||||||
S->printPretty(OS, nullptr, PP);
|
S->printPretty(OS, nullptr, PP);
|
||||||
else if (const Type *T = get<Type>())
|
else if (const Type *T = get<Type>())
|
||||||
QualType(T, 0).print(OS, PP);
|
QualType(T, 0).print(OS, PP);
|
||||||
|
else if (const Attr *A = get<Attr>())
|
||||||
|
A->printPretty(OS, PP);
|
||||||
else
|
else
|
||||||
OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
|
OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
|
||||||
}
|
}
|
||||||
|
@ -195,5 +211,7 @@ SourceRange DynTypedNode::getSourceRange() const {
|
||||||
return SourceRange(C->getBeginLoc(), C->getEndLoc());
|
return SourceRange(C->getBeginLoc(), C->getEndLoc());
|
||||||
if (const auto *CBS = get<CXXBaseSpecifier>())
|
if (const auto *CBS = get<CXXBaseSpecifier>())
|
||||||
return CBS->getSourceRange();
|
return CBS->getSourceRange();
|
||||||
|
if (const auto *A = get<Attr>())
|
||||||
|
return A->getRange();
|
||||||
return SourceRange();
|
return SourceRange();
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,6 +429,11 @@ private:
|
||||||
[&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
|
[&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
|
||||||
&Map.OtherParents);
|
&Map.OtherParents);
|
||||||
}
|
}
|
||||||
|
bool TraverseAttr(Attr *AttrNode) {
|
||||||
|
return TraverseNode(
|
||||||
|
AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); },
|
||||||
|
&Map.PointerParents);
|
||||||
|
}
|
||||||
|
|
||||||
// Using generic TraverseNode for Stmt would prevent data-recursion.
|
// Using generic TraverseNode for Stmt would prevent data-recursion.
|
||||||
bool dataTraverseStmtPre(Stmt *StmtNode) {
|
bool dataTraverseStmtPre(Stmt *StmtNode) {
|
||||||
|
|
|
@ -133,6 +133,8 @@ public:
|
||||||
else if (const TemplateArgumentLoc *TALoc =
|
else if (const TemplateArgumentLoc *TALoc =
|
||||||
DynNode.get<TemplateArgumentLoc>())
|
DynNode.get<TemplateArgumentLoc>())
|
||||||
traverse(*TALoc);
|
traverse(*TALoc);
|
||||||
|
else if (const Attr *A = DynNode.get<Attr>())
|
||||||
|
traverse(*A);
|
||||||
// FIXME: Add other base types after adding tests.
|
// FIXME: Add other base types after adding tests.
|
||||||
|
|
||||||
// It's OK to always overwrite the bound nodes, as if there was
|
// It's OK to always overwrite the bound nodes, as if there was
|
||||||
|
@ -263,6 +265,15 @@ public:
|
||||||
|
|
||||||
return match(*Node->getLHS()) && match(*Node->getRHS());
|
return match(*Node->getLHS()) && match(*Node->getRHS());
|
||||||
}
|
}
|
||||||
|
bool TraverseAttr(Attr *A) {
|
||||||
|
if (A == nullptr ||
|
||||||
|
(A->isImplicit() &&
|
||||||
|
Finder->getASTContext().getParentMapContext().getTraversalKind() ==
|
||||||
|
TK_IgnoreUnlessSpelledInSource))
|
||||||
|
return true;
|
||||||
|
ScopedIncrement ScopedDepth(&CurrentDepth);
|
||||||
|
return traverse(*A);
|
||||||
|
}
|
||||||
bool TraverseLambdaExpr(LambdaExpr *Node) {
|
bool TraverseLambdaExpr(LambdaExpr *Node) {
|
||||||
if (!Finder->isTraversalIgnoringImplicitNodes())
|
if (!Finder->isTraversalIgnoringImplicitNodes())
|
||||||
return VisitorBase::TraverseLambdaExpr(Node);
|
return VisitorBase::TraverseLambdaExpr(Node);
|
||||||
|
@ -345,6 +356,9 @@ private:
|
||||||
bool baseTraverse(TemplateArgumentLoc TAL) {
|
bool baseTraverse(TemplateArgumentLoc TAL) {
|
||||||
return VisitorBase::TraverseTemplateArgumentLoc(TAL);
|
return VisitorBase::TraverseTemplateArgumentLoc(TAL);
|
||||||
}
|
}
|
||||||
|
bool baseTraverse(const Attr &AttrNode) {
|
||||||
|
return VisitorBase::TraverseAttr(const_cast<Attr *>(&AttrNode));
|
||||||
|
}
|
||||||
|
|
||||||
// Sets 'Matched' to true if 'Matcher' matches 'Node' and:
|
// Sets 'Matched' to true if 'Matcher' matches 'Node' and:
|
||||||
// 0 < CurrentDepth <= MaxDepth.
|
// 0 < CurrentDepth <= MaxDepth.
|
||||||
|
@ -489,6 +503,7 @@ public:
|
||||||
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
|
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
|
||||||
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
|
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
|
||||||
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
|
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
|
||||||
|
bool TraverseAttr(Attr *AttrNode);
|
||||||
|
|
||||||
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
|
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
|
||||||
if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
|
if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
|
||||||
|
@ -694,6 +709,8 @@ public:
|
||||||
match(*N);
|
match(*N);
|
||||||
} else if (auto *N = Node.get<TemplateArgumentLoc>()) {
|
} else if (auto *N = Node.get<TemplateArgumentLoc>()) {
|
||||||
match(*N);
|
match(*N);
|
||||||
|
} else if (auto *N = Node.get<Attr>()) {
|
||||||
|
match(*N);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,6 +911,9 @@ private:
|
||||||
void matchDispatch(const TemplateArgumentLoc *Node) {
|
void matchDispatch(const TemplateArgumentLoc *Node) {
|
||||||
matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
|
matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
|
||||||
}
|
}
|
||||||
|
void matchDispatch(const Attr *Node) {
|
||||||
|
matchWithoutFilter(*Node, Matchers->Attr);
|
||||||
|
}
|
||||||
void matchDispatch(const void *) { /* Do nothing. */ }
|
void matchDispatch(const void *) { /* Do nothing. */ }
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
@ -1300,6 +1320,11 @@ bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
|
||||||
return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
|
return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
|
||||||
|
match(*AttrNode);
|
||||||
|
return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
|
||||||
|
}
|
||||||
|
|
||||||
class MatchASTConsumer : public ASTConsumer {
|
class MatchASTConsumer : public ASTConsumer {
|
||||||
public:
|
public:
|
||||||
MatchASTConsumer(MatchFinder *Finder,
|
MatchASTConsumer(MatchFinder *Finder,
|
||||||
|
@ -1394,6 +1419,12 @@ void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
|
||||||
Matchers.AllCallbacks.insert(Action);
|
Matchers.AllCallbacks.insert(Action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MatchFinder::addMatcher(const AttrMatcher &AttrMatch,
|
||||||
|
MatchCallback *Action) {
|
||||||
|
Matchers.Attr.emplace_back(AttrMatch, Action);
|
||||||
|
Matchers.AllCallbacks.insert(Action);
|
||||||
|
}
|
||||||
|
|
||||||
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
|
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
|
||||||
MatchCallback *Action) {
|
MatchCallback *Action) {
|
||||||
if (NodeMatch.canConvertTo<Decl>()) {
|
if (NodeMatch.canConvertTo<Decl>()) {
|
||||||
|
@ -1420,6 +1451,9 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
|
||||||
} else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
|
} else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
|
||||||
addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
|
addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (NodeMatch.canConvertTo<Attr>()) {
|
||||||
|
addMatcher(NodeMatch.convertTo<Attr>(), Action);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1000,19 +1000,20 @@ const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher>
|
||||||
forEachDescendant = {};
|
forEachDescendant = {};
|
||||||
const internal::ArgumentAdaptingMatcherFunc<
|
const internal::ArgumentAdaptingMatcherFunc<
|
||||||
internal::HasParentMatcher,
|
internal::HasParentMatcher,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>,
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>>
|
||||||
hasParent = {};
|
hasParent = {};
|
||||||
const internal::ArgumentAdaptingMatcherFunc<
|
const internal::ArgumentAdaptingMatcherFunc<
|
||||||
internal::HasAncestorMatcher,
|
internal::HasAncestorMatcher,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>,
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>,
|
||||||
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
|
internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr>>
|
||||||
hasAncestor = {};
|
hasAncestor = {};
|
||||||
const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
|
const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
|
||||||
internal::DynTypedMatcher::VO_UnaryNot};
|
internal::DynTypedMatcher::VO_UnaryNot};
|
||||||
const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
|
const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
|
||||||
const internal::VariadicAllOfMatcher<NestedNameSpecifierLoc>
|
const internal::VariadicAllOfMatcher<NestedNameSpecifierLoc>
|
||||||
nestedNameSpecifierLoc;
|
nestedNameSpecifierLoc;
|
||||||
|
const internal::VariadicAllOfMatcher<Attr> attr;
|
||||||
const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
|
const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
|
||||||
cudaKernelCallExpr;
|
cudaKernelCallExpr;
|
||||||
const AstTypeMatcher<BuiltinType> builtinType;
|
const AstTypeMatcher<BuiltinType> builtinType;
|
||||||
|
|
|
@ -142,6 +142,7 @@ RegistryMaps::RegistryMaps() {
|
||||||
REGISTER_MATCHER(asmStmt);
|
REGISTER_MATCHER(asmStmt);
|
||||||
REGISTER_MATCHER(atomicExpr);
|
REGISTER_MATCHER(atomicExpr);
|
||||||
REGISTER_MATCHER(atomicType);
|
REGISTER_MATCHER(atomicType);
|
||||||
|
REGISTER_MATCHER(attr);
|
||||||
REGISTER_MATCHER(autoType);
|
REGISTER_MATCHER(autoType);
|
||||||
REGISTER_MATCHER(autoreleasePoolStmt)
|
REGISTER_MATCHER(autoreleasePoolStmt)
|
||||||
REGISTER_MATCHER(binaryConditionalOperator);
|
REGISTER_MATCHER(binaryConditionalOperator);
|
||||||
|
|
|
@ -132,6 +132,7 @@ TEST(ASTNodeKind, Name) {
|
||||||
VERIFY_NAME(CallExpr);
|
VERIFY_NAME(CallExpr);
|
||||||
VERIFY_NAME(Type);
|
VERIFY_NAME(Type);
|
||||||
VERIFY_NAME(ConstantArrayType);
|
VERIFY_NAME(ConstantArrayType);
|
||||||
|
VERIFY_NAME(NonNullAttr);
|
||||||
#undef VERIFY_NAME
|
#undef VERIFY_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +161,13 @@ TEST(DynTypedNode, NNSLocSourceRange) {
|
||||||
nestedNameSpecifierLoc()));
|
nestedNameSpecifierLoc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DynTypedNode, AttrSourceRange) {
|
||||||
|
RangeVerifier<DynTypedNode> Verifier;
|
||||||
|
Verifier.expectRange(1, 31, 1, 31);
|
||||||
|
EXPECT_TRUE(Verifier.match("void x(char *y __attribute__((nonnull)) );",
|
||||||
|
ast_matchers::attr()));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DynTypedNode, DeclDump) {
|
TEST(DynTypedNode, DeclDump) {
|
||||||
DumpVerifier Verifier;
|
DumpVerifier Verifier;
|
||||||
Verifier.expectSubstring("FunctionDecl");
|
Verifier.expectSubstring("FunctionDecl");
|
||||||
|
|
|
@ -1885,6 +1885,29 @@ TEST_P(ASTMatchersTest, NestedNameSpecifier) {
|
||||||
nestedNameSpecifier()));
|
nestedNameSpecifier()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(ASTMatchersTest, Attr) {
|
||||||
|
// Windows adds some implicit attributes.
|
||||||
|
bool AutomaticAttributes = StringRef(GetParam().Target).contains("win32");
|
||||||
|
if (GetParam().isCXX11OrLater()) {
|
||||||
|
EXPECT_TRUE(matches("struct [[clang::warn_unused_result]] F{};", attr()));
|
||||||
|
|
||||||
|
// Unknown attributes are not parsed into an AST node.
|
||||||
|
if (!AutomaticAttributes)
|
||||||
|
EXPECT_TRUE(notMatches("int x [[unknownattr]];", attr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GetParam().isCXX17OrLater()) {
|
||||||
|
EXPECT_TRUE(matches("struct [[nodiscard]] F{};", attr()));
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(matches("int x(int * __attribute__((nonnull)) );", attr()));
|
||||||
|
if (!AutomaticAttributes) {
|
||||||
|
EXPECT_TRUE(notMatches("struct F{}; int x(int *);", attr()));
|
||||||
|
// Some known attributes are not parsed into an AST node.
|
||||||
|
EXPECT_TRUE(notMatches("typedef int x __attribute__((ext_vector_type(1)));",
|
||||||
|
attr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(ASTMatchersTest, NullStmt) {
|
TEST_P(ASTMatchersTest, NullStmt) {
|
||||||
EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
|
EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
|
||||||
EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
|
EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
|
||||||
|
|
|
@ -298,7 +298,7 @@ testing::AssertionResult matchAndVerifyResultConditionally(
|
||||||
// Some tests use typeof, which is a gnu extension. Using an explicit
|
// Some tests use typeof, which is a gnu extension. Using an explicit
|
||||||
// unknown-unknown triple is good for a large speedup, because it lets us
|
// unknown-unknown triple is good for a large speedup, because it lets us
|
||||||
// avoid constructing a full system triple.
|
// avoid constructing a full system triple.
|
||||||
std::vector<std::string> Args = {"-std=gnu++98", "-target",
|
std::vector<std::string> Args = {"-std=gnu++11", "-target",
|
||||||
"i386-unknown-unknown"};
|
"i386-unknown-unknown"};
|
||||||
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
|
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
|
||||||
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
|
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ASTMatchersTest.h"
|
#include "ASTMatchersTest.h"
|
||||||
|
#include "clang/AST/Attrs.inc"
|
||||||
#include "clang/AST/PrettyPrinter.h"
|
#include "clang/AST/PrettyPrinter.h"
|
||||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||||
|
@ -2820,7 +2821,7 @@ B func1() { return 42; }
|
||||||
auto M = expr(unless(integerLiteral(equals(24)))).bind("intLit");
|
auto M = expr(unless(integerLiteral(equals(24)))).bind("intLit");
|
||||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
Code, traverse(TK_AsIs, M),
|
Code, traverse(TK_AsIs, M),
|
||||||
std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit", 7)));
|
std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit", 6)));
|
||||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
|
Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
|
||||||
std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit", 1)));
|
std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit", 1)));
|
||||||
|
@ -2866,7 +2867,7 @@ B func1() { return 42; }
|
||||||
auto M = expr().bind("allExprs");
|
auto M = expr().bind("allExprs");
|
||||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
Code, traverse(TK_AsIs, M),
|
Code, traverse(TK_AsIs, M),
|
||||||
std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs", 7)));
|
std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs", 6)));
|
||||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
|
Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
|
||||||
std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs", 1)));
|
std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs", 1)));
|
||||||
|
@ -5446,6 +5447,24 @@ TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
|
||||||
// Nested names: a, a::A and a::A::B.
|
// Nested names: a, a::A and a::A::B.
|
||||||
std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifierLoc>>("x", 3)));
|
std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifierLoc>>("x", 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Attr, AttrsAsDescendants) {
|
||||||
|
StringRef Fragment = "namespace a { struct [[clang::warn_unused_result]] "
|
||||||
|
"F{}; [[noreturn]] void foo(); }";
|
||||||
|
EXPECT_TRUE(matches(Fragment, namespaceDecl(hasDescendant(attr()))));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
Fragment,
|
||||||
|
namespaceDecl(hasName("a"),
|
||||||
|
forEachDescendant(attr(unless(isImplicit())).bind("x"))),
|
||||||
|
std::make_unique<VerifyIdIsBoundTo<Attr>>("x", 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Attr, ParentsOfAttrs) {
|
||||||
|
StringRef Fragment =
|
||||||
|
"namespace a { struct [[clang::warn_unused_result]] F{}; }";
|
||||||
|
EXPECT_TRUE(matches(Fragment, attr(hasAncestor(namespaceDecl()))));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> class VerifyMatchOnNode : public BoundNodesCallback {
|
template <typename T> class VerifyMatchOnNode : public BoundNodesCallback {
|
||||||
public:
|
public:
|
||||||
VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher,
|
VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher,
|
||||||
|
|
Loading…
Reference in New Issue