diff options
Diffstat (limited to 'clang/lib/ASTMatchers/Dynamic')
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp | 221 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Marshallers.h | 822 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Parser.cpp | 683 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Registry.cpp | 693 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/VariantValue.cpp | 457 |
5 files changed, 2876 insertions, 0 deletions
diff --git a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp new file mode 100644 index 000000000000..8656bca870ec --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -0,0 +1,221 @@ +//===--- Diagnostics.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type, + SourceRange Range) { + ContextStack.emplace_back(); + ContextFrame& data = ContextStack.back(); + data.Type = Type; + data.Range = Range; + return ArgStream(&data.Args); +} + +Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error, + StringRef MatcherName, + SourceRange MatcherRange) + : Error(Error) { + Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName; +} + +Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error, + StringRef MatcherName, + SourceRange MatcherRange, + unsigned ArgNumber) + : Error(Error) { + Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber + << MatcherName; +} + +Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); } + +Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error) + : Error(Error), BeginIndex(Error->Errors.size()) {} + +Diagnostics::OverloadContext::~OverloadContext() { + // Merge all errors that happened while in this context. + if (BeginIndex < Error->Errors.size()) { + Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex]; + for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) { + Dest.Messages.push_back(Error->Errors[i].Messages[0]); + } + Error->Errors.resize(BeginIndex + 1); + } +} + +void Diagnostics::OverloadContext::revertErrors() { + // Revert the errors. + Error->Errors.resize(BeginIndex); +} + +Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) { + Out->push_back(Arg.str()); + return *this; +} + +Diagnostics::ArgStream Diagnostics::addError(SourceRange Range, + ErrorType Error) { + Errors.emplace_back(); + ErrorContent &Last = Errors.back(); + Last.ContextStack = ContextStack; + Last.Messages.emplace_back(); + Last.Messages.back().Range = Range; + Last.Messages.back().Type = Error; + return ArgStream(&Last.Messages.back().Args); +} + +static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) { + switch (Type) { + case Diagnostics::CT_MatcherConstruct: + return "Error building matcher $0."; + case Diagnostics::CT_MatcherArg: + return "Error parsing argument $0 for matcher $1."; + } + llvm_unreachable("Unknown ContextType value."); +} + +static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { + switch (Type) { + case Diagnostics::ET_RegistryMatcherNotFound: + return "Matcher not found: $0"; + case Diagnostics::ET_RegistryWrongArgCount: + return "Incorrect argument count. (Expected = $0) != (Actual = $1)"; + case Diagnostics::ET_RegistryWrongArgType: + return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)"; + case Diagnostics::ET_RegistryNotBindable: + return "Matcher does not support binding."; + case Diagnostics::ET_RegistryAmbiguousOverload: + // TODO: Add type info about the overload error. + return "Ambiguous matcher overload."; + case Diagnostics::ET_RegistryValueNotFound: + return "Value not found: $0"; + + case Diagnostics::ET_ParserStringError: + return "Error parsing string token: <$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_ParserMalformedBindExpr: + return "Malformed bind() expression."; + case Diagnostics::ET_ParserTrailingCode: + return "Expected end of code."; + case Diagnostics::ET_ParserNumberError: + return "Error parsing numeric literal: <$0>"; + case Diagnostics::ET_ParserOverloadedType: + return "Input value has unresolved overloaded type: $0"; + + case Diagnostics::ET_None: + return "<N/A>"; + } + llvm_unreachable("Unknown ErrorType value."); +} + +static void formatErrorString(StringRef FormatString, + ArrayRef<std::string> Args, + llvm::raw_ostream &OS) { + while (!FormatString.empty()) { + std::pair<StringRef, StringRef> Pieces = FormatString.split("$"); + OS << 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()) { + OS << Args[Index]; + } else { + OS << "<Argument_Not_Provided>"; + } + } + } +} + +static void maybeAddLineAndColumn(SourceRange Range, + llvm::raw_ostream &OS) { + if (Range.Start.Line > 0 && Range.Start.Column > 0) { + OS << Range.Start.Line << ":" << Range.Start.Column << ": "; + } +} + +static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame, + llvm::raw_ostream &OS) { + maybeAddLineAndColumn(Frame.Range, OS); + formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS); +} + +static void +printMessageToStream(const Diagnostics::ErrorContent::Message &Message, + const Twine Prefix, llvm::raw_ostream &OS) { + maybeAddLineAndColumn(Message.Range, OS); + OS << Prefix; + formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS); +} + +static void printErrorContentToStream(const Diagnostics::ErrorContent &Content, + llvm::raw_ostream &OS) { + if (Content.Messages.size() == 1) { + printMessageToStream(Content.Messages[0], "", OS); + } else { + for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + printMessageToStream(Content.Messages[i], + "Candidate " + Twine(i + 1) + ": ", OS); + } + } +} + +void Diagnostics::printToStream(llvm::raw_ostream &OS) const { + for (size_t i = 0, e = Errors.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + printErrorContentToStream(Errors[i], OS); + } +} + +std::string Diagnostics::toString() const { + std::string S; + llvm::raw_string_ostream OS(S); + printToStream(OS); + return OS.str(); +} + +void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const { + for (size_t i = 0, e = Errors.size(); i != e; ++i) { + if (i != 0) OS << "\n"; + const ErrorContent &Error = Errors[i]; + for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) { + printContextFrameToStream(Error.ContextStack[i], OS); + OS << "\n"; + } + printErrorContentToStream(Error, OS); + } +} + +std::string Diagnostics::toStringFull() const { + std::string S; + llvm::raw_string_ostream OS(S); + printToStreamFull(OS); + return OS.str(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h new file mode 100644 index 000000000000..9f46108d1848 --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -0,0 +1,822 @@ +//===- Marshallers.h - Generic matcher function marshallers -----*- 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 +/// 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_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/OperationKinds.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/OpenMPKinds.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <limits> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace internal { + +/// 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(); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_String); + } +}; + +template <> +struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> { +}; + +template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> { + static bool is(const VariantValue &Value) { + return Value.isMatcher() && Value.getMatcher().hasTypedMatcher<T>(); + } + + static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { + return Value.getMatcher().getTypedMatcher<T>(); + } + + static ArgKind getKind() { + return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } +}; + +template <> struct ArgTypeTraits<bool> { + static bool is(const VariantValue &Value) { return Value.isBoolean(); } + + static bool get(const VariantValue &Value) { + return Value.getBoolean(); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_Boolean); + } +}; + +template <> struct ArgTypeTraits<double> { + static bool is(const VariantValue &Value) { return Value.isDouble(); } + + static double get(const VariantValue &Value) { + return Value.getDouble(); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_Double); + } +}; + +template <> struct ArgTypeTraits<unsigned> { + static bool is(const VariantValue &Value) { return Value.isUnsigned(); } + + static unsigned get(const VariantValue &Value) { + return Value.getUnsigned(); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_Unsigned); + } +}; + +template <> struct ArgTypeTraits<attr::Kind> { +private: + static Optional<attr::Kind> getAttrKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<Optional<attr::Kind>>(AttrKind) +#define ATTR(X) .Case("attr::" #X, attr:: X) +#include "clang/Basic/AttrList.inc" + .Default(llvm::None); + } + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getAttrKind(Value.getString()); + } + + static attr::Kind get(const VariantValue &Value) { + return *getAttrKind(Value.getString()); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_String); + } +}; + +template <> struct ArgTypeTraits<CastKind> { +private: + static Optional<CastKind> getCastKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<Optional<CastKind>>(AttrKind) +#define CAST_OPERATION(Name) .Case( #Name, CK_##Name) +#include "clang/AST/OperationKinds.def" + .Default(llvm::None); + } + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getCastKind(Value.getString()); + } + + static CastKind get(const VariantValue &Value) { + return *getCastKind(Value.getString()); + } + + static ArgKind getKind() { + return ArgKind(ArgKind::AK_String); + } +}; + +template <> struct ArgTypeTraits<OpenMPClauseKind> { +private: + static Optional<OpenMPClauseKind> getClauseKind(llvm::StringRef ClauseKind) { + return llvm::StringSwitch<Optional<OpenMPClauseKind>>(ClauseKind) +#define OPENMP_CLAUSE(TextualSpelling, Class) \ + .Case("OMPC_" #TextualSpelling, OMPC_##TextualSpelling) +#include "clang/Basic/OpenMPKinds.def" + .Default(llvm::None); + } + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getClauseKind(Value.getString()); + } + + static OpenMPClauseKind get(const VariantValue &Value) { + return *getClauseKind(Value.getString()); + } + + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } +}; + +/// Matcher descriptor interface. +/// +/// Provides a \c create() method that constructs the matcher from the provided +/// arguments, and various other methods for type introspection. +class MatcherDescriptor { +public: + virtual ~MatcherDescriptor() = default; + + virtual VariantMatcher create(SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const = 0; + + /// Returns whether the matcher is variadic. Variadic matchers can take any + /// number of arguments, but they must be of the same type. + virtual bool isVariadic() const = 0; + + /// Returns the number of arguments accepted by the matcher if not variadic. + virtual unsigned getNumArgs() const = 0; + + /// Given that the matcher is being converted to type \p ThisKind, append the + /// set of argument types accepted for argument \p ArgNo to \p ArgKinds. + // FIXME: We should provide the ability to constrain the output of this + // function based on the types of other matcher arguments. + virtual void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &ArgKinds) const = 0; + + /// Returns whether this matcher is convertible to the given type. If it is + /// so convertible, store in *Specificity a value corresponding to the + /// "specificity" of the converted matcher to the given context, and in + /// *LeastDerivedKind the least derived matcher kind which would result in the + /// same matcher overload. 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. + virtual bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity = nullptr, + ast_type_traits::ASTNodeKind *LeastDerivedKind = nullptr) const = 0; + + /// Returns whether the matcher will, given a matcher of any type T, yield a + /// matcher of type T. + virtual bool isPolymorphic() const { return false; } +}; + +inline bool isRetKindConvertibleTo( + ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) { + for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) { + if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) { + if (LeastDerivedKind) + *LeastDerivedKind = NodeKind; + return true; + } + } + return false; +} + +/// Simple callback implementation. Marshaller and function are provided. +/// +/// This class wraps a function of arbitrary signature and a marshaller +/// function into a MatcherDescriptor. +/// The marshaller is in charge of taking the VariantValue arguments, checking +/// their types, unpacking them and calling the underlying function. +class FixedArgCountMatcherDescriptor : public MatcherDescriptor { +public: + using MarshallerType = VariantMatcher (*)(void (*Func)(), + StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + /// \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. + /// \param RetKinds The list of matcher types to which the matcher is + /// convertible. + /// \param ArgKinds The types of the arguments this matcher takes. + FixedArgCountMatcherDescriptor( + MarshallerType Marshaller, void (*Func)(), StringRef MatcherName, + ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, + ArrayRef<ArgKind> ArgKinds) + : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName), + RetKinds(RetKinds.begin(), RetKinds.end()), + ArgKinds(ArgKinds.begin(), ArgKinds.end()) {} + + VariantMatcher create(SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + return Marshaller(Func, MatcherName, NameRange, Args, Error); + } + + bool isVariadic() const override { return false; } + unsigned getNumArgs() const override { return ArgKinds.size(); } + + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + Kinds.push_back(ArgKinds[ArgNo]); + } + + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + return isRetKindConvertibleTo(RetKinds, Kind, Specificity, + LeastDerivedKind); + } + +private: + const MarshallerType Marshaller; + void (* const Func)(); + const std::string MatcherName; + const std::vector<ast_type_traits::ASTNodeKind> RetKinds; + const std::vector<ArgKind> ArgKinds; +}; + +/// Helper methods to extract and merge all possible typed matchers +/// out of the polymorphic object. +template <class PolyMatcher> +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector<DynTypedMatcher> &Out, + ast_matchers::internal::EmptyTypeList) {} + +template <class PolyMatcher, class TypeList> +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector<DynTypedMatcher> &Out, TypeList) { + Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly)); + mergePolyMatchers(Poly, Out, typename TypeList::tail()); +} + +/// Convert the return values of the functions into a VariantMatcher. +/// +/// There are 2 cases right now: The return value is a Matcher<T> or is a +/// polymorphic matcher. For the former, we just construct the VariantMatcher. +/// For the latter, we instantiate all the possible Matcher<T> of the poly +/// matcher. +static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) { + return VariantMatcher::SingleMatcher(Matcher); +} + +template <typename T> +static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, + typename T::ReturnTypes * = + nullptr) { + std::vector<DynTypedMatcher> Matchers; + mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes()); + VariantMatcher Out = VariantMatcher::PolymorphicMatcher(std::move(Matchers)); + return Out; +} + +template <typename T> +inline void buildReturnTypeVectorFromTypeList( + std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { + RetTypes.push_back( + ast_type_traits::ASTNodeKind::getFromNodeKind<typename T::head>()); + buildReturnTypeVectorFromTypeList<typename T::tail>(RetTypes); +} + +template <> +inline void +buildReturnTypeVectorFromTypeList<ast_matchers::internal::EmptyTypeList>( + std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {} + +template <typename T> +struct BuildReturnTypeVector { + static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { + buildReturnTypeVectorFromTypeList<typename T::ReturnTypes>(RetTypes); + } +}; + +template <typename T> +struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T>> { + static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { + RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } +}; + +template <typename T> +struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T>> { + static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { + RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } +}; + +/// Variadic marshaller function. +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> +VariantMatcher +variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange, + ArrayRef<ParserValue> Args, Diagnostics *Error) { + ArgT **InnerArgs = new ArgT *[Args.size()](); + + bool HasError = false; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + using ArgTraits = ArgTypeTraits<ArgT>; + + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!ArgTraits::is(Value)) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << ArgTraits::getKind().asString() << Value.getTypeAsString(); + HasError = true; + break; + } + InnerArgs[i] = new ArgT(ArgTraits::get(Value)); + } + + VariantMatcher Out; + if (!HasError) { + Out = outvalueToVariantMatcher(Func(llvm::makeArrayRef(InnerArgs, + Args.size()))); + } + + for (size_t i = 0, e = Args.size(); i != e; ++i) { + delete InnerArgs[i]; + } + delete[] InnerArgs; + return Out; +} + +/// Matcher descriptor for variadic functions. +/// +/// This class simply wraps a VariadicFunction with the right signature to export +/// it as a MatcherDescriptor. +/// This allows us to have one implementation of the interface for as many free +/// functions as we want, reducing the number of symbols and size of the +/// object file. +class VariadicFuncMatcherDescriptor : public MatcherDescriptor { +public: + using RunFunc = VariantMatcher (*)(StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + template <typename ResultT, typename ArgT, + ResultT (*F)(ArrayRef<const ArgT *>)> + VariadicFuncMatcherDescriptor( + ast_matchers::internal::VariadicFunction<ResultT, ArgT, F> Func, + StringRef MatcherName) + : Func(&variadicMatcherDescriptor<ResultT, ArgT, F>), + MatcherName(MatcherName.str()), + ArgsKind(ArgTypeTraits<ArgT>::getKind()) { + BuildReturnTypeVector<ResultT>::build(RetKinds); + } + + VariantMatcher create(SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + return Func(MatcherName, NameRange, Args, Error); + } + + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } + + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + Kinds.push_back(ArgsKind); + } + + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + return isRetKindConvertibleTo(RetKinds, Kind, Specificity, + LeastDerivedKind); + } + +private: + const RunFunc Func; + const std::string MatcherName; + std::vector<ast_type_traits::ASTNodeKind> RetKinds; + const ArgKind ArgsKind; +}; + +/// Return CK_Trivial when appropriate for VariadicDynCastAllOfMatchers. +class DynCastAllOfMatcherDescriptor : public VariadicFuncMatcherDescriptor { +public: + template <typename BaseT, typename DerivedT> + DynCastAllOfMatcherDescriptor( + ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> Func, + StringRef MatcherName) + : VariadicFuncMatcherDescriptor(Func, MatcherName), + DerivedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<DerivedT>()) { + } + + bool + isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + // If Kind is not a base of DerivedKind, either DerivedKind is a base of + // Kind (in which case the match will always succeed) or Kind and + // DerivedKind are unrelated (in which case it will always fail), so set + // Specificity to 0. + if (VariadicFuncMatcherDescriptor::isConvertibleTo(Kind, Specificity, + LeastDerivedKind)) { + if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) { + if (Specificity) + *Specificity = 0; + } + return true; + } else { + return false; + } + } + +private: + const ast_type_traits::ASTNodeKind DerivedKind; +}; + +/// Helper macros to check the arguments on all marshaller functions. +#define CHECK_ARG_COUNT(count) \ + if (Args.size() != count) { \ + Error->addError(NameRange, Error->ET_RegistryWrongArgCount) \ + << count << Args.size(); \ + return VariantMatcher(); \ + } + +#define CHECK_ARG_TYPE(index, type) \ + if (!ArgTypeTraits<type>::is(Args[index].Value)) { \ + Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ + << (index + 1) << ArgTypeTraits<type>::getKind().asString() \ + << Args[index].Value.getTypeAsString(); \ + return VariantMatcher(); \ + } + +/// 0-arg marshaller function. +template <typename ReturnType> +static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + using FuncType = ReturnType (*)(); + CHECK_ARG_COUNT(0); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)()); +} + +/// 1-arg marshaller function. +template <typename ReturnType, typename ArgType1> +static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + using FuncType = ReturnType (*)(ArgType1); + CHECK_ARG_COUNT(1); + CHECK_ARG_TYPE(0, ArgType1); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)( + ArgTypeTraits<ArgType1>::get(Args[0].Value))); +} + +/// 2-arg marshaller function. +template <typename ReturnType, typename ArgType1, typename ArgType2> +static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + using FuncType = ReturnType (*)(ArgType1, ArgType2); + CHECK_ARG_COUNT(2); + CHECK_ARG_TYPE(0, ArgType1); + CHECK_ARG_TYPE(1, ArgType2); + return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)( + ArgTypeTraits<ArgType1>::get(Args[0].Value), + ArgTypeTraits<ArgType2>::get(Args[1].Value))); +} + +#undef CHECK_ARG_COUNT +#undef CHECK_ARG_TYPE + +/// Helper class used to collect all the possible overloads of an +/// argument adaptative matcher function. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +class AdaptativeOverloadCollector { +public: + AdaptativeOverloadCollector( + StringRef Name, std::vector<std::unique_ptr<MatcherDescriptor>> &Out) + : Name(Name), Out(Out) { + collect(FromTypes()); + } + +private: + using AdaptativeFunc = ast_matchers::internal::ArgumentAdaptingMatcherFunc< + ArgumentAdapterT, FromTypes, ToTypes>; + + /// End case for the recursion + static void collect(ast_matchers::internal::EmptyTypeList) {} + + /// Recursive case. Get the overload for the head of the list, and + /// recurse to the tail. + template <typename FromTypeList> + inline void collect(FromTypeList); + + StringRef Name; + std::vector<std::unique_ptr<MatcherDescriptor>> &Out; +}; + +/// MatcherDescriptor that wraps multiple "overloads" of the same +/// matcher. +/// +/// It will try every overload and generate appropriate errors for when none or +/// more than one overloads match the arguments. +class OverloadedMatcherDescriptor : public MatcherDescriptor { +public: + OverloadedMatcherDescriptor( + MutableArrayRef<std::unique_ptr<MatcherDescriptor>> Callbacks) + : Overloads(std::make_move_iterator(Callbacks.begin()), + std::make_move_iterator(Callbacks.end())) {} + + ~OverloadedMatcherDescriptor() override = default; + + VariantMatcher create(SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + std::vector<VariantMatcher> Constructed; + Diagnostics::OverloadContext Ctx(Error); + for (const auto &O : Overloads) { + VariantMatcher SubMatcher = O->create(NameRange, Args, Error); + if (!SubMatcher.isNull()) { + Constructed.push_back(SubMatcher); + } + } + + if (Constructed.empty()) return VariantMatcher(); // No overload matched. + // We ignore the errors if any matcher succeeded. + Ctx.revertErrors(); + if (Constructed.size() > 1) { + // More than one constructed. It is ambiguous. + Error->addError(NameRange, Error->ET_RegistryAmbiguousOverload); + return VariantMatcher(); + } + return Constructed[0]; + } + + bool isVariadic() const override { + bool Overload0Variadic = Overloads[0]->isVariadic(); +#ifndef NDEBUG + for (const auto &O : Overloads) { + assert(Overload0Variadic == O->isVariadic()); + } +#endif + return Overload0Variadic; + } + + unsigned getNumArgs() const override { + unsigned Overload0NumArgs = Overloads[0]->getNumArgs(); +#ifndef NDEBUG + for (const auto &O : Overloads) { + assert(Overload0NumArgs == O->getNumArgs()); + } +#endif + return Overload0NumArgs; + } + + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + for (const auto &O : Overloads) { + if (O->isConvertibleTo(ThisKind)) + O->getArgKinds(ThisKind, ArgNo, Kinds); + } + } + + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + for (const auto &O : Overloads) { + if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind)) + return true; + } + return false; + } + +private: + std::vector<std::unique_ptr<MatcherDescriptor>> Overloads; +}; + +/// Variadic operator marshaller function. +class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { +public: + using VarOp = DynTypedMatcher::VariadicOperator; + + VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount, + VarOp Op, StringRef MatcherName) + : MinCount(MinCount), MaxCount(MaxCount), Op(Op), + MatcherName(MatcherName) {} + + VariantMatcher create(SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + if (Args.size() < MinCount || MaxCount < Args.size()) { + const std::string MaxStr = + (MaxCount == std::numeric_limits<unsigned>::max() ? "" + : Twine(MaxCount)) + .str(); + Error->addError(NameRange, Error->ET_RegistryWrongArgCount) + << ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size(); + return VariantMatcher(); + } + + std::vector<VariantMatcher> InnerArgs; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!Value.isMatcher()) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << "Matcher<>" << Value.getTypeAsString(); + return VariantMatcher(); + } + InnerArgs.push_back(Value.getMatcher()); + } + return VariantMatcher::VariadicOperatorMatcher(Op, std::move(InnerArgs)); + } + + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } + + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + Kinds.push_back(ThisKind); + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + if (Specificity) + *Specificity = 1; + if (LeastDerivedKind) + *LeastDerivedKind = Kind; + return true; + } + + bool isPolymorphic() const override { return true; } + +private: + const unsigned MinCount; + const unsigned MaxCount; + const VarOp Op; + const StringRef MatcherName; +}; + +/// Helper functions to select the appropriate marshaller functions. +/// They detect the number of arguments, arguments types and return type. + +/// 0-arg overload +template <typename ReturnType> +std::unique_ptr<MatcherDescriptor> +makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) { + std::vector<ast_type_traits::ASTNodeKind> RetTypes; + BuildReturnTypeVector<ReturnType>::build(RetTypes); + return std::make_unique<FixedArgCountMatcherDescriptor>( + matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func), + MatcherName, RetTypes, None); +} + +/// 1-arg overload +template <typename ReturnType, typename ArgType1> +std::unique_ptr<MatcherDescriptor> +makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), StringRef MatcherName) { + std::vector<ast_type_traits::ASTNodeKind> RetTypes; + BuildReturnTypeVector<ReturnType>::build(RetTypes); + ArgKind AK = ArgTypeTraits<ArgType1>::getKind(); + return std::make_unique<FixedArgCountMatcherDescriptor>( + matcherMarshall1<ReturnType, ArgType1>, + reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AK); +} + +/// 2-arg overload +template <typename ReturnType, typename ArgType1, typename ArgType2> +std::unique_ptr<MatcherDescriptor> +makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2), + StringRef MatcherName) { + std::vector<ast_type_traits::ASTNodeKind> RetTypes; + BuildReturnTypeVector<ReturnType>::build(RetTypes); + ArgKind AKs[] = { ArgTypeTraits<ArgType1>::getKind(), + ArgTypeTraits<ArgType2>::getKind() }; + return std::make_unique<FixedArgCountMatcherDescriptor>( + matcherMarshall2<ReturnType, ArgType1, ArgType2>, + reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs); +} + +/// Variadic overload. +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> +std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( + ast_matchers::internal::VariadicFunction<ResultT, ArgT, Func> VarFunc, + StringRef MatcherName) { + return std::make_unique<VariadicFuncMatcherDescriptor>(VarFunc, MatcherName); +} + +/// Overload for VariadicDynCastAllOfMatchers. +/// +/// Not strictly necessary, but DynCastAllOfMatcherDescriptor gives us better +/// completion results for that type of matcher. +template <typename BaseT, typename DerivedT> +std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( + ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> + VarFunc, + StringRef MatcherName) { + return std::make_unique<DynCastAllOfMatcherDescriptor>(VarFunc, MatcherName); +} + +/// Argument adaptative overload. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( + ast_matchers::internal::ArgumentAdaptingMatcherFunc<ArgumentAdapterT, + FromTypes, ToTypes>, + StringRef MatcherName) { + std::vector<std::unique_ptr<MatcherDescriptor>> Overloads; + AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>(MatcherName, + Overloads); + return std::make_unique<OverloadedMatcherDescriptor>(Overloads); +} + +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +template <typename FromTypeList> +inline void AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, + ToTypes>::collect(FromTypeList) { + Out.push_back(makeMatcherAutoMarshall( + &AdaptativeFunc::template create<typename FromTypeList::head>, Name)); + collect(typename FromTypeList::tail()); +} + +/// Variadic operator overload. +template <unsigned MinCount, unsigned MaxCount> +std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( + ast_matchers::internal::VariadicOperatorMatcherFunc<MinCount, MaxCount> + Func, + StringRef MatcherName) { + return std::make_unique<VariadicOperatorMatcherDescriptor>( + MinCount, MaxCount, Func.Op, MatcherName); +} + +} // namespace internal +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp new file mode 100644 index 000000000000..e3b00b46832c --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp @@ -0,0 +1,683 @@ +//===- Parser.cpp - Matcher expression parser -----------------------------===// +// +// 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 +/// Recursive parser implementation for the matcher expression grammar. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstddef> +#include <cstdlib> +#include <string> +#include <utility> +#include <vector> + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// Simple structure to hold information for one token from the parser. +struct Parser::TokenInfo { + /// Different possible tokens. + enum TokenKind { + TK_Eof, + TK_OpenParen, + TK_CloseParen, + TK_Comma, + TK_Period, + TK_Literal, + TK_Ident, + TK_InvalidChar, + TK_Error, + TK_CodeCompletion + }; + + /// Some known identifiers. + static const char* const ID_Bind; + + TokenInfo() = default; + + StringRef Text; + TokenKind Kind = TK_Eof; + SourceRange Range; + VariantValue Value; +}; + +const char* const Parser::TokenInfo::ID_Bind = "bind"; + +/// Simple tokenizer for the parser. +class Parser::CodeTokenizer { +public: + explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) + : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) { + NextToken = getNextToken(); + } + + CodeTokenizer(StringRef MatcherCode, Diagnostics *Error, + unsigned CodeCompletionOffset) + : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error), + CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) { + NextToken = getNextToken(); + } + + /// Returns but doesn't consume the next token. + const TokenInfo &peekNextToken() const { return NextToken; } + + /// 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 (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) { + Result.Kind = TokenInfo::TK_CodeCompletion; + Result.Text = StringRef(CodeCompletionLocation, 0); + CodeCompletionLocation = nullptr; + return Result; + } + + if (Code.empty()) { + Result.Kind = TokenInfo::TK_Eof; + Result.Text = ""; + return Result; + } + + switch (Code[0]) { + case '#': + Result.Kind = TokenInfo::TK_Eof; + Result.Text = ""; + return Result; + case ',': + Result.Kind = TokenInfo::TK_Comma; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case '.': + Result.Kind = TokenInfo::TK_Period; + 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; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // Parse an unsigned and float literal. + consumeNumberLiteral(&Result); + break; + + default: + if (isAlphanumeric(Code[0])) { + // Parse an identifier + size_t TokenLength = 1; + while (true) { + // A code completion location in/immediately after an identifier will + // cause the portion of the identifier before the code completion + // location to become a code completion token. + if (CodeCompletionLocation == Code.data() + TokenLength) { + CodeCompletionLocation = nullptr; + Result.Kind = TokenInfo::TK_CodeCompletion; + Result.Text = Code.substr(0, TokenLength); + Code = Code.drop_front(TokenLength); + return Result; + } + if (TokenLength == Code.size() || !isAlphanumeric(Code[TokenLength])) + break; + ++TokenLength; + } + if (TokenLength == 4 && Code.startswith("true")) { + Result.Kind = TokenInfo::TK_Literal; + Result.Value = true; + } else if (TokenLength == 5 && Code.startswith("false")) { + Result.Kind = TokenInfo::TK_Literal; + Result.Value = false; + } else { + 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; + } + + /// Consume an unsigned and float literal. + void consumeNumberLiteral(TokenInfo *Result) { + bool isFloatingLiteral = false; + unsigned Length = 1; + if (Code.size() > 1) { + // Consume the 'x' or 'b' radix modifier, if present. + switch (toLowercase(Code[1])) { + case 'x': case 'b': Length = 2; + } + } + while (Length < Code.size() && isHexDigit(Code[Length])) + ++Length; + + // Try to recognize a floating point literal. + while (Length < Code.size()) { + char c = Code[Length]; + if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) { + isFloatingLiteral = true; + Length++; + } else { + break; + } + } + + Result->Text = Code.substr(0, Length); + Code = Code.drop_front(Length); + + if (isFloatingLiteral) { + char *end; + errno = 0; + std::string Text = Result->Text.str(); + double doubleValue = strtod(Text.c_str(), &end); + if (*end == 0 && errno == 0) { + Result->Kind = TokenInfo::TK_Literal; + Result->Value = doubleValue; + return; + } + } else { + unsigned Value; + if (!Result->Text.getAsInteger(0, Value)) { + Result->Kind = TokenInfo::TK_Literal; + Result->Value = Value; + return; + } + } + + SourceRange Range; + Range.Start = Result->Range.Start; + Range.End = currentLocation(); + Error->addError(Range, Error->ET_ParserNumberError) << Result->Text; + Result->Kind = TokenInfo::TK_Error; + } + + /// 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); + 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->addError(Range, Error->ET_ParserStringError) << ErrorText; + Result->Kind = TokenInfo::TK_Error; + } + + /// 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 = 1; + Diagnostics *Error; + TokenInfo NextToken; + const char *CodeCompletionLocation = nullptr; +}; + +Parser::Sema::~Sema() = default; + +std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return {}; +} + +std::vector<MatcherCompletion> +Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) { + return {}; +} + +struct Parser::ScopedContextEntry { + Parser *P; + + ScopedContextEntry(Parser *P, MatcherCtor C) : P(P) { + P->ContextStack.push_back(std::make_pair(C, 0u)); + } + + ~ScopedContextEntry() { + P->ContextStack.pop_back(); + } + + void nextArg() { + ++P->ContextStack.back().second; + } +}; + +/// Parse expressions that start with an identifier. +/// +/// This function can parse named values and matchers. +/// In case of failure it will try to determine the user's intent to give +/// an appropriate error message. +bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) { + const TokenInfo NameToken = Tokenizer->consumeNextToken(); + + if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) { + // Parse as a named value. + if (const VariantValue NamedValue = + NamedValues ? NamedValues->lookup(NameToken.Text) + : VariantValue()) { + + if (Tokenizer->nextTokenKind() != TokenInfo::TK_Period) { + *Value = NamedValue; + return true; + } + + std::string BindID; + if (!parseBindID(BindID)) + return false; + + assert(NamedValue.isMatcher()); + llvm::Optional<DynTypedMatcher> Result = + NamedValue.getMatcher().getSingleMatcher(); + if (Result.hasValue()) { + llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID); + if (Bound.hasValue()) { + *Value = VariantMatcher::SingleMatcher(*Bound); + return true; + } + } + return false; + } + // If the syntax is correct and the name is not a matcher either, report + // unknown named value. + if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma || + Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen || + Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) && + !S->lookupMatcherCtor(NameToken.Text)) { + Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound) + << NameToken.Text; + return false; + } + // Otherwise, fallback to the matcher parser. + } + + // Parse as a matcher expression. + return parseMatcherExpressionImpl(NameToken, Value); +} + +bool Parser::parseBindID(std::string &BindID) { + // Parse .bind("foo") + assert(Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period); + Tokenizer->consumeNextToken(); // consume the period. + const TokenInfo BindToken = Tokenizer->consumeNextToken(); + if (BindToken.Kind == TokenInfo::TK_CodeCompletion) { + addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1)); + return false; + } + + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + const TokenInfo IDToken = Tokenizer->consumeNextToken(); + const TokenInfo CloseToken = Tokenizer->consumeNextToken(); + + // TODO: We could use different error codes for each/some to be more + // explicit about the syntax error. + if (BindToken.Kind != TokenInfo::TK_Ident || + BindToken.Text != TokenInfo::ID_Bind) { + Error->addError(BindToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) { + Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + if (CloseToken.Kind != TokenInfo::TK_CloseParen) { + Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr); + return false; + } + BindID = IDToken.Value.getString(); + return true; +} + +/// 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(const TokenInfo &NameToken, + VariantValue *Value) { + assert(NameToken.Kind == TokenInfo::TK_Ident); + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen) + << OpenToken.Text; + return false; + } + + llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text); + + if (!Ctor) { + Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound) + << NameToken.Text; + // Do not return here. We need to continue to give completion suggestions. + } + + std::vector<ParserValue> Args; + TokenInfo EndToken; + + { + ScopedContextEntry SCE(this, Ctor ? *Ctor : nullptr); + + while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) { + if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) { + // End of args. + EndToken = Tokenizer->consumeNextToken(); + break; + } + if (!Args.empty()) { + // We must find a , token to continue. + const TokenInfo CommaToken = Tokenizer->consumeNextToken(); + if (CommaToken.Kind != TokenInfo::TK_Comma) { + Error->addError(CommaToken.Range, Error->ET_ParserNoComma) + << CommaToken.Text; + return false; + } + } + + Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error, + NameToken.Text, NameToken.Range, + Args.size() + 1); + ParserValue ArgValue; + ArgValue.Text = Tokenizer->peekNextToken().Text; + ArgValue.Range = Tokenizer->peekNextToken().Range; + if (!parseExpressionImpl(&ArgValue.Value)) { + return false; + } + + Args.push_back(ArgValue); + SCE.nextArg(); + } + } + + if (EndToken.Kind == TokenInfo::TK_Eof) { + Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen); + return false; + } + + std::string BindID; + if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) { + if (!parseBindID(BindID)) + return false; + } + + if (!Ctor) + return false; + + // Merge the start and end infos. + Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error, + NameToken.Text, NameToken.Range); + SourceRange MatcherRange = NameToken.Range; + MatcherRange.End = EndToken.Range.End; + VariantMatcher Result = S->actOnMatcherExpression( + *Ctor, MatcherRange, BindID, Args, Error); + if (Result.isNull()) return false; + + *Value = Result; + return true; +} + +// If the prefix of this completion matches the completion token, add it to +// Completions minus the prefix. +void Parser::addCompletion(const TokenInfo &CompToken, + const MatcherCompletion& Completion) { + if (StringRef(Completion.TypedText).startswith(CompToken.Text) && + Completion.Specificity > 0) { + Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()), + Completion.MatcherDecl, Completion.Specificity); + } +} + +std::vector<MatcherCompletion> Parser::getNamedValueCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + if (!NamedValues) return std::vector<MatcherCompletion>(); + std::vector<MatcherCompletion> Result; + for (const auto &Entry : *NamedValues) { + unsigned Specificity; + if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) { + std::string Decl = + (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str(); + Result.emplace_back(Entry.getKey(), Decl, Specificity); + } + } + return Result; +} + +void Parser::addExpressionCompletions() { + const TokenInfo CompToken = Tokenizer->consumeNextToken(); + assert(CompToken.Kind == TokenInfo::TK_CodeCompletion); + + // We cannot complete code if there is an invalid element on the context + // stack. + for (ContextStackTy::iterator I = ContextStack.begin(), + E = ContextStack.end(); + I != E; ++I) { + if (!I->first) + return; + } + + auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack); + for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); + } + + for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); + } +} + +/// Parse an <Expression> +bool Parser::parseExpressionImpl(VariantValue *Value) { + switch (Tokenizer->nextTokenKind()) { + case TokenInfo::TK_Literal: + *Value = Tokenizer->consumeNextToken().Value; + return true; + + case TokenInfo::TK_Ident: + return parseIdentifierPrefixImpl(Value); + + case TokenInfo::TK_CodeCompletion: + addExpressionCompletions(); + return false; + + case TokenInfo::TK_Eof: + Error->addError(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_Period: + case TokenInfo::TK_InvalidChar: + const TokenInfo Token = Tokenizer->consumeNextToken(); + Error->addError(Token.Range, Error->ET_ParserInvalidToken) << Token.Text; + return false; + } + + llvm_unreachable("Unknown token kind."); +} + +static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema; + +Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, + const NamedValueMap *NamedValues, Diagnostics *Error) + : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema), + NamedValues(NamedValues), Error(Error) {} + +Parser::RegistrySema::~RegistrySema() = default; + +llvm::Optional<MatcherCtor> +Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) { + return Registry::lookupMatcherCtor(MatcherName); +} + +VariantMatcher Parser::RegistrySema::actOnMatcherExpression( + MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, + ArrayRef<ParserValue> Args, Diagnostics *Error) { + if (BindID.empty()) { + return Registry::constructMatcher(Ctor, NameRange, Args, Error); + } else { + return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args, + Error); + } +} + +std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return Registry::getAcceptedCompletionTypes(Context); +} + +std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + return Registry::getMatcherCompletions(AcceptedTypes); +} + +bool Parser::parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, + VariantValue *Value, Diagnostics *Error) { + CodeTokenizer Tokenizer(Code, Error); + if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value)) + return false; + if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) { + Error->addError(Tokenizer.peekNextToken().Range, + Error->ET_ParserTrailingCode); + return false; + } + return true; +} + +std::vector<MatcherCompletion> +Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues) { + Diagnostics Error; + CodeTokenizer Tokenizer(Code, &Error, CompletionOffset); + Parser P(&Tokenizer, S, NamedValues, &Error); + VariantValue Dummy; + P.parseExpressionImpl(&Dummy); + + // Sort by specificity, then by name. + llvm::sort(P.Completions, + [](const MatcherCompletion &A, const MatcherCompletion &B) { + if (A.Specificity != B.Specificity) + return A.Specificity > B.Specificity; + return A.TypedText < B.TypedText; + }); + + return P.Completions; +} + +llvm::Optional<DynTypedMatcher> +Parser::parseMatcherExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error) { + VariantValue Value; + if (!parseExpression(Code, S, NamedValues, &Value, Error)) + return llvm::Optional<DynTypedMatcher>(); + if (!Value.isMatcher()) { + Error->addError(SourceRange(), Error->ET_ParserNotAMatcher); + return llvm::Optional<DynTypedMatcher>(); + } + llvm::Optional<DynTypedMatcher> Result = + Value.getMatcher().getSingleMatcher(); + if (!Result.hasValue()) { + Error->addError(SourceRange(), Error->ET_ParserOverloadedType) + << Value.getTypeAsString(); + } + return Result; +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp new file mode 100644 index 000000000000..8c11e069cb05 --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -0,0 +1,693 @@ +//===- Registry.cpp - Matcher registry ------------------------------------===// +// +// 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 map populated at static initialization time. +// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "Marshallers.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <iterator> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +using namespace clang::ast_type_traits; + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace { + +using internal::MatcherDescriptor; + +using ConstructorMap = llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>; + +class RegistryMaps { +public: + RegistryMaps(); + ~RegistryMaps(); + + const ConstructorMap &constructors() const { return Constructors; } + +private: + void registerMatcher(StringRef MatcherName, + std::unique_ptr<MatcherDescriptor> Callback); + + ConstructorMap Constructors; +}; + +} // namespace + +void RegistryMaps::registerMatcher( + StringRef MatcherName, std::unique_ptr<MatcherDescriptor> Callback) { + assert(Constructors.find(MatcherName) == Constructors.end()); + Constructors[MatcherName] = std::move(Callback); +} + +#define REGISTER_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherAutoMarshall( \ + ::clang::ast_matchers::name, #name)); + +#define REGISTER_MATCHER_OVERLOAD(name) \ + registerMatcher(#name, \ + std::make_unique<internal::OverloadedMatcherDescriptor>(name##Callbacks)) + +#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \ + static_cast<::clang::ast_matchers::name##_Type##Id>( \ + ::clang::ast_matchers::name) + +#define MATCHER_OVERLOAD_ENTRY(name, Id) \ + internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, Id), \ + #name) + +#define REGISTER_OVERLOADED_2(name) \ + do { \ + std::unique_ptr<MatcherDescriptor> name##Callbacks[] = { \ + MATCHER_OVERLOAD_ENTRY(name, 0), \ + MATCHER_OVERLOAD_ENTRY(name, 1)}; \ + REGISTER_MATCHER_OVERLOAD(name); \ + } while (false) + +/// Generate a registry map with all the known matchers. +/// Please keep sorted alphabetically! +RegistryMaps::RegistryMaps() { + // TODO: Here is the list of the missing matchers, grouped by reason. + // + // Need Variant/Parser fixes: + // ofKind + // + // Polymorphic + argument overload: + // findAll + // + // Other: + // equalsNode + + REGISTER_OVERLOADED_2(callee); + REGISTER_OVERLOADED_2(hasPrefix); + REGISTER_OVERLOADED_2(hasType); + REGISTER_OVERLOADED_2(ignoringParens); + REGISTER_OVERLOADED_2(isDerivedFrom); + REGISTER_OVERLOADED_2(isDirectlyDerivedFrom); + REGISTER_OVERLOADED_2(isSameOrDerivedFrom); + REGISTER_OVERLOADED_2(loc); + REGISTER_OVERLOADED_2(pointsTo); + REGISTER_OVERLOADED_2(references); + REGISTER_OVERLOADED_2(thisPointerType); + + std::unique_ptr<MatcherDescriptor> equalsCallbacks[] = { + MATCHER_OVERLOAD_ENTRY(equals, 0), + MATCHER_OVERLOAD_ENTRY(equals, 1), + MATCHER_OVERLOAD_ENTRY(equals, 2), + }; + REGISTER_MATCHER_OVERLOAD(equals); + + REGISTER_MATCHER(accessSpecDecl); + REGISTER_MATCHER(addrLabelExpr); + REGISTER_MATCHER(alignOfExpr); + REGISTER_MATCHER(allOf); + REGISTER_MATCHER(anyOf); + REGISTER_MATCHER(anything); + REGISTER_MATCHER(argumentCountIs); + REGISTER_MATCHER(arraySubscriptExpr); + REGISTER_MATCHER(arrayType); + REGISTER_MATCHER(asString); + REGISTER_MATCHER(asmStmt); + REGISTER_MATCHER(atomicExpr); + REGISTER_MATCHER(atomicType); + REGISTER_MATCHER(autoType); + REGISTER_MATCHER(autoreleasePoolStmt) + REGISTER_MATCHER(binaryConditionalOperator); + REGISTER_MATCHER(binaryOperator); + REGISTER_MATCHER(blockDecl); + REGISTER_MATCHER(blockExpr); + REGISTER_MATCHER(blockPointerType); + REGISTER_MATCHER(booleanType); + REGISTER_MATCHER(breakStmt); + REGISTER_MATCHER(builtinType); + REGISTER_MATCHER(cStyleCastExpr); + REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(caseStmt); + REGISTER_MATCHER(castExpr); + REGISTER_MATCHER(characterLiteral); + REGISTER_MATCHER(chooseExpr); + REGISTER_MATCHER(classTemplateDecl); + REGISTER_MATCHER(classTemplateSpecializationDecl); + REGISTER_MATCHER(complexType); + REGISTER_MATCHER(compoundLiteralExpr); + REGISTER_MATCHER(compoundStmt); + REGISTER_MATCHER(conditionalOperator); + REGISTER_MATCHER(constantArrayType); + REGISTER_MATCHER(constantExpr); + REGISTER_MATCHER(containsDeclaration); + REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(cudaKernelCallExpr); + REGISTER_MATCHER(cxxBindTemporaryExpr); + REGISTER_MATCHER(cxxBoolLiteral); + REGISTER_MATCHER(cxxCatchStmt); + REGISTER_MATCHER(cxxConstCastExpr); + REGISTER_MATCHER(cxxConstructExpr); + REGISTER_MATCHER(cxxConstructorDecl); + REGISTER_MATCHER(cxxConversionDecl); + REGISTER_MATCHER(cxxCtorInitializer); + REGISTER_MATCHER(cxxDeductionGuideDecl); + REGISTER_MATCHER(cxxDefaultArgExpr); + REGISTER_MATCHER(cxxDeleteExpr); + REGISTER_MATCHER(cxxDependentScopeMemberExpr); + REGISTER_MATCHER(cxxDestructorDecl); + REGISTER_MATCHER(cxxDynamicCastExpr); + REGISTER_MATCHER(cxxForRangeStmt); + REGISTER_MATCHER(cxxFunctionalCastExpr); + REGISTER_MATCHER(cxxMemberCallExpr); + REGISTER_MATCHER(cxxMethodDecl); + REGISTER_MATCHER(cxxNewExpr); + REGISTER_MATCHER(cxxNullPtrLiteralExpr); + REGISTER_MATCHER(cxxOperatorCallExpr); + REGISTER_MATCHER(cxxRecordDecl); + REGISTER_MATCHER(cxxReinterpretCastExpr); + REGISTER_MATCHER(cxxStaticCastExpr); + REGISTER_MATCHER(cxxStdInitializerListExpr); + REGISTER_MATCHER(cxxTemporaryObjectExpr); + REGISTER_MATCHER(cxxThisExpr); + REGISTER_MATCHER(cxxThrowExpr); + REGISTER_MATCHER(cxxTryStmt); + REGISTER_MATCHER(cxxUnresolvedConstructExpr); + REGISTER_MATCHER(decayedType); + REGISTER_MATCHER(decl); + REGISTER_MATCHER(declCountIs); + REGISTER_MATCHER(declRefExpr); + REGISTER_MATCHER(declStmt); + REGISTER_MATCHER(declaratorDecl); + REGISTER_MATCHER(decltypeType); + REGISTER_MATCHER(defaultStmt); + REGISTER_MATCHER(dependentSizedArrayType); + REGISTER_MATCHER(designatedInitExpr); + REGISTER_MATCHER(designatorCountIs); + REGISTER_MATCHER(doStmt); + REGISTER_MATCHER(eachOf); + REGISTER_MATCHER(elaboratedType); + REGISTER_MATCHER(enumConstantDecl); + REGISTER_MATCHER(enumDecl); + REGISTER_MATCHER(enumType); + REGISTER_MATCHER(equalsBoundNode); + REGISTER_MATCHER(equalsIntegralValue); + REGISTER_MATCHER(explicitCastExpr); + REGISTER_MATCHER(expr); + REGISTER_MATCHER(exprWithCleanups); + REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(floatLiteral); + REGISTER_MATCHER(forEach); + REGISTER_MATCHER(forEachArgumentWithParam); + REGISTER_MATCHER(forEachConstructorInitializer); + REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachOverridden); + REGISTER_MATCHER(forEachSwitchCase); + REGISTER_MATCHER(forField); + REGISTER_MATCHER(forFunction); + REGISTER_MATCHER(forStmt); + REGISTER_MATCHER(friendDecl); + REGISTER_MATCHER(functionDecl); + REGISTER_MATCHER(functionProtoType); + REGISTER_MATCHER(functionTemplateDecl); + REGISTER_MATCHER(functionType); + REGISTER_MATCHER(gnuNullExpr); + REGISTER_MATCHER(gotoStmt); + REGISTER_MATCHER(has); + REGISTER_MATCHER(hasAncestor); + REGISTER_MATCHER(hasAnyArgument); + REGISTER_MATCHER(hasAnyClause); + REGISTER_MATCHER(hasAnyConstructorInitializer); + REGISTER_MATCHER(hasAnyDeclaration); + REGISTER_MATCHER(hasAnyName); + REGISTER_MATCHER(hasAnyParameter); + REGISTER_MATCHER(hasAnySelector); + REGISTER_MATCHER(hasAnySubstatement); + REGISTER_MATCHER(hasAnyTemplateArgument); + REGISTER_MATCHER(hasAnyUsingShadowDecl); + REGISTER_MATCHER(hasArgument); + REGISTER_MATCHER(hasArgumentOfType); + REGISTER_MATCHER(hasArraySize); + REGISTER_MATCHER(hasAttr); + REGISTER_MATCHER(hasAutomaticStorageDuration); + REGISTER_MATCHER(hasBase); + REGISTER_MATCHER(hasBitWidth); + REGISTER_MATCHER(hasBody); + REGISTER_MATCHER(hasCanonicalType); + REGISTER_MATCHER(hasCaseConstant); + REGISTER_MATCHER(hasCastKind); + REGISTER_MATCHER(hasCondition); + REGISTER_MATCHER(hasConditionVariableStatement); + REGISTER_MATCHER(hasDecayedType); + REGISTER_MATCHER(hasDeclContext); + REGISTER_MATCHER(hasDeclaration); + REGISTER_MATCHER(hasDeducedType); + REGISTER_MATCHER(hasDefaultArgument); + REGISTER_MATCHER(hasDefinition); + REGISTER_MATCHER(hasDescendant); + REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasDynamicExceptionSpec); + REGISTER_MATCHER(hasEitherOperand); + REGISTER_MATCHER(hasElementType); + REGISTER_MATCHER(hasElse); + REGISTER_MATCHER(hasExplicitSpecifier); + REGISTER_MATCHER(hasExternalFormalLinkage); + REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasGlobalStorage); + REGISTER_MATCHER(hasImplicitDestinationType); + REGISTER_MATCHER(hasInClassInitializer); + REGISTER_MATCHER(hasIncrement); + REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); + REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasKeywordSelector); + REGISTER_MATCHER(hasLHS); + REGISTER_MATCHER(hasLocalQualifiers); + REGISTER_MATCHER(hasLocalStorage); + REGISTER_MATCHER(hasLoopInit); + REGISTER_MATCHER(hasLoopVariable); + REGISTER_MATCHER(hasMethod); + REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasNullSelector); + REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasOperatorName); + REGISTER_MATCHER(hasOverloadedOperatorName); + REGISTER_MATCHER(hasParameter); + REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasQualifier); + REGISTER_MATCHER(hasRHS); + REGISTER_MATCHER(hasRangeInit); + REGISTER_MATCHER(hasReceiver); + REGISTER_MATCHER(hasReceiverType); + REGISTER_MATCHER(hasReplacementType); + REGISTER_MATCHER(hasReturnValue); + REGISTER_MATCHER(hasSelector); + REGISTER_MATCHER(hasSingleDecl); + REGISTER_MATCHER(hasSize); + REGISTER_MATCHER(hasSizeExpr); + REGISTER_MATCHER(hasSourceExpression); + REGISTER_MATCHER(hasSpecializedTemplate); + REGISTER_MATCHER(hasStaticStorageDuration); + REGISTER_MATCHER(hasStructuredBlock); + REGISTER_MATCHER(hasSyntacticForm); + REGISTER_MATCHER(hasTargetDecl); + REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasThen); + REGISTER_MATCHER(hasThreadStorageDuration); + REGISTER_MATCHER(hasTrailingReturn); + REGISTER_MATCHER(hasTrueExpression); + REGISTER_MATCHER(hasTypeLoc); + REGISTER_MATCHER(hasUnaryOperand); + REGISTER_MATCHER(hasUnarySelector); + REGISTER_MATCHER(hasUnderlyingDecl); + REGISTER_MATCHER(hasUnderlyingType); + REGISTER_MATCHER(hasUnqualifiedDesugaredType); + REGISTER_MATCHER(hasValueType); + REGISTER_MATCHER(ifStmt); + REGISTER_MATCHER(ignoringElidableConstructorCall); + REGISTER_MATCHER(ignoringImpCasts); + REGISTER_MATCHER(ignoringImplicit); + REGISTER_MATCHER(ignoringParenCasts); + REGISTER_MATCHER(ignoringParenImpCasts); + REGISTER_MATCHER(imaginaryLiteral); + REGISTER_MATCHER(implicitCastExpr); + REGISTER_MATCHER(implicitValueInitExpr); + REGISTER_MATCHER(incompleteArrayType); + REGISTER_MATCHER(indirectFieldDecl); + REGISTER_MATCHER(initListExpr); + REGISTER_MATCHER(injectedClassNameType); + REGISTER_MATCHER(innerType); + REGISTER_MATCHER(integerLiteral); + REGISTER_MATCHER(isAllowedToContainClauseKind); + REGISTER_MATCHER(isAnonymous); + REGISTER_MATCHER(isAnyCharacter); + REGISTER_MATCHER(isAnyPointer); + REGISTER_MATCHER(isArray); + REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isAssignmentOperator); + REGISTER_MATCHER(isBaseInitializer); + REGISTER_MATCHER(isBitField); + REGISTER_MATCHER(isCatchAll); + REGISTER_MATCHER(isClass); + REGISTER_MATCHER(isClassMessage); + REGISTER_MATCHER(isClassMethod); + REGISTER_MATCHER(isConst); + REGISTER_MATCHER(isConstQualified); + REGISTER_MATCHER(isConstexpr); + REGISTER_MATCHER(isCopyAssignmentOperator); + REGISTER_MATCHER(isCopyConstructor); + REGISTER_MATCHER(isDefaultConstructor); + REGISTER_MATCHER(isDefaulted); + REGISTER_MATCHER(isDefinition); + REGISTER_MATCHER(isDelegatingConstructor); + REGISTER_MATCHER(isDeleted); + REGISTER_MATCHER(isExceptionVariable); + REGISTER_MATCHER(isExpansionInFileMatching); + REGISTER_MATCHER(isExpansionInMainFile); + REGISTER_MATCHER(isExpansionInSystemHeader); + REGISTER_MATCHER(isExplicit); + REGISTER_MATCHER(isExplicitTemplateSpecialization); + REGISTER_MATCHER(isExpr); + REGISTER_MATCHER(isExternC); + REGISTER_MATCHER(isFinal); + REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(isInStdNamespace); + REGISTER_MATCHER(isInTemplateInstantiation); + REGISTER_MATCHER(isInline); + REGISTER_MATCHER(isInstanceMessage); + REGISTER_MATCHER(isInstanceMethod); + REGISTER_MATCHER(isInstantiated); + REGISTER_MATCHER(isInstantiationDependent); + REGISTER_MATCHER(isInteger); + REGISTER_MATCHER(isIntegral); + REGISTER_MATCHER(isLambda); + REGISTER_MATCHER(isListInitialization); + REGISTER_MATCHER(isMain); + REGISTER_MATCHER(isMemberInitializer); + REGISTER_MATCHER(isMoveAssignmentOperator); + REGISTER_MATCHER(isMoveConstructor); + REGISTER_MATCHER(isNoReturn); + REGISTER_MATCHER(isNoThrow); + REGISTER_MATCHER(isNoneKind); + REGISTER_MATCHER(isOMPStructuredBlock); + REGISTER_MATCHER(isOverride); + REGISTER_MATCHER(isPrivate); + REGISTER_MATCHER(isProtected); + REGISTER_MATCHER(isPublic); + REGISTER_MATCHER(isPure); + REGISTER_MATCHER(isScoped); + REGISTER_MATCHER(isSharedKind); + REGISTER_MATCHER(isSignedInteger); + REGISTER_MATCHER(isStandaloneDirective); + REGISTER_MATCHER(isStaticLocal); + REGISTER_MATCHER(isStaticStorageClass); + REGISTER_MATCHER(isStruct); + REGISTER_MATCHER(isTemplateInstantiation); + REGISTER_MATCHER(isTypeDependent); + REGISTER_MATCHER(isUnion); + REGISTER_MATCHER(isUnsignedInteger); + REGISTER_MATCHER(isUserProvided); + REGISTER_MATCHER(isValueDependent); + REGISTER_MATCHER(isVariadic); + REGISTER_MATCHER(isVirtual); + REGISTER_MATCHER(isVirtualAsWritten); + REGISTER_MATCHER(isVolatileQualified); + REGISTER_MATCHER(isWritten); + REGISTER_MATCHER(lValueReferenceType); + REGISTER_MATCHER(labelDecl); + REGISTER_MATCHER(labelStmt); + REGISTER_MATCHER(lambdaExpr); + REGISTER_MATCHER(linkageSpecDecl); + REGISTER_MATCHER(matchesName); + REGISTER_MATCHER(matchesSelector); + REGISTER_MATCHER(materializeTemporaryExpr); + REGISTER_MATCHER(member); + REGISTER_MATCHER(memberExpr); + REGISTER_MATCHER(memberPointerType); + REGISTER_MATCHER(namedDecl); + REGISTER_MATCHER(namesType); + REGISTER_MATCHER(namespaceAliasDecl); + REGISTER_MATCHER(namespaceDecl); + REGISTER_MATCHER(nestedNameSpecifier); + REGISTER_MATCHER(nestedNameSpecifierLoc); + REGISTER_MATCHER(nonTypeTemplateParmDecl); + REGISTER_MATCHER(nullPointerConstant); + REGISTER_MATCHER(nullStmt); + REGISTER_MATCHER(numSelectorArgs); + REGISTER_MATCHER(objcCatchStmt); + REGISTER_MATCHER(objcCategoryDecl); + REGISTER_MATCHER(objcCategoryImplDecl); + REGISTER_MATCHER(objcFinallyStmt); + REGISTER_MATCHER(objcImplementationDecl); + REGISTER_MATCHER(objcInterfaceDecl); + REGISTER_MATCHER(objcIvarDecl); + REGISTER_MATCHER(objcIvarRefExpr); + REGISTER_MATCHER(objcMessageExpr); + REGISTER_MATCHER(objcMethodDecl); + REGISTER_MATCHER(objcObjectPointerType); + REGISTER_MATCHER(objcPropertyDecl); + REGISTER_MATCHER(objcProtocolDecl); + REGISTER_MATCHER(objcThrowStmt); + REGISTER_MATCHER(objcTryStmt); + REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(ompDefaultClause); + REGISTER_MATCHER(ompExecutableDirective); + REGISTER_MATCHER(on); + REGISTER_MATCHER(onImplicitObjectArgument); + REGISTER_MATCHER(opaqueValueExpr); + REGISTER_MATCHER(parameterCountIs); + REGISTER_MATCHER(parenExpr); + REGISTER_MATCHER(parenListExpr); + REGISTER_MATCHER(parenType); + REGISTER_MATCHER(parmVarDecl); + REGISTER_MATCHER(pointee); + REGISTER_MATCHER(pointerType); + REGISTER_MATCHER(predefinedExpr); + REGISTER_MATCHER(qualType); + REGISTER_MATCHER(rValueReferenceType); + REGISTER_MATCHER(realFloatingPointType); + REGISTER_MATCHER(recordDecl); + REGISTER_MATCHER(recordType); + REGISTER_MATCHER(referenceType); + REGISTER_MATCHER(refersToDeclaration); + REGISTER_MATCHER(refersToIntegralType); + REGISTER_MATCHER(refersToTemplate); + REGISTER_MATCHER(refersToType); + REGISTER_MATCHER(requiresZeroInitialization); + REGISTER_MATCHER(returnStmt); + REGISTER_MATCHER(returns); + REGISTER_MATCHER(sizeOfExpr); + REGISTER_MATCHER(specifiesNamespace); + REGISTER_MATCHER(specifiesType); + REGISTER_MATCHER(specifiesTypeLoc); + REGISTER_MATCHER(statementCountIs); + REGISTER_MATCHER(staticAssertDecl); + REGISTER_MATCHER(stmt); + REGISTER_MATCHER(stmtExpr); + REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(substNonTypeTemplateParmExpr); + REGISTER_MATCHER(substTemplateTypeParmType); + REGISTER_MATCHER(switchCase); + REGISTER_MATCHER(switchStmt); + REGISTER_MATCHER(tagType); + REGISTER_MATCHER(templateArgument); + REGISTER_MATCHER(templateArgumentCountIs); + REGISTER_MATCHER(templateName); + REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(templateTypeParmDecl); + REGISTER_MATCHER(templateTypeParmType); + REGISTER_MATCHER(throughUsingDecl); + REGISTER_MATCHER(to); + REGISTER_MATCHER(translationUnitDecl); + REGISTER_MATCHER(type); + REGISTER_MATCHER(typeAliasDecl); + REGISTER_MATCHER(typeAliasTemplateDecl); + REGISTER_MATCHER(typeLoc); + REGISTER_MATCHER(typedefDecl); + REGISTER_MATCHER(typedefNameDecl); + REGISTER_MATCHER(typedefType); + REGISTER_MATCHER(unaryExprOrTypeTraitExpr); + REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(unaryTransformType); + REGISTER_MATCHER(unless); + REGISTER_MATCHER(unresolvedLookupExpr); + REGISTER_MATCHER(unresolvedMemberExpr); + REGISTER_MATCHER(unresolvedUsingTypenameDecl); + REGISTER_MATCHER(unresolvedUsingValueDecl); + REGISTER_MATCHER(userDefinedLiteral); + REGISTER_MATCHER(usesADL); + REGISTER_MATCHER(usingDecl); + REGISTER_MATCHER(usingDirectiveDecl); + REGISTER_MATCHER(valueDecl); + REGISTER_MATCHER(varDecl); + REGISTER_MATCHER(variableArrayType); + REGISTER_MATCHER(voidType); + REGISTER_MATCHER(whileStmt); + REGISTER_MATCHER(withInitializer); +} + +RegistryMaps::~RegistryMaps() = default; + +static llvm::ManagedStatic<RegistryMaps> RegistryData; + +// static +llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) { + auto it = RegistryData->constructors().find(MatcherName); + return it == RegistryData->constructors().end() + ? llvm::Optional<MatcherCtor>() + : it->second.get(); +} + +static llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const std::set<ASTNodeKind> &KS) { + unsigned Count = 0; + for (std::set<ASTNodeKind>::const_iterator I = KS.begin(), E = KS.end(); + I != E; ++I) { + if (I != KS.begin()) + OS << "|"; + if (Count++ == 3) { + OS << "..."; + break; + } + OS << *I; + } + return OS; +} + +std::vector<ArgKind> Registry::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + ASTNodeKind InitialTypes[] = { + ASTNodeKind::getFromNodeKind<Decl>(), + ASTNodeKind::getFromNodeKind<QualType>(), + ASTNodeKind::getFromNodeKind<Type>(), + ASTNodeKind::getFromNodeKind<Stmt>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), + ASTNodeKind::getFromNodeKind<TypeLoc>()}; + + // Starting with the above seed of acceptable top-level matcher types, compute + // the acceptable type set for the argument indicated by each context element. + std::set<ArgKind> TypeSet(std::begin(InitialTypes), std::end(InitialTypes)); + for (const auto &CtxEntry : Context) { + MatcherCtor Ctor = CtxEntry.first; + unsigned ArgNumber = CtxEntry.second; + std::vector<ArgKind> NextTypeSet; + for (const ArgKind &Kind : TypeSet) { + if (Kind.getArgKind() == Kind.AK_Matcher && + Ctor->isConvertibleTo(Kind.getMatcherKind()) && + (Ctor->isVariadic() || ArgNumber < Ctor->getNumArgs())) + Ctor->getArgKinds(Kind.getMatcherKind(), ArgNumber, NextTypeSet); + } + TypeSet.clear(); + TypeSet.insert(NextTypeSet.begin(), NextTypeSet.end()); + } + return std::vector<ArgKind>(TypeSet.begin(), TypeSet.end()); +} + +std::vector<MatcherCompletion> +Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) { + std::vector<MatcherCompletion> Completions; + + // Search the registry for acceptable matchers. + for (const auto &M : RegistryData->constructors()) { + const MatcherDescriptor& Matcher = *M.getValue(); + StringRef Name = M.getKey(); + + std::set<ASTNodeKind> RetKinds; + unsigned NumArgs = Matcher.isVariadic() ? 1 : Matcher.getNumArgs(); + bool IsPolymorphic = Matcher.isPolymorphic(); + std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs); + unsigned MaxSpecificity = 0; + for (const ArgKind& Kind : AcceptedTypes) { + if (Kind.getArgKind() != Kind.AK_Matcher) + continue; + unsigned Specificity; + ASTNodeKind LeastDerivedKind; + if (Matcher.isConvertibleTo(Kind.getMatcherKind(), &Specificity, + &LeastDerivedKind)) { + if (MaxSpecificity < Specificity) + MaxSpecificity = Specificity; + RetKinds.insert(LeastDerivedKind); + for (unsigned Arg = 0; Arg != NumArgs; ++Arg) + Matcher.getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]); + if (IsPolymorphic) + break; + } + } + + if (!RetKinds.empty() && MaxSpecificity > 0) { + std::string Decl; + llvm::raw_string_ostream OS(Decl); + + if (IsPolymorphic) { + OS << "Matcher<T> " << Name << "(Matcher<T>"; + } else { + OS << "Matcher<" << RetKinds << "> " << Name << "("; + for (const std::vector<ArgKind> &Arg : ArgsKinds) { + if (&Arg != &ArgsKinds[0]) + OS << ", "; + + bool FirstArgKind = true; + std::set<ASTNodeKind> MatcherKinds; + // Two steps. First all non-matchers, then matchers only. + for (const ArgKind &AK : Arg) { + if (AK.getArgKind() == ArgKind::AK_Matcher) { + MatcherKinds.insert(AK.getMatcherKind()); + } else { + if (!FirstArgKind) OS << "|"; + FirstArgKind = false; + OS << AK.asString(); + } + } + if (!MatcherKinds.empty()) { + if (!FirstArgKind) OS << "|"; + OS << "Matcher<" << MatcherKinds << ">"; + } + } + } + if (Matcher.isVariadic()) + OS << "..."; + OS << ")"; + + std::string TypedText = Name; + TypedText += "("; + if (ArgsKinds.empty()) + TypedText += ")"; + else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String) + TypedText += "\""; + + Completions.emplace_back(TypedText, OS.str(), MaxSpecificity); + } + } + + return Completions; +} + +VariantMatcher Registry::constructMatcher(MatcherCtor Ctor, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + return Ctor->create(NameRange, Args, Error); +} + +VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor, + SourceRange NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + VariantMatcher Out = constructMatcher(Ctor, NameRange, Args, Error); + if (Out.isNull()) return Out; + + llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher(); + if (Result.hasValue()) { + llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID); + if (Bound.hasValue()) { + return VariantMatcher::SingleMatcher(*Bound); + } + } + Error->addError(NameRange, Error->ET_RegistryNotBindable); + return VariantMatcher(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 000000000000..118ca2a41cb1 --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -0,0 +1,457 @@ +//===--- VariantValue.cpp - 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. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +std::string ArgKind::asString() const { + switch (getArgKind()) { + case AK_Matcher: + return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); + case AK_Boolean: + return "boolean"; + case AK_Double: + return "double"; + case AK_Unsigned: + return "unsigned"; + case AK_String: + return "string"; + } + llvm_unreachable("unhandled ArgKind"); +} + +bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const { + if (K != To.K) + return false; + if (K != AK_Matcher) { + if (Specificity) + *Specificity = 1; + return true; + } + unsigned Distance; + if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance)) + return false; + + if (Specificity) + *Specificity = 100 - Distance; + return true; +} + +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); + return Matcher.canConvertTo(NodeKind); +} + +llvm::Optional<DynTypedMatcher> +VariantMatcher::MatcherOps::constructVariadicOperator( + DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const { + std::vector<DynTypedMatcher> DynMatchers; + for (const auto &InnerMatcher : InnerMatchers) { + // Abort if any of the inner matchers can't be converted to + // Matcher<T>. + if (!InnerMatcher.Value) + return llvm::None; + llvm::Optional<DynTypedMatcher> Inner = + InnerMatcher.Value->getTypedMatcher(*this); + if (!Inner) + return llvm::None; + DynMatchers.push_back(*Inner); + } + return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers); +} + +VariantMatcher::Payload::~Payload() {} + +class VariantMatcher::SinglePayload : public VariantMatcher::Payload { +public: + SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} + + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { + return Matcher; + } + + std::string getTypeAsString() const override { + return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") + .str(); + } + + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + bool Ignore; + if (Ops.canConstructFrom(Matcher, Ignore)) + return Matcher; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + return ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, Specificity); + } + +private: + const DynTypedMatcher Matcher; +}; + +class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { +public: + PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn) + : Matchers(std::move(MatchersIn)) {} + + ~PolymorphicPayload() override {} + + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { + if (Matchers.size() != 1) + return llvm::Optional<DynTypedMatcher>(); + return Matchers[0]; + } + + std::string getTypeAsString() const override { + std::string Inner; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + if (i != 0) + Inner += "|"; + Inner += Matchers[i].getSupportedKind().asStringRef(); + } + return (Twine("Matcher<") + Inner + ">").str(); + } + + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + bool FoundIsExact = false; + const DynTypedMatcher *Found = nullptr; + int NumFound = 0; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + bool IsExactMatch; + if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) { + if (Found) { + if (FoundIsExact) { + assert(!IsExactMatch && "We should not have two exact matches."); + continue; + } + } + Found = &Matchers[i]; + FoundIsExact = IsExactMatch; + ++NumFound; + } + } + // We only succeed if we found exactly one, or if we found an exact match. + if (Found && (FoundIsExact || NumFound == 1)) + return *Found; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + unsigned MaxSpecificity = 0; + for (const DynTypedMatcher &Matcher : Matchers) { + unsigned ThisSpecificity; + if (ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, &ThisSpecificity)) { + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + } + if (Specificity) + *Specificity = MaxSpecificity; + return MaxSpecificity > 0; + } + + const std::vector<DynTypedMatcher> Matchers; +}; + +class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { +public: + VariadicOpPayload(DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args) + : Op(Op), Args(std::move(Args)) {} + + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { + return llvm::Optional<DynTypedMatcher>(); + } + + std::string getTypeAsString() const override { + std::string Inner; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + if (i != 0) + Inner += "&"; + Inner += Args[i].getTypeAsString(); + } + return Inner; + } + + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + return Ops.constructVariadicOperator(Op, Args); + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + for (const VariantMatcher &Matcher : Args) { + if (!Matcher.isConvertibleTo(Kind, Specificity)) + return false; + } + return true; + } + +private: + const DynTypedMatcher::VariadicOperator Op; + const std::vector<VariantMatcher> Args; +}; + +VariantMatcher::VariantMatcher() {} + +VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { + return VariantMatcher(std::make_shared<SinglePayload>(Matcher)); +} + +VariantMatcher +VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { + return VariantMatcher( + std::make_shared<PolymorphicPayload>(std::move(Matchers))); +} + +VariantMatcher VariantMatcher::VariadicOperatorMatcher( + DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args) { + return VariantMatcher( + std::make_shared<VariadicOpPayload>(Op, std::move(Args))); +} + +llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { + return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>(); +} + +void VariantMatcher::reset() { Value.reset(); } + +std::string VariantMatcher::getTypeAsString() const { + if (Value) return Value->getTypeAsString(); + return "<Nothing>"; +} + +VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { + *this = Other; +} + +VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) { + setBoolean(Boolean); +} + +VariantValue::VariantValue(double Double) : Type(VT_Nothing) { + setDouble(Double); +} + +VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { + setUnsigned(Unsigned); +} + +VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { + setString(String); +} + +VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { + setMatcher(Matcher); +} + +VariantValue::~VariantValue() { reset(); } + +VariantValue &VariantValue::operator=(const VariantValue &Other) { + if (this == &Other) return *this; + reset(); + switch (Other.Type) { + case VT_Boolean: + setBoolean(Other.getBoolean()); + break; + case VT_Double: + setDouble(Other.getDouble()); + break; + case VT_Unsigned: + setUnsigned(Other.getUnsigned()); + break; + 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_Boolean: + case VT_Double: + case VT_Unsigned: + case VT_Nothing: + break; + } + Type = VT_Nothing; +} + +bool VariantValue::isBoolean() const { + return Type == VT_Boolean; +} + +bool VariantValue::getBoolean() const { + assert(isBoolean()); + return Value.Boolean; +} + +void VariantValue::setBoolean(bool NewValue) { + reset(); + Type = VT_Boolean; + Value.Boolean = NewValue; +} + +bool VariantValue::isDouble() const { + return Type == VT_Double; +} + +double VariantValue::getDouble() const { + assert(isDouble()); + return Value.Double; +} + +void VariantValue::setDouble(double NewValue) { + reset(); + Type = VT_Double; + Value.Double = NewValue; +} + +bool VariantValue::isUnsigned() const { + return Type == VT_Unsigned; +} + +unsigned VariantValue::getUnsigned() const { + assert(isUnsigned()); + return Value.Unsigned; +} + +void VariantValue::setUnsigned(unsigned NewValue) { + reset(); + Type = VT_Unsigned; + Value.Unsigned = NewValue; +} + +bool VariantValue::isString() const { + return Type == VT_String; +} + +const std::string &VariantValue::getString() const { + assert(isString()); + return *Value.String; +} + +void VariantValue::setString(StringRef NewValue) { + reset(); + Type = VT_String; + Value.String = new std::string(NewValue); +} + +bool VariantValue::isMatcher() const { + return Type == VT_Matcher; +} + +const VariantMatcher &VariantValue::getMatcher() const { + assert(isMatcher()); + return *Value.Matcher; +} + +void VariantValue::setMatcher(const VariantMatcher &NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = new VariantMatcher(NewValue); +} + +bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { + switch (Kind.getArgKind()) { + case ArgKind::AK_Boolean: + if (!isBoolean()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_Double: + if (!isDouble()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_Unsigned: + if (!isUnsigned()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_String: + if (!isString()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_Matcher: + if (!isMatcher()) + return false; + return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity); + } + llvm_unreachable("Invalid Type"); +} + +bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds, + unsigned *Specificity) const { + unsigned MaxSpecificity = 0; + for (const ArgKind& Kind : Kinds) { + unsigned ThisSpecificity; + if (!isConvertibleTo(Kind, &ThisSpecificity)) + continue; + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + if (Specificity && MaxSpecificity > 0) { + *Specificity = MaxSpecificity; + } + return MaxSpecificity > 0; +} + +std::string VariantValue::getTypeAsString() const { + switch (Type) { + case VT_String: return "String"; + case VT_Matcher: return getMatcher().getTypeAsString(); + case VT_Boolean: return "Boolean"; + case VT_Double: return "Double"; + case VT_Unsigned: return "Unsigned"; + case VT_Nothing: return "Nothing"; + } + llvm_unreachable("Invalid Type"); +} + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang |
