diff options
Diffstat (limited to 'clang-r353983/include/clang/ASTMatchers/Dynamic')
4 files changed, 931 insertions, 0 deletions
diff --git a/clang-r353983/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/clang-r353983/include/clang/ASTMatchers/Dynamic/Diagnostics.h new file mode 100644 index 00000000..7dd30479 --- /dev/null +++ b/clang-r353983/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -0,0 +1,184 @@ +//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Diagnostics class to manage error messages. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_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" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" +#include <string> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +struct SourceLocation { + SourceLocation() : Line(), Column() {} + unsigned Line; + unsigned Column; +}; + +struct SourceRange { + SourceLocation Start; + SourceLocation End; +}; + +/// A VariantValue instance annotated with its parser context. +struct ParserValue { + ParserValue() : Text(), Range(), Value() {} + StringRef Text; + SourceRange Range; + VariantValue Value; +}; + +/// Helper class to manage error messages. +class Diagnostics { +public: + /// Parser context types. + enum ContextType { + CT_MatcherArg = 0, + CT_MatcherConstruct = 1 + }; + + /// All errors from the system. + enum ErrorType { + ET_None = 0, + + ET_RegistryMatcherNotFound = 1, + ET_RegistryWrongArgCount = 2, + ET_RegistryWrongArgType = 3, + ET_RegistryNotBindable = 4, + ET_RegistryAmbiguousOverload = 5, + ET_RegistryValueNotFound = 6, + + ET_ParserStringError = 100, + ET_ParserNoOpenParen = 101, + ET_ParserNoCloseParen = 102, + ET_ParserNoComma = 103, + ET_ParserNoCode = 104, + ET_ParserNotAMatcher = 105, + ET_ParserInvalidToken = 106, + ET_ParserMalformedBindExpr = 107, + ET_ParserTrailingCode = 108, + ET_ParserNumberError = 109, + ET_ParserOverloadedType = 110 + }; + + /// Helper stream class. + class ArgStream { + public: + ArgStream(std::vector<std::string> *Out) : Out(Out) {} + template <class T> ArgStream &operator<<(const T &Arg) { + return operator<<(Twine(Arg)); + } + ArgStream &operator<<(const Twine &Arg); + + private: + std::vector<std::string> *Out; + }; + + /// Class defining a parser context. + /// + /// Used by the parser to specify (possibly recursive) contexts where the + /// parsing/construction can fail. Any error triggered within a context will + /// keep information about the context chain. + /// This class should be used as a RAII instance in the stack. + struct Context { + public: + /// About to call the constructor for a matcher. + enum ConstructMatcherEnum { ConstructMatcher }; + Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName, + SourceRange MatcherRange); + /// About to recurse into parsing one argument for a matcher. + enum MatcherArgEnum { MatcherArg }; + Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName, + SourceRange MatcherRange, unsigned ArgNumber); + ~Context(); + + private: + Diagnostics *const Error; + }; + + /// Context for overloaded matcher construction. + /// + /// This context will take care of merging all errors that happen within it + /// as "candidate" overloads for the same matcher. + struct OverloadContext { + public: + OverloadContext(Diagnostics* Error); + ~OverloadContext(); + + /// Revert all errors that happened within this context. + void revertErrors(); + + private: + Diagnostics *const Error; + unsigned BeginIndex; + }; + + /// Add an error to the diagnostics. + /// + /// All the context information will be kept on the error message. + /// \return a helper class to allow the caller to pass the arguments for the + /// error message, using the << operator. + ArgStream addError(SourceRange Range, ErrorType Error); + + /// Information stored for one frame of the context. + struct ContextFrame { + ContextType Type; + SourceRange Range; + std::vector<std::string> Args; + }; + + /// Information stored for each error found. + struct ErrorContent { + std::vector<ContextFrame> ContextStack; + struct Message { + SourceRange Range; + ErrorType Type; + std::vector<std::string> Args; + }; + std::vector<Message> Messages; + }; + ArrayRef<ErrorContent> errors() const { return Errors; } + + /// Returns a simple string representation of each error. + /// + /// Each error only shows the error message without any context. + void printToStream(llvm::raw_ostream &OS) const; + std::string toString() const; + + /// Returns the full string representation of each error. + /// + /// Each error message contains the full context. + void printToStreamFull(llvm::raw_ostream &OS) const; + std::string toStringFull() const; + +private: + /// Helper function used by the constructors of ContextFrame. + ArgStream pushContextFrame(ContextType Type, SourceRange Range); + + std::vector<ContextFrame> ContextStack; + std::vector<ErrorContent> Errors; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H diff --git a/clang-r353983/include/clang/ASTMatchers/Dynamic/Parser.h b/clang-r353983/include/clang/ASTMatchers/Dynamic/Parser.h new file mode 100644 index 00000000..15e0aa7e --- /dev/null +++ b/clang-r353983/include/clang/ASTMatchers/Dynamic/Parser.h @@ -0,0 +1,264 @@ +//===- Parser.h - Matcher expression parser ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// 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> := <Literal> | <NamedValue> | <MatcherExpression> +/// <Literal> := <StringLiteral> | <Boolean> | <Double> | <Unsigned> +/// <StringLiteral> := "quoted string" +/// <Boolean> := true | false +/// <Double> := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+ +/// <Unsigned> := [0-9]+ +/// <NamedValue> := <Identifier> +/// <MatcherExpression> := <Identifier>(<ArgumentList>) | +/// <Identifier>(<ArgumentList>).bind(<StringLiteral>) +/// <Identifier> := [a-zA-Z]+ +/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> +/// \endcode +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H + +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <utility> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +class Diagnostics; + +/// Matcher expression parser. +class Parser { +public: + /// 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(); + + /// Process a matcher expression. + /// + /// All the arguments passed here have already been processed. + /// + /// \param Ctor A matcher constructor looked up by lookupMatcherCtor. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param BindID The ID to use to bind the matcher, or a null \c StringRef + /// if no ID is specified. + /// + /// \param Args The argument list for the matcher. + /// + /// \return The matcher objects constructed by the processor, or a null + /// matcher if an error occurred. In that case, \c Error will contain a + /// description of the error. + virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) = 0; + + /// Look up a matcher by name. + /// + /// \param MatcherName The matcher name found by the parser. + /// + /// \return The matcher constructor, or Optional<MatcherCtor>() if not + /// found. + virtual llvm::Optional<MatcherCtor> + lookupMatcherCtor(StringRef MatcherName) = 0; + + /// Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + virtual std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + virtual std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes); + }; + + /// Sema implementation that uses the matcher registry to process the + /// tokens. + class RegistrySema : public Parser::Sema { + public: + ~RegistrySema() override; + + llvm::Optional<MatcherCtor> + lookupMatcherCtor(StringRef MatcherName) override; + + VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) override; + + std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override; + + std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; + }; + + using NamedValueMap = llvm::StringMap<VariantValue>; + + /// Parse a matcher expression. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// + /// \return The matcher object constructed by the processor, or an empty + /// Optional 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 llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, S, nullptr, Error); + } + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, nullptr, Error); + } + + /// 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. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + static bool parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, + VariantValue *Value, Diagnostics *Error); + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + return parseExpression(Code, S, nullptr, Value, Error); + } + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + return parseExpression(Code, nullptr, Value, Error); + } + + /// Complete an expression at the given offset. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// + /// \return The list of completions, which may be empty if there are no + /// available completions or if an error occurred. + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues); + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) { + return completeExpression(Code, CompletionOffset, S, nullptr); + } + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset) { + return completeExpression(Code, CompletionOffset, nullptr); + } + +private: + class CodeTokenizer; + struct ScopedContextEntry; + struct TokenInfo; + + Parser(CodeTokenizer *Tokenizer, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + + bool parseBindID(std::string &BindID); + bool parseExpressionImpl(VariantValue *Value); + bool parseMatcherExpressionImpl(const TokenInfo &NameToken, + VariantValue *Value); + bool parseIdentifierPrefixImpl(VariantValue *Value); + + void addCompletion(const TokenInfo &CompToken, + const MatcherCompletion &Completion); + void addExpressionCompletions(); + + std::vector<MatcherCompletion> + getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes); + + CodeTokenizer *const Tokenizer; + Sema *const S; + const NamedValueMap *const NamedValues; + Diagnostics *const Error; + + using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>; + + ContextStackTy ContextStack; + std::vector<MatcherCompletion> Completions; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/clang-r353983/include/clang/ASTMatchers/Dynamic/Registry.h b/clang-r353983/include/clang/ASTMatchers/Dynamic/Registry.h new file mode 100644 index 00000000..215206b2 --- /dev/null +++ b/clang-r353983/include/clang/ASTMatchers/Dynamic/Registry.h @@ -0,0 +1,135 @@ +//===- Registry.h - Matcher registry ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Registry of all known matchers. +/// +/// The registry provides a generic interface to construct any matcher by name. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <utility> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace internal { + +class MatcherDescriptor; + +} // namespace internal + +using MatcherCtor = const internal::MatcherDescriptor *; + +struct MatcherCompletion { + MatcherCompletion() = default; + MatcherCompletion(StringRef TypedText, StringRef MatcherDecl, + unsigned Specificity) + : TypedText(TypedText), MatcherDecl(MatcherDecl), + Specificity(Specificity) {} + + bool operator==(const MatcherCompletion &Other) const { + return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl; + } + + /// The text to type to select this matcher. + std::string TypedText; + + /// The "declaration" of the matcher, with type information. + std::string MatcherDecl; + + /// Value corresponding to the "specificity" of the converted matcher. + /// + /// Zero specificity indicates that this conversion would produce a trivial + /// matcher that will either always or never match. + /// Such matchers are excluded from code completion results. + unsigned Specificity; +}; + +class Registry { +public: + Registry() = delete; + + /// Look up a matcher in the registry by name, + /// + /// \return An opaque value which may be used to refer to the matcher + /// constructor, or Optional<MatcherCtor>() if not found. + static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName); + + /// Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + static std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + static std::vector<MatcherCompletion> + getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes); + + /// Construct a matcher from the registry. + /// + /// \param Ctor The matcher constructor 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 object constructed if no error was found. + /// A null matcher 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 VariantMatcher constructMatcher(MatcherCtor Ctor, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + /// Construct a matcher from the registry and bind it. + /// + /// Similar the \c constructMatcher() above, but it then tries to bind the + /// matcher to the specified \c BindID. + /// If the matcher is not bindable, it sets an error in \c Error and returns + /// a null matcher. + static VariantMatcher constructBoundMatcher(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error); +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/clang-r353983/include/clang/ASTMatchers/Dynamic/VariantValue.h b/clang-r353983/include/clang/ASTMatchers/Dynamic/VariantValue.h new file mode 100644 index 00000000..511472a4 --- /dev/null +++ b/clang-r353983/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -0,0 +1,348 @@ +//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// 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_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include <memory> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// Kind identifier. +/// +/// It supports all types that VariantValue can contain. +class ArgKind { + public: + enum Kind { + AK_Matcher, + AK_Boolean, + AK_Double, + AK_Unsigned, + AK_String + }; + /// Constructor for non-matcher types. + ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); } + + /// Constructor for matcher types. + ArgKind(ast_type_traits::ASTNodeKind MatcherKind) + : K(AK_Matcher), MatcherKind(MatcherKind) {} + + Kind getArgKind() const { return K; } + ast_type_traits::ASTNodeKind getMatcherKind() const { + assert(K == AK_Matcher); + return MatcherKind; + } + + /// Determines if this type can be converted to \p To. + /// + /// \param To the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// conversion. + bool isConvertibleTo(ArgKind To, unsigned *Specificity) const; + + bool operator<(const ArgKind &Other) const { + if (K == AK_Matcher && Other.K == AK_Matcher) + return MatcherKind < Other.MatcherKind; + return K < Other.K; + } + + /// String representation of the type. + std::string asString() const; + +private: + Kind K; + ast_type_traits::ASTNodeKind MatcherKind; +}; + +using ast_matchers::internal::DynTypedMatcher; + +/// A variant matcher object. +/// +/// The purpose of this object is to abstract simple and polymorphic matchers +/// into a single object type. +/// Polymorphic matchers might be implemented as a list of all the possible +/// overloads of the matcher. \c VariantMatcher knows how to select the +/// appropriate overload when needed. +/// To get a real matcher object out of a \c VariantMatcher you can do: +/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous +/// to decide which matcher to return. Eg. it contains only a single +/// matcher, or a polymorphic one with only one overload. +/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if +/// the underlying matcher(s) can unambiguously return a Matcher<T>. +class VariantMatcher { + /// Methods that depend on T from hasTypedMatcher/getTypedMatcher. + class MatcherOps { + public: + MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + + /// Convert \p Matcher the destination type and return it as a new + /// DynTypedMatcher. + virtual DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const = 0; + + /// Constructs a variadic typed matcher from \p InnerMatchers. + /// Will try to convert each inner matcher to the destination type and + /// return llvm::None if it fails to do so. + llvm::Optional<DynTypedMatcher> + constructVariadicOperator(DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const; + + protected: + ~MatcherOps() = default; + + private: + ast_type_traits::ASTNodeKind NodeKind; + }; + + /// Payload interface to be specialized by each matcher type. + /// + /// It follows a similar interface as VariantMatcher itself. + class Payload { + public: + virtual ~Payload(); + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0; + virtual std::string getTypeAsString() const = 0; + virtual llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const = 0; + virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const = 0; + }; + +public: + /// A null matcher. + VariantMatcher(); + + /// Clones the provided matcher. + static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); + + /// Clones the provided matchers. + /// + /// They should be the result of a polymorphic matcher. + static VariantMatcher + PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers); + + /// Creates a 'variadic' operator matcher. + /// + /// It will bind to the appropriate type on getTypedMatcher<T>(). + static VariantMatcher + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args); + + /// Makes the matcher the "null" matcher. + void reset(); + + /// Whether the matcher is null. + bool isNull() const { return !Value; } + + /// Return a single matcher, if there is no ambiguity. + /// + /// \returns the matcher, if there is only one matcher. An empty Optional, if + /// the underlying matcher is a polymorphic matcher with more than one + /// representation. + llvm::Optional<DynTypedMatcher> getSingleMatcher() const; + + /// Determines if the contained matcher can be converted to + /// \c Matcher<T>. + /// + /// For the Single case, it returns true if it can be converted to + /// \c Matcher<T>. + /// For the Polymorphic case, it returns true if one, and only one, of the + /// overloads can be converted to \c Matcher<T>. If there are more than one + /// that can, the result would be ambiguous and false is returned. + template <class T> + bool hasTypedMatcher() const { + if (!Value) return false; + return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue(); + } + + /// Determines if the contained matcher can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// conversion. + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const { + if (Value) + return Value->isConvertibleTo(Kind, Specificity); + return false; + } + + /// Return this matcher as a \c Matcher<T>. + /// + /// Handles the different types (Single, Polymorphic) accordingly. + /// Asserts that \c hasTypedMatcher<T>() is true. + template <class T> + ast_matchers::internal::Matcher<T> getTypedMatcher() const { + assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false"); + return Value->getTypedMatcher(TypedMatcherOps<T>()) + ->template convertTo<T>(); + } + + /// String representation of the type of the value. + /// + /// If the underlying matcher is a polymorphic one, the string will show all + /// the types. + std::string getTypeAsString() const; + +private: + explicit VariantMatcher(std::shared_ptr<Payload> Value) + : Value(std::move(Value)) {} + + template <typename T> struct TypedMatcherOps; + + class SinglePayload; + class PolymorphicPayload; + class VariadicOpPayload; + + std::shared_ptr<const Payload> Value; +}; + +template <typename T> +struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {} + typedef ast_matchers::internal::Matcher<T> MatcherT; + + DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const override { + return DynTypedMatcher(Matcher.convertTo<T>()); + } +}; + +/// 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 bool +// - \c double +/// - \c unsigned +/// - \c llvm::StringRef +/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>) +class VariantValue { +public: + VariantValue() : Type(VT_Nothing) {} + + VariantValue(const VariantValue &Other); + ~VariantValue(); + VariantValue &operator=(const VariantValue &Other); + + /// Specific constructors for each supported type. + VariantValue(bool Boolean); + VariantValue(double Double); + VariantValue(unsigned Unsigned); + VariantValue(StringRef String); + VariantValue(const VariantMatcher &Matchers); + + /// Constructs an \c unsigned value (disambiguation from bool). + VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {} + + /// Returns true iff this is not an empty value. + explicit operator bool() const { return hasValue(); } + bool hasValue() const { return Type != VT_Nothing; } + + /// Boolean value functions. + bool isBoolean() const; + bool getBoolean() const; + void setBoolean(bool Boolean); + + /// Double value functions. + bool isDouble() const; + double getDouble() const; + void setDouble(double Double); + + /// Unsigned value functions. + bool isUnsigned() const; + unsigned getUnsigned() const; + void setUnsigned(unsigned Unsigned); + + /// String value functions. + bool isString() const; + const std::string &getString() const; + void setString(StringRef String); + + /// Matcher value functions. + bool isMatcher() const; + const VariantMatcher &getMatcher() const; + void setMatcher(const VariantMatcher &Matcher); + + /// Determines if the contained value can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// conversion. + bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const; + + /// Determines if the contained value can be converted to any kind + /// in \p Kinds. + /// + /// \param Kinds the requested destination types. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// conversion. It is the maximum specificity of all the possible + /// conversions. + bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const; + + /// String representation of the type of the value. + std::string getTypeAsString() const; + +private: + void reset(); + + /// All supported value types. + enum ValueType { + VT_Nothing, + VT_Boolean, + VT_Double, + VT_Unsigned, + VT_String, + VT_Matcher + }; + + /// All supported value types. + union AllValues { + unsigned Unsigned; + double Double; + bool Boolean; + std::string *String; + VariantMatcher *Matcher; + }; + + ValueType Type; + AllValues Value; +}; + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H |
