r181768 - First revision of the dynamic ASTMatcher library.
Manuel Klimek
klimek at google.com
Tue May 14 13:37:01 PDT 2013
+sam
On May 14, 2013 10:25 PM, "Reid Kleckner" <rnk at google.com> wrote:
> This doesn't compile with MSVC 2012?
>
> http://bb.pgr.jp/builders/ninja-clang-i686-msc17-R/builds/1350/steps/build_clang/logs/stdio
>
> I get this locally:
>
> ..\tools\clang\include\clang/ASTMatchers/Dynamic/VariantValue.h(88) :
> error C2872: 'DynTypedMatcher' : ambiguous symbol
> could be
> '..\tools\clang\include\clang/ASTMatchers/Dynamic/VariantValue.h(29) :
> clang::ast_matchers::internal::DynTypedMatcher
> clang::ast_matchers::dynamic::DynTypedMatcher'
> or
> '..\tools\clang\include\clang/ASTMatchers/ASTMatchersInternal.h(233) :
> clang::ast_matchers::internal::DynTypedMatcher'
>
> ..\tools\clang\include\clang/ASTMatchers/Dynamic/VariantValue.h(77) : see
> reference to class template instantiation
> 'clang::ast_matchers::dynamic::VariantValue::DerivedTypeMatcher<T>' being
> compiled
> with
> [
> T=clang::Decl
> ]
>
> ..\tools\clang\unittests\ASTMatchers\Dynamic\VariantValueTest.cpp(79) : see
> reference to function template instantiation
> 'clang::ast_matchers::internal::Matcher<T>
> clang::ast_matchers::dynamic::VariantValue::getTypedMatcher<clang::Decl>(void)
> const' being compiled
> with
> [
> T=clang::Decl
> ]
> ..\tools\clang\include\clang/ASTMatchers/Dynamic/VariantValue.h(101) :
> error C2872: 'DynTypedMatcher' : ambiguous symbol
> could be
> '..\tools\clang\include\clang/ASTMatchers/Dynamic/VariantValue.h(29) :
> clang::ast_matchers::internal::DynTypedMatcher
> clang::ast_matchers::dynamic::DynTypedMatcher'
> or
> '..\tools\clang\include\clang/ASTMatchers/ASTMatchersInternal.h(233) :
> clang::ast_matchers::internal::DynTypedMatcher'
>
> I'll attempt to fix, but I may give up and revert.
>
>
> On Tue, May 14, 2013 at 5:13 AM, Manuel Klimek <klimek at google.com> wrote:
>
>> 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
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130514/8391fbe1/attachment.html>
More information about the cfe-commits
mailing list