Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -1612,33 +1612,16 @@ -Matcher<Decl>hasCudaDeviceAttr -
Matches declaration that has CUDA device attribute.
+Matcher<Decl>hasAttrattr::Kind AttrKind
+
Matches declaration that has a given attribute.
 
 Given
   __attribute__((device)) void f() { ... }
-matches the function declaration of f.
+decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+f.
 
-Matcher<Decl>hasCudaGlobalAttr -
Matches declaration that has CUDA global attribute.
-
-Given
-  __attribute__((global)) void f() { ... }
-matches the function declaration of f.
-
- - -Matcher<Decl>hasCudaHostAttr -
Matches declaration that has CUDA host attribute.
-
-Given
-  __attribute__((host)) void f() { ... }
-matches the function declaration of f.
-
- - Matcher<Decl>isImplicit
Matches a declaration that has been implicitly added
 by the compiler (eg. implicit defaultcopy constructors).
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3658,48 +3658,31 @@
   return InnerMatcher.matches(*Node.getLHS(), Finder, Builder);
 }
 
-/// \brief Matches CUDA kernel call expression.
+/// \brief Matches declaration that has a given attribute.
 ///
-/// Example matches,
-/// \code
-///   kernel<<>>();
-/// \endcode
-const internal::VariadicDynCastAllOfMatcher
-    CUDAKernelCallExpr;
-
-/// \brief Matches declaration that has CUDA device attribute.
-///
 /// Given
 /// \code
 ///   __attribute__((device)) void f() { ... }
 /// \endcode
-/// matches the function declaration of f.
-AST_MATCHER(Decl, hasCudaDeviceAttr) {
-  return Node.hasAttr();
+/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+/// f.
+AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
+  for (auto Attr : Node.attrs()) {
+    if (Attr->getKind() == AttrKind)
+      return true;
+  }
+  return false;
 }
 
-/// \brief Matches declaration that has CUDA host attribute.
+/// \brief Matches CUDA kernel call expression.
 ///
-/// Given
+/// Example matches,
 /// \code
-///   __attribute__((host)) void f() { ... }
+///   kernel<<>>();
 /// \endcode
-/// matches the function declaration of f.
-AST_MATCHER(Decl, hasCudaHostAttr) {
-  return Node.hasAttr();
-}
+const internal::VariadicDynCastAllOfMatcher
+    CUDAKernelCallExpr;
 
-/// \brief  Matches declaration that has CUDA global attribute.
-///
-/// Given
-/// \code
-///   __attribute__((global)) void f() { ... }
-/// \endcode
-/// matches the function declaration of f.
-AST_MATCHER(Decl, hasCudaGlobalAttr) {
-  return Node.hasAttr();
-}
-
 } // end namespace ast_matchers
 } // end namespace clang
 
Index: include/clang/Basic/AttrKinds.h
===================================================================
--- include/clang/Basic/AttrKinds.h
+++ include/clang/Basic/AttrKinds.h
@@ -15,6 +15,8 @@
 #ifndef LLVM_CLANG_BASIC_ATTRKINDS_H
 #define LLVM_CLANG_BASIC_ATTRKINDS_H
 
+#include "llvm/ADT/StringSwitch.h"
+
 namespace clang {
 
 namespace attr {
@@ -28,6 +30,10 @@
   NUM_ATTRS
 };
 
+/// \brief Transforms a string of an attribute to corresponding attribute. Return
+/// attr::Kind(-1) if string does not correspond to a attribute.
+attr::Kind getAttrKind(llvm::StringRef AttrKind);
+
 } // end namespace attr
 } // end namespace clang
 
Index: lib/ASTMatchers/Dynamic/Marshallers.h
===================================================================
--- lib/ASTMatchers/Dynamic/Marshallers.h
+++ lib/ASTMatchers/Dynamic/Marshallers.h
@@ -76,6 +76,16 @@
   }
 };
 
+template <> struct ArgTypeTraits {
+  static bool is(const VariantValue &Value) { return Value.isString(); }
+  static attr::Kind get(const VariantValue &Value) {
+    return attr::getAttrKind(Value.getString());
+  }
+  static ArgKind getKind() {
+    return ArgKind(ArgKind::AK_String);
+  }
+};
+
 /// \brief Matcher descriptor interface.
 ///
 /// Provides a \c create() method that constructs the matcher from the provided
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -176,6 +176,7 @@
   REGISTER_MATCHER(hasAnyUsingShadowDecl);
   REGISTER_MATCHER(hasArgument);
   REGISTER_MATCHER(hasArgumentOfType);
+  REGISTER_MATCHER(hasAttr);
   REGISTER_MATCHER(hasBase);
   REGISTER_MATCHER(hasBody);
   REGISTER_MATCHER(hasCanonicalType);
@@ -182,9 +183,6 @@
   REGISTER_MATCHER(hasCaseConstant);
   REGISTER_MATCHER(hasCondition);
   REGISTER_MATCHER(hasConditionVariableStatement);
-  REGISTER_MATCHER(hasCudaDeviceAttr);
-  REGISTER_MATCHER(hasCudaGlobalAttr);
-  REGISTER_MATCHER(hasCudaHostAttr);
   REGISTER_MATCHER(hasDeclContext);
   REGISTER_MATCHER(hasDeclaration);
   REGISTER_MATCHER(hasDeducedType);
Index: lib/Basic/AttrKinds.cpp
===================================================================
--- lib/Basic/AttrKinds.cpp
+++ lib/Basic/AttrKinds.cpp
@@ -0,0 +1,17 @@
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/Basic/AttrKinds.h"
+
+namespace clang {
+namespace attr {
+Kind getAttrKind(llvm::StringRef AttrKind) {
+#define STR_HELPER(X) #X
+#define STR(X) STR_HELPER(X)
+#define ATTR(X) .Case("clang::attr::" STR(X), X)
+#define LAST_INHERITABLE_ATTR(X)
+#define LAST_INHERITABLE_PARAM_ATTR(X)
+  return llvm::StringSwitch(AttrKind)
+#include "clang/Basic/AttrList.inc"
+      .Default(Kind(-1));
+}
+}  // namespace attr
+}  // namespace clang
Index: lib/Basic/CMakeLists.txt
===================================================================
--- lib/Basic/CMakeLists.txt
+++ lib/Basic/CMakeLists.txt
@@ -4,6 +4,7 @@
   )
 
 add_clang_library(clangBasic
+  AttrKinds.cpp
   Attributes.cpp
   Builtins.cpp
   CharInfo.cpp
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -649,22 +649,23 @@
   EXPECT_TRUE(matches("void f() { int i; }", CannotMemoize));
 }
 
+TEST(DeclarationMatcher, HasAttr) {
+  EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};",
+                      decl(hasAttr(clang::attr::WarnUnused))));
+  EXPECT_FALSE(matches("struct X {};",
+                       decl(hasAttr(clang::attr::WarnUnused))));
+}
+
 TEST(DeclarationMatcher, MatchCudaDecl) {
   EXPECT_TRUE(matchesWithCuda("__global__ void f() { }"
                               "void g() { f<<<1, 2>>>(); }",
                               CUDAKernelCallExpr()));
   EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
-                              hasCudaDeviceAttr()));
-  EXPECT_TRUE(matchesWithCuda("__attribute__((host)) void f() {}",
-                              hasCudaHostAttr()));
-  EXPECT_TRUE(matchesWithCuda("__attribute__((global)) void f() {}",
-                              hasCudaGlobalAttr()));
-  EXPECT_FALSE(matchesWithCuda("void f() {}",
-                               hasCudaGlobalAttr()));
+                              hasAttr(clang::attr::CUDADevice)));
   EXPECT_TRUE(notMatchesWithCuda("void f() {}",
-                                 hasCudaGlobalAttr()));
+                                 CUDAKernelCallExpr()));
   EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
-                                  hasCudaGlobalAttr()));
+                                  hasAttr(clang::attr::CUDAGlobal)));
 }
 
 // Implements a run method that returns whether BoundNodes contains a
Index: unittests/ASTMatchers/Dynamic/RegistryTest.cpp
===================================================================
--- unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -472,6 +472,14 @@
                             "Matcher hasName(string)"));
 }
 
+TEST_F(RegistryTest, HasArgs) {
+  Matcher Value = constructMatcher(
+      "decl", constructMatcher("hasAttr", std::string("clang::attr::WarnUnused")))
+      .getTypedMatcher();
+  EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
+  EXPECT_FALSE(matches("struct X {};", Value));
+}
+
 } // end anonymous namespace
 } // end namespace dynamic
 } // end namespace ast_matchers