summaryrefslogtreecommitdiff
path: root/clang-r353983/include/clang/ASTMatchers/Dynamic
diff options
context:
space:
mode:
Diffstat (limited to 'clang-r353983/include/clang/ASTMatchers/Dynamic')
-rw-r--r--clang-r353983/include/clang/ASTMatchers/Dynamic/Diagnostics.h184
-rw-r--r--clang-r353983/include/clang/ASTMatchers/Dynamic/Parser.h264
-rw-r--r--clang-r353983/include/clang/ASTMatchers/Dynamic/Registry.h135
-rw-r--r--clang-r353983/include/clang/ASTMatchers/Dynamic/VariantValue.h348
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