[llvm-branch-commits] [cfe-branch] r157622 - in /cfe/branches/tooling: include/clang/ASTMatchers/ include/clang/ASTMatchers/Dynamic/ lib/ASTMatchers/ lib/ASTMatchers/Dynamic/ tools/ tools/ast-query/ unittests/ unittests/ASTMatchers/ unittests/ASTMatchers/Dynamic/
Manuel Klimek
klimek at google.com
Tue May 29 07:10:54 PDT 2012
Author: klimek
Date: Tue May 29 09:10:54 2012
New Revision: 157622
URL: http://llvm.org/viewvc/llvm-project?rev=157622&view=rev
Log:
Adds dynamic matcher interface contributed by Samuel Benzaquen.
Added:
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h (with props)
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h (with props)
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h (with props)
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h (with props)
cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h (with props)
cfe/branches/tooling/lib/ASTMatchers/Dynamic/
cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt (with props)
cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile (with props)
cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h (with props)
cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp (with props)
cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp (with props)
cfe/branches/tooling/tools/ast-query/
cfe/branches/tooling/tools/ast-query/ASTQuery.cpp (with props)
cfe/branches/tooling/tools/ast-query/CMakeLists.txt (with props)
cfe/branches/tooling/tools/ast-query/Makefile (with props)
cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp (with props)
cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (with props)
Modified:
cfe/branches/tooling/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/branches/tooling/lib/ASTMatchers/CMakeLists.txt
cfe/branches/tooling/lib/ASTMatchers/Makefile
cfe/branches/tooling/tools/CMakeLists.txt
cfe/branches/tooling/tools/Makefile
cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.cpp
cfe/branches/tooling/unittests/ASTMatchers/Makefile
cfe/branches/tooling/unittests/CMakeLists.txt
Modified: cfe/branches/tooling/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/branches/tooling/include/clang/ASTMatchers/ASTMatchersInternal.h Tue May 29 09:10:54 2012
@@ -311,16 +311,18 @@
/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
template <typename T>
struct IsBaseType {
- static const bool value = (llvm::is_same<T, clang::Decl>::value ||
- llvm::is_same<T, clang::Stmt>::value ||
- llvm::is_same<T, clang::QualType>::value);
+ static const bool value =
+ (llvm::is_same<T, clang::Decl>::value ||
+ llvm::is_same<T, clang::Stmt>::value ||
+ llvm::is_same<T, clang::QualType>::value ||
+ llvm::is_same<T, clang::CXXCtorInitializer>::value);
};
template <typename T>
const bool IsBaseType<T>::value;
/// \brief Interface that can match any AST base node type and contains default
/// implementations returning false.
-class UntypedBaseMatcher {
+class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
public:
virtual ~UntypedBaseMatcher() {}
@@ -336,6 +338,11 @@
BoundNodesTreeBuilder *Builder) const {
return false;
}
+ virtual bool matches(const clang::CXXCtorInitializer &CtorInitNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return false;
+ }
/// \brief Returns a unique ID for the matcher.
virtual uint64_t getID() const = 0;
Added: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h (added)
+++ cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h Tue May 29 09:10:54 2012
@@ -0,0 +1,198 @@
+//===--- GenericMatcher.h - Polymorphic matcher type -*- C++ -*-===/
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A simple wrapper class that can impersonate any matcher type.
+// It provides appropriate conversion of matchers. An invalid conversion will
+// succeed, but return a matcher that won't match anything.
+// Eg. Converting a Matcher<Stmt> to Matcher<Decl>.
+// Used as the underlying matcher value on GenericValue.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_MATCHER_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_MATCHER_H
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+using ast_matchers::internal::Matcher;
+using ast_matchers::internal::UntypedBaseMatcher;
+using ast_matchers::internal::TypedBaseMatcher;
+using ast_matchers::internal::ASTMatchFinder;
+using ast_matchers::internal::BoundNodesTreeBuilder;
+
+namespace internal {
+
+
+} // namespace internal
+
+class GenericMatcher {
+ // Gives the base types for Decl/Expr and T for everything else.
+ // Callers to the GenericMatcher will use the derived classes when
+ // setting/getting the contents. This struct helps on the conversion.
+ template <typename T>
+ struct DerivedTypeHelper {
+ typedef typename llvm::conditional<llvm::is_base_of<clang::Decl, T>::value,
+ clang::Decl, T>::type Decl_type;
+ typedef typename llvm::conditional<llvm::is_base_of<clang::Stmt, T>::value,
+ clang::Stmt, Decl_type>::type Type;
+ };
+
+ public:
+ template <typename T>
+ GenericMatcher(Matcher<T> Inner)
+ : Untyped(makeUntyped(Inner)) { }
+
+ template <typename T>
+ Matcher<T> getAs() const {
+ return ast_matchers::internal::MakeMatcher(new UntypedWrapper<T>(Untyped));
+ }
+
+ static GenericMatcher anyOf(const GenericMatcher& First,
+ const GenericMatcher& Second) {
+ return GenericMatcher(new AnyOfUntypedMatcher(
+ First.Untyped, Second.Untyped));
+ }
+
+ static GenericMatcher allOf(const GenericMatcher& First,
+ const GenericMatcher& Second) {
+ return GenericMatcher(new AllOfUntypedMatcher(
+ First.Untyped, Second.Untyped));
+ }
+
+ private:
+ // Takes ownership.
+ explicit GenericMatcher(UntypedBaseMatcher* Inner) : Untyped(Inner) { }
+
+ typedef llvm::IntrusiveRefCntPtr<const UntypedBaseMatcher> UntypedMatcherPtr;
+
+ template <typename T>
+ static UntypedMatcherPtr makeUntyped(Matcher<T> Inner) {
+ typedef typename DerivedTypeHelper<T>::Type BaseType;
+ return new TypedBaseMatcher<BaseType>(
+ maybeMakeDynCastMatcher(Inner, static_cast<BaseType*>(NULL)));
+ }
+
+ // Use DynCastMatcher when From and To are different types.
+ // This allows skipping DynCastMatcher for QualType and CXXCtorInitializer
+ // that do not support it.
+ template <typename From, typename To>
+ static Matcher<From> maybeMakeDynCastMatcher(const Matcher<To>& BaseMatcher,
+ const From* dummy) {
+ return MakeMatcher(
+ new ast_matchers::internal::DynCastMatcher<From, To>(BaseMatcher));
+ }
+ template <typename T>
+ static Matcher<T> maybeMakeDynCastMatcher(const Matcher<T>& BaseMatcher,
+ const T* dummy) {
+ return BaseMatcher;
+ }
+
+ template <typename T>
+ class UntypedWrapper : public ast_matchers::internal::MatcherInterface<T> {
+ public:
+ explicit UntypedWrapper(const UntypedMatcherPtr& Inner) : Untyped(Inner) { }
+ virtual ~UntypedWrapper() { }
+ bool matches(const T& Node, ASTMatchFinder* Finder,
+ BoundNodesTreeBuilder* Builder) const {
+ return Untyped->matches(Node, Finder, Builder);
+ }
+
+ private:
+ const UntypedMatcherPtr Untyped;
+ };
+
+ class AnyOfUntypedMatcher : public UntypedBaseMatcher {
+ public:
+ AnyOfUntypedMatcher(const UntypedMatcherPtr& FirstIn,
+ const UntypedMatcherPtr& SecondIn)
+ : First(FirstIn), Second(SecondIn) { }
+ virtual ~AnyOfUntypedMatcher() {}
+
+ bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(DeclNode, Finder, Builder) ||
+ Second->matches(DeclNode, Finder, Builder);
+ }
+ bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(TypeNode, Finder, Builder) ||
+ Second->matches(TypeNode, Finder, Builder);
+ }
+ bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(StmtNode, Finder, Builder) ||
+ Second->matches(StmtNode, Finder, Builder);
+ }
+ bool matches(const clang::CXXCtorInitializer &CtorInitNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(CtorInitNode, Finder, Builder) ||
+ Second->matches(CtorInitNode, Finder, Builder);
+ }
+
+ uint64_t getID() const {
+ return reinterpret_cast<uint64_t>(this);
+ }
+
+ private:
+ const UntypedMatcherPtr First;
+ const UntypedMatcherPtr Second;
+ };
+
+ class AllOfUntypedMatcher : public UntypedBaseMatcher {
+ public:
+ AllOfUntypedMatcher(const UntypedMatcherPtr& FirstIn,
+ const UntypedMatcherPtr& SecondIn)
+ : First(FirstIn), Second(SecondIn) { }
+ virtual ~AllOfUntypedMatcher() {}
+
+ bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(DeclNode, Finder, Builder) &&
+ Second->matches(DeclNode, Finder, Builder);
+ }
+ bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(TypeNode, Finder, Builder) &&
+ Second->matches(TypeNode, Finder, Builder);
+ }
+ bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(StmtNode, Finder, Builder) &&
+ Second->matches(StmtNode, Finder, Builder);
+ }
+ bool matches(const clang::CXXCtorInitializer &CtorInitNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return First->matches(CtorInitNode, Finder, Builder) &&
+ Second->matches(CtorInitNode, Finder, Builder);
+ }
+
+ uint64_t getID() const {
+ return reinterpret_cast<uint64_t>(this);
+ }
+
+ private:
+ const UntypedMatcherPtr First;
+ const UntypedMatcherPtr Second;
+ };
+
+ UntypedMatcherPtr Untyped;
+};
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_MATCHER_H
Propchange: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericMatcher.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h (added)
+++ cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h Tue May 29 09:10:54 2012
@@ -0,0 +1,188 @@
+//===--- GenericValue.h - Polymorphic value type -*- C++ -*-===/
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Polymorphic value type that supports all the types required for dynamic
+// Matcher construction.
+// Used by the registry to construct matchers in a generic way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_VALUE_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_VALUE_H
+
+#include "GenericMatcher.h"
+#include "NumberHolder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+struct GenericError {
+ std::string Message;
+ GenericError() {}
+ explicit GenericError(const std::string& Message) : Message(Message) { }
+};
+
+class GenericValue {
+ public:
+ GenericValue() : Type(VT_Nothing) { }
+ template <typename T>
+ GenericValue(const T& Value) : Type(VT_Nothing) {
+ setImpl(Value);
+ }
+ GenericValue(const GenericValue& Other) : Type(VT_Nothing) {
+ *this = Other;
+ }
+
+ ~GenericValue() {
+ Reset();
+ }
+
+ GenericValue& operator=(const GenericValue& Other) {
+ Reset();
+ switch (Other.Type) {
+ case VT_String: setImpl(Other.get<std::string>()); break;
+ case VT_Error: setImpl(Other.get<GenericError>()); break;
+ case VT_Bool: setImpl(Other.get<bool>()); break;
+ case VT_Matcher: setImpl(Other.get<GenericMatcher>()); break;
+ case VT_Number: setImpl(Other.get<NumberHolder>()); break;
+ case VT_Nothing: Type = VT_Nothing; break;
+ }
+ return *this;
+ }
+
+ template <typename T>
+ bool is() const {
+ return isImpl(static_cast<T*>(NULL));
+ }
+
+ template <typename T>
+ T get() const {
+ assert(is<T>());
+ return getImpl(static_cast<T*>(NULL));
+ }
+
+ private:
+ void Reset() {
+ switch (Type) {
+ case VT_String: delete Value.String; break;
+ case VT_Error: delete Value.Error; break;
+ case VT_Matcher: delete Value.Matcher; break;
+ case VT_Number: delete Value.Number; break;
+ // Cases that do nothing.
+ case VT_Bool: break;
+ case VT_Nothing: break;
+ }
+ Type = VT_Nothing;
+ }
+
+ // std::string
+ bool isImpl(std::string* Dummy) const { return Type == VT_String; }
+ const std::string& getImpl(std::string* Dummy) const {
+ return *Value.String;
+ }
+ void setImpl(const std::string& NewValue) {
+ Type = VT_String;
+ Value.String = new std::string(NewValue);
+ }
+
+ // GenericError
+ bool isImpl(GenericError* Dummy) const { return Type == VT_Error; }
+ const GenericError& getImpl(GenericError* Dummy) const {
+ return *Value.Error;
+ }
+ void setImpl(const GenericError& NewValue) {
+ Type = VT_Error;
+ Value.Error = new GenericError(NewValue);
+ }
+
+ // bool
+ bool isImpl(bool* Dummy) const { return Type == VT_Bool; }
+ bool getImpl(bool* Dummy) const { return Value.Bool; }
+ void setImpl(bool NewValue) {
+ Type = VT_Bool;
+ Value.Bool = NewValue;
+ }
+
+ // GenericMatcher and Matcher<T>
+ bool isImpl(GenericMatcher* Dummy) const { return Type == VT_Matcher; }
+ const GenericMatcher& getImpl(GenericMatcher* Dummy) const {
+ return *Value.Matcher;
+ }
+ void setImpl(const GenericMatcher& NewValue) {
+ Type = VT_Matcher;
+ Value.Matcher = new GenericMatcher(NewValue);
+ }
+
+ template <typename T>
+ bool isImpl(Matcher<T>* Dummy) const { return Type == VT_Matcher; }
+ template <typename T>
+ Matcher<T> getImpl(Matcher<T>* Dummy) const {
+ return Value.Matcher->getAs<T>();
+ }
+ template <typename T>
+ void setImpl(const Matcher<T>& NewValue) {
+ Type = VT_Matcher;
+ Value.Matcher = new GenericMatcher(NewValue);
+ }
+
+ // All numbers.
+ bool isImpl(NumberHolder* Dummy) const { return Type == VT_Number; }
+ const NumberHolder& getImpl(NumberHolder* Dummy) const {
+ return *Value.Number;
+ }
+ void setImpl(const NumberHolder& NewValue) {
+ Type = VT_Number;
+ Value.Number = new NumberHolder(NewValue);
+ }
+
+ // For now, we assume any other type is a number.
+ // A compile time error should stop any other use since it will not be
+ // compatible with NumberHolder.
+ template <typename T>
+ bool isImpl(T* Dummy) const {
+ return Type == VT_Number && Value.Number->is<T>();
+ }
+ template <typename T>
+ T getImpl(T* Dummy) const {
+ return Value.Number->get<T>();
+ }
+ template <typename T>
+ void setImpl(const T& NewValue) {
+ Type = VT_Number;
+ Value.Number = new NumberHolder(NewValue);
+ }
+
+ enum ValueType {
+ VT_Nothing,
+ VT_Bool,
+ VT_String,
+ VT_Error,
+ VT_Matcher,
+ VT_Number
+ };
+
+ union AllValues {
+ std::string* String;
+ GenericError* Error;
+ bool Bool;
+ GenericMatcher* Matcher;
+ NumberHolder* Number;
+ };
+
+ ValueType Type;
+ AllValues Value;
+};
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_GENERIC_VALUE_H
Propchange: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/GenericValue.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h (added)
+++ cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h Tue May 29 09:10:54 2012
@@ -0,0 +1,115 @@
+//===--- NumberHolder.h - Generic number type -*- C++ -*-===/
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a simple number type holder data structure.
+// It provides the storage for the value plus templated conversion operators
+// to any other numeric type.
+// Used as the underlying number value on GenericValue.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_NUMBER_HOLDER_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_NUMBER_HOLDER_H
+
+#include <limits>
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+class NumberHolder {
+ public:
+ template <typename T>
+ explicit NumberHolder(T Input) {
+ if (convertToImpl(Input, &Value.Unsigned64)) {
+ Type = NT_Unsigned64;
+ } else if (convertToImpl(Input, &Value.Signed64)) {
+ Type = NT_Signed64;
+ } else if (convertToImpl(Input, &Value.Double)) {
+ Type = NT_Double;
+ } else {
+ Type = NT_Nothing;
+ }
+ }
+
+ template <typename T>
+ bool is() const {
+ T Converted;
+ return convertTo(&Converted);
+ }
+ template <typename T>
+ T get() const {
+ T Converted;
+ convertTo(&Converted);
+ return Converted;
+ }
+
+ private:
+ template <typename DestType>
+ bool convertTo(DestType* Dest) const {
+ switch (Type) {
+ case NT_Unsigned64: return convertToImpl(Value.Unsigned64, Dest);
+ case NT_Signed64: return convertToImpl(Value.Signed64, Dest);
+ case NT_Double: return convertToImpl(Value.Double, Dest);
+ case NT_Nothing: return false;
+ }
+ return false;
+ }
+
+ template <typename SourceType, typename DestType>
+ static bool convertToImpl(const SourceType Source, DestType* Dest) {
+ *Dest = Source;
+ // Try to convert back. This makes sure we didn't lose precision.
+ // Eg. Like converting 1.1 to int.
+ if (SourceType(*Dest) != Source) return false;
+ // Make sure that we didn't change the sign.
+ // Eg. Converting -1 to uint32_t.
+ if (isNegative(*Dest) ^ isNegative(Source))
+ return false;
+ return true;
+ }
+
+ template <typename ValueType>
+ struct CanBeNegative : public llvm::integral_constant<
+ bool, std::numeric_limits<ValueType>::is_signed> {};
+
+ template <typename ValueType>
+ static bool isNegative(ValueType Value, llvm::true_type CanBeNegative) {
+ return Value < 0;
+ }
+ template <typename ValueType>
+ static bool isNegative(ValueType Value, llvm::false_type CanBeNegative) {
+ return false;
+ }
+ template <typename ValueType>
+ static bool isNegative(ValueType Value) {
+ return isNegative(Value, CanBeNegative<ValueType>());
+ }
+
+ enum Type {
+ NT_Nothing,
+ NT_Unsigned64,
+ NT_Signed64,
+ NT_Double
+ };
+ Type Type;
+ union {
+ uint64_t Unsigned64;
+ int64_t Signed64;
+ double Double;
+ } Value;
+};
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_NUMBER_HOLDER_H
Propchange: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/NumberHolder.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h (added)
+++ cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h Tue May 29 09:10:54 2012
@@ -0,0 +1,65 @@
+//===--- Parser.h - Matcher expression parser -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple matcher expression parser.
+// The parser understand matcher expressions of the form:
+// MatcherName(Arg0, Arg1, ..., ArgN)
+// as well as simple types like string, character, number and boolean literals.
+// The parser does not know how to process the matchers. It delegates this task
+// to a TokenProcessor object received as an argument.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/GenericValue.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+class Parser {
+ public:
+ struct TokenInfo {
+ llvm::StringRef Token;
+ int StartLine;
+ int EndLine;
+ int StartColumn;
+ int EndColumn;
+ };
+
+ class TokenProcessor {
+ public:
+ virtual ~TokenProcessor(){}
+ virtual GenericValue processValueToken(const GenericValue& Value,
+ const TokenInfo& Info) {
+ return Value;
+ }
+ virtual GenericValue processMatcherToken(
+ llvm::StringRef MatcherName,
+ const std::vector<GenericValue>& Args,
+ const TokenInfo& Info) = 0;
+ };
+
+ static GenericValue parseMatcher(llvm::StringRef MatcherCode,
+ TokenProcessor* Processor);
+
+ private:
+ Parser(); // Declared, but not defined.
+};
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
Propchange: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Parser.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h (added)
+++ cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h Tue May 29 09:10:54 2012
@@ -0,0 +1,47 @@
+//===--- Registry.h - Matcher registry -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Registry of all known matchers.
+// The registry provides a generic interface to construct any matcher by name.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/GenericValue.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+class Registry {
+ public:
+ // Consult the registry of known matchers and construct the appropriate
+ // matcher by name.
+ // It will return GenericError if the matcher is not found, or if the
+ // number of arguments or argument types do not match the signature.
+ static GenericValue constructMatcher(const std::string& MatcherName,
+ const std::vector<GenericValue>& Args);
+
+ static const std::string* getTypeMatcherName(const std::string& TypeName);
+ static bool isKindName(const std::string& MatcherName);
+
+ private:
+ Registry(); // Declared, but not defined.
+};
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
Propchange: cfe/branches/tooling/include/clang/ASTMatchers/Dynamic/Registry.h
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: cfe/branches/tooling/lib/ASTMatchers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/CMakeLists.txt?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/ASTMatchers/CMakeLists.txt Tue May 29 09:10:54 2012
@@ -1,3 +1,5 @@
+add_subdirectory(Dynamic)
+
set(LLVM_LINK_COMPONENTS support)
SET(LLVM_USED_LIBS clangBasic clangAST)
Added: cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt (added)
+++ cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt Tue May 29 09:10:54 2012
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS support)
+SET(LLVM_USED_LIBS clangBasic clangAST clangASTMatchers)
+
+add_clang_library(clangDynamicASTMatchers
+ Parser.cpp
+ Registry.cpp
+ )
Propchange: cfe/branches/tooling/lib/ASTMatchers/Dynamic/CMakeLists.txt
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile (added)
+++ cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile Tue May 29 09:10:54 2012
@@ -0,0 +1,13 @@
+##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangDynamicASTMatchers
+
+include $(CLANG_LEVEL)/Makefile
Propchange: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Makefile
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h (added)
+++ cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h Tue May 29 09:10:54 2012
@@ -0,0 +1,276 @@
+//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A collection of template function and classes that provide a generic
+// marshalling layer on top of matcher construct functions.
+// These are used by the registry to export all marshaller constructors with
+// the same generic interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/GenericMatcher.h"
+#include "clang/ASTMatchers/Dynamic/GenericValue.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+namespace internal {
+
+// Generic MatcherCreate interface.
+// Provides a run() method that constructs the matcher from the provided
+// arguments.
+class MatcherCreateCallback {
+ public:
+ virtual ~MatcherCreateCallback() { }
+ virtual GenericValue run(const std::vector<GenericValue>& Args) const = 0;
+};
+
+// Generic callback implementation.
+// The Marshaller function will unpack the arguments, call Func and repack the
+// return value.
+// It should also check that the arguments are valid for Func.
+template <typename MarshallerType, typename FuncType>
+class MatcherCreateCallbackImpl : public MatcherCreateCallback {
+ public:
+ MatcherCreateCallbackImpl(MarshallerType Marshaller,
+ FuncType Func,
+ const std::string& MatcherName)
+ : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName) { }
+
+ GenericValue run(const std::vector<GenericValue>& Args) const {
+ return Marshaller(Func, MatcherName, Args);
+ }
+ private:
+ const MarshallerType Marshaller;
+ const FuncType Func;
+ const std::string MatcherName;
+};
+
+template <typename MarshallerType, typename FuncType>
+MatcherCreateCallback* CreateMarshallerCallback(
+ MarshallerType Marshaller,
+ FuncType Func,
+ const std::string& MatcherName) {
+ return new MatcherCreateCallbackImpl<MarshallerType, FuncType>(
+ Marshaller, Func, MatcherName);
+}
+
+#define CHECK_ARG_COUNT(count) \
+ if (Args.size() != count) { \
+ return GenericError(llvm::Twine( \
+ "Incorrect argument count on function " + MatcherName + \
+ ". (Expected = " + llvm::Twine(count) + \
+ ") != (Actual = " + llvm::Twine(Args.size()) + ")").str()); \
+ }
+#define CHECK_ARG_TYPE(index, type) \
+ if (Args[index].is<GenericError>()) return Args[index]; \
+ if (!Args[index].is<type>()) { \
+ return GenericError(llvm::Twine( \
+ "Incorrect type on function " + MatcherName + \
+ " for arg " + llvm::Twine(index)).str()); \
+ }
+
+// 0-arg marshaller function.
+template <typename FuncType, typename ReturnType>
+GenericValue MatcherMarshall0(FuncType Func,
+ const std::string& MatcherName,
+ const std::vector<GenericValue>& Args) {
+ CHECK_ARG_COUNT(0);
+ return GenericValue(ReturnType(Func()));
+}
+
+// 1-arg marshaller function.
+template <typename FuncType, typename ReturnType, typename ArgType1>
+GenericValue MatcherMarshall1(FuncType Func,
+ const std::string& MatcherName,
+ const std::vector<GenericValue>& Args) {
+ CHECK_ARG_COUNT(1);
+ CHECK_ARG_TYPE(0, ArgType1);
+ return GenericValue(ReturnType(Func(Args[0].get<ArgType1>())));
+}
+
+// 2-arg marshaller function.
+template <typename FuncType, typename ReturnType,
+ typename ArgType1, typename ArgType2>
+GenericValue MatcherMarshall2(FuncType Func,
+ const std::string& MatcherName,
+ const std::vector<GenericValue>& Args) {
+ CHECK_ARG_COUNT(2);
+ CHECK_ARG_TYPE(0, ArgType1);
+ CHECK_ARG_TYPE(1, ArgType2);
+ return GenericValue(ReturnType(Func(Args[0].get<ArgType1>(),
+ Args[1].get<ArgType2>())));
+}
+
+// Variadic marshaller function.
+template <typename BaseType, typename DerivedType>
+class MatcherMarshallVariadic : public MatcherCreateCallback {
+ public:
+ explicit MatcherMarshallVariadic(const std::string& MatcherName)
+ : MatcherName(MatcherName) { }
+
+ typedef Matcher<DerivedType> DerivedMatcherType;
+
+ GenericValue run(const std::vector<GenericValue>& Args) const {
+ std::list<DerivedMatcherType> References;
+ std::vector<const DerivedMatcherType*> InnerArgs(Args.size());
+ for (size_t i = 0; i < Args.size(); ++i) {
+ CHECK_ARG_TYPE(i, DerivedMatcherType);
+ References.push_back(Args[i].get<DerivedMatcherType>());
+ InnerArgs[i] = &References.back();
+ }
+ return GenericValue(
+ ast_matchers::internal::MakeDynCastAllOfComposite<BaseType>(
+ ArrayRef<const DerivedMatcherType*>(InnerArgs)));
+ }
+
+ private:
+ const std::string MatcherName;
+};
+
+#undef CHECK_ARG_COUNT
+#undef CHECK_ARG_TYPE
+
+// We need to remove the const& out of the function parameters to be able to
+// find values on GenericValue.
+template <typename T>
+struct remove_const_ref
+ : public llvm::remove_const<typename llvm::remove_reference<T>::type> {
+};
+
+// Helper functions to select the appropriate marshaller functions.
+// We have two names:
+// - MakeMatcherAutoMarshall: Detects the number of arguments, arguments types
+// and return types.
+// - MakeMatcherAutoMarshallPoly: Same as MakeMatcherAutoMarshall, but allows
+// passing the desired return type for polymorphic matchers.
+
+// 0-arg
+template <typename ReturnType, typename PolyReturnType>
+MatcherCreateCallback* MakeMatcherAutoMarshallPoly(
+ PolyReturnType (*Func)(),
+ const std::string& MatcherName) {
+ return CreateMarshallerCallback(
+ MatcherMarshall0<PolyReturnType(*)(), ReturnType>, Func, MatcherName);
+}
+template <typename ReturnType>
+MatcherCreateCallback* MakeMatcherAutoMarshall(
+ ReturnType (*Func)(),
+ const std::string& MatcherName) {
+ return MakeMatcherAutoMarshallPoly<ReturnType>(Func, MatcherName);
+}
+
+// 1-arg
+template <typename ReturnType, typename PolyReturnType, typename InArgType1>
+MatcherCreateCallback* MakeMatcherAutoMarshallPoly(
+ PolyReturnType (*Func)(InArgType1),
+ const std::string& MatcherName) {
+ typedef typename remove_const_ref<InArgType1>::type ArgType1;
+ return CreateMarshallerCallback(
+ MatcherMarshall1<PolyReturnType (*)(InArgType1), ReturnType, ArgType1>,
+ Func, MatcherName);
+}
+template <typename ReturnType, typename InArgType1>
+MatcherCreateCallback* MakeMatcherAutoMarshall(
+ ReturnType (*Func)(InArgType1),
+ const std::string& MatcherName) {
+ return MakeMatcherAutoMarshallPoly<ReturnType>(Func, MatcherName);
+}
+
+// 2-arg
+template <typename ReturnType, typename PolyReturnType,
+ typename InArgType1, typename InArgType2>
+MatcherCreateCallback* MakeMatcherAutoMarshallPoly(
+ PolyReturnType (*Func)(InArgType1, InArgType2),
+ const std::string& MatcherName) {
+ typedef typename remove_const_ref<InArgType1>::type ArgType1;
+ typedef typename remove_const_ref<InArgType2>::type ArgType2;
+ return CreateMarshallerCallback(
+ MatcherMarshall2<PolyReturnType (*)(InArgType1, InArgType2),
+ ReturnType, ArgType1, ArgType2>,
+ Func, MatcherName);
+}
+template <typename ReturnType, typename InArgType1, typename InArgType2>
+MatcherCreateCallback* MakeMatcherAutoMarshall(
+ ReturnType (*Func)(InArgType1, InArgType2),
+ const std::string& MatcherName) {
+ return MakeMatcherAutoMarshallPoly<ReturnType>(Func, MatcherName);
+}
+
+// Variadic
+template <typename BaseType, typename MatcherType>
+MatcherCreateCallback* MakeMatcherAutoMarshall(
+ ast_matchers::internal::VariadicDynCastAllOfMatcher<
+ BaseType, MatcherType> Func,
+ const std::string& MatcherName) {
+ return new MatcherMarshallVariadic<BaseType, MatcherType>(MatcherName);
+}
+
+
+// Some basic functions that are easier to reimplement than reuse.
+class MatcherMarshallAnyOf : public MatcherCreateCallback {
+ public:
+ GenericValue run(const std::vector<GenericValue>& Args) const {
+ if (Args.empty())
+ return GenericError("anyOf() needs at least one argument!");
+
+ // Validate them
+ for (size_t i = 0; i < Args.size(); ++i) {
+ if (!Args[i].is<GenericMatcher>()) {
+ return GenericError(llvm::Twine("Argument " + llvm::Twine(i) +
+ " is not a matcher.").str());
+ }
+ }
+
+ GenericMatcher Matcher = Args[0].get<GenericMatcher>();
+ for (size_t i = 1; i < Args.size(); ++i) {
+ Matcher = GenericMatcher::anyOf(Matcher, Args[i].get<GenericMatcher>());
+ }
+ return Matcher;
+ }
+};
+
+class MatcherMarshallAllOf : public MatcherCreateCallback {
+ public:
+ GenericValue run(const std::vector<GenericValue>& Args) const {
+ if (Args.empty())
+ return GenericError("allOf() needs at least one argument!");
+
+ // Validate them
+ for (size_t i = 0; i < Args.size(); ++i) {
+ if (!Args[i].is<GenericMatcher>()) {
+ return GenericError(llvm::Twine("Argument " + llvm::Twine(i) +
+ " is not a matcher.").str());
+ }
+ }
+
+ GenericMatcher Matcher = Args[0].get<GenericMatcher>();
+ for (size_t i = 1; i < Args.size(); ++i) {
+ Matcher = GenericMatcher::allOf(Matcher, Args[i].get<GenericMatcher>());
+ }
+ return Matcher;
+ }
+};
+
+} // namespace internal
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
Propchange: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Marshallers.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp (added)
+++ cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,294 @@
+//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple matcher expression parser.
+// The parser understand matcher expressions of the form:
+// MatcherName(Arg0, Arg1, ..., ArgN)
+// as well as simple types like string, character, number and boolean literals.
+// The parser does not know how to process the matchers. It delegates this task
+// to a TokenProcessor object received as an argument.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+namespace {
+
+class CodeTokenizer {
+ public:
+ explicit CodeTokenizer(llvm::StringRef MatcherCode)
+ : Code(MatcherCode), StartOfLine(MatcherCode), Line(1) { }
+
+ Parser::TokenInfo getNextToken() {
+ consumeWhitespace();
+ Parser::TokenInfo Result;
+ Result.StartLine = Line;
+ Result.StartColumn = Column();
+
+ if (Code.empty()) {
+ // Nothing to do.
+ } else if (isSingleCharToken(Code[0])) {
+ Result.Token = Code.substr(0, 1);
+ Code = Code.drop_front();
+
+ } else if (Code[0] == '"' || Code[0] == '\'') {
+ // Parse a string literal.
+ Result.Token = consumeStringLiteral();
+ Code = Code.drop_front(Result.Token.size());
+
+ } else {
+ size_t TokenLength = 0;
+ while (TokenLength < Code.size() &&
+ !isspace(Code[TokenLength]) &&
+ !isSingleCharToken(Code[TokenLength]))
+ ++TokenLength;
+ Result.Token = Code.substr(0, TokenLength);
+ Code = Code.drop_front(TokenLength);
+ }
+
+ Result.EndLine = Line;
+ Result.EndColumn = Column() - 1;
+ return Result;
+ }
+
+ bool isDone() const { return Code.empty(); }
+
+ private:
+ llvm::StringRef consumeStringLiteral() const {
+ bool InEscape = false;
+ const char Marker = Code[0];
+ for (size_t Length = 1; Length < Code.size(); ++Length) {
+ if (InEscape) {
+ InEscape = false;
+ continue;
+ }
+ if (Code[Length] == '\\') {
+ InEscape = true;
+ continue;
+ }
+ if (Code[Length] == Marker) {
+ return Code.substr(0, Length + 1);
+ }
+ }
+ return Code;
+ }
+
+ void consumeWhitespace() {
+ while (!Code.empty() && isspace(Code[0])) {
+ if (Code[0] == '\n') {
+ ++Line;
+ StartOfLine = Code.drop_front();
+ }
+ Code = Code.drop_front();
+ }
+ }
+ static bool isSingleCharToken(const char Char) {
+ return Char == ',' || Char == '(' || Char == ')';
+ }
+
+ llvm::StringRef Code;
+ llvm::StringRef StartOfLine;
+ int Line;
+ int Column() const {
+ return Code.data() - StartOfLine.data() + 1;
+ }
+};
+
+char UnescapeCharSequence(llvm::StringRef* Escaped) {
+ if (Escaped->empty()) return 0;
+ char Char = (*Escaped)[0];
+ *Escaped = Escaped->drop_front();
+ if (Char != '\\') {
+ return Char;
+ }
+
+ if (Escaped->empty()) return 0;
+ Char = (*Escaped)[0];
+ *Escaped = Escaped->drop_front();
+ // TODO: Does not escape octal/hex sequences. Eg. "\123"
+ switch (Char) {
+ case 'a': Char = '\a'; break;
+ case 'b': Char = '\b'; break;
+ case 'f': Char = '\f'; break;
+ case 'n': Char = '\n'; break;
+ case 'r': Char = '\r'; break;
+ case 't': Char = '\t'; break;
+ case 'v': Char = '\v'; break;
+ case '\\': Char = '\\'; break;
+ case '?': Char = '\?'; break;
+ case '\'': Char = '\''; break;
+ case '"': Char = '\"'; break;
+ }
+ return Char;
+}
+
+GenericValue ParseString(const Parser::TokenInfo& Token,
+ Parser::TokenProcessor* Processor) {
+ if (Token.Token.size() < 2 ||
+ !Token.Token.startswith("\"") || !Token.Token.endswith("\"")) {
+ return GenericError(
+ llvm::Twine("Error parsing string token: <" + Token.Token + ">").str());
+ }
+
+ llvm::StringRef Escaped = Token.Token.drop_front().drop_back();
+ std::string Unescaped;
+
+ while (!Escaped.empty()) {
+ Unescaped.push_back(UnescapeCharSequence(&Escaped));
+ }
+
+ GenericValue Value = Unescaped;
+ return Processor->processValueToken(Value, Token);
+}
+
+GenericValue ParseChar(const Parser::TokenInfo& Token,
+ Parser::TokenProcessor* Processor) {
+ if (Token.Token.size() < 3 ||
+ !Token.Token.startswith("'") || !Token.Token.endswith("'")) {
+ return GenericError(
+ llvm::Twine("Error parsing char token: <" + Token.Token + ">").str());
+ }
+ llvm::StringRef Escaped = Token.Token.drop_front().drop_back();
+ const int Unescaped = UnescapeCharSequence(&Escaped);
+ if (!Escaped.empty()) {
+ return GenericError(
+ llvm::Twine("Error parsing char token: <" + Token.Token + ">").str());
+ }
+
+ GenericValue Value = Unescaped;
+ return Processor->processValueToken(Value, Token);
+}
+
+GenericValue ParseNumber(const Parser::TokenInfo& Token,
+ Parser::TokenProcessor* Processor) {
+ long long SignedLong;
+ if (!Token.Token.getAsInteger(0, SignedLong)) {
+ return Processor->processValueToken(NumberHolder(SignedLong), Token);
+ }
+ unsigned long long UnsignedLong;
+ if (!Token.Token.getAsInteger(0, UnsignedLong)) {
+ return Processor->processValueToken(NumberHolder(UnsignedLong), Token);
+ }
+
+ // TODO: Figure out a way to do this without copying the token.
+ const std::string AsString = Token.Token;
+ char* endptr = NULL;
+ double Double = strtod(AsString.c_str(), &endptr);
+ if (endptr[0] == 0)
+ return Processor->processValueToken(NumberHolder(Double), Token);
+
+ return GenericError(
+ llvm::Twine("Error parsing number token: <" + Token.Token + ">").str());
+}
+
+GenericValue ParseToken(const Parser::TokenInfo& Token,
+ CodeTokenizer* Tokenizer,
+ Parser::TokenProcessor* Processor);
+
+GenericValue ParseMatcher(const Parser::TokenInfo& Token,
+ CodeTokenizer* Tokenizer,
+ Parser::TokenProcessor* Processor) {
+ const Parser::TokenInfo& OpenToken = Tokenizer->getNextToken();
+ if (OpenToken.Token != "(") {
+ return GenericError(
+ llvm::Twine("Error parsing matcher. Found token <" +
+ OpenToken.Token + "> while looking for '('").str());
+ }
+
+ std::vector<GenericValue> Args;
+ Parser::TokenInfo EndToken;
+ while (!Tokenizer->isDone()) {
+ Parser::TokenInfo NextToken = Tokenizer->getNextToken();
+ if (NextToken.Token == ")") {
+ // End of args.
+ EndToken = NextToken;
+ break;
+ }
+ if (Args.size() > 0) {
+ // We must find a , token to continue.
+ if (NextToken.Token != ",") {
+ return GenericError(
+ llvm::Twine("Error parsing matcher. Found token <" +
+ NextToken.Token + "> while looking for ','").str());
+ }
+ NextToken = Tokenizer->getNextToken();
+ }
+ const GenericValue Arg = ParseToken(NextToken, Tokenizer, Processor);
+ if (Arg.is<GenericError>()) {
+ return GenericError(
+ llvm::Twine("Error parsing argument " + llvm::Twine(Args.size()) +
+ " for matcher " + Token.Token + ": " +
+ Arg.get<GenericError>().Message).str());
+ }
+ Args.push_back(Arg);
+ }
+
+ if (EndToken.Token == "") {
+ return GenericError("Error parsing matcher. Found end-of-code while "
+ "looking for ')'");
+ }
+
+ // Merge the start and end infos.
+ Parser::TokenInfo NewInfo = Token;
+ NewInfo.EndLine = EndToken.EndLine;
+ NewInfo.EndColumn = EndToken.EndColumn;
+ const GenericValue Result = Processor->processMatcherToken(
+ Token.Token, Args, NewInfo);
+ if (Result.is<GenericError>()) {
+ return GenericError(
+ llvm::Twine("Error building matcher " + Token.Token +
+ ": " + Result.get<GenericError>().Message).str());
+ }
+
+ return Result;
+}
+
+GenericValue ParseToken(const Parser::TokenInfo& Token,
+ CodeTokenizer* Tokenizer,
+ Parser::TokenProcessor* Processor) {
+ if (Token.Token.empty()) {
+ return GenericError("End of code found while looking for token.");
+ }
+
+ if (Token.Token[0] == '"') return ParseString(Token, Processor);
+ if (Token.Token[0] == '\'') return ParseChar(Token, Processor);
+ if (isdigit(Token.Token[0]) ||
+ Token.Token[0] == '-' || Token.Token[0] == '+') {
+ return ParseNumber(Token, Processor);
+ }
+
+ // TODO: Do this better when we have more constants.
+ // TODO: Add more constants (like INT_MAX and stuff like that).
+ if (Token.Token == "true")
+ return Processor->processValueToken(true, Token);
+ if (Token.Token == "false")
+ return Processor->processValueToken(false, Token);
+
+ return ParseMatcher(Token, Tokenizer, Processor);
+}
+
+} // anonymous namespace
+
+GenericValue Parser::parseMatcher(llvm::StringRef Code,
+ Parser::TokenProcessor* Processor) {
+ CodeTokenizer Tokenizer(Code);
+ return ParseToken(Tokenizer.getNextToken(), &Tokenizer, Processor);
+}
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
Propchange: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Parser.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp (added)
+++ cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,371 @@
+//===--- Registry.cpp - Matcher registry ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Registry of all known matchers.
+// The registry provides a generic interface to construct any matcher by name.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+
+#include <map>
+#include <set>
+#include <utility>
+
+#include "Marshallers.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/GenericMatcher.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+
+// A utility function that returns that name of a type, for all the types
+// defined in the AST.
+#define DECL(DERIVED, BASE) \
+class DERIVED##Decl; \
+const char* GetRegistryTypeName(DERIVED##Decl* dummy) { return #DERIVED; }
+#include "clang/AST/DeclNodes.inc"
+#define STMT(CLASS, PARENT) \
+class CLASS; \
+const char* GetRegistryTypeName(CLASS* dummy) { return #CLASS; }
+#include "clang/AST/StmtNodes.inc"
+const char* GetRegistryTypeName(Stmt* dummy) { return "Stmt"; }
+
+namespace ast_matchers {
+
+// Create some functions to help disambiguate certain overloaded matchers.
+
+#define MAKE_HELPER_POLY_FUNCTION1(func, name, R) \
+template <typename P1> \
+R name(const P1& t1) { return func(t1); } \
+
+MAKE_HELPER_POLY_FUNCTION1(HasType, HasType_Expr,
+ internal::Matcher<clang::Expr>)
+MAKE_HELPER_POLY_FUNCTION1(HasType, HasType_ValueDecl,
+ internal::Matcher<clang::ValueDecl>)
+
+namespace dynamic {
+
+namespace {
+
+using internal::MatcherCreateCallback;
+
+typedef std::map<std::string, const MatcherCreateCallback*> ConstructorMap;
+typedef std::map<std::string, std::string> KindNameMap;
+typedef std::set<std::string> KindSet;
+struct RegistryMaps {
+ ConstructorMap Constructors;
+ KindNameMap KindNames;
+ KindSet AllKinds;
+};
+
+// If both input callbacks return a matcher, the output will be anyOf() of them.
+// If only one of them (any of them) returns a matcher, the output will be that
+// returned matcher.
+// If they both return an error, the output will be any of them.
+class MatcherCallbackUnion : public MatcherCreateCallback {
+ public:
+ MatcherCallbackUnion(const MatcherCreateCallback* Callback1,
+ const MatcherCreateCallback* Callback2)
+ : Callback1(Callback1), Callback2(Callback2) { }
+
+ GenericValue run(const std::vector<GenericValue>& args) const {
+ // If they are both matchers, return the union of them.
+ // If only one is a matcher, return that one.
+ // Otherwise, return any of them, which should be an error.
+ const GenericValue Out1 = Callback1->run(args);
+ const GenericValue Out2 = Callback2->run(args);
+ if (!Out1.is<GenericMatcher>()) {
+ return Out2;
+ } else if (!Out2.is<GenericMatcher>()) {
+ return Out1;
+ } else {
+ return GenericMatcher::anyOf(Out1.get<GenericMatcher>(),
+ Out2.get<GenericMatcher>());
+ }
+ }
+
+ private:
+ const llvm::OwningPtr<const MatcherCreateCallback> Callback1;
+ const llvm::OwningPtr<const MatcherCreateCallback> Callback2;
+};
+
+void RegisterMatcher(const std::string& MatcherName,
+ MatcherCreateCallback* Callback,
+ RegistryMaps* Data) {
+ const MatcherCreateCallback** MapCallback = &Data->Constructors[MatcherName];
+ if (*MapCallback) {
+ Callback = new MatcherCallbackUnion(*MapCallback, Callback);
+ }
+ *MapCallback = Callback;
+}
+
+template <typename T>
+void RegisterKindName(const std::string& MatcherName, const T& t,
+ RegistryMaps* Data) { }
+template <typename Base, typename Type>
+void RegisterKindName(
+ const std::string& MatcherName,
+ ast_matchers::internal::VariadicDynCastAllOfMatcher<Base, Type> Func,
+ RegistryMaps* Data) {
+ Data->KindNames[GetRegistryTypeName(static_cast<Type*>(NULL))] = MatcherName;
+ Data->AllKinds.insert(MatcherName);
+}
+
+#define MATCH_NS ::clang::ast_matchers
+
+#define REGISTER_NAMED_MATCHER_AUTO(name, func) \
+ RegisterMatcher(#name, \
+ internal::MakeMatcherAutoMarshall(MATCH_NS::func, #name), \
+ Data)
+
+#define REGISTER_MATCHER_AUTO(name) \
+ REGISTER_NAMED_MATCHER_AUTO(name, name); \
+ RegisterKindName(#name, MATCH_NS::name, Data)
+
+#define REGISTER_POLY_NAMED_MATCHER_AUTO(name, func, R) \
+ RegisterMatcher(#name, \
+ internal::MakeMatcherAutoMarshallPoly<Matcher<R> >( \
+ MATCH_NS::func, #name), Data)
+
+#define REGISTER_POLY_MATCHER_AUTO(name, R) \
+ REGISTER_POLY_NAMED_MATCHER_AUTO(name, name, R)
+
+#define REGISTER_MATCHER1(name, R, P1) \
+ RegisterMatcher(#name, internal::MakeMatcherAutoMarshallPoly<R, R, P1>( \
+ MATCH_NS::name, #name), Data)
+
+RegistryMaps* RegisterMatchers() {
+ RegistryMaps* Data = new RegistryMaps();
+
+ REGISTER_MATCHER_AUTO(BinaryOperator);
+ REGISTER_MATCHER_AUTO(BindTemporaryExpression);
+ REGISTER_MATCHER_AUTO(BoolLiteral);
+ REGISTER_MATCHER_AUTO(Call);
+ REGISTER_MATCHER_AUTO(CharacterLiteral);
+ REGISTER_MATCHER_AUTO(Class);
+ REGISTER_MATCHER_AUTO(CompoundStatement);
+ REGISTER_MATCHER_AUTO(ConditionalOperator);
+ REGISTER_MATCHER_AUTO(ConstCast);
+ REGISTER_MATCHER_AUTO(Constructor);
+ REGISTER_MATCHER_AUTO(ConstructorCall);
+ REGISTER_MATCHER_AUTO(DeclarationReference);
+ REGISTER_MATCHER_AUTO(DeclarationStatement);
+ REGISTER_MATCHER_AUTO(DefaultArgument);
+ REGISTER_MATCHER_AUTO(Do);
+ REGISTER_MATCHER_AUTO(DynamicCast);
+ REGISTER_MATCHER_AUTO(ExplicitCast);
+ REGISTER_MATCHER_AUTO(Expression);
+ REGISTER_MATCHER_AUTO(Field);
+ REGISTER_MATCHER_AUTO(For);
+ REGISTER_MATCHER_AUTO(ForField);
+ REGISTER_MATCHER_AUTO(Function);
+ REGISTER_MATCHER_AUTO(FunctionalCast);
+ REGISTER_MATCHER_AUTO(HasAnyConstructorInitializer);
+ REGISTER_MATCHER_AUTO(HasAnyConstructorInitializer);
+ REGISTER_MATCHER_AUTO(HasAnyParameter);
+ REGISTER_MATCHER_AUTO(HasAnySubstatement);
+ REGISTER_MATCHER_AUTO(HasBody);
+ REGISTER_MATCHER_AUTO(HasConditionVariableStatement);
+ REGISTER_MATCHER_AUTO(HasDestinationType);
+ REGISTER_MATCHER_AUTO(HasEitherOperand);
+ REGISTER_MATCHER_AUTO(HasFalseExpression);
+ REGISTER_MATCHER_AUTO(HasImplicitDestinationType);
+ REGISTER_MATCHER_AUTO(HasInitializer);
+ REGISTER_MATCHER_AUTO(HasLHS);
+ REGISTER_MATCHER_AUTO(HasName);
+ REGISTER_MATCHER_AUTO(HasObjectExpression);
+ REGISTER_MATCHER_AUTO(HasOverloadedOperatorName);
+ REGISTER_MATCHER_AUTO(HasParameter);
+ REGISTER_MATCHER_AUTO(HasRHS);
+ REGISTER_MATCHER_AUTO(HasSourceExpression);
+ REGISTER_MATCHER_AUTO(HasTrueExpression);
+ REGISTER_MATCHER_AUTO(HasUnaryOperand);
+ REGISTER_MATCHER_AUTO(If);
+ REGISTER_MATCHER_AUTO(ImplicitCast);
+ REGISTER_MATCHER_AUTO(IntegerLiteral);
+ REGISTER_MATCHER_AUTO(IsArrow);
+ REGISTER_MATCHER_AUTO(IsConstQualified);
+ REGISTER_MATCHER_AUTO(IsDerivedFrom);
+ REGISTER_MATCHER_AUTO(IsImplicit);
+ REGISTER_MATCHER_AUTO(IsWritten);
+ REGISTER_MATCHER_AUTO(Member);
+ REGISTER_MATCHER_AUTO(MemberExpression);
+ REGISTER_MATCHER_AUTO(Method);
+ REGISTER_MATCHER_AUTO(NameableDeclaration);
+ REGISTER_MATCHER_AUTO(NewExpression);
+ REGISTER_MATCHER_AUTO(OfClass);
+ REGISTER_MATCHER_AUTO(On);
+ REGISTER_MATCHER_AUTO(OnImplicitObjectArgument);
+ REGISTER_MATCHER_AUTO(OverloadedOperatorCall);
+ REGISTER_MATCHER_AUTO(ReinterpretCast);
+ REGISTER_MATCHER_AUTO(Statement);
+ REGISTER_MATCHER_AUTO(StatementCountIs);
+ REGISTER_MATCHER_AUTO(StaticCast);
+ REGISTER_MATCHER_AUTO(StringLiteral);
+ REGISTER_MATCHER_AUTO(SwitchCase);
+ REGISTER_MATCHER_AUTO(To);
+ REGISTER_MATCHER_AUTO(UnaryOperator);
+ REGISTER_MATCHER_AUTO(Variable);
+ REGISTER_MATCHER_AUTO(While);
+ REGISTER_MATCHER_AUTO(WithInitializer);
+
+ // HasType is very special. It is overloaded on parameter and return value.
+ REGISTER_NAMED_MATCHER_AUTO(HasType, HasType_Expr<Matcher<clang::QualType> >);
+ REGISTER_NAMED_MATCHER_AUTO(HasType, HasType_Expr<Matcher<clang::Decl> >);
+ REGISTER_NAMED_MATCHER_AUTO(HasType,
+ HasType_ValueDecl<Matcher<clang::QualType> >);
+ REGISTER_NAMED_MATCHER_AUTO(HasType,
+ HasType_ValueDecl<Matcher<clang::Decl> >);
+
+ // True
+ REGISTER_POLY_MATCHER_AUTO(True, clang::Stmt);
+ REGISTER_POLY_MATCHER_AUTO(True, clang::QualType);
+ REGISTER_POLY_MATCHER_AUTO(True, clang::Decl);
+ REGISTER_POLY_MATCHER_AUTO(True, clang::CXXCtorInitializer);
+
+ // HasAnyArgument
+ REGISTER_POLY_MATCHER_AUTO(HasAnyArgument, clang::CallExpr);
+ REGISTER_POLY_MATCHER_AUTO(HasAnyArgument, clang::CXXConstructExpr);
+
+ // HasDeclaration
+ REGISTER_POLY_MATCHER_AUTO(HasDeclaration, clang::QualType);
+ REGISTER_POLY_MATCHER_AUTO(HasDeclaration, clang::CallExpr);
+ REGISTER_POLY_MATCHER_AUTO(HasDeclaration, clang::CXXConstructExpr);
+
+ // HasArgument
+ REGISTER_POLY_MATCHER_AUTO(HasArgument, clang::CallExpr);
+ REGISTER_POLY_MATCHER_AUTO(HasArgument, clang::CXXConstructExpr);
+
+ // HasOperatorName
+ REGISTER_POLY_MATCHER_AUTO(HasOperatorName, clang::BinaryOperator);
+ REGISTER_POLY_MATCHER_AUTO(HasOperatorName, clang::UnaryOperator);
+
+ // IsDefinition
+ REGISTER_POLY_MATCHER_AUTO(IsDefinition, clang::TagDecl);
+ REGISTER_POLY_MATCHER_AUTO(IsDefinition, clang::VarDecl);
+ REGISTER_POLY_MATCHER_AUTO(IsDefinition, clang::FunctionDecl);
+
+ // IsTemplateInstantiation
+ REGISTER_POLY_MATCHER_AUTO(IsTemplateInstantiation, clang::FunctionDecl);
+ REGISTER_POLY_MATCHER_AUTO(IsTemplateInstantiation, clang::VarDecl);
+ REGISTER_POLY_MATCHER_AUTO(IsTemplateInstantiation, clang::CXXRecordDecl);
+
+ // ArgumentCountIs
+ REGISTER_POLY_MATCHER_AUTO(ArgumentCountIs, clang::CallExpr);
+ REGISTER_POLY_MATCHER_AUTO(ArgumentCountIs, clang::CXXConstructExpr);
+
+ // For if() and (?:)
+ REGISTER_POLY_MATCHER_AUTO(HasCondition, clang::IfStmt);
+ REGISTER_POLY_MATCHER_AUTO(HasCondition, clang::ConditionalOperator);
+
+ // Equals. TODO: Needs more.
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Equals, Equals<bool>,
+ clang::CXXBoolLiteralExpr);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Equals, Equals<unsigned long long>,
+ clang::IntegerLiteral);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Equals, Equals<long long>,
+ clang::IntegerLiteral);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Equals, Equals<unsigned>,
+ clang::CharacterLiteral);
+
+ // Has/hasDescendant/forEach/forEachDescendant for Decl and Stmt
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Has, has<clang::Decl>, clang::Decl);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Has, has<clang::Stmt>, clang::Stmt);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(hasDescendant, hasDescendant<clang::Decl>,
+ clang::Decl);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(hasDescendant, hasDescendant<clang::Stmt>,
+ clang::Stmt);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(forEach, forEach<clang::Decl>, clang::Decl);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(forEach, forEach<clang::Stmt>, clang::Stmt);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(forEachDescendant,
+ forEachDescendant<clang::Decl>, clang::Decl);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(forEachDescendant,
+ forEachDescendant<clang::Stmt>, clang::Stmt);
+
+
+ // Id
+ REGISTER_NAMED_MATCHER_AUTO(Id, Id<clang::Decl>);
+ REGISTER_NAMED_MATCHER_AUTO(Id, Id<clang::Stmt>);
+
+ // Not. One per basic type.
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Not, Not<Matcher<clang::Decl> >,
+ clang::Decl);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Not, Not<Matcher<clang::Stmt> >,
+ clang::Stmt);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Not, Not<Matcher<clang::QualType> >,
+ clang::QualType);
+ REGISTER_POLY_NAMED_MATCHER_AUTO(Not,
+ Not<Matcher<clang::CXXCtorInitializer> >,
+ clang::CXXCtorInitializer);
+
+ // ThisPointerType is overloaded.
+ REGISTER_MATCHER1(ThisPointerType, Matcher<clang::CallExpr>,
+ const Matcher<clang::QualType>&);
+ REGISTER_MATCHER1(ThisPointerType, Matcher<clang::CallExpr>,
+ const Matcher<clang::Decl>&);
+
+ // Callee is overloaded.
+ REGISTER_MATCHER1(Callee, Matcher<clang::CallExpr>,
+ const Matcher<clang::Stmt>&);
+ REGISTER_MATCHER1(Callee, Matcher<clang::CallExpr>,
+ const Matcher<clang::Decl>&);
+
+ // PointsTo is overloaded.
+ REGISTER_MATCHER1(PointsTo, Matcher<clang::QualType>,
+ const Matcher<clang::QualType>&);
+ REGISTER_MATCHER1(PointsTo, Matcher<clang::QualType>,
+ const Matcher<clang::Decl>&);
+
+ // References is overloaded.
+ REGISTER_MATCHER1(References, Matcher<clang::QualType>,
+ const Matcher<clang::QualType>&);
+ REGISTER_MATCHER1(References, Matcher<clang::QualType>,
+ const Matcher<clang::Decl>&);
+
+ // Some hardcoded marshallers
+ RegisterMatcher("allOf", new internal::MatcherMarshallAllOf, Data);
+ RegisterMatcher("anyOf", new internal::MatcherMarshallAnyOf, Data);
+
+ return Data;
+}
+
+// The registry is const to make it thread-safe.
+static const RegistryMaps* const RegistryData = RegisterMatchers();
+
+} // anonymous namespace
+
+// static
+GenericValue Registry::constructMatcher(
+ const std::string& MatcherName,
+ const std::vector<GenericValue>& Args) {
+ ConstructorMap::const_iterator it =
+ RegistryData->Constructors.find(MatcherName);
+ if (it == RegistryData->Constructors.end()) {
+ return GenericError("Not found: " + MatcherName);
+ }
+
+ return it->second->run(Args);
+}
+
+// static
+const std::string* Registry::getTypeMatcherName(const std::string& TypeName) {
+ KindNameMap::const_iterator it = RegistryData->KindNames.find(TypeName);
+ if (it == RegistryData->KindNames.end()) return NULL;
+ return &it->second;
+}
+
+// static
+bool Registry::isKindName(const std::string& MatcherName) {
+ return RegistryData->AllKinds.count(MatcherName);
+}
+
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
Propchange: cfe/branches/tooling/lib/ASTMatchers/Dynamic/Registry.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: cfe/branches/tooling/lib/ASTMatchers/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/ASTMatchers/Makefile?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/lib/ASTMatchers/Makefile (original)
+++ cfe/branches/tooling/lib/ASTMatchers/Makefile Tue May 29 09:10:54 2012
@@ -10,4 +10,6 @@
CLANG_LEVEL := ../..
LIBRARYNAME := clangASTMatchers
+PARALLEL_DIRS = Dynamic
+
include $(CLANG_LEVEL)/Makefile
Modified: cfe/branches/tooling/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/tools/CMakeLists.txt?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/tools/CMakeLists.txt (original)
+++ cfe/branches/tooling/tools/CMakeLists.txt Tue May 29 09:10:54 2012
@@ -5,6 +5,7 @@
add_subdirectory(diagtool)
add_subdirectory(driver)
add_subdirectory(clang-check)
+add_subdirectory(ast-query)
add_subdirectory(remove-cstr-calls)
add_subdirectory(fix-llvm-style)
add_subdirectory(rename)
Modified: cfe/branches/tooling/tools/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/tools/Makefile?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/tools/Makefile (original)
+++ cfe/branches/tooling/tools/Makefile Tue May 29 09:10:54 2012
@@ -9,7 +9,7 @@
CLANG_LEVEL := ..
DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
- clang-check remove-cstr-calls
+ clang-check remove-cstr-calls ast-query
include $(CLANG_LEVEL)/../../Makefile.config
Added: cfe/branches/tooling/tools/ast-query/ASTQuery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/tools/ast-query/ASTQuery.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/tools/ast-query/ASTQuery.cpp (added)
+++ cfe/branches/tooling/tools/ast-query/ASTQuery.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,215 @@
+//===- tools/ast-query/ASTQuery.cpp - Command line tool to query the AST ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file implements a tool to query the AST of a compilation unit by using
+// the matcher syntax.
+//
+// Usage:
+// ast-query <matcher> <cmake-output-dir> <file1> <file2> ...
+//
+// Where <matcher> is a string representing the AST Matcher that will be run
+// over the compilation unit.
+//
+// <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use find all calls to a function <func> on all files in a
+// subtree of the source tree, use:
+//
+// /path/in/subtree $ ast-query "Call(Callee(HasName(\"func\")))" \
+// /path/to/build $(find . -name '*.cpp')
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "llvm/Support/CommandLine.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/Dynamic/GenericMatcher.h"
+#include "clang/ASTMatchers/Dynamic/GenericValue.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Tooling.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace llvm;
+
+namespace {
+
+template <typename T>
+std::string GetFilePath(const SourceManager& SourceManager,
+ const T& Node) {
+ SourceLocation Location = Node.getLocStart();
+ static const char InvalidLocation[] = "<nofile>";
+ if (Location.isInvalid()) {
+ return InvalidLocation;
+ }
+
+ const FileEntry* Entry = SourceManager.getFileEntryForID(
+ SourceManager.getFileID(SourceManager.getSpellingLoc(Location)));
+ std::string FileName = Entry ? Entry->getName() : InvalidLocation;
+ return FileName + ":";
+}
+
+template <typename T>
+std::string GetPositionString(const SourceManager& SourceManager,
+ const T& Node) {
+ SourceLocation StartLocation = Node.getLocStart();
+ StartLocation = StartLocation.isMacroID() ?
+ SourceManager.getExpansionLoc(StartLocation) :
+ SourceManager.getSpellingLoc(StartLocation);
+
+ if (!StartLocation.isValid()) return std::string();
+
+ PresumedLoc StartPresumed = SourceManager.getPresumedLoc(StartLocation);
+
+ return (llvm::Twine(StartPresumed.getLine()) + ":" +
+ llvm::Twine(StartPresumed.getColumn()) + ": ").str();
+}
+
+// Returns the text that makes up 'node' in the source.
+// Returns an empty string if the text cannot be found.
+template <typename T>
+std::string GetText(const SourceManager& SourceManager, const T& Node) {
+ SourceLocation StartSpellingLocation =
+ SourceManager.getSpellingLoc(Node.getLocStart());
+ SourceLocation EndSpellingLocation =
+ SourceManager.getSpellingLoc(Node.getLocEnd());
+ if (!StartSpellingLocation.isValid() || !EndSpellingLocation.isValid()) {
+ return std::string();
+ }
+ bool Invalid = true;
+ const char* Text =
+ SourceManager.getCharacterData(StartSpellingLocation, &Invalid);
+ if (Invalid) {
+ return std::string();
+ }
+ std::pair<FileID, unsigned> Start =
+ SourceManager.getDecomposedLoc(StartSpellingLocation);
+ std::pair<FileID, unsigned> End =
+ SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
+ EndSpellingLocation, 0, SourceManager, LangOptions()));
+ if (Start.first != End.first) {
+ // Start and end are in different files.
+ return std::string();
+ }
+ if (End.second < Start.second) {
+ // Shuffling text with macros may cause this.
+ return std::string();
+ }
+ std::string Line = std::string(Text, End.second - Start.second);
+ const size_t EndOfLine = Line.find("\n");
+ if (EndOfLine != Line.npos) {
+ Line = Line.substr(0, EndOfLine);
+ }
+ return Line;
+}
+
+class RegistryProcessor : public dynamic::Parser::TokenProcessor {
+ public:
+ virtual ~RegistryProcessor() {}
+ dynamic::GenericValue processMatcherToken(
+ llvm::StringRef MatcherName,
+ const std::vector<dynamic::GenericValue>& Args,
+ const dynamic::Parser::TokenInfo& Info) {
+ return dynamic::Registry::constructMatcher(MatcherName, Args);
+ }
+};
+
+dynamic::GenericValue AddIdNode(const dynamic::GenericValue& Value) {
+ std::vector<dynamic::GenericValue> Args;
+ Args.push_back(std::string("__toplevel__"));
+ Args.push_back(Value);
+ return dynamic::Registry::constructMatcher("Id", Args);
+}
+
+class ReportTopLevel : public ast_matchers::MatchFinder::MatchCallback {
+ public:
+ virtual ~ReportTopLevel() {}
+ virtual void run(const MatchFinder::MatchResult& Result) {
+ if (const Decl* Node = Result.Nodes.getDeclAs<Decl>("__toplevel__")) {
+ ReportNode(*Result.SourceManager, *Node);
+ }
+ if (const Stmt* Node = Result.Nodes.getStmtAs<Stmt>("__toplevel__")) {
+ ReportNode(*Result.SourceManager, *Node);
+ }
+ }
+
+ private:
+ template <typename NodeType>
+ void ReportNode(const SourceManager& SourceManager, const NodeType& Node) {
+ std::cout << GetFilePath(SourceManager, Node)
+ << GetPositionString(SourceManager, Node)
+ << GetText(SourceManager, Node)
+ << std::endl;
+ }
+};
+
+} // end anonymous namespace
+
+cl::opt<std::string> MatcherCode(
+ cl::Positional,
+ cl::desc("<matcher-code>"));
+
+cl::opt<std::string> BuildPath(
+ cl::Positional,
+ cl::desc("<build-path>"));
+
+cl::list<std::string> SourcePaths(
+ cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+int main(int argc, const char **argv) {
+ llvm::OwningPtr<CompilationDatabase> Compilations(
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ cl::ParseCommandLineOptions(argc, argv);
+ if (!Compilations) {
+ std::string ErrorMessage;
+ Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
+ ErrorMessage));
+ if (!Compilations)
+ llvm::report_fatal_error(ErrorMessage);
+ }
+
+ RegistryProcessor Processor;
+ const dynamic::GenericValue Value = AddIdNode(
+ dynamic::Parser::parseMatcher(MatcherCode, &Processor));
+ if (Value.is<dynamic::GenericError>()) {
+ std::cerr << Value.get<dynamic::GenericError>().Message << std::endl;
+ return 1;
+ } else if (!Value.is<dynamic::GenericMatcher>()) {
+ std::cerr << "Invalid matcher code.";
+ return 1;
+ }
+
+ tooling::ClangTool Tool(*Compilations, SourcePaths);
+ ast_matchers::MatchFinder Finder;
+ Finder.addMatcher(Value.get<internal::Matcher<clang::Decl> >(),
+ new ReportTopLevel());
+ Finder.addMatcher(Value.get<internal::Matcher<clang::Stmt> >(),
+ new ReportTopLevel());
+ return Tool.run(newFrontendActionFactory(&Finder));
+}
Propchange: cfe/branches/tooling/tools/ast-query/ASTQuery.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/tools/ast-query/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/tools/ast-query/CMakeLists.txt?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/tools/ast-query/CMakeLists.txt (added)
+++ cfe/branches/tooling/tools/ast-query/CMakeLists.txt Tue May 29 09:10:54 2012
@@ -0,0 +1,6 @@
+set(LLVM_USED_LIBS clangTooling clangBasic clangAST clangASTMatchers
+ clangDynamicASTMatchers)
+
+add_clang_executable(ast-query
+ ASTQuery.cpp
+ )
Propchange: cfe/branches/tooling/tools/ast-query/CMakeLists.txt
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/tools/ast-query/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/tools/ast-query/Makefile?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/tools/ast-query/Makefile (added)
+++ cfe/branches/tooling/tools/ast-query/Makefile Tue May 29 09:10:54 2012
@@ -0,0 +1,24 @@
+##===- tools/ast-query/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+
+TOOLNAME = ast-query
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangDynamicASTMatchers.a \
+ clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
Propchange: cfe/branches/tooling/tools/ast-query/Makefile
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.cpp Tue May 29 09:10:54 2012
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ASTMatchersTest.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
@@ -15,108 +16,6 @@
namespace clang {
namespace ast_matchers {
-using clang::tooling::runToolOnCode;
-
-class BoundNodesCallback {
-public:
- virtual ~BoundNodesCallback() {}
- virtual bool run(const BoundNodes *BoundNodes) = 0;
-};
-
-// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
-// running 'FindResultVerifier' with the bound nodes as argument.
-// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
-class VerifyMatch : public MatchFinder::MatchCallback {
-public:
- VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
- : Verified(Verified), FindResultReviewer(FindResultVerifier) {}
-
- virtual void run(const MatchFinder::MatchResult &Result) {
- if (FindResultReviewer != NULL) {
- *Verified = FindResultReviewer->run(&Result.Nodes);
- } else {
- *Verified = true;
- }
- }
-
-private:
- bool *const Verified;
- BoundNodesCallback *const FindResultReviewer;
-};
-
-template <typename T>
-testing::AssertionResult matchesConditionally(const std::string &Code,
- const T &AMatcher,
- bool ExpectMatch) {
- bool Found = false;
- MatchFinder Finder;
- VerifyMatch Callback(0, &Found);
- Finder.addMatcher(AMatcher, &Callback);
- if (!runToolOnCode(Finder.newFrontendAction(), Code)) {
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
- }
- if (!Found && ExpectMatch) {
- return testing::AssertionFailure()
- << "Could not find match in \"" << Code << "\"";
- } else if (Found && !ExpectMatch) {
- return testing::AssertionFailure()
- << "Found unexpected match in \"" << Code << "\"";
- }
- return testing::AssertionSuccess();
-}
-
-template <typename T>
-testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, true);
-}
-
-template <typename T>
-testing::AssertionResult notMatches(const std::string &Code,
- const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, false);
-}
-
-template <typename T>
-testing::AssertionResult
-matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
- BoundNodesCallback *FindResultVerifier,
- bool ExpectResult) {
- llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
- bool VerifiedResult = false;
- MatchFinder Finder;
- VerifyMatch Callback(FindResultVerifier, &VerifiedResult);
- Finder.addMatcher(AMatcher, &Callback);
- if (!runToolOnCode(Finder.newFrontendAction(), Code)) {
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
- }
- if (!VerifiedResult && ExpectResult) {
- return testing::AssertionFailure()
- << "Could not verify result in \"" << Code << "\"";
- } else if (VerifiedResult && !ExpectResult) {
- return testing::AssertionFailure()
- << "Verified unexpected result in \"" << Code << "\"";
- }
- return testing::AssertionSuccess();
-}
-
-// FIXME: Find better names for these functions (or document what they
-// do more precisely).
-template <typename T>
-testing::AssertionResult
-matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher,
- BoundNodesCallback *FindResultVerifier) {
- return matchAndVerifyResultConditionally(
- Code, AMatcher, FindResultVerifier, true);
-}
-
-template <typename T>
-testing::AssertionResult
-matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher,
- BoundNodesCallback *FindResultVerifier) {
- return matchAndVerifyResultConditionally(
- Code, AMatcher, FindResultVerifier, false);
-}
-
TEST(HasNameDeathTest, DiesOnEmptyName) {
ASSERT_DEBUG_DEATH({
DeclarationMatcher HasEmptyName = Class(HasName(""));
@@ -2077,5 +1976,5 @@
Class(IsTemplateInstantiation())));
}
-} // end namespace tooling
+} // end namespace ast_matchers
} // end namespace clang
Added: cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h Tue May 29 09:10:54 2012
@@ -0,0 +1,124 @@
+//===- unittest/Tooling/ASTMatchersTest.h - Matcher tests helpers ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::runToolOnCode;
+
+class BoundNodesCallback {
+public:
+ virtual ~BoundNodesCallback() {}
+ virtual bool run(const BoundNodes *BoundNodes) = 0;
+};
+
+// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
+// running 'FindResultVerifier' with the bound nodes as argument.
+// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
+class VerifyMatch : public MatchFinder::MatchCallback {
+public:
+ VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
+ : Verified(Verified), FindResultReviewer(FindResultVerifier) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ if (FindResultReviewer != NULL) {
+ *Verified = FindResultReviewer->run(&Result.Nodes);
+ } else {
+ *Verified = true;
+ }
+ }
+
+private:
+ bool *const Verified;
+ BoundNodesCallback *const FindResultReviewer;
+};
+
+template <typename T>
+testing::AssertionResult matchesConditionally(const std::string &Code,
+ const T &AMatcher,
+ bool ExpectMatch) {
+ bool Found = false;
+ MatchFinder Finder;
+ Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
+ if (!runToolOnCode(Finder.newFrontendAction(), Code)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (!Found && ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Could not find match in \"" << Code << "\"";
+ } else if (Found && !ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Found unexpected match in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, true);
+}
+
+template <typename T>
+testing::AssertionResult notMatches(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, false);
+}
+
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier,
+ bool ExpectResult) {
+ llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
+ bool VerifiedResult = false;
+ MatchFinder Finder;
+ Finder.addMatcher(
+ AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
+ if (!runToolOnCode(Finder.newFrontendAction(), Code)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (!VerifiedResult && ExpectResult) {
+ return testing::AssertionFailure()
+ << "Could not verify result in \"" << Code << "\"";
+ } else if (VerifiedResult && !ExpectResult) {
+ return testing::AssertionFailure()
+ << "Verified unexpected result in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+// FIXME: Find better names for these functions (or document what they
+// do more precisely).
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier) {
+ return matchAndVerifyResultConditionally(
+ Code, AMatcher, FindResultVerifier, true);
+}
+
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier) {
+ return matchAndVerifyResultConditionally(
+ Code, AMatcher, FindResultVerifier, false);
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
Propchange: cfe/branches/tooling/unittests/ASTMatchers/ASTMatchersTest.h
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,108 @@
+//===- unittest/ASTMatchers/Dynamic/GenericMatcherTest.cpp - GenericMatcher unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------------===//
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/GenericMatcher.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+testing::AssertionResult MatchesGeneric(const std::string& Code,
+ const GenericMatcher& Generic) {
+ if (matches(Code, Generic.getAs<clang::Decl>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Generic.getAs<clang::Stmt>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Generic.getAs<clang::QualType>())) {
+ return testing::AssertionSuccess();
+ }
+ return testing::AssertionFailure();
+}
+
+TEST(GeneicMatcherTest, SingleNode) {
+ EXPECT_TRUE(MatchesGeneric("class X {};",
+ GenericMatcher(Class(HasName("X")))));
+ EXPECT_TRUE(MatchesGeneric("int x;", GenericMatcher(Variable())));
+ EXPECT_TRUE(MatchesGeneric("int foo() { return 1 + 1; }",
+ GenericMatcher(Function())));
+
+ EXPECT_FALSE(MatchesGeneric("int x;", GenericMatcher(Function())));
+ EXPECT_FALSE(MatchesGeneric("int foo() { return 1 + 1; }",
+ GenericMatcher(DeclarationReference())));
+}
+
+TEST(GeneicMatcherTest, AnyOf) {
+ GenericMatcher Generic(Class(HasName("X")));
+
+ EXPECT_TRUE(MatchesGeneric("class X {};", Generic));
+ EXPECT_FALSE(MatchesGeneric("int x;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int foo() { return 1 + 1; }", Generic));
+
+ Generic = GenericMatcher::anyOf(Generic, Variable());
+
+ EXPECT_TRUE(MatchesGeneric("class X {};", Generic));
+ EXPECT_TRUE(MatchesGeneric("int x;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int foo() { return 1 + 1; }", Generic));
+
+ // We can mix different types of matchers (statements and declarations)
+ Generic = GenericMatcher::anyOf(Generic,
+ BinaryOperator(HasOperatorName("+")));
+
+ EXPECT_TRUE(MatchesGeneric("class X {};", Generic));
+ EXPECT_TRUE(MatchesGeneric("int x;", Generic));
+ EXPECT_TRUE(MatchesGeneric("int foo() { return 1 + 1; }", Generic));
+}
+
+TEST(GeneicMatcherTest, AllOf) {
+ GenericMatcher Generic(BinaryOperator(HasOperatorName("+")));
+
+ EXPECT_TRUE(MatchesGeneric("int i = 1 + 1;", Generic));
+ EXPECT_TRUE(MatchesGeneric("int i = 2 + 1;", Generic));
+ EXPECT_TRUE(MatchesGeneric("int i = 1 + 3;", Generic));
+ EXPECT_FALSE(MatchesGeneric("void foo() { }", Generic));
+
+ Generic = GenericMatcher::allOf(
+ Generic,
+ BinaryOperator(HasLHS(IntegerLiteral(Equals(1)))));
+
+ EXPECT_TRUE( MatchesGeneric("int i = 1 + 1;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", Generic));
+ EXPECT_TRUE( MatchesGeneric("int i = 1 + 3;", Generic));
+ EXPECT_FALSE(MatchesGeneric("void foo() { }", Generic));
+
+ Generic = GenericMatcher::allOf(
+ Generic,
+ BinaryOperator(HasRHS(IntegerLiteral(Equals(3)))));
+
+ EXPECT_FALSE(MatchesGeneric("int i = 1 + 1;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", Generic));
+ EXPECT_TRUE( MatchesGeneric("int i = 1 + 3;", Generic));
+ EXPECT_FALSE(MatchesGeneric("void foo() { }", Generic));
+
+ Generic = GenericMatcher::allOf(Generic, Function());
+ // Now nothing matches. Not even the function one because it is an AllOf().
+
+ EXPECT_FALSE(MatchesGeneric("int i = 1 + 1;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", Generic));
+ EXPECT_FALSE(MatchesGeneric("int i = 1 + 3;", Generic));
+ EXPECT_FALSE(MatchesGeneric("void foo() { }", Generic));
+
+ // Still no match, because it has to match all of it on the same node.
+ EXPECT_FALSE(MatchesGeneric("int foo() { return 1 + 3; }", Generic));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericMatcherTest.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,151 @@
+//===- unittest/ASTMatchers/Dynamic/GenericValueTest.cpp - GenericValue unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/GenericValue.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+TEST(GenericValueTest, String) {
+ const ::std::string kString = "string";
+ GenericValue Value = kString;
+
+ EXPECT_TRUE(Value.is< ::std::string>());
+ EXPECT_EQ(kString, Value.get< ::std::string>());
+
+ EXPECT_FALSE(Value.is<GenericError>());
+ EXPECT_FALSE(Value.is<bool>());
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_FALSE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_FALSE(Value.is<Matcher<clang::UnaryOperator> >());
+ EXPECT_FALSE(Value.is<NumberHolder>());
+ EXPECT_FALSE(Value.is<int>());
+ EXPECT_FALSE(Value.is<double>());
+}
+
+TEST(GenericValueTest, GenericError) {
+ const ::std::string kString = "string";
+ GenericValue Value = GenericError(kString);
+
+ EXPECT_FALSE(Value.is< ::std::string>());
+
+ EXPECT_TRUE(Value.is<GenericError>());
+ EXPECT_EQ(kString, Value.get<GenericError>().Message);
+
+ EXPECT_FALSE(Value.is<bool>());
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_FALSE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_FALSE(Value.is<Matcher<clang::UnaryOperator> >());
+ EXPECT_FALSE(Value.is<NumberHolder>());
+ EXPECT_FALSE(Value.is<int>());
+ EXPECT_FALSE(Value.is<double>());
+}
+
+TEST(GenericValueTest, Bool) {
+ GenericValue Value = true;
+
+ EXPECT_FALSE(Value.is< ::std::string>());
+ EXPECT_FALSE(Value.is<GenericError>());
+
+ EXPECT_TRUE(Value.is<bool>());
+ EXPECT_EQ(true, Value.get<bool>());
+
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_FALSE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_FALSE(Value.is<Matcher<clang::UnaryOperator> >());
+ EXPECT_FALSE(Value.is<NumberHolder>());
+ EXPECT_FALSE(Value.is<int>());
+ EXPECT_FALSE(Value.is<double>());
+}
+
+TEST(GenericValueTest, GenericMatcher) {
+ GenericValue Value = Statement();
+
+ EXPECT_FALSE(Value.is< ::std::string>());
+ EXPECT_FALSE(Value.is<GenericError>());
+ EXPECT_FALSE(Value.is<bool>());
+
+ EXPECT_TRUE(Value.is<GenericMatcher>());
+ EXPECT_TRUE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_TRUE(Value.is<Matcher<clang::UnaryOperator> >());
+
+ EXPECT_FALSE(Value.is<NumberHolder>());
+ EXPECT_FALSE(Value.is<int>());
+ EXPECT_FALSE(Value.is<double>());
+
+ // Conversion to any type of matcher works.
+ // If they are not compatible it would just return a matcher that matches
+ // nothing. That is tested in GenericMatcher's unittest.
+ Value = GenericMatcher(Class());
+ EXPECT_TRUE(Value.is<GenericMatcher>());
+ EXPECT_TRUE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_TRUE(Value.is<Matcher<clang::UnaryOperator> >());
+
+ Value = GenericMatcher(UnaryOperator());
+ EXPECT_TRUE(Value.is<GenericMatcher>());
+ EXPECT_TRUE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_TRUE(Value.is<Matcher<clang::Stmt> >());
+ EXPECT_TRUE(Value.is<Matcher<clang::UnaryOperator> >());
+}
+
+TEST(GenericValueTest, NumberHolder) {
+ GenericValue Value = NumberHolder(0);
+
+ EXPECT_FALSE(Value.is< ::std::string>());
+ EXPECT_FALSE(Value.is<GenericError>());
+ EXPECT_FALSE(Value.is<bool>());
+
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_FALSE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_FALSE(Value.is<Matcher<clang::UnaryOperator> >());
+
+ EXPECT_TRUE(Value.is<NumberHolder>());
+ EXPECT_EQ(0, Value.get<NumberHolder>().get<int>());
+ EXPECT_TRUE(Value.is<int>());
+ EXPECT_EQ(0, Value.get<int>());
+ EXPECT_TRUE(Value.is<double>());
+ EXPECT_EQ(0.0, Value.get<double>());
+
+ // Conversions
+ Value = NumberHolder(1.1);
+ EXPECT_TRUE(Value.is<NumberHolder>());
+ EXPECT_EQ(1.1, Value.get<NumberHolder>().get<double>());
+ EXPECT_FALSE(Value.is<int>());
+ EXPECT_TRUE(Value.is<double>());
+ EXPECT_EQ(1.1, Value.get<double>());
+}
+
+TEST(GenericValueTest, Assignment) {
+ GenericValue Value = true;
+ EXPECT_TRUE(Value.is<bool>());
+ EXPECT_EQ(true, Value.get<bool>());
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_FALSE(Value.is<GenericError>());
+
+ Value = GenericError("foo");
+ EXPECT_FALSE(Value.is<bool>());
+ EXPECT_FALSE(Value.is<GenericMatcher>());
+ EXPECT_TRUE(Value.is<GenericError>());
+ EXPECT_EQ("foo", Value.get<GenericError>().Message);
+
+ Value = GenericMatcher(Class());
+ EXPECT_FALSE(Value.is<bool>());
+ EXPECT_TRUE(Value.is<GenericMatcher>());
+ EXPECT_TRUE(Value.is<Matcher<clang::Decl> >());
+ EXPECT_TRUE(Value.is<Matcher<clang::UnaryOperator> >());
+ EXPECT_FALSE(Value.is<GenericError>());
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/GenericValueTest.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile Tue May 29 09:10:54 2012
@@ -0,0 +1,18 @@
+##===- unittests/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../../..
+TESTNAME = DynamicASTMatchers
+LINK_COMPONENTS := support mc
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a \
+ clangDynamicASTMatchers.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/Makefile
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,222 @@
+//===- unittest/ASTMatchers/Dynamic/NumberHolderTest.cpp - NumberHolder unit tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===------------------------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/NumberHolder.h"
+
+#include <limits>
+
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+TEST(NumberHolderTest, CanCovertBetweenTypes) {
+ // Every type can represent 123.
+ const int32_t Expected = 123;
+ NumberHolder Holder(Expected);
+
+ EXPECT_TRUE(Holder.is<int8_t>());
+ EXPECT_EQ(Expected, Holder.get<int8_t>());
+
+ EXPECT_TRUE(Holder.is<int16_t>());
+ EXPECT_EQ(Expected, Holder.get<int16_t>());
+
+ EXPECT_TRUE(Holder.is<int32_t>());
+ EXPECT_EQ(Expected, Holder.get<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(Expected, Holder.get<int64_t>());
+
+ EXPECT_TRUE(Holder.is<uint8_t>());
+ EXPECT_EQ(Expected, Holder.get<uint8_t>());
+
+ EXPECT_TRUE(Holder.is<uint16_t>());
+ EXPECT_EQ(Expected, Holder.get<uint16_t>());
+
+ EXPECT_TRUE(Holder.is<uint32_t>());
+ EXPECT_EQ(static_cast<uint32_t>(Expected), Holder.get<uint32_t>());
+
+ EXPECT_TRUE(Holder.is<uint64_t>());
+ EXPECT_EQ(static_cast<uint64_t>(Expected), Holder.get<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+TEST(NumberHolderTest, NegativeValues) {
+ // Only signed types can represent -123.
+ const int32_t Expected = -123;
+ NumberHolder Holder(Expected);
+
+ EXPECT_TRUE(Holder.is<int8_t>());
+ EXPECT_EQ(Expected, Holder.get<int8_t>());
+
+ EXPECT_TRUE(Holder.is<int16_t>());
+ EXPECT_EQ(Expected, Holder.get<int16_t>());
+
+ EXPECT_TRUE(Holder.is<int32_t>());
+ EXPECT_EQ(Expected, Holder.get<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(Expected, Holder.get<int64_t>());
+
+ EXPECT_FALSE(Holder.is<uint8_t>());
+ EXPECT_FALSE(Holder.is<uint16_t>());
+ EXPECT_FALSE(Holder.is<uint32_t>());
+ EXPECT_FALSE(Holder.is<unsigned long>());
+ EXPECT_FALSE(Holder.is<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+TEST(NumberHolderTest, SignedOverflow) {
+ // Overflow int16_t. Value is still a valid uint16_t.
+ const uint64_t Expected = std::numeric_limits<int16_t>::max() + 1LL;
+ NumberHolder Holder(Expected);
+
+ EXPECT_FALSE(Holder.is<int8_t>());
+ EXPECT_FALSE(Holder.is<int16_t>());
+
+ EXPECT_TRUE(Holder.is<int32_t>());
+ EXPECT_EQ(static_cast<int32_t>(Expected), Holder.get<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(static_cast<int64_t>(Expected), Holder.get<int64_t>());
+
+ EXPECT_FALSE(Holder.is<uint8_t>());
+
+ EXPECT_TRUE(Holder.is<uint16_t>());
+ EXPECT_EQ(Expected, Holder.get<uint16_t>());
+
+ EXPECT_TRUE(Holder.is<uint32_t>());
+ EXPECT_EQ(Expected, Holder.get<uint32_t>());
+
+ EXPECT_TRUE(Holder.is<uint64_t>());
+ EXPECT_EQ(Expected, Holder.get<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+TEST(NumberHolderTest, UnsignedOverflow) {
+ // Overflow everything up to uint32_t.
+ const uint64_t Expected = std::numeric_limits<uint32_t>::max() + 1LL;
+ NumberHolder Holder(Expected);
+
+ EXPECT_FALSE(Holder.is<int8_t>());
+ EXPECT_FALSE(Holder.is<int16_t>());
+ EXPECT_FALSE(Holder.is<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(static_cast<int64_t>(Expected), Holder.get<int64_t>());
+
+ EXPECT_FALSE(Holder.is<uint8_t>());
+ EXPECT_FALSE(Holder.is<uint16_t>());
+ EXPECT_FALSE(Holder.is<uint32_t>());
+
+ EXPECT_TRUE(Holder.is<uint64_t>());
+ EXPECT_EQ(Expected, Holder.get<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+TEST(NumberHolderTest, DoubleOverflow) {
+ // Overflow a double using a very large integer.
+ const int64_t Expected = std::numeric_limits<int64_t>::max();
+ NumberHolder Holder(Expected);
+
+ EXPECT_FALSE(Holder.is<int8_t>());
+ EXPECT_FALSE(Holder.is<int16_t>());
+ EXPECT_FALSE(Holder.is<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(Expected, Holder.get<int64_t>());
+
+ EXPECT_FALSE(Holder.is<uint8_t>());
+ EXPECT_FALSE(Holder.is<uint16_t>());
+ EXPECT_FALSE(Holder.is<uint32_t>());
+
+ EXPECT_TRUE(Holder.is<uint64_t>());
+ EXPECT_EQ(static_cast<uint64_t>(Expected), Holder.get<uint64_t>());
+
+ EXPECT_FALSE(Holder.is<float>());
+ EXPECT_FALSE(Holder.is<double>());
+}
+
+TEST(NumberHolderTest, FloatingPoint) {
+ // No integer should accept a floating point.
+ const double Expected = 1.5;
+ NumberHolder Holder(Expected);
+
+ EXPECT_FALSE(Holder.is<int8_t>());
+ EXPECT_FALSE(Holder.is<int16_t>());
+ EXPECT_FALSE(Holder.is<int32_t>());
+ EXPECT_FALSE(Holder.is<int64_t>());
+ EXPECT_FALSE(Holder.is<uint8_t>());
+ EXPECT_FALSE(Holder.is<uint16_t>());
+ EXPECT_FALSE(Holder.is<uint32_t>());
+ EXPECT_FALSE(Holder.is<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+TEST(NumberHolderTest, NotReallyFloatingPoint) {
+ // If the double is not really a floating point, then we accept it as ints.
+ const double Expected = 1234e5;
+ NumberHolder Holder(Expected);
+
+ EXPECT_FALSE(Holder.is<int8_t>());
+ EXPECT_FALSE(Holder.is<int16_t>());
+
+ EXPECT_TRUE(Holder.is<int32_t>());
+ EXPECT_EQ(Expected, Holder.get<int32_t>());
+
+ EXPECT_TRUE(Holder.is<int64_t>());
+ EXPECT_EQ(Expected, Holder.get<int64_t>());
+
+ EXPECT_FALSE(Holder.is<uint8_t>());
+ EXPECT_FALSE(Holder.is<uint16_t>());
+
+ EXPECT_TRUE(Holder.is<uint32_t>());
+ EXPECT_EQ(Expected, Holder.get<uint32_t>());
+
+ EXPECT_TRUE(Holder.is<uint64_t>());
+ EXPECT_EQ(Expected, Holder.get<uint64_t>());
+
+ EXPECT_TRUE(Holder.is<float>());
+ EXPECT_EQ(Expected, Holder.get<float>());
+
+ EXPECT_TRUE(Holder.is<double>());
+ EXPECT_EQ(Expected, Holder.get<double>());
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/NumberHolderTest.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,215 @@
+//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+class ValueProcessor : public Parser::TokenProcessor {
+ public:
+ virtual ~ValueProcessor() { }
+
+ void Parse(const std::string& Code) {
+ const GenericValue Value = Parser::parseMatcher(Code, this);
+ if (Value.is<GenericError>()) {
+ ValueInfo ToStore = { Value, Parser::TokenInfo() };
+ Values.push_back(ToStore);
+ }
+ }
+
+ GenericValue processValueToken(const GenericValue& Value,
+ const Parser::TokenInfo& Info) {
+ ValueInfo ToStore = { Value, Info };
+ Values.push_back(ToStore);
+ return Value;
+ }
+ GenericValue processMatcherToken(
+ llvm::StringRef MatcherName,
+ const std::vector<GenericValue>& Args,
+ const Parser::TokenInfo& Info) {
+ MatcherInfo ToStore = { MatcherName, Info, Args };
+ Matchers.push_back(ToStore);
+ // Return the matcher name with a special format to be able to EXPECT_EQ
+ // down there. No reason to actually create matchers here.
+ return GenericValue("__" + MatcherName.str() + "__");
+ }
+
+ struct ValueInfo {
+ GenericValue Value;
+ Parser::TokenInfo Info;
+ };
+ struct MatcherInfo {
+ std::string MatcherName;
+ Parser::TokenInfo Info;
+ std::vector<GenericValue> Args;
+ };
+
+ std::vector<ValueInfo> Values;
+ std::vector<MatcherInfo> Matchers;
+};
+
+TEST(ParserTest, ParseString) {
+ ValueProcessor Processor;
+ Processor.Parse("\"Foo\"");
+ Processor.Parse("\"F\\\"o o\\n\"");
+ Processor.Parse("\"\"");
+ Processor.Parse("\"Baz");
+ EXPECT_EQ(4ULL, Processor.Values.size());
+ EXPECT_EQ("Foo", Processor.Values[0].Value.get<std::string>());
+ EXPECT_EQ("F\"o o\n", Processor.Values[1].Value.get<std::string>());
+ EXPECT_EQ("", Processor.Values[2].Value.get<std::string>());
+ EXPECT_EQ("Error parsing string token: <\"Baz>",
+ Processor.Values[3].Value.get<GenericError>().Message);
+}
+
+TEST(ParserTest, ParseChar) {
+ ValueProcessor Processor;
+ Processor.Parse("'a'");
+ Processor.Parse("'^'");
+ Processor.Parse("'\\n'");
+ Processor.Parse("'aa'");
+ Processor.Parse("'6");
+ Processor.Parse("' '");
+ Processor.Parse("','");
+ EXPECT_EQ(7ULL, Processor.Values.size());
+ EXPECT_EQ('a', Processor.Values[0].Value.get<int>());
+ EXPECT_EQ('^', Processor.Values[1].Value.get<int>());
+ EXPECT_EQ('\n', Processor.Values[2].Value.get<int>());
+ EXPECT_EQ("Error parsing char token: <'aa'>",
+ Processor.Values[3].Value.get<GenericError>().Message);
+ EXPECT_EQ("Error parsing char token: <'6>",
+ Processor.Values[4].Value.get<GenericError>().Message);
+ EXPECT_EQ(' ', Processor.Values[5].Value.get<int>());
+ EXPECT_EQ(',', Processor.Values[6].Value.get<int>());
+}
+
+TEST(ParserTest, ParseNumber) {
+ ValueProcessor Processor;
+ Processor.Parse("123456789012345");
+ Processor.Parse("-1234567890123456");
+ Processor.Parse("1.23e5");
+ Processor.Parse("1.234e-5");
+ Processor.Parse("0x5");
+ Processor.Parse("0d3jg#");
+ EXPECT_EQ(6ULL, Processor.Values.size());
+ EXPECT_EQ(123456789012345ULL, Processor.Values[0].Value.get<uint64_t>());
+ EXPECT_EQ(-1234567890123456LL, Processor.Values[1].Value.get<int64_t>());
+ EXPECT_EQ(1.23e5, Processor.Values[2].Value.get<int>());
+ EXPECT_EQ(1.234e-5, Processor.Values[3].Value.get<double>());
+ EXPECT_EQ(0x5, Processor.Values[4].Value.get<char>());
+ EXPECT_EQ("Error parsing number token: <0d3jg#>",
+ Processor.Values[5].Value.get<GenericError>().Message);
+}
+
+TEST(ParserTest, ParseBool) {
+ ValueProcessor Processor;
+ Processor.Parse("true");
+ Processor.Parse("false");
+ EXPECT_EQ(2UL, Processor.Values.size());
+ EXPECT_EQ(true, Processor.Values[0].Value.get<bool>());
+ EXPECT_EQ(false, Processor.Values[1].Value.get<bool>());
+}
+
+bool MatchesInfo(const Parser::TokenInfo& Info,
+ int StartLine, int EndLine, int StartColumn, int EndColumn) {
+ EXPECT_EQ(StartLine, Info.StartLine);
+ EXPECT_EQ(EndLine, Info.EndLine);
+ EXPECT_EQ(StartColumn, Info.StartColumn);
+ EXPECT_EQ(EndColumn, Info.EndColumn);
+ return Info.StartLine == StartLine && Info.EndLine == EndLine &&
+ Info.StartColumn == StartColumn && Info.EndColumn == EndColumn;
+}
+
+TEST(ParserTest, ParseMatcher) {
+ ValueProcessor Processor;
+ Processor.Parse(" Foo ( 1.2, Bar (), Baz( \n \"B \\nA,\\\"Z\"), \ntrue) ");
+ for (size_t i = 0; i < Processor.Values.size(); ++i) {
+ EXPECT_FALSE(Processor.Values[i].Value.is<GenericError>())
+ << Processor.Values[i].Value.get<GenericError>().Message;
+ }
+
+ EXPECT_EQ(3ULL, Processor.Matchers.size());
+ const ValueProcessor::MatcherInfo Bar = Processor.Matchers[0];
+ EXPECT_EQ("Bar", Bar.MatcherName);
+ EXPECT_TRUE(MatchesInfo(Bar.Info, 1, 1, 13, 18));
+ EXPECT_EQ(0ULL, Bar.Args.size());
+
+ const ValueProcessor::MatcherInfo Baz = Processor.Matchers[1];
+ EXPECT_EQ("Baz", Baz.MatcherName);
+ EXPECT_TRUE(MatchesInfo(Baz.Info, 1, 2, 21, 13));
+ EXPECT_EQ(1ULL, Baz.Args.size());
+ EXPECT_EQ("B \nA,\"Z", Baz.Args[0].get<std::string>());
+
+ const ValueProcessor::MatcherInfo Foo = Processor.Matchers[2];
+ EXPECT_EQ("Foo", Foo.MatcherName);
+ EXPECT_TRUE(MatchesInfo(Foo.Info, 1, 3, 2, 5));
+ EXPECT_EQ(4ULL, Foo.Args.size());
+ EXPECT_EQ(1.2, Foo.Args[0].get<double>());
+ EXPECT_EQ("__Bar__", Foo.Args[1].get<std::string>());
+ EXPECT_EQ("__Baz__", Foo.Args[2].get<std::string>());
+ EXPECT_EQ(true, Foo.Args[3].get<bool>());
+}
+
+class RealProcessor : public Parser::TokenProcessor {
+ public:
+ virtual ~RealProcessor() {}
+ GenericValue processMatcherToken(llvm::StringRef MatcherName,
+ const std::vector<GenericValue>& Args,
+ const Parser::TokenInfo& Info) {
+ return Registry::constructMatcher(MatcherName, Args);
+ }
+};
+
+testing::AssertionResult MatchesGeneric(const std::string& Code,
+ const GenericValue& Value) {
+ if (!Value.is<GenericMatcher>())
+ return testing::AssertionFailure();
+ const GenericMatcher Matcher = Value.get<GenericMatcher>();
+ if (matches(Code, Matcher.getAs<clang::Decl>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Matcher.getAs<clang::Stmt>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Matcher.getAs<clang::QualType>())) {
+ return testing::AssertionSuccess();
+ }
+ return testing::AssertionFailure();
+}
+
+TEST(ParserTest, FullParserTest) {
+ RealProcessor Processor;
+ const GenericValue Value = Parser::parseMatcher(
+ "BinaryOperator( HasOperatorName(\"+\"),\n"
+ " HasLHS(IntegerLiteral(Equals(1))))", &Processor);
+ EXPECT_TRUE(MatchesGeneric("int x = 1 + 1;", Value));
+ EXPECT_FALSE(MatchesGeneric("int x = 2 + 1;", Value));
+
+ const GenericValue Error = Parser::parseMatcher(
+ "BinaryOperator( HasOperatorName(6),\n"
+ " HasLHS(IntegerLiteral(Equals(1))))", &Processor);
+ EXPECT_EQ("Error parsing argument 0 for matcher BinaryOperator: "
+ "Error building matcher HasOperatorName: "
+ "Incorrect type on function HasOperatorName for arg 0",
+ Error.get<GenericError>().Message);
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/ParserTest.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Added: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=157622&view=auto
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (added)
+++ cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Tue May 29 09:10:54 2012
@@ -0,0 +1,141 @@
+//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+testing::AssertionResult MatchesGeneric(const std::string& Code,
+ const GenericValue& Value) {
+ if (Value.is<GenericError>()) {
+ EXPECT_EQ("", Value.get<GenericError>().Message);
+ return testing::AssertionFailure();
+ }
+ const GenericMatcher Matcher = Value.get<GenericMatcher>();
+ if (matches(Code, Matcher.getAs<clang::Decl>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Matcher.getAs<clang::Stmt>())) {
+ return testing::AssertionSuccess();
+ }
+ if (matches(Code, Matcher.getAs<clang::QualType>())) {
+ return testing::AssertionSuccess();
+ }
+ return testing::AssertionFailure();
+}
+
+GenericValue ConstructMatcher(const std::string& MatcherName) {
+ const std::vector<GenericValue> Args;
+ return Registry::constructMatcher(MatcherName, Args);
+}
+
+GenericValue ConstructMatcher(const std::string& MatcherName,
+ const GenericValue Arg1) {
+ std::vector<GenericValue> Args;
+ Args.push_back(Arg1);
+ return Registry::constructMatcher(MatcherName, Args);
+}
+
+GenericValue ConstructMatcher(const std::string& MatcherName,
+ const GenericValue Arg1,
+ const GenericValue Arg2) {
+ std::vector<GenericValue> Args;
+ Args.push_back(Arg1);
+ Args.push_back(Arg2);
+ return Registry::constructMatcher(MatcherName, Args);
+}
+
+TEST(RegistryTest, CanConstructNoArgs) {
+ const GenericValue IsArrowValue = ConstructMatcher("IsArrow");
+ const GenericValue BoolValue = ConstructMatcher("BoolLiteral");
+
+ const std::string ClassSnippet =
+ "struct Foo { int x; };\n"
+ "Foo* foo = new Foo;\n"
+ "int i = foo->x;\n";
+ const std::string BoolSnippet = "bool Foo = true;\n";
+
+ EXPECT_TRUE(MatchesGeneric(ClassSnippet, IsArrowValue));
+ EXPECT_TRUE(MatchesGeneric(BoolSnippet, BoolValue));
+ EXPECT_FALSE(MatchesGeneric(ClassSnippet, BoolValue));
+ EXPECT_FALSE(MatchesGeneric(BoolSnippet, IsArrowValue));
+}
+
+TEST(RegistryTest, ConstructWithSimpleArgs) {
+ const GenericValue Value = ConstructMatcher("HasName", std::string("X"));
+ EXPECT_TRUE(MatchesGeneric("class X {};", Value));
+ EXPECT_FALSE(MatchesGeneric("int x;", Value));
+}
+
+TEST(RegistryTest, ContructWithMatcherArgs) {
+ const GenericValue OperatorPlus =
+ ConstructMatcher("HasOperatorName", std::string("+"));
+ const GenericValue OperatorMinus =
+ ConstructMatcher("HasOperatorName", std::string("-"));
+ const GenericValue One =
+ ConstructMatcher("IntegerLiteral", ConstructMatcher("Equals", 1));
+ const GenericValue HasLHSOne = ConstructMatcher("HasLHS", One);
+
+ const GenericValue OnePlus =
+ ConstructMatcher("BinaryOperator", OperatorPlus, HasLHSOne);
+ const GenericValue JustPlus =
+ ConstructMatcher("BinaryOperator", OperatorPlus);
+
+ const GenericValue OneMinus =
+ ConstructMatcher("BinaryOperator", OperatorMinus, HasLHSOne);
+ const GenericValue JustMinus =
+ ConstructMatcher("BinaryOperator", OperatorMinus);
+
+ EXPECT_TRUE( MatchesGeneric("int i = 1 + 1;", OnePlus));
+ EXPECT_TRUE( MatchesGeneric("int i = 1 + 1;", JustPlus));
+ EXPECT_FALSE(MatchesGeneric("int i = 1 + 1;", OneMinus));
+ EXPECT_FALSE(MatchesGeneric("int i = 1 + 1;", JustMinus));
+
+ EXPECT_FALSE(MatchesGeneric("int i = 1 - 1;", OnePlus));
+ EXPECT_FALSE(MatchesGeneric("int i = 1 - 1;", JustPlus));
+ EXPECT_TRUE( MatchesGeneric("int i = 1 - 1;", OneMinus));
+ EXPECT_TRUE( MatchesGeneric("int i = 1 - 1;", JustMinus));
+
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", OnePlus));
+ EXPECT_TRUE( MatchesGeneric("int i = 2 + 1;", JustPlus));
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", OneMinus));
+ EXPECT_FALSE(MatchesGeneric("int i = 2 + 1;", JustMinus));
+}
+
+TEST(RegistryTest, Errors) {
+ // Incorrect argument count.
+ GenericValue BadArgCount = ConstructMatcher("HasBody");
+ EXPECT_EQ("Incorrect argument count on function HasBody. "
+ "(Expected = 1) != (Actual = 0)",
+ BadArgCount.get<GenericError>().Message);
+ BadArgCount = ConstructMatcher("IsArrow", std::string());
+ EXPECT_EQ("Incorrect argument count on function IsArrow. "
+ "(Expected = 0) != (Actual = 1)",
+ BadArgCount.get<GenericError>().Message);
+
+ // Bad argument type
+ GenericValue BadArgType = ConstructMatcher("OfClass", true);
+ EXPECT_EQ("Incorrect type on function OfClass for arg 0",
+ BadArgType.get<GenericError>().Message);
+ BadArgType = ConstructMatcher("Class", Class(), 3);
+ EXPECT_EQ("Incorrect type on function Class for arg 1",
+ BadArgType.get<GenericError>().Message);
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
Propchange: cfe/branches/tooling/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: cfe/branches/tooling/unittests/ASTMatchers/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/ASTMatchers/Makefile?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/unittests/ASTMatchers/Makefile (original)
+++ cfe/branches/tooling/unittests/ASTMatchers/Makefile Tue May 29 09:10:54 2012
@@ -8,6 +8,8 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL = ../..
+PARALLEL_DIRS = Dynamic
+
TESTNAME = ASTMatchers
LINK_COMPONENTS := support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
Modified: cfe/branches/tooling/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/unittests/CMakeLists.txt?rev=157622&r1=157621&r2=157622&view=diff
==============================================================================
--- cfe/branches/tooling/unittests/CMakeLists.txt (original)
+++ cfe/branches/tooling/unittests/CMakeLists.txt Tue May 29 09:10:54 2012
@@ -55,6 +55,15 @@
USED_LIBS gtest gtest_main clangASTMatchers clangTooling
)
+add_clang_unittest(ASTMatchers/Dynamic
+ ASTMatchers/Dynamic/GenericMatcherTest.cpp
+ ASTMatchers/Dynamic/GenericValueTest.cpp
+ ASTMatchers/Dynamic/NumberHolderTest.cpp
+ ASTMatchers/Dynamic/ParserTest.cpp
+ ASTMatchers/Dynamic/RegistryTest.cpp
+ USED_LIBS gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling
+ )
+
add_clang_unittest(Basic
Basic/FileManagerTest.cpp
Basic/SourceManagerTest.cpp
More information about the llvm-branch-commits
mailing list