diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -100,6 +100,17 @@
Matches attributes.
+
+Given
+ struct [[nodiscard]] Foo{};
+ void bar(int * __attribute__((nonnull)) );
+attr()
+ matches "nodiscard" and "nonnull"
+Matches constructor initializers.
diff --git a/clang/include/clang/AST/ASTFwd.h b/clang/include/clang/AST/ASTFwd.h
--- a/clang/include/clang/AST/ASTFwd.h
+++ b/clang/include/clang/AST/ASTFwd.h
@@ -29,7 +29,9 @@
class OMPClause;
#define OMP_CLAUSE_CLASS(Enum, Str, Class) class Class;
#include "llvm/Frontend/OpenMP/OMPKinds.def"
-
+class Attr;
+#define ATTR(A) class A##Attr;
+#include "clang/Basic/AttrList.inc"
} // end namespace clang
diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h
--- a/clang/include/clang/AST/ASTTypeTraits.h
+++ b/clang/include/clang/AST/ASTTypeTraits.h
@@ -25,10 +25,8 @@
#include "llvm/Support/AlignOf.h"
namespace llvm {
-
class raw_ostream;
-
-}
+} // namespace llvm
namespace clang {
@@ -70,6 +68,7 @@
static ASTNodeKind getFromNode(const Stmt &S);
static ASTNodeKind getFromNode(const Type &T);
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.
@@ -153,6 +152,9 @@
NKI_OMPClause,
#define OMP_CLAUSE_CLASS(Enum, Str, Class) NKI_##Class,
#include "llvm/Frontend/OpenMP/OMPKinds.def"
+ NKI_Attr,
+#define ATTR(A) NKI_##A##Attr,
+#include "clang/Basic/AttrList.inc"
NKI_NumberOfKinds
};
@@ -202,6 +204,7 @@
KIND_TO_KIND_ID(Stmt)
KIND_TO_KIND_ID(Type)
KIND_TO_KIND_ID(OMPClause)
+KIND_TO_KIND_ID(Attr)
KIND_TO_KIND_ID(CXXBaseSpecifier)
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
#include "clang/AST/DeclNodes.inc"
@@ -211,6 +214,8 @@
#include "clang/AST/TypeNodes.inc"
#define OMP_CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class)
#include "llvm/Frontend/OpenMP/OMPKinds.def"
+#define ATTR(A) KIND_TO_KIND_ID(A##Attr)
+#include "clang/Basic/AttrList.inc"
#undef KIND_TO_KIND_ID
inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
@@ -487,6 +492,11 @@
T, std::enable_if_t::value>>
: public DynCastPtrConverter {};
+template
+struct DynTypedNode::BaseConverter<
+ T, std::enable_if_t::value>>
+ : public DynCastPtrConverter {};
+
template <>
struct DynTypedNode::BaseConverter<
NestedNameSpecifier, void> : public PtrConverter {};
diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
--- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -161,6 +161,7 @@
MatchCallback *Action);
void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
MatchCallback *Action);
+ void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
/// @}
/// Adds a matcher to execute when running over the AST.
@@ -213,6 +214,7 @@
std::vector> CtorInit;
std::vector>
TemplateArgumentLoc;
+ std::vector> Attr;
/// All the callbacks in one container to simplify iteration.
llvm::SmallPtrSet AllCallbacks;
};
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -146,6 +146,7 @@
using NestedNameSpecifierLocMatcher = internal::Matcher;
using CXXCtorInitializerMatcher = internal::Matcher;
using TemplateArgumentLocMatcher = internal::Matcher;
+using AttrMatcher = internal::Matcher;
/// @}
/// Matches any node.
@@ -6728,6 +6729,17 @@
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
}
+/// Matches attributes.
+///
+/// Given
+/// \code
+/// struct [[nodiscard]] Foo{};
+/// void bar(int * __attribute__((nonnull)) );
+/// \endcode
+/// attr()
+/// matches "nodiscard" and "nonnull"
+extern const internal::VariadicAllOfMatcher attr;
+
/// Overloads for the \c equalsNode matcher.
/// FIXME: Implement for other node types.
/// @{
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -944,7 +944,8 @@
std::is_same::value ||
std::is_same::value ||
std::is_same::value ||
- std::is_same::value;
+ std::is_same::value ||
+ std::is_same::value;
};
template
const bool IsBaseType::value;
diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp
--- a/clang/lib/AST/ASTTypeTraits.cpp
+++ b/clang/lib/AST/ASTTypeTraits.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OpenMPClause.h"
@@ -21,28 +22,31 @@
using namespace clang;
const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
- { NKI_None, "" },
- { NKI_None, "TemplateArgument" },
- { NKI_None, "TemplateArgumentLoc" },
- { NKI_None, "TemplateName" },
- { NKI_None, "NestedNameSpecifierLoc" },
- { NKI_None, "QualType" },
- { NKI_None, "TypeLoc" },
- { NKI_None, "CXXBaseSpecifier" },
- { NKI_None, "CXXCtorInitializer" },
- { NKI_None, "NestedNameSpecifier" },
- { NKI_None, "Decl" },
+ {NKI_None, ""},
+ {NKI_None, "TemplateArgument"},
+ {NKI_None, "TemplateArgumentLoc"},
+ {NKI_None, "TemplateName"},
+ {NKI_None, "NestedNameSpecifierLoc"},
+ {NKI_None, "QualType"},
+ {NKI_None, "TypeLoc"},
+ {NKI_None, "CXXBaseSpecifier"},
+ {NKI_None, "CXXCtorInitializer"},
+ {NKI_None, "NestedNameSpecifier"},
+ {NKI_None, "Decl"},
#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
#include "clang/AST/DeclNodes.inc"
- { NKI_None, "Stmt" },
+ {NKI_None, "Stmt"},
#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
#include "clang/AST/StmtNodes.inc"
- { NKI_None, "Type" },
+ {NKI_None, "Type"},
#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
#include "clang/AST/TypeNodes.inc"
- { NKI_None, "OMPClause" },
+ {NKI_None, "OMPClause"},
#define OMP_CLAUSE_CLASS(Enum, Str, Class) {NKI_OMPClause, #Class},
#include "llvm/Frontend/OpenMP/OMPKinds.def"
+ {NKI_None, "Attr"},
+#define ATTR(A) {NKI_Attr, #A "Attr"},
+#include "clang/Basic/AttrList.inc"
};
bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
@@ -123,7 +127,17 @@
break;
#include "llvm/Frontend/OpenMP/OMPKinds.def"
}
- 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,
@@ -151,6 +165,8 @@
S->printPretty(OS, nullptr, PP);
else if (const Type *T = get())
QualType(T, 0).print(OS, PP);
+ else if (const Attr *A = get())
+ A->printPretty(OS, PP);
else
OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
}
@@ -182,5 +198,7 @@
return TAL->getSourceRange();
if (const auto *C = get())
return SourceRange(C->getBeginLoc(), C->getEndLoc());
+ if (const auto *A = get())
+ return A->getRange();
return SourceRange();
}
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -131,6 +131,8 @@
else if (const TemplateArgumentLoc *TALoc =
DynNode.get())
traverse(*TALoc);
+ else if (const Attr *A = DynNode.get())
+ traverse(*A);
// FIXME: Add other base types after adding tests.
// It's OK to always overwrite the bound nodes, as if there was
@@ -231,6 +233,10 @@
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(TAL);
}
+ bool TraverseAttr(Attr *A) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ return (A == nullptr || traverse(*A));
+ }
bool TraverseLambdaExpr(LambdaExpr *Node) {
if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
TK_IgnoreUnlessSpelledInSource)
@@ -314,6 +320,9 @@
bool baseTraverse(TemplateArgumentLoc TAL) {
return VisitorBase::TraverseTemplateArgumentLoc(TAL);
}
+ bool baseTraverse(const Attr &AttrNode) {
+ return VisitorBase::TraverseAttr(const_cast(&AttrNode));
+ }
// Sets 'Matched' to true if 'Matcher' matches 'Node' and:
// 0 < CurrentDepth <= MaxDepth.
@@ -458,6 +467,7 @@
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
+ bool TraverseAttr(Attr *AttrNode);
// Matches children or descendants of 'Node' with 'BaseMatcher'.
bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
@@ -571,6 +581,8 @@
match(*N);
} else if (auto *N = Node.get()) {
match(*N);
+ } else if (auto *N = Node.get()) {
+ match(*N);
}
}
@@ -697,6 +709,9 @@
void matchDispatch(const TemplateArgumentLoc *Node) {
matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
}
+ void matchDispatch(const Attr *Node) {
+ matchWithoutFilter(*Node, Matchers->Attr);
+ }
void matchDispatch(const void *) { /* Do nothing. */ }
/// @}
@@ -1068,6 +1083,11 @@
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(Loc);
}
+bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
+ match(*AttrNode);
+ return RecursiveASTVisitor::TraverseAttr(AttrNode);
+}
+
class MatchASTConsumer : public ASTConsumer {
public:
MatchASTConsumer(MatchFinder *Finder,
@@ -1150,6 +1170,12 @@
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,
MatchCallback *Action) {
if (NodeMatch.canConvertTo()) {
@@ -1176,6 +1202,9 @@
} else if (NodeMatch.canConvertTo()) {
addMatcher(NodeMatch.convertTo(), Action);
return true;
+ } else if (NodeMatch.canConvertTo()) {
+ addMatcher(NodeMatch.convertTo(), Action);
+ return true;
}
return false;
}
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -973,6 +973,7 @@
const internal::VariadicAllOfMatcher nestedNameSpecifier;
const internal::VariadicAllOfMatcher
nestedNameSpecifierLoc;
+const internal::VariadicAllOfMatcher attr;
const internal::VariadicDynCastAllOfMatcher
cudaKernelCallExpr;
const AstTypeMatcher builtinType;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -141,6 +141,7 @@
REGISTER_MATCHER(asmStmt);
REGISTER_MATCHER(atomicExpr);
REGISTER_MATCHER(atomicType);
+ REGISTER_MATCHER(attr);
REGISTER_MATCHER(autoType);
REGISTER_MATCHER(autoreleasePoolStmt)
REGISTER_MATCHER(binaryConditionalOperator);
diff --git a/clang/unittests/AST/ASTTypeTraitsTest.cpp b/clang/unittests/AST/ASTTypeTraitsTest.cpp
--- a/clang/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/clang/unittests/AST/ASTTypeTraitsTest.cpp
@@ -120,6 +120,7 @@
VERIFY_NAME(CallExpr);
VERIFY_NAME(Type);
VERIFY_NAME(ConstantArrayType);
+ VERIFY_NAME(NonNullAttr);
#undef VERIFY_NAME
}
@@ -148,6 +149,13 @@
nestedNameSpecifierLoc()));
}
+TEST(DynTypedNode, AttrSourceRange) {
+ RangeVerifier Verifier;
+ Verifier.expectRange(1, 31, 1, 31);
+ EXPECT_TRUE(Verifier.match("void x(char *y __attribute__((nonnull)) );",
+ ast_matchers::attr()));
+}
+
TEST(DynTypedNode, DeclDump) {
DumpVerifier Verifier;
Verifier.expectSubstring("FunctionDecl");
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1875,6 +1875,17 @@
nestedNameSpecifier()));
}
+TEST_P(ASTMatchersTest, Attr) {
+ if (!GetParam().isCXX())
+ return;
+ if (GetParam().isCXX17OrLater())
+ EXPECT_TRUE(matches("struct [[nodiscard]] F{};", attr()));
+ EXPECT_TRUE(matches("int x(int * __attribute__((nonnull)) );", attr()));
+ // On windows, some nodes an implicit visibility attribute.
+ if (!GetParam().hasDelayedTemplateParsing() /* Windows */)
+ EXPECT_TRUE(notMatches("struct F{}; int x(int *);", attr()));
+}
+
TEST_P(ASTMatchersTest, NullStmt) {
EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));