ajohnson-uoregon updated this revision to Diff 418338.
ajohnson-uoregon added a comment.

I overloaded hasAttr and had to fix a couple CUDA tests to explicitly use the 
decl overload (the other tests 
for hasAttr did this already, so I think it was just a mistake in those tests).

I also had to remove an assert from Decl::getAttrs in DeclBase.cpp that checked 
if there were actually attributes 
on that decl to make the overload work (when I wrote the overload, I made both 
use getAttrs because AttributedStmts 
don't have attrs() like Decls do). After trawling git blame a bit, it looks 
like that assert was added way 
back in like 2010 when ASTContext::getDeclAttrs just did a straight lookup in 
the DeclAttrs map, which 
presumably would have done bad things if the decl had no attrs. In this commit 
though 
https://github.com/llvm/llvm-project/commit/561eceb4c4a20280d5324c873ddad1940960b891
 that got fixed, so 
getDeclAttrs will return a new empty AttrVec if the lookup fails. The assert is 
not necessary since that commit, 
but I guess no one realized they could remove the assert.

tl;dr That assert broke lots of the old hasAttr tests for Decls that were now 
using getAttrs() instead of attrs(), 
and removing it fixes them, and since it's no longer needed I think it's okay 
to get rid of it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120949/new/

https://reviews.llvm.org/D120949

Files:
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/AST/DeclBase.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -184,9 +184,9 @@
 
 TEST(ASTMatchersTestCUDA, HasAttrCUDA) {
   EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
-                              hasAttr(clang::attr::CUDADevice)));
+                              decl(hasAttr(clang::attr::CUDADevice))));
   EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
-                                  hasAttr(clang::attr::CUDAGlobal)));
+                                  decl(hasAttr(clang::attr::CUDAGlobal))));
 }
 
 TEST_P(ASTMatchersTest, ValueDecl) {
@@ -2509,6 +2509,37 @@
   EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr));
 }
 
+TEST(ASTMatchersTest, AttributedStmtBasic) {
+  StringRef Code = "int foo() { [[likely]] return 1; }";
+  EXPECT_TRUE(
+      matchesConditionally(Code, attributedStmt(), true, {"-std=c++20"}));
+}
+
+TEST(ASTMatchersTest, AttributedStmt_hasAttr) {
+  StringRef Code = "int foo() { [[unlikely]] return 1; }";
+  EXPECT_TRUE(matchesConditionally(
+      Code, attributedStmt(hasAttr(attr::Unlikely)), true, {"-std=c++20"}));
+  EXPECT_FALSE(matchesConditionally(
+      Code, attributedStmt(hasAttr(attr::Builtin)), true, {"-std=c++20"}));
+}
+
+TEST(ASTMatchersTest, AttributedStmt_hasSubStmt) {
+  StringRef Code = "int foo() { [[likely]] return 1; }";
+  EXPECT_TRUE(matchesConditionally(
+      Code, attributedStmt(hasSubStmt(returnStmt())), true, {"-std=c++20"}));
+  EXPECT_FALSE(matchesConditionally(Code, attributedStmt(hasSubStmt(ifStmt())),
+                                    true, {"-std=c++20"}));
+}
+
+TEST(ASTMatchersTest, AttributedStmt_multipleAttrs) {
+  StringRef Code = "int foo();\n int main() {\n  [[clang::nomerge]] [[likely]] "
+                   "return foo();\n }";
+  EXPECT_TRUE(matchesConditionally(Code, attributedStmt(hasAttr(attr::Likely)),
+                                   true, {"-std=c++20"}));
+  EXPECT_TRUE(matchesConditionally(Code, attributedStmt(hasAttr(attr::NoMerge)),
+                                   true, {"-std=c++20"}));
+}
+
 TEST(MatchFinderAPI, MatchesDynamic) {
   StringRef SourceCode = "struct A { void f() {} };";
   auto Matcher = functionDecl(isDefinition()).bind("method");
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -142,6 +142,7 @@
   REGISTER_MATCHER(atomicExpr);
   REGISTER_MATCHER(atomicType);
   REGISTER_MATCHER(attr);
+  REGISTER_MATCHER(attributedStmt);
   REGISTER_MATCHER(autoType);
   REGISTER_MATCHER(autoreleasePoolStmt)
   REGISTER_MATCHER(binaryConditionalOperator);
@@ -355,6 +356,7 @@
   REGISTER_MATCHER(hasSpecializedTemplate);
   REGISTER_MATCHER(hasStaticStorageDuration);
   REGISTER_MATCHER(hasStructuredBlock);
+  REGISTER_MATCHER(hasSubStmt);
   REGISTER_MATCHER(hasSyntacticForm);
   REGISTER_MATCHER(hasTargetDecl);
   REGISTER_MATCHER(hasTemplateArgument);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -981,6 +981,8 @@
     predefinedExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, DesignatedInitExpr>
     designatedInitExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, AttributedStmt>
+    attributedStmt;
 const internal::VariadicOperatorMatcherFunc<
     2, std::numeric_limits<unsigned>::max()>
     eachOf = {internal::DynTypedMatcher::VO_EachOf};
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -906,7 +906,6 @@
 }
 
 const AttrVec &Decl::getAttrs() const {
-  assert(HasAttrs && "No attrs to get!");
   return getASTContext().getDeclAttrs(this);
 }
 
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2699,6 +2699,40 @@
   return Node.size() == N;
 }
 
+/// Matches the attribute(s) attached to a Stmt
+///
+/// Given:
+/// \code
+///   constexpr double pow(double x, long long n) noexcept {
+///     if (n > 0) [[likely]]
+///          return x * pow(x, n - 1);
+///     else [[unlikely]]
+///          return 1;
+///   }
+/// \endcode
+/// attributedStmt() matches "[[likely]] return ...;" and
+/// "[[unlikely]] return 1;"
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, AttributedStmt>
+    attributedStmt;
+
+/// Matches the statement an attribute is attached to.
+///
+/// Example:
+/// \code
+///   attributedStmt(hasSubStmt(returnStmt()))
+/// \endcode
+/// would match "return 1;" here:
+/// \code
+///   else [[unlikely]]
+///     return 1;
+/// \endcode
+AST_MATCHER_P(AttributedStmt, hasSubStmt, internal::Matcher<Stmt>,
+              InnerMatcher) {
+  const Stmt *Statement = Node.getSubStmt();
+  return Statement != nullptr &&
+         InnerMatcher.matches(*Statement, Finder, Builder);
+}
+
 /// Matches \c QualTypes in the clang AST.
 extern const internal::VariadicAllOfMatcher<QualType> qualType;
 
@@ -7760,12 +7794,11 @@
 /// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
 /// f. If the matcher is used from clang-query, attr::Kind parameter should be
 /// passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
-AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
-  for (const auto *Attr : Node.attrs()) {
-    if (Attr->getKind() == AttrKind)
-      return true;
-  }
-  return false;
+AST_POLYMORPHIC_MATCHER_P(hasAttr,
+                          AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, AttributedStmt),
+                          attr::Kind, AttrKind) {
+  return llvm::any_of(Node.getAttrs(),
+                      [&](const Attr *A) { return A->getKind() == AttrKind; });
 }
 
 /// Matches the return value expression of a return statement
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -1283,6 +1283,21 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;</td><td class="name" onclick="toggle('attributedStmt0')"><a name="attributedStmt0Anchor">attributedStmt</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1AttributedStmt.html";>AttributedStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="attributedStmt0"><pre>Matches the attribute(s) attached to a Stmt
+
+Given:
+  constexpr double pow(double x, long long n) noexcept {
+    if (n &gt; 0) [[likely]]
+         return x * pow(x, n - 1);
+    else [[unlikely]]
+         return 1;
+  }
+attributedStmt() matches "[[likely]] return ...;" and
+"[[unlikely]] return 1;"
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;</td><td class="name" onclick="toggle('autoreleasePoolStmt0')"><a name="autoreleasePoolStmt0Anchor">autoreleasePoolStmt</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCAutoreleasePoolStmt.html";>ObjCAutoreleasePoolStmt</a>&gt;...</td></tr>
 <tr><td colspan="4" class="doc" id="autoreleasePoolStmt0"><pre>Matches an Objective-C autorelease pool statement.
 
@@ -2852,6 +2867,17 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1AttributedStmt.html";>AttributedStmt</a>&gt;</td><td class="name" onclick="toggle('hasAttr1')"><a name="hasAttr1Anchor">hasAttr</a></td><td>attr::Kind AttrKind</td></tr>
+<tr><td colspan="4" class="doc" id="hasAttr1"><pre>Matches declaration that has a given attribute.
+
+Given
+  __attribute__((device)) void f() { ... }
+decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+f. If the matcher is used from clang-query, attr::Kind parameter should be
+passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html";>Attr</a>&gt;</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).
@@ -6214,6 +6240,17 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1AttributedStmt.html";>AttributedStmt</a>&gt;</td><td class="name" onclick="toggle('hasSubStmt0')"><a name="hasSubStmt0Anchor">hasSubStmt</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSubStmt0"><pre>Matches the statement an attribute is attached to.
+
+Example:
+  attributedStmt(hasSubStmt(returnStmt()))
+would match "return 1;" here:
+  else [[unlikely]]
+    return 1;
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1AutoType.html";>AutoType</a>&gt;</td><td class="name" onclick="toggle('hasDeducedType0')"><a name="hasDeducedType0Anchor">hasDeducedType</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html";>Type</a>&gt;</td></tr>
 <tr><td colspan="4" class="doc" id="hasDeducedType0"><pre>Matches AutoType nodes where the deduced type is a specific type.
 
@@ -9799,5 +9836,3 @@
 </div>
 </body>
 </html>
-
-
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to