diff options
Diffstat (limited to 'lib/ASTMatchers/Dynamic')
-rw-r--r-- | lib/ASTMatchers/Dynamic/CMakeLists.txt | 16 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Diagnostics.cpp | 113 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Makefile | 13 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Marshallers.h | 223 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Parser.cpp | 332 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Registry.cpp | 153 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/VariantValue.cpp | 105 |
7 files changed, 955 insertions, 0 deletions
diff --git a/lib/ASTMatchers/Dynamic/CMakeLists.txt b/lib/ASTMatchers/Dynamic/CMakeLists.txt new file mode 100644 index 0000000000..843341b297 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangDynamicASTMatchers + Diagnostics.cpp + VariantValue.cpp + Parser.cpp + Registry.cpp + ) + +add_dependencies(clangDynamicASTMatchers + clangASTMatchers + ) + +target_link_libraries(clangDynamicASTMatchers + clangASTMatchers + ) diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp new file mode 100644 index 0000000000..fb3cac370f --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -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 diff --git a/lib/ASTMatchers/Dynamic/Makefile b/lib/ASTMatchers/Dynamic/Makefile new file mode 100644 index 0000000000..a57d752229 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Makefile @@ -0,0 +1,13 @@ +##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../../.. +LIBRARYNAME := clangDynamicASTMatchers + +include $(CLANG_LEVEL)/Makefile diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h new file mode 100644 index 0000000000..e75a175738 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -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 diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp new file mode 100644 index 0000000000..1678820da0 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -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 diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp new file mode 100644 index 0000000000..53e90f1c77 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -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 diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 0000000000..e310fbfc58 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -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 |