[cfe-commits] r166094 - in /cfe/trunk: include/clang/ASTMatchers/ASTMatchFinder.h include/clang/ASTMatchers/ASTMatchers.h include/clang/ASTMatchers/ASTMatchersInternal.h include/clang/ASTMatchers/ASTMatchersMacros.h include/clang/ASTMatchers/ASTTypeTraits.h lib/ASTMatchers/ASTMatchFinder.cpp unittests/ASTMatchers/ASTMatchersTest.cpp
Daniel Jasper
djasper at google.com
Wed Oct 17 01:52:59 PDT 2012
Author: djasper
Date: Wed Oct 17 03:52:59 2012
New Revision: 166094
URL: http://llvm.org/viewvc/llvm-project?rev=166094&view=rev
Log:
First version of matchers for Types and TypeLocs.
Review: http://llvm-reviews.chandlerc.com/D47
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h Wed Oct 17 03:52:59 2012
@@ -116,6 +116,8 @@
MatchCallback *Action);
void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
MatchCallback *Action);
+ void addMatcher(const TypeLocMatcher &NodeMatch,
+ MatchCallback *Action);
/// @}
/// \brief Creates a clang ASTConsumer that finds all matches.
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed Oct 17 03:52:59 2012
@@ -108,8 +108,9 @@
/// hierarchy.
/// @{
typedef internal::Matcher<Decl> DeclarationMatcher;
-typedef internal::Matcher<QualType> TypeMatcher;
typedef internal::Matcher<Stmt> StatementMatcher;
+typedef internal::Matcher<QualType> TypeMatcher;
+typedef internal::Matcher<TypeLoc> TypeLocMatcher;
typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher;
typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
/// @}
@@ -2438,6 +2439,282 @@
internal::IsExplicitTemplateSpecializationMatcher>();
}
+/// \brief Matches \c QualTypes in the clang AST.
+const internal::VariadicAllOfMatcher<QualType> qualType;
+
+/// \brief Matches \c Types in the clang AST.
+const internal::VariadicDynCastAllOfMatcher<Type, Type> type;
+
+/// \brief Matches \c TypeLocs in the clang AST.
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc;
+
+/// \brief Matches \c TypeLocs for which the given inner
+/// QualType-matcher matches.
+inline internal::BindableMatcher<TypeLoc> loc(
+ const internal::Matcher<QualType> &InnerMatcher) {
+ return internal::BindableMatcher<TypeLoc>(
+ new internal::TypeLocTypeMatcher(InnerMatcher));
+}
+
+/// \brief Matches builtin Types.
+///
+/// Given
+/// \code
+/// struct A {};
+/// A a;
+/// int b;
+/// float c;
+/// bool d;
+/// \endcode
+/// builtinType()
+/// matches "int b", "float c" and "bool d"
+AST_TYPE_MATCHER(BuiltinType, builtinType);
+
+/// \brief Matches all kinds of arrays.
+///
+/// Given
+/// \code
+/// int a[] = { 2, 3 };
+/// int b[4];
+/// void f() { int c[a[0]]; }
+/// \endcode
+/// arrayType()
+/// matches "int a[]", "int b[4]" and "int c[a[0]]";
+AST_TYPE_MATCHER(ArrayType, arrayType);
+
+/// \brief Matches C99 complex types.
+///
+/// Given
+/// \code
+/// _Complex float f;
+/// \endcode
+/// complexType()
+/// matches "_Complex float f"
+AST_TYPE_MATCHER(ComplexType, complexType);
+
+/// \brief Matches arrays and C99 complex types that have a specific element
+/// type.
+///
+/// Given
+/// \code
+/// struct A {};
+/// A a[7];
+/// int b[7];
+/// \endcode
+/// arrayType(hasElementType(builtinType()))
+/// matches "int b[7]"
+///
+/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
+AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement);
+
+/// \brief Matches C arrays with a specified constant size.
+///
+/// Given
+/// \code
+/// void() {
+/// int a[2];
+/// int b[] = { 2, 3 };
+/// int c[b[0]];
+/// }
+/// \endcode
+/// constantArrayType()
+/// matches "int a[2]"
+AST_TYPE_MATCHER(ConstantArrayType, constantArrayType);
+
+/// \brief Matches \c ConstantArrayType nodes that have the specified size.
+///
+/// Given
+/// \code
+/// int a[42];
+/// int b[2 * 21];
+/// int c[41], d[43];
+/// \endcode
+/// constantArrayType(hasSize(42))
+/// matches "int a[42]" and "int b[2 * 21]"
+AST_MATCHER_P(ConstantArrayType, hasSize, unsigned, N) {
+ return Node.getSize() == N;
+}
+
+/// \brief Matches C++ arrays whose size is a value-dependent expression.
+///
+/// Given
+/// \code
+/// template<typename T, int Size>
+/// class array {
+/// T data[Size];
+/// };
+/// \endcode
+/// dependentSizedArrayType
+/// matches "T data[Size]"
+AST_TYPE_MATCHER(DependentSizedArrayType, dependentSizedArrayType);
+
+/// \brief Matches C arrays with unspecified size.
+///
+/// Given
+/// \code
+/// int a[] = { 2, 3 };
+/// int b[42];
+/// void f(int c[]) { int d[a[0]]; };
+/// \endcode
+/// incompleteArrayType()
+/// matches "int a[]" and "int c[]"
+AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType);
+
+/// \brief Matches C arrays with a specified size that is not an
+/// integer-constant-expression.
+///
+/// Given
+/// \code
+/// void f() {
+/// int a[] = { 2, 3 }
+/// int b[42];
+/// int c[a[0]];
+/// \endcode
+/// variableArrayType()
+/// matches "int c[a[0]]"
+AST_TYPE_MATCHER(VariableArrayType, variableArrayType);
+
+/// \brief Matches \c VariableArrayType nodes that have a specific size
+/// expression.
+///
+/// Given
+/// \code
+/// void f(int b) {
+/// int a[b];
+/// }
+/// \endcode
+/// variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+/// varDecl(hasName("b")))))))
+/// matches "int a[b]"
+AST_MATCHER_P(VariableArrayType, hasSizeExpr,
+ internal::Matcher<Expr>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getSizeExpr(), Finder, Builder);
+}
+
+/// \brief Matches atomic types.
+///
+/// Given
+/// \code
+/// _Atomic(int) i;
+/// \endcode
+/// atomicType()
+/// matches "_Atomic(int) i"
+AST_TYPE_MATCHER(AtomicType, atomicType);
+
+/// \brief Matches atomic types with a specific value type.
+///
+/// Given
+/// \code
+/// _Atomic(int) i;
+/// _Atomic(float) f;
+/// \endcode
+/// atomicType(hasValueType(isInteger()))
+/// matches "_Atomic(int) i"
+///
+/// Usable as: Matcher<AtomicType>
+AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue);
+
+/// \brief Matches types nodes representing C++11 auto types.
+///
+/// Given:
+/// \code
+/// auto n = 4;
+/// int v[] = { 2, 3 }
+/// for (auto i : v) { }
+/// \endcode
+/// autoType()
+/// matches "auto n" and "auto i"
+AST_TYPE_MATCHER(AutoType, autoType);
+
+/// \brief Matches \c AutoType nodes where the deduced type is a specific type.
+///
+/// Note: There is no \c TypeLoc for the deduced type and thus no
+/// \c getDeducedLoc() matcher.
+///
+/// Given
+/// \code
+/// auto a = 1;
+/// auto b = 2.0;
+/// \endcode
+/// autoType(hasDeducedType(isInteger()))
+/// matches "auto a"
+///
+/// Usable as: Matcher<AutoType>
+AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
+
+/// \brief Matches block pointer types, i.e. types syntactically represented as
+/// "void (^)(int)".
+///
+/// The \c pointee is always required to be a \c FunctionType.
+AST_TYPE_MATCHER(BlockPointerType, blockPointerType);
+
+/// \brief Matches member pointer types.
+/// Given
+/// \code
+/// struct A { int i; }
+/// A::* ptr = A::i;
+/// \endcode
+/// memberPointerType()
+/// matches "A::* ptr"
+AST_TYPE_MATCHER(MemberPointerType, memberPointerType);
+
+/// \brief Matches pointer types.
+///
+/// Given
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int c = 5;
+/// \endcode
+/// pointerType()
+/// matches "int *a"
+AST_TYPE_MATCHER(PointerType, pointerType);
+
+/// \brief Matches reference types.
+///
+/// Given
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int c = 5;
+/// \endcode
+/// pointerType()
+/// matches "int &b"
+AST_TYPE_MATCHER(ReferenceType, referenceType);
+
+/// \brief Narrows PointerType (and similar) matchers to those where the
+/// \c pointee matches a given matcher.
+///
+/// Given
+/// \code
+/// int *a;
+/// int const *b;
+/// float const *f;
+/// \endcode
+/// pointerType(pointee(isConstQualified(), isInteger()))
+/// matches "int const *b"
+///
+/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
+/// Matcher<PointerType>, Matcher<ReferenceType>
+AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
+
+/// \brief Matches typedef types.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// \endcode
+/// typedefType()
+/// matches "typedef int X"
+AST_TYPE_MATCHER(TypedefType, typedefType);
+
+/// \brief Matches \c TypedefTypes referring to a specific
+/// \c TypedefNameDecl.
+AST_MATCHER_P(TypedefType, hasDecl,
+ internal::Matcher<TypedefNameDecl>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getDecl(), Finder, Builder);
+}
+
/// \brief Matches nested name specifiers.
///
/// Given
@@ -2468,8 +2745,6 @@
/// \brief Matches nested name specifiers that specify a type matching the
/// given \c QualType matcher without qualifiers.
-/// FIXME: This is a temporary solution. Switch to using Type-matchers as soon
-/// as we have those.
///
/// Given
/// \code
@@ -2485,8 +2760,23 @@
return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder);
}
-/// \brief Matches on the prefix of a \c NestedNameSpecifier or
-/// \c NestedNameSpecifierLoc.
+/// \brief Matches nested name specifier locs that specify a type matching the
+/// given \c TypeLoc.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
+/// nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
+/// hasDeclaration(recordDecl(hasName("A")))))))
+/// matches "A::"
+AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
+ internal::Matcher<TypeLoc>, InnerMatcher) {
+ return InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
+}
+
+/// \brief Matches on the prefix of a \c NestedNameSpecifier.
///
/// Given
/// \code
@@ -2494,9 +2784,27 @@
/// A::B::C c;
/// \endcode
/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
+/// matches "A::"
+inline internal::Matcher<NestedNameSpecifier> hasPrefix(
+ const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
+ return internal::makeMatcher(
+ new internal::NestedNameSpecifierPrefixMatcher(InnerMatcher));
+}
+
+/// \brief Matches on the prefix of a \c NestedNameSpecifierLoc.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
-/// both match "A::"
-LOC_TRAVERSE_MATCHER(hasPrefix, NestedNameSpecifier, getPrefix)
+/// matches "A::"
+inline internal::Matcher<NestedNameSpecifierLoc> hasPrefix(
+ const internal::Matcher<NestedNameSpecifierLoc> &InnerMatcher) {
+ return internal::makeMatcher(
+ new internal::NestedNameSpecifierLocPrefixMatcher(InnerMatcher));
+}
/// \brief Matches nested name specifiers that specify a namespace matching the
/// given namespace matcher.
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Wed Oct 17 03:52:59 2012
@@ -268,6 +268,16 @@
!llvm::is_same<From, T>::value >::type* = 0)
: Implementation(new ImplicitCastMatcher<From>(Other)) {}
+ /// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
+ ///
+ /// The resulting matcher is not strict, i.e. ignores qualifiers.
+ template <typename TypeT>
+ Matcher(const Matcher<TypeT> &Other,
+ typename llvm::enable_if_c<
+ llvm::is_same<T, QualType>::value &&
+ llvm::is_same<TypeT, Type>::value >::type* = 0)
+ : Implementation(new TypeToQualType<TypeT>(Other)) {}
+
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
@@ -291,6 +301,29 @@
return matches(*Node, Finder, Builder);
}
+ /// \brief Allows the conversion of a \c Matcher<Type> to a \c
+ /// Matcher<QualType>.
+ ///
+ /// Depending on the constructor argument, the matcher is either strict, i.e.
+ /// does only matches in the absence of qualifiers, or not, i.e. simply
+ /// ignores any qualifiers.
+ template <typename TypeT>
+ class TypeToQualType : public MatcherInterface<QualType> {
+ public:
+ TypeToQualType(const Matcher<TypeT> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const QualType &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (Node.isNull())
+ return false;
+ return InnerMatcher.matches(*Node, Finder, Builder);
+ }
+ private:
+ const Matcher<TypeT> InnerMatcher;
+ };
+
private:
/// \brief Allows conversion from Matcher<Base> to Matcher<T> if T
/// is derived from Base.
@@ -950,7 +983,6 @@
}
};
-
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
public:
virtual bool matchesNode(const MemberExpr &Node) const {
@@ -1011,7 +1043,7 @@
class LocMatcher : public MatcherInterface<TLoc> {
public:
explicit LocMatcher(const Matcher<T> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
+ : InnerMatcher(InnerMatcher) {}
virtual bool matches(const TLoc &Node,
ASTMatchFinder *Finder,
@@ -1025,61 +1057,128 @@
const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
return Loc.getNestedNameSpecifier();
}
- // FIXME: Add overload for TypeLoc when implementing TypeLoc-matchers.
const Matcher<T> InnerMatcher;
};
+/// \brief Matches \c NestedNameSpecifiers with a prefix matching another
+/// \c Matcher<NestedNameSpecifier>.
+class NestedNameSpecifierPrefixMatcher
+ : public MatcherInterface<NestedNameSpecifier> {
+public:
+ explicit NestedNameSpecifierPrefixMatcher(
+ const Matcher<NestedNameSpecifier> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const NestedNameSpecifier &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ NestedNameSpecifier *NextNode = Node.getPrefix();
+ if (NextNode == NULL)
+ return false;
+ return InnerMatcher.matches(*NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<NestedNameSpecifier> InnerMatcher;
+};
+
+/// \brief Matches \c NestedNameSpecifierLocs with a prefix matching another
+/// \c Matcher<NestedNameSpecifierLoc>.
+class NestedNameSpecifierLocPrefixMatcher
+ : public MatcherInterface<NestedNameSpecifierLoc> {
+public:
+ explicit NestedNameSpecifierLocPrefixMatcher(
+ const Matcher<NestedNameSpecifierLoc> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const NestedNameSpecifierLoc &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ NestedNameSpecifierLoc NextNode = Node.getPrefix();
+ if (!NextNode)
+ return false;
+ return InnerMatcher.matches(NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<NestedNameSpecifierLoc> InnerMatcher;
+};
+
+/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
+/// \c QualType.
+///
+/// Used to implement the \c loc() matcher.
+class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
+public:
+ explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const TypeLoc &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (!Node)
+ return false;
+ return InnerMatcher.matches(Node.getType(), Finder, Builder);
+ }
+
+private:
+ const Matcher<QualType> InnerMatcher;
+};
+
/// \brief Matches nodes of type \c T for which the inner matcher matches on a
/// another node of type \c T that can be reached using a given traverse
/// function.
template <typename T>
-class TraverseMatcher : public MatcherInterface<T> {
+class TypeTraverseMatcher : public MatcherInterface<T> {
public:
- explicit TraverseMatcher(const Matcher<T> &InnerMatcher,
- T *(T::*TraverseFunction)() const)
+ explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher,
+ QualType (T::*TraverseFunction)() const)
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- T* NextNode = (Node.*TraverseFunction)();
- if (NextNode == NULL)
+ QualType NextNode = (Node.*TraverseFunction)();
+ if (NextNode.isNull())
return false;
- return InnerMatcher.matches(*NextNode, Finder, Builder);
+ return InnerMatcher.matches(NextNode, Finder, Builder);
}
private:
- const Matcher<T> InnerMatcher;
- T *(T::*TraverseFunction)() const;
+ const Matcher<QualType> InnerMatcher;
+ QualType (T::*TraverseFunction)() const;
};
/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner
/// matcher matches on a another node of type \c T that can be reached using a
/// given traverse function.
template <typename T>
-class LocTraverseMatcher : public MatcherInterface<T> {
+class TypeLocTraverseMatcher : public MatcherInterface<T> {
public:
- explicit LocTraverseMatcher(const Matcher<T> &InnerMatcher,
- T (T::*TraverseFunction)() const)
+ explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher,
+ TypeLoc (T::*TraverseFunction)() const)
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- if (!Node)
- return false;
- T NextNode = (Node.*TraverseFunction)();
+ TypeLoc NextNode = (Node.*TraverseFunction)();
if (!NextNode)
return false;
return InnerMatcher.matches(NextNode, Finder, Builder);
}
private:
- const Matcher<T> InnerMatcher;
- T (T::*TraverseFunction)() const;
+ const Matcher<TypeLoc> InnerMatcher;
+ TypeLoc (T::*TraverseFunction)() const;
};
+template <typename T, typename InnerT>
+T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
+ return T(makeAllOfComposite<InnerT>(InnerMatchers));
+}
+
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h Wed Oct 17 03:52:59 2012
@@ -221,23 +221,69 @@
const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
-/// \brief LOC_TRAVERSE_MATCHER(MatcherName, NodeType, FunctionName)
-/// defines the matcher \c MatcherName that can be used to traverse
-/// a Type or NestedNameSpecifier as well as the corresponding ..Loc.
+/// \brief Creates a variadic matcher for both a specific \c Type as well as
+/// the corresponding \c TypeLoc.
+#define AST_TYPE_MATCHER(NodeType, MatcherName) \
+ const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName; \
+ const internal::VariadicDynCastAllOfMatcher<TypeLoc, \
+ NodeType##Loc> MatcherName##Loc
+
+/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
+/// the matcher \c MatcherName that can be used to traverse from one \c Type
+/// to another.
///
-/// The traversal is done using the given \c FunctionName.
-#define LOC_TRAVERSE_MATCHER( \
- MatcherName, NodeType, FunctionName) \
- inline internal::Matcher<NodeType> hasPrefix( \
- const internal::Matcher<NodeType> &InnerMatcher) { \
- return internal::makeMatcher(new internal::TraverseMatcher<NodeType>( \
- InnerMatcher, &NodeType::getPrefix)); \
+/// For a specific \c SpecificType, the traversal is done using
+/// \c SpecificType::FunctionName. The existance of such a function determines
+/// whether a corresponding matcher can be used on \c SpecificType.
+#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \
+class Polymorphic##MatcherName##TypeMatcher { \
+public: \
+ Polymorphic##MatcherName##TypeMatcher( \
+ const internal::Matcher<QualType> &InnerMatcher) \
+ : InnerMatcher(InnerMatcher) {} \
+ template <typename T> operator internal::Matcher<T>() { \
+ return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
+ InnerMatcher, &T::FunctionName)); \
+ } \
+private: \
+ const internal::Matcher<QualType> InnerMatcher; \
+}; \
+class Variadic##MatcherName##TypeTraverseMatcher \
+ : public llvm::VariadicFunction< \
+ Polymorphic##MatcherName##TypeMatcher, \
+ internal::Matcher<QualType>, \
+ internal::makeTypeAllOfComposite< \
+ Polymorphic##MatcherName##TypeMatcher, QualType> > { \
+public: \
+ Variadic##MatcherName##TypeTraverseMatcher() {} \
+}; \
+const Variadic##MatcherName##TypeTraverseMatcher MatcherName
+
+/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
+/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
+#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \
+class Polymorphic##MatcherName##TypeLocMatcher { \
+public: \
+ Polymorphic##MatcherName##TypeLocMatcher( \
+ const internal::Matcher<TypeLoc> &InnerMatcher) \
+ : InnerMatcher(InnerMatcher) {} \
+ template <typename T> operator internal::Matcher<T>() { \
+ return internal::Matcher<T>(new internal::TypeLocTraverseMatcher<T>( \
+ InnerMatcher, &T::FunctionName##Loc)); \
} \
- inline internal::Matcher<NodeType##Loc> hasPrefix( \
- const internal::Matcher<NodeType##Loc> &InnerMatcher) { \
- return internal::makeMatcher( \
- new internal::LocTraverseMatcher<NodeType##Loc>( \
- InnerMatcher, &NodeType##Loc::getPrefix)); \
- }
+private: \
+ const internal::Matcher<TypeLoc> InnerMatcher; \
+}; \
+class Variadic##MatcherName##TypeLocTraverseMatcher \
+ : public llvm::VariadicFunction< \
+ Polymorphic##MatcherName##TypeLocMatcher, \
+ internal::Matcher<TypeLoc>, \
+ internal::makeTypeAllOfComposite< \
+ Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
+public: \
+ Variadic##MatcherName##TypeLocTraverseMatcher() {} \
+}; \
+const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
+AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
Modified: cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h Wed Oct 17 03:52:59 2012
@@ -74,9 +74,11 @@
enum NodeTypeTag {
NT_Decl,
NT_Stmt,
+ NT_Type,
NT_NestedNameSpecifier,
NT_NestedNameSpecifierLoc,
- NT_QualType
+ NT_QualType,
+ NT_TypeLoc
} Tag;
/// \brief Stores the data of the node.
@@ -85,8 +87,11 @@
/// guaranteed to be unique pointers pointing to dedicated storage in the
/// AST. \c QualTypes on the other hand do not have storage or unique
/// pointers and thus need to be stored by value.
- llvm::AlignedCharArrayUnion<Decl*, Stmt*, NestedNameSpecifierLoc, QualType> Storage;
+ llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
+ Storage;
};
+
+// FIXME: Pull out abstraction for the following.
template<typename T> struct DynTypedNode::BaseConverter<T,
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
static const T *get(NodeTypeTag Tag, const char Storage[]) {
@@ -115,6 +120,20 @@
return Result;
}
};
+template<typename T> struct DynTypedNode::BaseConverter<T,
+ typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
+ static const T *get(NodeTypeTag Tag, const char Storage[]) {
+ if (Tag == NT_Type)
+ return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
+ return NULL;
+ }
+ static DynTypedNode create(const Type &Node) {
+ DynTypedNode Result;
+ Result.Tag = NT_Type;
+ new (Result.Storage.buffer) const Type*(&Node);
+ return Result;
+ }
+};
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_NestedNameSpecifier)
@@ -155,6 +174,19 @@
return Result;
}
};
+template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
+ static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
+ if (Tag == NT_TypeLoc)
+ return reinterpret_cast<const TypeLoc*>(Storage);
+ return NULL;
+ }
+ static DynTypedNode create(const TypeLoc &Node) {
+ DynTypedNode Result;
+ Result.Tag = NT_TypeLoc;
+ new (Result.Storage.buffer) TypeLoc(Node);
+ return Result;
+ }
+};
// The only operation we allow on unsupported types is \c get.
// This allows to conveniently use \c DynTypedNode when having an arbitrary
// AST node that is not supported, but prevents misuse - a user cannot create
Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Wed Oct 17 03:52:59 2012
@@ -553,10 +553,15 @@
return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
}
-bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) {
- match(TypeLoc.getType());
- return RecursiveASTVisitor<MatchASTVisitor>::
- TraverseTypeLoc(TypeLoc);
+bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
+ // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
+ // We still want to find those types via matchers, so we match them here. Note
+ // that the TypeLocs are structurally a shadow-hierarchy to the expressed
+ // type, so we visit all involved parts of a compound type when matching on
+ // each TypeLoc.
+ match(TypeLocNode);
+ match(TypeLocNode.getType());
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
}
bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
@@ -649,6 +654,12 @@
new NestedNameSpecifierLocMatcher(NodeMatch), Action));
}
+void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new TypeLocMatcher(NodeMatch), Action));
+}
+
ASTConsumer *MatchFinder::newASTConsumer() {
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
}
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=166094&r1=166093&r2=166094&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Wed Oct 17 03:52:59 2012
@@ -2884,6 +2884,185 @@
hasAncestor(recordDecl(hasName("A")))))))));
}
+TEST(TypeMatching, MatchesTypes) {
+ EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
+}
+
+TEST(TypeMatching, MatchesArrayTypes) {
+ EXPECT_TRUE(matches("int a[] = {2,3};", arrayType()));
+ EXPECT_TRUE(matches("int a[42];", arrayType()));
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", arrayType()));
+
+ EXPECT_TRUE(notMatches("struct A {}; A a[7];",
+ arrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "typedef const int T; T x[] = { 1, 2 };",
+ qualType(isConstQualified(), arrayType())));
+
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(isConstQualified(), builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())),
+ unless(isConstQualified()))));
+
+ EXPECT_TRUE(matches("int a[2];",
+ constantArrayType(hasElementType(builtinType()))));
+ EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger())));
+}
+
+TEST(TypeMatching, MatchesComplexTypes) {
+ EXPECT_TRUE(matches("_Complex float f;", complexType()));
+ EXPECT_TRUE(matches(
+ "_Complex float f;",
+ complexType(hasElementType(builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "_Complex float f;",
+ complexType(hasElementType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesConstantArrayTypes) {
+ EXPECT_TRUE(matches("int a[2];", constantArrayType()));
+ EXPECT_TRUE(notMatches(
+ "void f() { int a[] = { 2, 3 }; int b[a[0]]; }",
+ constantArrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches("int a[42];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(matches("int b[2*21];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42))));
+}
+
+TEST(TypeMatching, MatchesDependentSizedArrayTypes) {
+ EXPECT_TRUE(matches(
+ "template <typename T, int Size> class array { T data[Size]; };",
+ dependentSizedArrayType()));
+ EXPECT_TRUE(notMatches(
+ "int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedArrayType()));
+}
+
+TEST(TypeMatching, MatchesIncompleteArrayType) {
+ EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
+ EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
+
+ EXPECT_TRUE(notMatches("int a[42]; void f() { int b[a[0]]; }",
+ incompleteArrayType()));
+}
+
+TEST(TypeMatching, MatchesVariableArrayType) {
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType()));
+ EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType()));
+
+ EXPECT_TRUE(matches(
+ "void f(int b) { int a[b]; }",
+ variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+ varDecl(hasName("b")))))))));
+}
+
+TEST(TypeMatching, MatchesAtomicTypes) {
+ EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
+
+ EXPECT_TRUE(matches("_Atomic(int) i;",
+ atomicType(hasValueType(isInteger()))));
+ EXPECT_TRUE(notMatches("_Atomic(float) f;",
+ atomicType(hasValueType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesAutoTypes) {
+ EXPECT_TRUE(matches("auto i = 2;", autoType()));
+ EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
+ autoType()));
+
+ EXPECT_TRUE(matches("auto a = 1;",
+ autoType(hasDeducedType(isInteger()))));
+ EXPECT_TRUE(notMatches("auto b = 2.0;",
+ autoType(hasDeducedType(isInteger()))));
+}
+
+TEST(TypeMatching, PointerTypes) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "int* a;",
+ pointerTypeLoc(pointeeLoc(typeLoc().bind("loc"))),
+ new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "int* a;",
+ pointerTypeLoc().bind("loc"),
+ new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ pointerTypeLoc(pointeeLoc(loc(qualType())))));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ loc(pointerType(pointee(pointerType())))));
+ EXPECT_TRUE(matches(
+ "int* b; int* * const a = &b;",
+ loc(qualType(isConstQualified(), pointerType()))));
+
+ std::string Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
+ EXPECT_TRUE(notMatches(Fragment, blockPointerType()));
+ EXPECT_TRUE(matches(Fragment, memberPointerType()));
+ EXPECT_TRUE(notMatches(Fragment, pointerType()));
+ EXPECT_TRUE(notMatches(Fragment, referenceType()));
+
+ Fragment = "int *I;";
+ EXPECT_TRUE(notMatches(Fragment, blockPointerType()));
+ EXPECT_TRUE(notMatches(Fragment, memberPointerType()));
+ EXPECT_TRUE(matches(Fragment, pointerType()));
+ EXPECT_TRUE(notMatches(Fragment, referenceType()));
+
+ Fragment = "int a; int &b = a;";
+ EXPECT_TRUE(notMatches(Fragment, blockPointerType()));
+ EXPECT_TRUE(notMatches(Fragment, memberPointerType()));
+ EXPECT_TRUE(notMatches(Fragment, pointerType()));
+ EXPECT_TRUE(matches(Fragment, referenceType()));
+}
+
+TEST(TypeMatching, PointeeTypes) {
+ EXPECT_TRUE(matches("int b; int &a = b;",
+ referenceType(pointee(builtinType()))));
+ EXPECT_TRUE(matches("int *a;", pointerType(pointee(builtinType()))));
+
+ EXPECT_TRUE(matches("int *a;",
+ pointerTypeLoc(pointeeLoc(loc(builtinType())))));
+
+ EXPECT_TRUE(matches(
+ "int const *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "int *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+}
+
+TEST(TypeMatching, MatchesPointersToConstTypes) {
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ loc(pointerType())));
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ pointerTypeLoc()));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerTypeLoc(pointeeLoc(builtinTypeLoc()))));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerType(pointee(builtinType()))));
+}
+
+TEST(TypeMatching, MatchesTypedefTypes) {
+ EXPECT_TRUE(matches("typedef int X;", typedefType()));
+
+ EXPECT_TRUE(matches("typedef int X;", typedefType(hasDecl(decl()))));
+}
+
TEST(NNS, MatchesNestedNameSpecifiers) {
EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;",
nestedNameSpecifier()));
@@ -2942,8 +3121,8 @@
nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
EXPECT_TRUE(matches(
"struct A { struct B { struct C {}; }; }; A::B::C c;",
- nestedNameSpecifierLoc(hasPrefix(loc(
- specifiesType(asString("struct A")))))));
+ nestedNameSpecifierLoc(hasPrefix(
+ specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
}
} // end namespace ast_matchers
More information about the cfe-commits
mailing list