r181768 - First revision of the dynamic ASTMatcher library.

Manuel Klimek klimek at google.com
Tue May 14 02:13:00 PDT 2013


Author: klimek
Date: Tue May 14 04:13:00 2013
New Revision: 181768

URL: http://llvm.org/viewvc/llvm-project?rev=181768&view=rev
Log:
First revision of the dynamic ASTMatcher library.

This library supports all the features of the compile-time based ASTMatcher
library, but allows the user to specify and construct the matchers at runtime.
It contains the following modules:
 - A variant type, to be used by the matcher factory.
 - A registry, where the matchers are indexed by name and have a factory method
   with a generic signature.
 - A simple matcher expression parser, that can be used to convert a matcher
   expression string into actual matchers that can be used with the AST at
   runtime.

Many features where omitted from this first revision to simplify this code
review. The main ideas are still represented in this change and it already has
support working use cases.
Things that are missing:
 - Support for polymorphic matchers. These requires supporting code in the
   registry, the marshallers and the variant type.
 - Support for numbers, char and bool arguments to the matchers. This requires
   supporting code in the parser and the variant type.
 - A command line program putting everything together and providing an already
   functional tool.

Patch by Samuel Benzaquen.

Added:
    cfe/trunk/include/clang/ASTMatchers/Dynamic/
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
    cfe/trunk/lib/ASTMatchers/Dynamic/
    cfe/trunk/lib/ASTMatchers/Dynamic/CMakeLists.txt
    cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Makefile
      - copied, changed from r181767, cfe/trunk/lib/ASTMatchers/Makefile
    cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/
    cfe/trunk/unittests/ASTMatchers/Dynamic/CMakeLists.txt
    cfe/trunk/unittests/ASTMatchers/Dynamic/Makefile
    cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
    cfe/trunk/lib/ASTMatchers/CMakeLists.txt
    cfe/trunk/lib/ASTMatchers/Makefile
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
    cfe/trunk/unittests/ASTMatchers/CMakeLists.txt
    cfe/trunk/unittests/ASTMatchers/Makefile

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h Tue May 14 04:13:00 2013
@@ -131,6 +131,17 @@ public:
                   MatchCallback *Action);
   /// @}
 
+  /// \brief Adds a matcher to execute when running over the AST.
+  ///
+  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
+  /// is more flexible, but the lost type information enables a caller to pass
+  /// a matcher that cannot match anything.
+  ///
+  /// \returns \c true if the matcher is a valid top-level matcher, \c false
+  ///   otherwise.
+  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+                         MatchCallback *Action);
+
   /// \brief Creates a clang ASTConsumer that finds all matches.
   clang::ASTConsumer *newASTConsumer();
 

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Tue May 14 04:13:00 2013
@@ -239,6 +239,9 @@ public:
                        ASTMatchFinder *Finder,
                        BoundNodesTreeBuilder *Builder) const = 0;
 
+  /// \brief Makes a copy of this matcher object.
+  virtual DynTypedMatcher *clone() const = 0;
+
   /// \brief Returns a unique ID for the matcher.
   virtual uint64_t getID() const = 0;
 };
@@ -301,6 +304,9 @@ public:
     return matches(*Node, Finder, Builder);
   }
 
+  /// \brief Makes a copy of this matcher object.
+  virtual Matcher<T> *clone() const { return new Matcher<T>(*this); }
+
   /// \brief Allows the conversion of a \c Matcher<Type> to a \c
   /// Matcher<QualType>.
   ///

Added: cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h?rev=181768&view=auto
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (added)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Tue May 14 04:13:00 2013
@@ -0,0 +1,109 @@
+//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Diagnostics class to manage error messages.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+struct SourceLocation {
+  SourceLocation() : Line(), Column() {}
+  unsigned Line;
+  unsigned Column;
+};
+
+struct SourceRange {
+  SourceLocation Start;
+  SourceLocation End;
+};
+
+/// \brief A VariantValue instance annotated with its parser context.
+struct ParserValue {
+  ParserValue() : Text(), Range(), Value() {}
+  StringRef Text;
+  SourceRange Range;
+  VariantValue Value;
+};
+
+/// \brief Helper class to manage error messages.
+class Diagnostics {
+ public:
+  /// \brief All errors from the system.
+  enum ErrorType {
+    ET_None = 0,
+
+    ET_RegistryNotFound = 1,
+    ET_RegistryWrongArgCount = 2,
+    ET_RegistryWrongArgType = 3,
+
+    ET_ParserStringError = 100,
+    ET_ParserMatcherArgFailure = 101,
+    ET_ParserMatcherFailure = 102,
+    ET_ParserNoOpenParen = 103,
+    ET_ParserNoCloseParen = 104,
+    ET_ParserNoComma = 105,
+    ET_ParserNoCode = 106,
+    ET_ParserNotAMatcher = 107,
+    ET_ParserInvalidToken = 108
+  };
+
+  /// \brief Helper stream class.
+  struct ArgStream {
+    template <class T> ArgStream &operator<<(const T &Arg) {
+      return operator<<(Twine(Arg));
+    }
+    ArgStream &operator<<(const Twine &Arg);
+    std::vector<std::string> *Out;
+  };
+
+  /// \brief Push a frame to the beginning of the list
+  ///
+  /// Returns a helper class to allow the caller to pass the arguments for the
+  /// error message, using the << operator.
+  ArgStream pushErrorFrame(const SourceRange &Range, ErrorType Error);
+
+  struct ErrorFrame {
+    SourceRange Range;
+    ErrorType Type;
+    std::vector<std::string> Args;
+
+    std::string ToString() const;
+  };
+  ArrayRef<ErrorFrame> frames() const { return Frames; }
+
+  /// \brief Returns a string representation of the last frame.
+  std::string ToString() const;
+  /// \brief Returns a string representation of the whole frame stack.
+  std::string ToStringFull() const;
+
+ private:
+   std::vector<ErrorFrame> Frames;
+};
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang
+
+#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H

Added: cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h?rev=181768&view=auto
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h (added)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h Tue May 14 04:13:00 2013
@@ -0,0 +1,143 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Simple matcher expression parser.
+///
+/// The parser understands matcher expressions of the form:
+///   MatcherName(Arg0, Arg1, ..., ArgN)
+/// as well as simple types like strings.
+/// The parser does not know how to process the matchers. It delegates this task
+/// to a Sema object received as an argument.
+///
+/// \code
+/// Grammar for the expressions supported:
+/// <Expression>        := <StringLiteral> | <MatcherExpression>
+/// <StringLiteral>     := "quoted string"
+/// <MatcherExpression> := <MatcherName>(<ArgumentList>)
+/// <MatcherName>       := [a-zA-Z]+
+/// <ArgumentList>      := <Expression> | <Expression>,<ArgumentList>
+/// \endcode
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+/// \brief Matcher expression parser.
+class Parser {
+public:
+  /// \brief Interface to connect the parser with the registry and more.
+  ///
+  /// The parser uses the Sema instance passed into
+  /// parseMatcherExpression() to handle all matcher tokens. The simplest
+  /// processor implementation would simply call into the registry to create
+  /// the matchers.
+  /// However, a more complex processor might decide to intercept the matcher
+  /// creation and do some extra work. For example, it could apply some
+  /// transformation to the matcher by adding some id() nodes, or could detect
+  /// specific matcher nodes for more efficient lookup.
+  class Sema {
+  public:
+    virtual ~Sema();
+
+    /// \brief Process a matcher expression.
+    ///
+    /// All the arguments passed here have already been processed.
+    ///
+    /// \param MatcherName The matcher name found by the parser.
+    ///
+    /// \param NameRange The location of the name in the matcher source.
+    ///   Useful for error reporting.
+    ///
+    /// \param Args The argument list for the matcher.
+    ///
+    /// \return The matcher object constructed by the processor, or NULL
+    ///   if an error occurred. In that case, \c Error will contain a
+    ///   description of the error.
+    ///   The caller takes ownership of the DynTypedMatcher object returned.
+    virtual DynTypedMatcher *
+    actOnMatcherExpression(StringRef MatcherName, const SourceRange &NameRange,
+                           ArrayRef<ParserValue> Args, Diagnostics *Error) = 0;
+  };
+
+  /// \brief Parse a matcher expression, creating matchers from the registry.
+  ///
+  /// This overload creates matchers calling directly into the registry. If the
+  /// caller needs more control over how the matchers are created, then it can
+  /// use the overload below that takes a Sema.
+  ///
+  /// \param MatcherCode The matcher expression to parse.
+  ///
+  /// \return The matcher object constructed, or NULL if an error occurred.
+  //    In that case, \c Error will contain a description of the error.
+  ///   The caller takes ownership of the DynTypedMatcher object returned.
+  static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode,
+                                                 Diagnostics *Error);
+
+  /// \brief Parse a matcher expression.
+  ///
+  /// \param MatcherCode The matcher expression to parse.
+  ///
+  /// \param S The Sema instance that will help the parser
+  ///   construct the matchers.
+  /// \return The matcher object constructed by the processor, or NULL
+  ///   if an error occurred. In that case, \c Error will contain a
+  ///   description of the error.
+  ///   The caller takes ownership of the DynTypedMatcher object returned.
+  static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode,
+                                                 Sema *S,
+                                                 Diagnostics *Error);
+
+  /// \brief Parse an expression, creating matchers from the registry.
+  ///
+  /// Parses any expression supported by this parser. In general, the
+  /// \c parseMatcherExpression function is a better approach to get a matcher
+  /// object.
+  static bool parseExpression(StringRef Code, VariantValue *Value,
+                              Diagnostics *Error);
+
+  /// \brief Parse an expression.
+  ///
+  /// Parses any expression supported by this parser. In general, the
+  /// \c parseMatcherExpression function is a better approach to get a matcher
+  /// object.
+  static bool parseExpression(StringRef Code, Sema *S,
+                              VariantValue *Value, Diagnostics *Error);
+
+private:
+  class CodeTokenizer;
+  struct TokenInfo;
+
+  Parser(CodeTokenizer *Tokenizer, Sema *S,
+         Diagnostics *Error);
+
+  bool parseExpressionImpl(VariantValue *Value);
+  bool parseMatcherExpressionImpl(VariantValue *Value);
+
+  CodeTokenizer *const Tokenizer;
+  Sema *const S;
+  Diagnostics *const Error;
+};
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang
+
+#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H

Added: cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h?rev=181768&view=auto
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h (added)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h Tue May 14 04:13:00 2013
@@ -0,0 +1,63 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief 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 "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+class Registry {
+public:
+  /// \brief Construct a matcher from the registry by name.
+  ///
+  /// Consult the registry of known matchers and construct the appropriate
+  /// matcher by name.
+  ///
+  /// \param MatcherName The name of the matcher to instantiate.
+  ///
+  /// \param NameRange The location of the name in the matcher source.
+  ///   Useful for error reporting.
+  ///
+  /// \param Args The argument list for the matcher. The number and types of the
+  ///   values must be valid for the matcher requested. Otherwise, the function
+  ///   will return an error.
+  ///
+  /// \return The matcher if no error was found. NULL if the matcher is not
+  //    found, or if the number of arguments or argument types do not
+  ///   match the signature. In that case \c Error will contain the description
+  ///   of the error.
+  static DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                           const SourceRange &NameRange,
+                                           ArrayRef<ParserValue> Args,
+                                           Diagnostics *Error);
+
+private:
+  Registry() LLVM_DELETED_FUNCTION;
+};
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang
+
+#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H

Added: cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h?rev=181768&view=auto
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (added)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Tue May 14 04:13:00 2013
@@ -0,0 +1,125 @@
+//===--- VariantValue.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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Polymorphic value type.
+///
+/// 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_VARIANT_VALUE_H
+#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+typedef ast_matchers::internal::DynTypedMatcher DynTypedMatcher;
+
+/// \brief Variant value class.
+///
+/// Basically, a tagged union with value type semantics.
+/// It is used by the registry as the return value and argument type for the
+/// matcher factory methods.
+/// It can be constructed from any of the supported types. It supports
+/// copy/assignment.
+///
+/// Supported types:
+///  - \c std::string
+///  - \c DynTypedMatcher, and any \c Matcher<T>
+class VariantValue {
+public:
+  VariantValue() : Type(VT_Nothing) {}
+
+  VariantValue(const VariantValue &Other);
+  ~VariantValue();
+  VariantValue &operator=(const VariantValue &Other);
+
+  /// \brief Specific constructors for each supported type.
+  VariantValue(const std::string &String);
+  VariantValue(const DynTypedMatcher &Matcher);
+
+  /// \brief String value functions.
+  bool isString() const;
+  const std::string &getString() const;
+  void setString(const std::string &String);
+
+  /// \brief Matcher value functions.
+  bool isMatcher() const;
+  const DynTypedMatcher &getMatcher() const;
+  void setMatcher(const DynTypedMatcher &Matcher);
+  /// \brief Set the value to be \c Matcher by taking ownership of the object.
+  void takeMatcher(DynTypedMatcher *Matcher);
+
+  /// \brief Specialized Matcher<T> is/get functions.
+  template <class T>
+  bool isTypedMatcher() const {
+    // TODO: Add some logic to test if T is actually valid for the underlying
+    // type of the matcher.
+    return isMatcher();
+  }
+
+  template <class T>
+  ast_matchers::internal::Matcher<T> getTypedMatcher() const {
+    return ast_matchers::internal::makeMatcher(
+        new DerivedTypeMatcher<T>(getMatcher()));
+  }
+
+private:
+  void reset();
+
+  /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher.
+  template <class T>
+  class DerivedTypeMatcher :
+      public ast_matchers::internal::MatcherInterface<T> {
+  public:
+    explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher)
+        : DynMatcher(DynMatcher.clone()) {}
+    virtual ~DerivedTypeMatcher() {}
+
+    typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
+    typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
+    bool matches(const T &Node, ASTMatchFinder *Finder,
+                 BoundNodesTreeBuilder *Builder) const {
+      return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node),
+                                 Finder, Builder);
+    }
+
+  private:
+    const OwningPtr<DynTypedMatcher> DynMatcher;
+  };
+
+  /// \brief All supported value types.
+  enum ValueType {
+    VT_Nothing,
+    VT_String,
+    VT_Matcher
+  };
+
+  /// \brief All supported value types.
+  union AllValues {
+    std::string *String;
+    DynTypedMatcher *Matcher;
+  };
+
+  ValueType Type;
+  AllValues Value;
+};
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Tue May 14 04:13:00 2013
@@ -744,6 +744,14 @@ void MatchFinder::addMatcher(const TypeL
     new TypeLocMatcher(NodeMatch), Action));
 }
 
+bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+                                    MatchCallback *Action) {
+  MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action));
+  // TODO: Do runtime type checking to make sure the matcher is one of the valid
+  // top-level matchers.
+  return true;
+}
+
 ASTConsumer *MatchFinder::newASTConsumer() {
   return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
 }

Modified: cfe/trunk/lib/ASTMatchers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/CMakeLists.txt?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/CMakeLists.txt (original)
+++ cfe/trunk/lib/ASTMatchers/CMakeLists.txt Tue May 14 04:13:00 2013
@@ -1,3 +1,5 @@
+add_subdirectory(Dynamic)
+
 set(LLVM_LINK_COMPONENTS support)
 
 add_clang_library(clangASTMatchers

Added: cfe/trunk/lib/ASTMatchers/Dynamic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/CMakeLists.txt?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/CMakeLists.txt (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/CMakeLists.txt Tue May 14 04:13:00 2013
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangDynamicASTMatchers
+  Diagnostics.cpp
+  VariantValue.cpp
+  Parser.cpp
+  Registry.cpp
+  )
+
+add_dependencies(clangDynamicASTMatchers
+  clangASTMatchers
+  )

Added: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,113 @@
+//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
+//
+//                     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/Diagnostics.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+Diagnostics::ArgStream &
+Diagnostics::ArgStream::operator<<(const Twine &Arg) {
+  Out->push_back(Arg.str());
+  return *this;
+}
+
+Diagnostics::ArgStream Diagnostics::pushErrorFrame(const SourceRange &Range,
+                                                   ErrorType Error) {
+  Frames.insert(Frames.begin(), ErrorFrame());
+  ErrorFrame &Last = Frames.front();
+  Last.Range = Range;
+  Last.Type = Error;
+  ArgStream Out = { &Last.Args };
+  return Out;
+}
+
+StringRef ErrorTypeToString(Diagnostics::ErrorType Type) {
+  switch (Type) {
+  case Diagnostics::ET_RegistryNotFound:
+    return "Matcher not found: $0";
+  case Diagnostics::ET_RegistryWrongArgCount:
+    return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
+  case Diagnostics::ET_RegistryWrongArgType:
+    return "Incorrect type on function $0 for arg $1.";
+
+  case Diagnostics::ET_ParserStringError:
+    return "Error parsing string token: <$0>";
+  case Diagnostics::ET_ParserMatcherArgFailure:
+    return "Error parsing argument $0 for matcher $1.";
+  case Diagnostics::ET_ParserMatcherFailure:
+    return "Error building matcher $0.";
+  case Diagnostics::ET_ParserNoOpenParen:
+    return "Error parsing matcher. Found token <$0> while looking for '('.";
+  case Diagnostics::ET_ParserNoCloseParen:
+    return "Error parsing matcher. Found end-of-code while looking for ')'.";
+  case Diagnostics::ET_ParserNoComma:
+    return "Error parsing matcher. Found token <$0> while looking for ','.";
+  case Diagnostics::ET_ParserNoCode:
+    return "End of code found while looking for token.";
+  case Diagnostics::ET_ParserNotAMatcher:
+    return "Input value is not a matcher expression.";
+  case Diagnostics::ET_ParserInvalidToken:
+    return "Invalid token <$0> found when looking for a value.";
+
+  case Diagnostics::ET_None:
+    return "<N/A>";
+  }
+  llvm_unreachable("Unknown ErrorType value.");
+}
+
+std::string FormatErrorString(StringRef FormatString,
+                              ArrayRef<std::string> Args) {
+  std::string Out;
+  while (!FormatString.empty()) {
+    std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
+    Out += Pieces.first.str();
+    if (Pieces.second.empty()) break;
+
+    const char Next = Pieces.second.front();
+    FormatString = Pieces.second.drop_front();
+    if (Next >= '0' && Next <= '9') {
+      const unsigned Index = Next - '0';
+      if (Index < Args.size()) {
+        Out += Args[Index];
+      } else {
+        Out += "<Argument_Not_Provided>";
+      }
+    }
+  }
+  return Out;
+}
+
+std::string Diagnostics::ErrorFrame::ToString() const {
+  StringRef FormatString = ErrorTypeToString(Type);
+  std::string ErrorOut = FormatErrorString(FormatString, Args);
+  if (Range.Start.Line > 0 && Range.Start.Column > 0)
+    return (Twine(Range.Start.Line) + ":" + Twine(Range.Start.Column) + ": " +
+            ErrorOut).str();
+  return ErrorOut;
+}
+
+std::string Diagnostics::ToString() const {
+  if (Frames.empty()) return "";
+  return Frames[Frames.size() - 1].ToString();
+}
+
+std::string Diagnostics::ToStringFull() const {
+  std::string Result;
+  for (size_t i = 0, end = Frames.size(); i != end; ++i) {
+    if (i > 0) Result += "\n";
+    Result += Frames[i].ToString();
+  }
+  return Result;
+}
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang

Copied: cfe/trunk/lib/ASTMatchers/Dynamic/Makefile (from r181767, cfe/trunk/lib/ASTMatchers/Makefile)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Makefile?p2=cfe/trunk/lib/ASTMatchers/Dynamic/Makefile&p1=cfe/trunk/lib/ASTMatchers/Makefile&r1=181767&r2=181768&rev=181768&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Makefile (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Makefile Tue May 14 04:13:00 2013
@@ -1,4 +1,4 @@
-##===- clang/lib/ASTMatchers/Makefile ----------------------*- Makefile -*-===##
+##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
 #
 #                     The LLVM Compiler Infrastructure
 #
@@ -7,7 +7,7 @@
 #
 ##===----------------------------------------------------------------------===##
 
-CLANG_LEVEL := ../..
-LIBRARYNAME := clangASTMatchers
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangDynamicASTMatchers
 
 include $(CLANG_LEVEL)/Makefile

Added: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Tue May 14 04:13:00 2013
@@ -0,0 +1,223 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Functions templates and classes to wrap matcher construct functions.
+///
+/// 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/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+namespace internal {
+
+/// \brief Helper template class to just from argument type to the right is/get
+///   functions in VariantValue.
+/// Used to verify and extract the matcher arguments below.
+template <class T> struct ArgTypeTraits;
+template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {
+};
+
+template <> struct ArgTypeTraits<std::string> {
+  static bool is(const VariantValue &Value) { return Value.isString(); }
+  static const std::string &get(const VariantValue &Value) {
+    return Value.getString();
+  }
+};
+
+template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
+  static bool is(const VariantValue &Value) { return Value.isMatcher(); }
+  static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
+    return Value.getTypedMatcher<T>();
+  }
+
+};
+
+/// \brief Generic MatcherCreate interface.
+///
+/// Provides a \c run() method that constructs the matcher from the provided
+/// arguments.
+class MatcherCreateCallback {
+public:
+  virtual ~MatcherCreateCallback() {}
+  virtual DynTypedMatcher *run(const SourceRange &NameRange,
+                               ArrayRef<ParserValue> Args,
+                               Diagnostics *Error) const = 0;
+};
+
+/// \brief Simple callback implementation. Marshaller and function are provided.
+///
+/// \param Marshaller Function to unpack the arguments and call \c Func
+/// \param Func Matcher construct function. This is the function that
+///   compile-time matcher expressions would use to create the matcher.
+template <typename MarshallerType, typename FuncType>
+class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback {
+public:
+  FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, FuncType Func,
+                                     StringRef MatcherName)
+      : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {}
+
+  DynTypedMatcher *run(const SourceRange &NameRange,
+                       ArrayRef<ParserValue> Args, Diagnostics *Error) const {
+    return Marshaller(Func, MatcherName, NameRange, Args, Error);
+  }
+
+private:
+  const MarshallerType Marshaller;
+  const FuncType Func;
+  const std::string MatcherName;
+};
+
+/// \brief Helper function to do template argument deduction.
+template <typename MarshallerType, typename FuncType>
+MatcherCreateCallback *
+createMarshallerCallback(MarshallerType Marshaller, FuncType Func,
+                         StringRef MatcherName) {
+  return new FixedArgCountMatcherCreateCallback<MarshallerType, FuncType>(
+      Marshaller, Func, MatcherName);
+}
+
+/// \brief Helper macros to check the arguments on all marshaller functions.
+#define CHECK_ARG_COUNT(count)                                                 \
+  if (Args.size() != count) {                                                  \
+    Error->pushErrorFrame(NameRange, Error->ET_RegistryWrongArgCount)          \
+        << count << Args.size();                                               \
+    return NULL;                                                               \
+  }
+
+#define CHECK_ARG_TYPE(index, type)                                            \
+  if (!ArgTypeTraits<type>::is(Args[index].Value)) {                           \
+    Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType)   \
+        << MatcherName << (index + 1);                                         \
+    return NULL;                                                               \
+  }
+
+/// \brief Metafunction to normalize argument types.
+///
+/// We need to remove the const& out of the function parameters to be able to
+/// find values on VariantValue.
+template <typename T>
+struct remove_const_ref :
+    public llvm::remove_const<typename llvm::remove_reference<T>::type> {
+};
+
+/// \brief 0-arg marshaller function.
+template <typename ReturnType>
+DynTypedMatcher *matcherMarshall0(ReturnType (*Func)(), StringRef MatcherName,
+                                  const SourceRange &NameRange,
+                                  ArrayRef<ParserValue> Args,
+                                  Diagnostics *Error) {
+  CHECK_ARG_COUNT(0);
+  return Func().clone();
+}
+
+/// \brief 1-arg marshaller function.
+template <typename ReturnType, typename InArgType1>
+DynTypedMatcher *matcherMarshall1(ReturnType (*Func)(InArgType1),
+                                  StringRef MatcherName,
+                                  const SourceRange &NameRange,
+                                  ArrayRef<ParserValue> Args,
+                                  Diagnostics *Error) {
+  typedef typename remove_const_ref<InArgType1>::type ArgType1;
+  CHECK_ARG_COUNT(1);
+  CHECK_ARG_TYPE(0, ArgType1);
+  return Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)).clone();
+}
+
+/// \brief Variadic marshaller function.
+template <typename BaseType, typename DerivedType>
+class VariadicMatcherCreateCallback : public MatcherCreateCallback {
+public:
+  explicit VariadicMatcherCreateCallback(StringRef MatcherName)
+      : MatcherName(MatcherName.str()) {}
+
+  typedef ast_matchers::internal::Matcher<DerivedType> DerivedMatcherType;
+
+  DynTypedMatcher *run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
+                       Diagnostics *Error) const {
+    std::list<DerivedMatcherType> References;
+    std::vector<const DerivedMatcherType *> InnerArgs(Args.size());
+    for (size_t i = 0, e = Args.size(); i != e; ++i) {
+      CHECK_ARG_TYPE(i, DerivedMatcherType);
+      References.push_back(
+          ArgTypeTraits<DerivedMatcherType>::get(Args[i].Value));
+      InnerArgs[i] = &References.back();
+    }
+    return ast_matchers::internal::makeDynCastAllOfComposite<BaseType>(
+        ArrayRef<const DerivedMatcherType *>(InnerArgs)).clone();
+  }
+
+private:
+  const std::string MatcherName;
+};
+
+#undef CHECK_ARG_COUNT
+#undef CHECK_ARG_TYPE
+
+/// Helper functions to select the appropriate marshaller functions.
+/// They detects the number of arguments, arguments types and return type.
+
+/// \brief 0-arg overload
+template <typename ReturnType>
+MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(),
+                                               StringRef MatcherName) {
+  return createMarshallerCallback(matcherMarshall0<ReturnType>, Func,
+                                  MatcherName);
+}
+
+/// \brief 1-arg overload
+template <typename ReturnType, typename ArgType1>
+MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1),
+                                               StringRef MatcherName) {
+  return createMarshallerCallback(matcherMarshall1<ReturnType, ArgType1>, Func,
+                                  MatcherName);
+}
+
+/// \brief Variadic overload.
+template <typename MatcherType>
+MatcherCreateCallback *makeMatcherAutoMarshall(
+    ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func,
+    StringRef MatcherName) {
+  return new VariadicMatcherCreateCallback<MatcherType, MatcherType>(
+      MatcherName);
+}
+
+template <typename BaseType, typename MatcherType>
+MatcherCreateCallback *
+makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher<
+                            BaseType, MatcherType> Func,
+                        StringRef MatcherName) {
+  return new VariadicMatcherCreateCallback<BaseType, MatcherType>(MatcherName);
+}
+
+}  // namespace internal
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang
+
+#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H

Added: cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,332 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Recursive parser implementation for the matcher expression grammar.
+///
+//===----------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+/// \brief Simple structure to hold information for one token from the parser.
+struct Parser::TokenInfo {
+  /// \brief Different possible tokens.
+  enum TokenKind {
+    TK_Eof = 0,
+    TK_OpenParen = 1,
+    TK_CloseParen = 2,
+    TK_Comma = 3,
+    TK_Literal = 4,
+    TK_Ident = 5,
+    TK_InvalidChar = 6,
+    TK_Error = 7
+  };
+
+  TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {}
+
+  StringRef Text;
+  TokenKind Kind;
+  SourceRange Range;
+  VariantValue Value;
+};
+
+/// \brief Simple tokenizer for the parser.
+class Parser::CodeTokenizer {
+public:
+  explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
+      : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) {
+    NextToken = getNextToken();
+  }
+
+  /// \brief Returns but doesn't consume the next token.
+  const TokenInfo &peekNextToken() const { return NextToken; }
+
+  /// \brief Consumes and returns the next token.
+  TokenInfo consumeNextToken() {
+    TokenInfo ThisToken = NextToken;
+    NextToken = getNextToken();
+    return ThisToken;
+  }
+
+  TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }
+
+private:
+  TokenInfo getNextToken() {
+    consumeWhitespace();
+    TokenInfo Result;
+    Result.Range.Start = currentLocation();
+
+    if (Code.empty()) {
+      Result.Kind = TokenInfo::TK_Eof;
+      Result.Text = "";
+      return Result;
+    }
+
+    switch (Code[0]) {
+    case ',':
+      Result.Kind = TokenInfo::TK_Comma;
+      Result.Text = Code.substr(0, 1);
+      Code = Code.drop_front();
+      break;
+    case '(':
+      Result.Kind = TokenInfo::TK_OpenParen;
+      Result.Text = Code.substr(0, 1);
+      Code = Code.drop_front();
+      break;
+    case ')':
+      Result.Kind = TokenInfo::TK_CloseParen;
+      Result.Text = Code.substr(0, 1);
+      Code = Code.drop_front();
+      break;
+
+    case '"':
+    case '\'':
+      // Parse a string literal.
+      consumeStringLiteral(&Result);
+      break;
+
+    default:
+      if (isAlphanumeric(Code[0])) {
+        // Parse an identifier
+        size_t TokenLength = 1;
+        while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength]))
+          ++TokenLength;
+        Result.Kind = TokenInfo::TK_Ident;
+        Result.Text = Code.substr(0, TokenLength);
+        Code = Code.drop_front(TokenLength);
+      } else {
+        Result.Kind = TokenInfo::TK_InvalidChar;
+        Result.Text = Code.substr(0, 1);
+        Code = Code.drop_front(1);
+      }
+      break;
+    }
+
+    Result.Range.End = currentLocation();
+    return Result;
+  }
+
+  /// \brief Consume a string literal.
+  ///
+  /// \c Code must be positioned at the start of the literal (the opening
+  /// quote). Consumed until it finds the same closing quote character.
+  void consumeStringLiteral(TokenInfo *Result) {
+    bool InEscape = false;
+    const char Marker = Code[0];
+    for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
+      if (InEscape) {
+        InEscape = false;
+        continue;
+      }
+      if (Code[Length] == '\\') {
+        InEscape = true;
+        continue;
+      }
+      if (Code[Length] == Marker) {
+        Result->Kind = TokenInfo::TK_Literal;
+        Result->Text = Code.substr(0, Length + 1);
+        Result->Value = Code.substr(1, Length - 1).str();
+        Code = Code.drop_front(Length + 1);
+        return;
+      }
+    }
+
+    StringRef ErrorText = Code;
+    Code = Code.drop_front(Code.size());
+    SourceRange Range;
+    Range.Start = Result->Range.Start;
+    Range.End = currentLocation();
+    Error->pushErrorFrame(Range, Error->ET_ParserStringError)
+        << ErrorText;
+    Result->Kind = TokenInfo::TK_Error;
+  }
+
+  /// \brief Consume all leading whitespace from \c Code.
+  void consumeWhitespace() {
+    while (!Code.empty() && isWhitespace(Code[0])) {
+      if (Code[0] == '\n') {
+        ++Line;
+        StartOfLine = Code.drop_front();
+      }
+      Code = Code.drop_front();
+    }
+  }
+
+  SourceLocation currentLocation() {
+    SourceLocation Location;
+    Location.Line = Line;
+    Location.Column = Code.data() - StartOfLine.data() + 1;
+    return Location;
+  }
+
+  StringRef Code;
+  StringRef StartOfLine;
+  unsigned Line;
+  Diagnostics *Error;
+  TokenInfo NextToken;
+};
+
+Parser::Sema::~Sema() {}
+
+/// \brief Parse and validate a matcher expression.
+/// \return \c true on success, in which case \c Value has the matcher parsed.
+///   If the input is malformed, or some argument has an error, it
+///   returns \c false.
+bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
+  const TokenInfo NameToken = Tokenizer->consumeNextToken();
+  assert(NameToken.Kind == TokenInfo::TK_Ident);
+  const TokenInfo OpenToken = Tokenizer->consumeNextToken();
+  if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
+    Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoOpenParen)
+        << OpenToken.Text;
+    return false;
+  }
+
+  std::vector<ParserValue> Args;
+  TokenInfo EndToken;
+  while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {
+    if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {
+      // End of args.
+      EndToken = Tokenizer->consumeNextToken();
+      break;
+    }
+    if (Args.size() > 0) {
+      // We must find a , token to continue.
+      const TokenInfo CommaToken = Tokenizer->consumeNextToken();
+      if (CommaToken.Kind != TokenInfo::TK_Comma) {
+        Error->pushErrorFrame(CommaToken.Range, Error->ET_ParserNoComma)
+            << CommaToken.Text;
+        return false;
+      }
+    }
+
+    ParserValue ArgValue;
+    ArgValue.Text = Tokenizer->peekNextToken().Text;
+    ArgValue.Range = Tokenizer->peekNextToken().Range;
+    if (!parseExpressionImpl(&ArgValue.Value)) {
+      Error->pushErrorFrame(NameToken.Range,
+                            Error->ET_ParserMatcherArgFailure)
+          << (Args.size() + 1) << NameToken.Text;
+      return false;
+    }
+
+    Args.push_back(ArgValue);
+  }
+
+  if (EndToken.Kind == TokenInfo::TK_Eof) {
+    Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoCloseParen);
+    return false;
+  }
+
+  // Merge the start and end infos.
+  SourceRange MatcherRange = NameToken.Range;
+  MatcherRange.End = EndToken.Range.End;
+  DynTypedMatcher *Result =
+      S->actOnMatcherExpression(NameToken.Text, MatcherRange, Args, Error);
+  if (Result == NULL) {
+    Error->pushErrorFrame(NameToken.Range, Error->ET_ParserMatcherFailure)
+        << NameToken.Text;
+    return false;
+  }
+
+  Value->takeMatcher(Result);
+  return true;
+}
+
+/// \brief Parse an <Expresssion>
+bool Parser::parseExpressionImpl(VariantValue *Value) {
+  switch (Tokenizer->nextTokenKind()) {
+  case TokenInfo::TK_Literal:
+    *Value = Tokenizer->consumeNextToken().Value;
+    return true;
+
+  case TokenInfo::TK_Ident:
+    return parseMatcherExpressionImpl(Value);
+
+  case TokenInfo::TK_Eof:
+    Error->pushErrorFrame(Tokenizer->consumeNextToken().Range,
+                          Error->ET_ParserNoCode);
+    return false;
+
+  case TokenInfo::TK_Error:
+    // This error was already reported by the tokenizer.
+    return false;
+
+  case TokenInfo::TK_OpenParen:
+  case TokenInfo::TK_CloseParen:
+  case TokenInfo::TK_Comma:
+  case TokenInfo::TK_InvalidChar:
+    const TokenInfo Token = Tokenizer->consumeNextToken();
+    Error->pushErrorFrame(Token.Range, Error->ET_ParserInvalidToken)
+        << Token.Text;
+    return false;
+  }
+
+  llvm_unreachable("Unknown token kind.");
+}
+
+Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
+               Diagnostics *Error)
+    : Tokenizer(Tokenizer), S(S), Error(Error) {}
+
+class RegistrySema : public Parser::Sema {
+public:
+  virtual ~RegistrySema() {}
+  DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
+                                          const SourceRange &NameRange,
+                                          ArrayRef<ParserValue> Args,
+                                          Diagnostics *Error) {
+    return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
+  }
+};
+
+bool Parser::parseExpression(StringRef Code, VariantValue *Value,
+                             Diagnostics *Error) {
+  RegistrySema S;
+  return parseExpression(Code, &S, Value, Error);
+}
+
+bool Parser::parseExpression(StringRef Code, Sema *S,
+                             VariantValue *Value, Diagnostics *Error) {
+  CodeTokenizer Tokenizer(Code, Error);
+  return Parser(&Tokenizer, S, Error).parseExpressionImpl(Value);
+}
+
+DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code,
+                                                Diagnostics *Error) {
+  RegistrySema S;
+  return parseMatcherExpression(Code, &S, Error);
+}
+
+DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code,
+                                                Parser::Sema *S,
+                                                Diagnostics *Error) {
+  VariantValue Value;
+  if (!parseExpression(Code, S, &Value, Error))
+    return NULL;
+  if (!Value.isMatcher()) {
+    Error->pushErrorFrame(SourceRange(), Error->ET_ParserNotAMatcher);
+    return NULL;
+  }
+  return Value.getMatcher().clone();
+}
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang

Added: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,153 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Registry map populated at static initialization time.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+
+#include <utility>
+
+#include "Marshallers.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ManagedStatic.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using internal::MatcherCreateCallback;
+
+typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap;
+class RegistryMaps {
+public:
+  RegistryMaps();
+  ~RegistryMaps();
+
+  const ConstructorMap &constructors() const { return Constructors; }
+
+private:
+  void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback);
+  ConstructorMap Constructors;
+};
+
+void RegistryMaps::registerMatcher(StringRef MatcherName,
+                                   MatcherCreateCallback *Callback) {
+  Constructors[MatcherName] = Callback;
+}
+
+#define REGISTER_MATCHER(name)                                                 \
+  registerMatcher(#name, internal::makeMatcherAutoMarshall(                    \
+                             ::clang::ast_matchers::name, #name));
+
+/// \brief Generate a registry map with all the known matchers.
+RegistryMaps::RegistryMaps() {
+  // TODO: This list is not complete. It only has non-overloaded matchers,
+  // which are the simplest to add to the system. Overloaded matchers require
+  // more supporting code that was omitted from the first revision for
+  // simplicitly of code review.
+
+  REGISTER_MATCHER(binaryOperator);
+  REGISTER_MATCHER(bindTemporaryExpr);
+  REGISTER_MATCHER(boolLiteral);
+  REGISTER_MATCHER(callExpr);
+  REGISTER_MATCHER(characterLiteral);
+  REGISTER_MATCHER(compoundStmt);
+  REGISTER_MATCHER(conditionalOperator);
+  REGISTER_MATCHER(constCastExpr);
+  REGISTER_MATCHER(constructExpr);
+  REGISTER_MATCHER(constructorDecl);
+  REGISTER_MATCHER(declRefExpr);
+  REGISTER_MATCHER(declStmt);
+  REGISTER_MATCHER(defaultArgExpr);
+  REGISTER_MATCHER(doStmt);
+  REGISTER_MATCHER(dynamicCastExpr);
+  REGISTER_MATCHER(explicitCastExpr);
+  REGISTER_MATCHER(expr);
+  REGISTER_MATCHER(fieldDecl);
+  REGISTER_MATCHER(forStmt);
+  REGISTER_MATCHER(functionDecl);
+  REGISTER_MATCHER(hasAnyParameter);
+  REGISTER_MATCHER(hasAnySubstatement);
+  REGISTER_MATCHER(hasConditionVariableStatement);
+  REGISTER_MATCHER(hasDestinationType);
+  REGISTER_MATCHER(hasEitherOperand);
+  REGISTER_MATCHER(hasFalseExpression);
+  REGISTER_MATCHER(hasImplicitDestinationType);
+  REGISTER_MATCHER(hasInitializer);
+  REGISTER_MATCHER(hasLHS);
+  REGISTER_MATCHER(hasName);
+  REGISTER_MATCHER(hasObjectExpression);
+  REGISTER_MATCHER(hasRHS);
+  REGISTER_MATCHER(hasSourceExpression);
+  REGISTER_MATCHER(hasTrueExpression);
+  REGISTER_MATCHER(hasUnaryOperand);
+  REGISTER_MATCHER(ifStmt);
+  REGISTER_MATCHER(implicitCastExpr);
+  REGISTER_MATCHER(integerLiteral);
+  REGISTER_MATCHER(isArrow);
+  REGISTER_MATCHER(isConstQualified);
+  REGISTER_MATCHER(isImplicit);
+  REGISTER_MATCHER(member);
+  REGISTER_MATCHER(memberExpr);
+  REGISTER_MATCHER(methodDecl);
+  REGISTER_MATCHER(namedDecl);
+  REGISTER_MATCHER(newExpr);
+  REGISTER_MATCHER(ofClass);
+  REGISTER_MATCHER(on);
+  REGISTER_MATCHER(onImplicitObjectArgument);
+  REGISTER_MATCHER(operatorCallExpr);
+  REGISTER_MATCHER(recordDecl);
+  REGISTER_MATCHER(reinterpretCastExpr);
+  REGISTER_MATCHER(staticCastExpr);
+  REGISTER_MATCHER(stmt);
+  REGISTER_MATCHER(stringLiteral);
+  REGISTER_MATCHER(switchCase);
+  REGISTER_MATCHER(to);
+  REGISTER_MATCHER(unaryOperator);
+  REGISTER_MATCHER(varDecl);
+  REGISTER_MATCHER(whileStmt);
+}
+
+RegistryMaps::~RegistryMaps() {
+  for (ConstructorMap::iterator it = Constructors.begin(),
+                                end = Constructors.end();
+       it != end; ++it) {
+    delete it->second;
+  }
+}
+
+static llvm::ManagedStatic<RegistryMaps> RegistryData;
+
+} // anonymous namespace
+
+// static
+DynTypedMatcher *Registry::constructMatcher(StringRef MatcherName,
+                                            const SourceRange &NameRange,
+                                            ArrayRef<ParserValue> Args,
+                                            Diagnostics *Error) {
+  ConstructorMap::const_iterator it =
+      RegistryData->constructors().find(MatcherName);
+  if (it == RegistryData->constructors().end()) {
+    Error->pushErrorFrame(NameRange, Error->ET_RegistryNotFound)
+        << MatcherName;
+    return NULL;
+  }
+
+  return it->second->run(NameRange, Args, Error);
+}
+
+}  // namespace dynamic
+}  // namespace ast_matchers
+}  // namespace clang

Added: cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp (added)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,105 @@
+//===--- VariantValue.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Polymorphic value type.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+
+VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
+  *this = Other;
+}
+
+VariantValue::VariantValue(const DynTypedMatcher &Matcher) : Type(VT_Nothing) {
+  setMatcher(Matcher);
+}
+
+VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) {
+  setString(String);
+}
+
+VariantValue::~VariantValue() { reset(); }
+
+VariantValue &VariantValue::operator=(const VariantValue &Other) {
+  if (this == &Other) return *this;
+  reset();
+  switch (Other.Type) {
+  case VT_String:
+    setString(Other.getString());
+    break;
+  case VT_Matcher:
+    setMatcher(Other.getMatcher());
+    break;
+  case VT_Nothing:
+    Type = VT_Nothing;
+    break;
+  }
+  return *this;
+}
+
+void VariantValue::reset() {
+  switch (Type) {
+  case VT_String:
+    delete Value.String;
+    break;
+  case VT_Matcher:
+    delete Value.Matcher;
+    break;
+  // Cases that do nothing.
+  case VT_Nothing:
+    break;
+  }
+  Type = VT_Nothing;
+}
+
+bool VariantValue::isString() const {
+  return Type == VT_String;
+}
+
+const std::string &VariantValue::getString() const {
+  assert(isString());
+  return *Value.String;
+}
+
+void VariantValue::setString(const std::string &NewValue) {
+  reset();
+  Type = VT_String;
+  Value.String = new std::string(NewValue);
+}
+
+bool VariantValue::isMatcher() const {
+  return Type == VT_Matcher;
+}
+
+const DynTypedMatcher &VariantValue::getMatcher() const {
+  assert(isMatcher());
+  return *Value.Matcher;
+}
+
+void VariantValue::setMatcher(const DynTypedMatcher &NewValue) {
+  reset();
+  Type = VT_Matcher;
+  Value.Matcher = NewValue.clone();
+}
+
+void VariantValue::takeMatcher(DynTypedMatcher *NewValue) {
+  reset();
+  Type = VT_Matcher;
+  Value.Matcher = NewValue;
+}
+
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang

Modified: cfe/trunk/lib/ASTMatchers/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Makefile?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Makefile (original)
+++ cfe/trunk/lib/ASTMatchers/Makefile Tue May 14 04:13:00 2013
@@ -10,4 +10,6 @@
 CLANG_LEVEL := ../..
 LIBRARYNAME := clangASTMatchers
 
+PARALLEL_DIRS = Dynamic
+
 include $(CLANG_LEVEL)/Makefile

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h Tue May 14 04:13:00 2013
@@ -84,6 +84,41 @@ testing::AssertionResult notMatches(cons
   return matchesConditionally(Code, AMatcher, false, "-std=c++11");
 }
 
+inline testing::AssertionResult
+matchesConditionallyDynamic(const std::string &Code,
+                            const internal::DynTypedMatcher &AMatcher,
+                            bool ExpectMatch, llvm::StringRef CompileArg) {
+  bool Found = false;
+  MatchFinder Finder;
+  Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &Found));
+  OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+  // Some tests use typeof, which is a gnu extension.
+  std::vector<std::string> Args(1, CompileArg);
+  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
+    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();
+}
+
+inline testing::AssertionResult
+matchesDynamic(const std::string &Code,
+               const internal::DynTypedMatcher &AMatcher) {
+  return matchesConditionallyDynamic(Code, AMatcher, true, "-std=c++11");
+}
+
+inline testing::AssertionResult
+notMatchesDynamic(const std::string &Code,
+                  const internal::DynTypedMatcher &AMatcher) {
+  return matchesConditionallyDynamic(Code, AMatcher, false, "-std=c++11");
+}
+
 template <typename T>
 testing::AssertionResult
 matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,

Modified: cfe/trunk/unittests/ASTMatchers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/CMakeLists.txt?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/CMakeLists.txt (original)
+++ cfe/trunk/unittests/ASTMatchers/CMakeLists.txt Tue May 14 04:13:00 2013
@@ -11,3 +11,5 @@ add_clang_unittest(ASTMatchersTests
 
 target_link_libraries(ASTMatchersTests
   gtest gtest_main clangASTMatchers clangTooling)
+
+add_subdirectory(Dynamic)

Added: cfe/trunk/unittests/ASTMatchers/Dynamic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/CMakeLists.txt?rev=181768&view=auto
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/CMakeLists.txt (added)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/CMakeLists.txt Tue May 14 04:13:00 2013
@@ -0,0 +1,7 @@
+add_clang_unittest(DynamicASTMatchersTests
+  VariantValueTest.cpp
+  ParserTest.cpp
+  RegistryTest.cpp)
+
+target_link_libraries(DynamicASTMatchersTests
+  gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling)

Added: cfe/trunk/unittests/ASTMatchers/Dynamic/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/Makefile?rev=181768&view=auto
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/Makefile (added)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/Makefile Tue May 14 04:13:00 2013
@@ -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 = clangEdit.a 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

Added: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (added)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,194 @@
+//===- 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"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+class DummyDynTypedMatcher : public DynTypedMatcher {
+public:
+  DummyDynTypedMatcher(uint64_t ID) : ID(ID) {}
+
+  typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
+  typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
+  virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
+                       ASTMatchFinder *Finder,
+                       BoundNodesTreeBuilder *Builder) const {
+    return false;
+  }
+
+  /// \brief Makes a copy of this matcher object.
+  virtual DynTypedMatcher *clone() const {
+    return new DummyDynTypedMatcher(ID);
+  }
+
+  /// \brief Returns a unique ID for the matcher.
+  virtual uint64_t getID() const { return ID; }
+
+private:
+  uint64_t ID;
+};
+
+class MockSema : public Parser::Sema {
+public:
+  virtual ~MockSema() {}
+
+  uint64_t expectMatcher(StringRef MatcherName) {
+    uint64_t ID = ExpectedMatchers.size() + 1;
+    ExpectedMatchers[MatcherName] = ID;
+    return ID;
+  }
+
+  void parse(StringRef Code) {
+    Diagnostics Error;
+    VariantValue Value;
+    Parser::parseExpression(Code, this, &Value, &Error);
+    Values.push_back(Value);
+    Errors.push_back(Error.ToStringFull());
+  }
+
+  DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
+                                          const SourceRange &NameRange,
+                                          ArrayRef<ParserValue> Args,
+                                          Diagnostics *Error) {
+    MatcherInfo ToStore = { MatcherName, NameRange, Args };
+    Matchers.push_back(ToStore);
+    return new DummyDynTypedMatcher(ExpectedMatchers[MatcherName]);
+  }
+
+  struct MatcherInfo {
+    StringRef MatcherName;
+    SourceRange NameRange;
+    std::vector<ParserValue> Args;
+  };
+
+  std::vector<std::string> Errors;
+  std::vector<VariantValue> Values;
+  std::vector<MatcherInfo> Matchers;
+  llvm::StringMap<uint64_t> ExpectedMatchers;
+};
+
+TEST(ParserTest, ParseString) {
+  MockSema Sema;
+  Sema.parse("\"Foo\"");
+  Sema.parse("\"\"");
+  Sema.parse("\"Baz");
+  EXPECT_EQ(3ULL, Sema.Values.size());
+  EXPECT_EQ("Foo", Sema.Values[0].getString());
+  EXPECT_EQ("", Sema.Values[1].getString());
+  EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]);
+}
+
+bool matchesRange(const SourceRange &Range, unsigned StartLine,
+                  unsigned EndLine, unsigned StartColumn, unsigned EndColumn) {
+  EXPECT_EQ(StartLine, Range.Start.Line);
+  EXPECT_EQ(EndLine, Range.End.Line);
+  EXPECT_EQ(StartColumn, Range.Start.Column);
+  EXPECT_EQ(EndColumn, Range.End.Column);
+  return Range.Start.Line == StartLine && Range.End.Line == EndLine &&
+         Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
+}
+
+TEST(ParserTest, ParseMatcher) {
+  MockSema Sema;
+  const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");
+  const uint64_t ExpectedBar = Sema.expectMatcher("Bar");
+  const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");
+  Sema.parse(" Foo ( Bar (), Baz( \n \"B A,Z\") )  ");
+  for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) {
+    EXPECT_EQ("", Sema.Errors[i]);
+  }
+
+  EXPECT_EQ(1ULL, Sema.Values.size());
+  EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID());
+
+  EXPECT_EQ(3ULL, Sema.Matchers.size());
+  const MockSema::MatcherInfo Bar = Sema.Matchers[0];
+  EXPECT_EQ("Bar", Bar.MatcherName);
+  EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 14));
+  EXPECT_EQ(0ULL, Bar.Args.size());
+
+  const MockSema::MatcherInfo Baz = Sema.Matchers[1];
+  EXPECT_EQ("Baz", Baz.MatcherName);
+  EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 16, 10));
+  EXPECT_EQ(1ULL, Baz.Args.size());
+  EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString());
+
+  const MockSema::MatcherInfo Foo = Sema.Matchers[2];
+  EXPECT_EQ("Foo", Foo.MatcherName);
+  EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
+  EXPECT_EQ(2ULL, Foo.Args.size());
+  EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID());
+  EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID());
+}
+
+using ast_matchers::internal::Matcher;
+
+TEST(ParserTest, FullParserTest) {
+  OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
+      "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
+  EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
+  EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
+
+  Diagnostics Error;
+  EXPECT_TRUE(Parser::parseMatcherExpression(
+      "hasInitializer(\n    binaryOperator(hasLHS(\"A\")))", &Error) == NULL);
+  EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
+            "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
+            "2:20: Error building matcher hasLHS.\n"
+            "2:27: Incorrect type on function hasLHS for arg 1.",
+            Error.ToStringFull());
+}
+
+std::string ParseWithError(StringRef Code) {
+  Diagnostics Error;
+  VariantValue Value;
+  Parser::parseExpression(Code, &Value, &Error);
+  return Error.ToStringFull();
+}
+
+std::string ParseMatcherWithError(StringRef Code) {
+  Diagnostics Error;
+  Parser::parseMatcherExpression(Code, &Error);
+  return Error.ToStringFull();
+}
+
+TEST(ParserTest, Errors) {
+  EXPECT_EQ(
+      "1:5: Error parsing matcher. Found token <123> while looking for '('.",
+      ParseWithError("Foo 123"));
+  EXPECT_EQ(
+      "1:9: Error parsing matcher. Found token <123> while looking for ','.",
+      ParseWithError("Foo(\"A\" 123)"));
+  EXPECT_EQ(
+      "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
+      ParseWithError("Foo("));
+  EXPECT_EQ("1:1: End of code found while looking for token.",
+            ParseWithError(""));
+  EXPECT_EQ("Input value is not a matcher expression.",
+            ParseMatcherWithError("\"A\""));
+  EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
+            "1:5: Invalid token <(> found when looking for a value.",
+            ParseWithError("Foo(("));
+}
+
+}  // end anonymous namespace
+}  // end namespace dynamic
+}  // end namespace ast_matchers
+}  // end namespace clang

Added: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (added)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,112 @@
+//===- 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 {
+
+using ast_matchers::internal::Matcher;
+
+DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) {
+  const std::vector<ParserValue> Args;
+  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+}
+
+DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                  const VariantValue &Arg1,
+                                  Diagnostics *Error) {
+  std::vector<ParserValue> Args(1);
+  Args[0].Value = Arg1;
+  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+}
+
+DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                  const VariantValue &Arg1,
+                                  const VariantValue &Arg2,
+                                  Diagnostics *Error) {
+  std::vector<ParserValue> Args(2);
+  Args[0].Value = Arg1;
+  Args[1].Value = Arg2;
+  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+}
+
+TEST(RegistryTest, CanConstructNoArgs) {
+  OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL));
+  OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL));
+
+  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(matchesDynamic(ClassSnippet, *IsArrowValue));
+  EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue));
+  EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue));
+  EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue));
+}
+
+TEST(RegistryTest, ConstructWithSimpleArgs) {
+  OwningPtr<DynTypedMatcher> Value(
+      constructMatcher("hasName", std::string("X"), NULL));
+  EXPECT_TRUE(matchesDynamic("class X {};", *Value));
+  EXPECT_FALSE(matchesDynamic("int x;", *Value));
+}
+
+TEST(RegistryTest, ConstructWithMatcherArgs) {
+  OwningPtr<DynTypedMatcher> HasInitializerSimple(
+      constructMatcher("hasInitializer", stmt(), NULL));
+  OwningPtr<DynTypedMatcher> HasInitializerComplex(
+      constructMatcher("hasInitializer", callExpr(), NULL));
+
+  std::string code = "int i;";
+  EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple));
+  EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+
+  code = "int i = 1;";
+  EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
+  EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+
+  code = "int y(); int i = y();";
+  EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
+  EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex));
+}
+
+TEST(RegistryTest, Errors) {
+  // Incorrect argument count.
+  OwningPtr<Diagnostics> Error(new Diagnostics());
+  EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get()));
+  EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
+            Error->ToString());
+  Error.reset(new Diagnostics());
+  EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get()));
+  EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
+            Error->ToString());
+
+  // Bad argument type
+  Error.reset(new Diagnostics());
+  EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get()));
+  EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString());
+  Error.reset(new Diagnostics());
+  EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(),
+                                       ::std::string(), Error.get()));
+  EXPECT_EQ("Incorrect type on function recordDecl for arg 2.",
+            Error->ToString());
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang

Added: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=181768&view=auto
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (added)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Tue May 14 04:13:00 2013
@@ -0,0 +1,97 @@
+//===- unittest/ASTMatchers/Dynamic/VariantValueTest.cpp - VariantValue 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/VariantValue.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using ast_matchers::internal::DynTypedMatcher;
+using ast_matchers::internal::Matcher;
+
+TEST(VariantValueTest, String) {
+  const ::std::string kString = "string";
+  VariantValue Value = kString;
+
+  EXPECT_TRUE(Value.isString());
+  EXPECT_EQ(kString, Value.getString());
+
+  EXPECT_FALSE(Value.isMatcher());
+  EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+}
+
+TEST(VariantValueTest, DynTypedMatcher) {
+  VariantValue Value = stmt();
+
+  EXPECT_FALSE(Value.isString());
+
+  EXPECT_TRUE(Value.isMatcher());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+
+  // Conversion to any type of matcher works.
+  // If they are not compatible it would just return a matcher that matches
+  // nothing. We test this below.
+  Value = recordDecl();
+  EXPECT_TRUE(Value.isMatcher());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+
+  Value = unaryOperator();
+  EXPECT_TRUE(Value.isMatcher());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+}
+
+TEST(VariantValueTest, Assignment) {
+  VariantValue Value = std::string("A");
+  EXPECT_TRUE(Value.isString());
+  EXPECT_EQ("A", Value.getString());
+  EXPECT_FALSE(Value.isMatcher());
+
+  Value = recordDecl();
+  EXPECT_FALSE(Value.isString());
+  EXPECT_TRUE(Value.isMatcher());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+
+  Value = VariantValue();
+  EXPECT_FALSE(Value.isString());
+  EXPECT_FALSE(Value.isMatcher());
+}
+
+TEST(GeneicValueTest, Matcher) {
+  EXPECT_TRUE(matchesDynamic(
+      "class X {};", VariantValue(recordDecl(hasName("X"))).getMatcher()));
+  EXPECT_TRUE(matchesDynamic(
+      "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>()));
+  EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }",
+                             VariantValue(functionDecl()).getMatcher()));
+  // Going through the wrong Matcher<T> will fail to match, even if the
+  // underlying matcher is correct.
+  EXPECT_FALSE(matchesDynamic(
+      "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>()));
+
+  EXPECT_FALSE(
+      matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher()));
+  EXPECT_FALSE(matchesDynamic(
+      "int foo() { return 1 + 1; }",
+      VariantValue(declRefExpr()).getTypedMatcher<clang::DeclRefExpr>()));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang

Modified: cfe/trunk/unittests/ASTMatchers/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Makefile?rev=181768&r1=181767&r2=181768&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Makefile (original)
+++ cfe/trunk/unittests/ASTMatchers/Makefile Tue May 14 04:13:00 2013
@@ -9,6 +9,8 @@
 
 CLANG_LEVEL = ../..
 
+PARALLEL_DIRS = Dynamic
+
 TESTNAME = ASTMatchers
 include $(CLANG_LEVEL)/../../Makefile.config
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc





More information about the cfe-commits mailing list