Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -410,7 +410,7 @@ Given typedef int X; - using Y = int; + using Y = int; typeAliasDecl() matches "using Y = int", but not "typedef int X" @@ -421,7 +421,7 @@ Given typedef int X; - using Y = int; + using Y = int; typedefDecl() matches "typedef int X", but not "using Y = int" @@ -432,7 +432,7 @@ Given typedef int X; - using Y = int; + using Y = int; typedefNameDecl() matches "typedef int X" and "using Y = int" @@ -2156,6 +2156,15 @@ +Matcher<CastExpr>hasCastKindCastKind Kind +
Matches casts that has a given cast kind.
+
+Example: matches the implicit cast around 0
+(matcher = castExpr(hasCastKind(CK_NullToPointer)))
+  int *p = 0;
+
+ + Matcher<CharacterLiteral>equalsValueT Value
Matches literals that are equal to the given value.
 
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3548,6 +3548,17 @@
           InnerMatcher.matches(*SubExpression, Finder, Builder));
 }
 
+/// \brief Matches casts that has a given cast kind.
+///
+/// Example: matches the implicit cast around \c 0
+/// (matcher = castExpr(hasCastKind(CK_NullToPointer)))
+/// \code
+///   int *p = 0;
+/// \endcode
+AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) {
+  return Node.getCastKind() == Kind;
+}
+
 /// \brief Matches casts whose destination type matches a given matcher.
 ///
 /// (Note: Clang's AST refers to other conversions as "casts" too, and calls
Index: lib/ASTMatchers/Dynamic/Marshallers.h
===================================================================
--- lib/ASTMatchers/Dynamic/Marshallers.h
+++ lib/ASTMatchers/Dynamic/Marshallers.h
@@ -96,6 +96,85 @@
   }
 };
 
+template <> struct ArgTypeTraits {
+private:
+  static clang::CastKind getCastKind(llvm::StringRef AttrKind) {
+    return llvm::StringSwitch(AttrKind)
+      .Case("CK_Dependent", CK_Dependent)
+      .Case("CK_BitCast", CK_BitCast)
+      .Case("CK_LValueBitCast", CK_LValueBitCast)
+      .Case("CK_LValueToRValue", CK_LValueToRValue)
+      .Case("CK_NoOp", CK_NoOp)
+      .Case("CK_BaseToDerived", CK_BaseToDerived)
+      .Case("CK_DerivedToBase", CK_DerivedToBase)
+      .Case("CK_UncheckedDerivedToBase", CK_UncheckedDerivedToBase)
+      .Case("CK_Dynamic", CK_Dynamic)
+      .Case("CK_ToUnion", CK_ToUnion)
+      .Case("CK_ArrayToPointerDecay", CK_ArrayToPointerDecay)
+      .Case("CK_FunctionToPointerDecay", CK_FunctionToPointerDecay)
+      .Case("CK_NullToMemberPointer", CK_NullToMemberPointer)
+      .Case("CK_NullToPointer", CK_NullToPointer)
+      .Case("CK_BaseToDerivedMemberPointer", CK_BaseToDerivedMemberPointer)
+      .Case("CK_DerivedToBaseMemberPointer", CK_DerivedToBaseMemberPointer)
+      .Case("CK_ReinterpretMemberPointer", CK_ReinterpretMemberPointer)
+      .Case("CK_UserDefinedConversion", CK_UserDefinedConversion)
+      .Case("CK_ConstructorConversion", CK_ConstructorConversion)
+      .Case("CK_IntegralToPointer", CK_IntegralToPointer)
+      .Case("CK_PointerToIntegral", CK_PointerToIntegral)
+      .Case("CK_PointerToBoolean", CK_PointerToBoolean)
+      .Case("CK_ToVoid", CK_ToVoid)
+      .Case("CK_VectorSplat", CK_VectorSplat)
+      .Case("CK_IntegralCast", CK_IntegralCast)
+      .Case("CK_BooleanToSignedIntegral", CK_BooleanToSignedIntegral)
+      .Case("CK_IntegralToBoolean", CK_IntegralToBoolean)
+      .Case("CK_IntegralToFloating", CK_IntegralToFloating)
+      .Case("CK_FloatingToIntegral", CK_FloatingToIntegral)
+      .Case("CK_FloatingCast", CK_FloatingCast)
+      .Case("CK_FloatingToBoolean", CK_FloatingToBoolean)
+      .Case("CK_MemberPointerToBoolean", CK_MemberPointerToBoolean)
+      .Case("CK_CPointerToObjCPointerCast", CK_CPointerToObjCPointerCast)
+      .Case("CK_BlockPointerToObjCPointerCast",
+             CK_BlockPointerToObjCPointerCast)
+      .Case("CK_AnyPointerToBlockPointerCast", CK_AnyPointerToBlockPointerCast)
+      .Case("CK_ObjCObjectLValueCast", CK_ObjCObjectLValueCast)
+      .Case("CK_FloatingRealToComplex", CK_FloatingRealToComplex)
+      .Case("CK_FloatingComplexToReal", CK_FloatingComplexToReal)
+      .Case("CK_FloatingComplexToBoolean", CK_FloatingComplexToBoolean)
+      .Case("CK_FloatingComplexCast", CK_FloatingComplexCast)
+      .Case("CK_FloatingComplexToIntegralComplex",
+             CK_FloatingComplexToIntegralComplex)
+      .Case("CK_IntegralRealToComplex", CK_IntegralRealToComplex)
+      .Case("CK_IntegralComplexToReal", CK_IntegralComplexToReal)
+      .Case("CK_IntegralComplexToBoolean", CK_IntegralComplexToBoolean)
+      .Case("CK_IntegralComplexCast", CK_IntegralComplexCast)
+      .Case("CK_IntegralComplexToFloatingComplex",
+            CK_IntegralComplexToFloatingComplex)
+      .Case("CK_ARCConsumeObject", CK_ARCConsumeObject)
+      .Case("CK_ARCProduceObject", CK_ARCProduceObject)
+      .Case("CK_ARCReclaimReturnedObject", CK_ARCReclaimReturnedObject)
+      .Case("CK_ARCExtendBlockObject", CK_ARCExtendBlockObject)
+      .Case("CK_AtomicToNonAtomic", CK_AtomicToNonAtomic)
+      .Case("CK_NonAtomicToAtomic", CK_NonAtomicToAtomic)
+      .Case("CK_CopyAndAutoreleaseBlockObject",
+            CK_CopyAndAutoreleaseBlockObject)
+      .Case("CK_BuiltinFnToFnPtr", CK_BuiltinFnToFnPtr)
+      .Case("CK_ZeroToOCLEvent", CK_ZeroToOCLEvent)
+      .Case("CK_AddressSpaceConversion", CK_AddressSpaceConversion)
+      .Default(clang::CastKind(-1));
+  }
+public:
+  static bool is(const VariantValue &Value) {
+    return Value.isString() &&
+        getCastKind(Value.getString()) != clang::CastKind(-1);
+  }
+  static clang::CastKind get(const VariantValue &Value) {
+    return getCastKind(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
@@ -209,6 +209,7 @@
   REGISTER_MATCHER(hasBody);
   REGISTER_MATCHER(hasCanonicalType);
   REGISTER_MATCHER(hasCaseConstant);
+  REGISTER_MATCHER(hasCastKind);
   REGISTER_MATCHER(hasCondition);
   REGISTER_MATCHER(hasConditionVariableStatement);
   REGISTER_MATCHER(hasDecayedType);
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3475,6 +3475,13 @@
   EXPECT_TRUE(notMatches("int i = 0;", castExpr()));
 }
 
+TEST(CastExpression, HasCastKind) {
+  EXPECT_TRUE(matches("char *p = 0;",
+              castExpr(hasCastKind(CK_NullToPointer))));
+  EXPECT_TRUE(notMatches("char *p = 0;",
+              castExpr(hasCastKind(CK_DerivedToBase))));
+}
+
 TEST(ReinterpretCast, MatchesSimpleCase) {
   EXPECT_TRUE(matches("char* p = reinterpret_cast(&p);",
                       cxxReinterpretCastExpr()));