Support named values in the autocomplete feature.

Summary:
This includes:
 - Passing a Sema to completeExpression to allow for named values in the
   expression.
 - Passing a map of names to values to the parser.
 - Update the Sema interface to include completion for matchers.
 - Change the parser to use the Sema for completion, instead of going
   directly to Registry.

Reviewers: pcc

Subscribers: klimek, cfe-commits

Differential Revision: http://reviews.llvm.org/D3509

llvm-svn: 215472
This commit is contained in:
Samuel Benzaquen 2014-08-12 21:11:37 +00:00
parent 4834ad2609
commit 646f23b809
9 changed files with 470 additions and 248 deletions

View File

@ -63,17 +63,6 @@ public:
public:
virtual ~Sema();
/// \brief Lookup a value by name.
///
/// This can be used in the Sema layer to declare known constants or to
/// allow to split an expression in pieces.
///
/// \param Name The name of the value to lookup.
///
/// \return The named value. It could be any type that VariantValue
/// supports. An empty value means that the name is not recognized.
virtual VariantValue getNamedValue(StringRef Name);
/// \brief Process a matcher expression.
///
/// All the arguments passed here have already been processed.
@ -105,6 +94,29 @@ public:
/// found.
virtual llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName) = 0;
/// \brief 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);
/// \brief Compute the list of completions that match any of
/// \p AcceptedTypes.
///
/// \param 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);
};
/// \brief Sema implementation that uses the matcher registry to process the
@ -121,58 +133,91 @@ public:
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;
};
/// \brief Parse a matcher expression, creating matchers from the registry.
///
/// This overload creates matchers calling directly into the registry. If the
/// caller needs more control over how the matchers are created, then it can
/// use the overload below that takes a Sema.
///
/// \param MatcherCode The matcher expression to parse.
///
/// \return The matcher object constructed, or 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, Diagnostics *Error);
typedef llvm::StringMap<VariantValue> NamedValueMap;
/// \brief Parse a matcher expression.
///
/// \param MatcherCode The matcher expression to parse.
///
/// \param S The Sema instance that will help the parser
/// construct the matchers.
/// 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, Diagnostics *Error);
/// \brief Parse an expression, creating matchers from the registry.
///
/// Parses any expression supported by this parser. In general, the
/// \c parseMatcherExpression function is a better approach to get a matcher
/// object.
static bool parseExpression(StringRef Code, VariantValue *Value,
Diagnostics *Error);
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);
}
/// \brief Parse an expression.
///
/// Parses any expression supported by this parser. In general, the
/// \c parseMatcherExpression function is a better approach to get a matcher
/// object.
///
/// \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);
}
/// \brief 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);
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;
@ -180,6 +225,7 @@ private:
struct TokenInfo;
Parser(CodeTokenizer *Tokenizer, Sema *S,
const NamedValueMap *NamedValues,
Diagnostics *Error);
bool parseExpressionImpl(VariantValue *Value);
@ -187,12 +233,16 @@ private:
VariantValue *Value);
bool parseIdentifierPrefixImpl(VariantValue *Value);
void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
StringRef Decl);
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;
typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy;

View File

@ -36,8 +36,10 @@ typedef const internal::MatcherDescriptor *MatcherCtor;
struct MatcherCompletion {
MatcherCompletion() {}
MatcherCompletion(StringRef TypedText, StringRef MatcherDecl)
: TypedText(TypedText), MatcherDecl(MatcherDecl) {}
MatcherCompletion(StringRef TypedText, StringRef MatcherDecl,
unsigned Specificity)
: TypedText(TypedText), MatcherDecl(MatcherDecl),
Specificity(Specificity) {}
/// \brief The text to type to select this matcher.
std::string TypedText;
@ -45,6 +47,13 @@ struct MatcherCompletion {
/// \brief The "declaration" of the matcher, with type information.
std::string MatcherDecl;
/// \brief 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;
bool operator==(const MatcherCompletion &Other) const {
return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl;
}
@ -58,28 +67,28 @@ public:
/// constructor, or Optional<MatcherCtor>() if not found.
static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName);
/// \brief Compute the list of completions for \p Context.
/// \brief 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.
/// 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);
/// \brief Compute the list of completions that match any of
/// \p AcceptedTypes.
///
/// The completions are ordered first by decreasing relevance, then
/// alphabetically. Relevance is determined by how closely the matcher's
/// type matches that of the context. For example, if the innermost matcher
/// takes a FunctionDecl matcher, the FunctionDecl matchers are returned
/// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then
/// polymorphic matchers.
/// \param All types accepted for this completion.
///
/// Matchers which are technically convertible to the innermost context but
/// which would match either all or no nodes are excluded. For example,
/// namedDecl and varDecl are excluded in a FunctionDecl context, because
/// those matchers would match respectively all or no nodes in such a context.
/// \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>
getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context);
getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes);
/// \brief Construct a matcher from the registry.
///

View File

@ -29,6 +29,50 @@ namespace clang {
namespace ast_matchers {
namespace dynamic {
/// \brief Kind identifier.
///
/// It supports all types that VariantValue can contain.
class ArgKind {
public:
enum Kind {
AK_Matcher,
AK_Unsigned,
AK_String
};
/// \brief Constructor for non-matcher types.
ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
/// \brief 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;
}
/// \brief Determines if this type can be converted to \p To.
///
/// \param To the requested destination type.
///
/// \param Value corresponding to the "specificity" of the convertion.
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;
}
/// \brief String representation of the type.
std::string asString() const;
private:
Kind K;
ast_type_traits::ASTNodeKind MatcherKind;
};
using ast_matchers::internal::DynTypedMatcher;
/// \brief A variant matcher object.
@ -66,6 +110,8 @@ class VariantMatcher {
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const = 0;
};
public:
@ -116,6 +162,18 @@ public:
return Ops.hasMatcher();
}
/// \brief Determines if the contained matcher can be converted to \p Kind.
///
/// \param Kind the requested destination type.
///
/// \param Value corresponding to the "specificity" of the convertion.
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const {
if (Value)
return Value->isConvertibleTo(Kind, Specificity);
return false;
}
/// \brief Return this matcher as a \c Matcher<T>.
///
/// Handles the different types (Single, Polymorphic) accordingly.
@ -228,6 +286,22 @@ public:
const VariantMatcher &getMatcher() const;
void setMatcher(const VariantMatcher &Matcher);
/// \brief Determines if the contained value can be converted to \p Kind.
///
/// \param Kind the requested destination type.
///
/// \param Value corresponding to the "specificity" of the convertion.
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
/// \brief Determines if the contained value can be converted to any kind
/// in \p Kinds.
///
/// \param Kinds the requested destination types.
///
/// \param Value corresponding to the "specificity" of the convertion. It is
/// the maximum specificity of all the possible conversions.
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
/// \brief String representation of the type of the value.
std::string getTypeAsString() const;

View File

@ -30,48 +30,8 @@
namespace clang {
namespace ast_matchers {
namespace dynamic {
namespace internal {
struct ArgKind {
enum Kind {
AK_Matcher,
AK_Unsigned,
AK_String
};
ArgKind(Kind K)
: K(K) {}
ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
: K(AK_Matcher), MatcherKind(MatcherKind) {}
std::string asString() const {
switch (getArgKind()) {
case AK_Matcher:
return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
case AK_Unsigned:
return "unsigned";
case AK_String:
return "string";
}
llvm_unreachable("unhandled ArgKind");
}
Kind getArgKind() const { return K; }
ast_type_traits::ASTNodeKind getMatcherKind() const {
assert(K == AK_Matcher);
return MatcherKind;
}
bool operator<(const ArgKind &Other) const {
if (K == AK_Matcher && Other.K == AK_Matcher)
return MatcherKind < Other.MatcherKind;
return K < Other.K;
}
private:
Kind K;
ast_type_traits::ASTNodeKind MatcherKind;
};
/// \brief Helper template class to just from argument type to the right is/get
/// functions in VariantValue.
@ -161,16 +121,10 @@ inline bool isRetKindConvertibleTo(
ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
ast_type_traits::ASTNodeKind *LeastDerivedKind) {
for (ArrayRef<ast_type_traits::ASTNodeKind>::const_iterator
i = RetKinds.begin(),
e = RetKinds.end();
i != e; ++i) {
unsigned Distance;
if (i->isBaseOf(Kind, &Distance)) {
if (Specificity)
*Specificity = 100 - Distance;
for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) {
if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) {
if (LeastDerivedKind)
*LeastDerivedKind = *i;
*LeastDerivedKind = NodeKind;
return true;
}
}

View File

@ -17,6 +17,7 @@
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ManagedStatic.h"
#include <string>
#include <vector>
@ -258,8 +259,14 @@ private:
Parser::Sema::~Sema() {}
VariantValue Parser::Sema::getNamedValue(StringRef Name) {
return VariantValue();
std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(
llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
return std::vector<ArgKind>();
}
std::vector<MatcherCompletion>
Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {
return std::vector<MatcherCompletion>();
}
struct Parser::ScopedContextEntry {
@ -288,7 +295,9 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
// Parse as a named value.
if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) {
if (const VariantValue NamedValue =
NamedValues ? NamedValues->lookup(NameToken.Text)
: VariantValue()) {
*Value = NamedValue;
return true;
}
@ -379,7 +388,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
Tokenizer->consumeNextToken(); // consume the period.
const TokenInfo BindToken = Tokenizer->consumeNextToken();
if (BindToken.Kind == TokenInfo::TK_CodeCompletion) {
addCompletion(BindToken, "bind(\"", "bind");
addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1));
return false;
}
@ -427,15 +436,30 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
// If the prefix of this completion matches the completion token, add it to
// Completions minus the prefix.
void Parser::addCompletion(const TokenInfo &CompToken, StringRef TypedText,
StringRef Decl) {
if (TypedText.size() >= CompToken.Text.size() &&
TypedText.substr(0, CompToken.Text.size()) == CompToken.Text) {
Completions.push_back(
MatcherCompletion(TypedText.substr(CompToken.Text.size()), Decl));
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);
@ -449,12 +473,13 @@ void Parser::addExpressionCompletions() {
return;
}
std::vector<MatcherCompletion> RegCompletions =
Registry::getCompletions(ContextStack);
for (std::vector<MatcherCompletion>::iterator I = RegCompletions.begin(),
E = RegCompletions.end();
I != E; ++I) {
addCompletion(CompToken, I->TypedText, I->MatcherDecl);
auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
addCompletion(CompToken, Completion);
}
for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
addCompletion(CompToken, Completion);
}
}
@ -494,9 +519,12 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
llvm_unreachable("Unknown token kind.");
}
static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema;
Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
Diagnostics *Error)
: Tokenizer(Tokenizer), S(S), Error(Error) {}
const NamedValueMap *NamedValues, Diagnostics *Error)
: Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
NamedValues(NamedValues), Error(Error) {}
Parser::RegistrySema::~RegistrySema() {}
@ -516,16 +544,22 @@ VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
}
}
bool Parser::parseExpression(StringRef Code, VariantValue *Value,
Diagnostics *Error) {
RegistrySema S;
return parseExpression(Code, &S, Value, 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, Error).parseExpressionImpl(Value)) return false;
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);
@ -535,28 +569,31 @@ bool Parser::parseExpression(StringRef Code, Sema *S,
}
std::vector<MatcherCompletion>
Parser::completeExpression(StringRef Code, unsigned CompletionOffset) {
Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
const NamedValueMap *NamedValues) {
Diagnostics Error;
CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);
RegistrySema S;
Parser P(&Tokenizer, &S, &Error);
Parser P(&Tokenizer, S, NamedValues, &Error);
VariantValue Dummy;
P.parseExpressionImpl(&Dummy);
// Sort by specificity, then by name.
std::sort(P.Completions.begin(), P.Completions.end(),
[](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, Diagnostics *Error) {
RegistrySema S;
return parseMatcherExpression(Code, &S, Error);
}
llvm::Optional<DynTypedMatcher>
Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S,
Parser::parseMatcherExpression(StringRef Code, Sema *S,
const NamedValueMap *NamedValues,
Diagnostics *Error) {
VariantValue Value;
if (!parseExpression(Code, S, &Value, Error))
if (!parseExpression(Code, S, NamedValues, &Value, Error))
return llvm::Optional<DynTypedMatcher>();
if (!Value.isMatcher()) {
Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);

View File

@ -353,77 +353,63 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
return OS;
}
struct ReverseSpecificityThenName {
bool operator()(const std::pair<unsigned, std::string> &A,
const std::pair<unsigned, std::string> &B) const {
return A.first > B.first || (A.first == B.first && A.second < B.second);
}
};
} // namespace
}
std::vector<MatcherCompletion> Registry::getCompletions(
ArrayRef<std::pair<MatcherCtor, unsigned> > Context) {
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>()
};
ArrayRef<ASTNodeKind> InitialTypesRef(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<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end());
for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator
CtxI = Context.begin(),
CtxE = Context.end();
CtxI != CtxE; ++CtxI) {
std::vector<internal::ArgKind> NextTypeSet;
for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end();
I != E; ++I) {
if (CtxI->first->isConvertibleTo(*I) &&
(CtxI->first->isVariadic() ||
CtxI->second < CtxI->first->getNumArgs()))
CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet);
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();
for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(),
E = NextTypeSet.end();
I != E; ++I) {
if (I->getArgKind() == internal::ArgKind::AK_Matcher)
TypeSet.insert(I->getMatcherKind());
}
TypeSet.insert(NextTypeSet.begin(), NextTypeSet.end());
}
return std::vector<ArgKind>(TypeSet.begin(), TypeSet.end());
}
typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion,
ReverseSpecificityThenName> CompletionsTy;
CompletionsTy Completions;
std::vector<MatcherCompletion>
Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
std::vector<MatcherCompletion> Completions;
// TypeSet now contains the list of acceptable types for the argument we are
// completing. Search the registry for acceptable matchers.
// Search the registry for acceptable matchers.
for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(),
E = RegistryData->constructors().end();
I != E; ++I) {
std::set<ASTNodeKind> RetKinds;
unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs();
bool IsPolymorphic = I->second->isPolymorphic();
std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs);
std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs);
unsigned MaxSpecificity = 0;
for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(),
TE = TypeSet.end();
TI != TE; ++TI) {
for (const ArgKind& Kind : AcceptedTypes) {
if (Kind.getArgKind() != Kind.AK_Matcher)
continue;
unsigned Specificity;
ASTNodeKind LeastDerivedKind;
if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) {
if (I->second->isConvertibleTo(Kind.getMatcherKind(), &Specificity,
&LeastDerivedKind)) {
if (MaxSpecificity < Specificity)
MaxSpecificity = Specificity;
RetKinds.insert(LeastDerivedKind);
for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]);
I->second->getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]);
if (IsPolymorphic)
break;
}
@ -437,24 +423,20 @@ std::vector<MatcherCompletion> Registry::getCompletions(
OS << "Matcher<T> " << I->first() << "(Matcher<T>";
} else {
OS << "Matcher<" << RetKinds << "> " << I->first() << "(";
for (std::vector<std::vector<internal::ArgKind> >::iterator
KI = ArgsKinds.begin(),
KE = ArgsKinds.end();
KI != KE; ++KI) {
if (KI != ArgsKinds.begin())
for (const std::vector<ArgKind> &Arg : ArgsKinds) {
if (&Arg != &ArgsKinds[0])
OS << ", ";
// This currently assumes that a matcher may not overload a
// non-matcher, and all non-matcher overloads have identical
// arguments.
if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) {
if (Arg[0].getArgKind() == ArgKind::AK_Matcher) {
std::set<ASTNodeKind> MatcherKinds;
std::transform(
KI->begin(), KI->end(),
std::inserter(MatcherKinds, MatcherKinds.end()),
std::mem_fun_ref(&internal::ArgKind::getMatcherKind));
std::transform(Arg.begin(), Arg.end(),
std::inserter(MatcherKinds, MatcherKinds.end()),
std::mem_fun_ref(&ArgKind::getMatcherKind));
OS << "Matcher<" << MatcherKinds << ">";
} else {
OS << (*KI)[0].asString();
OS << Arg[0].asString();
}
}
}
@ -466,19 +448,14 @@ std::vector<MatcherCompletion> Registry::getCompletions(
TypedText += "(";
if (ArgsKinds.empty())
TypedText += ")";
else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String)
else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String)
TypedText += "\"";
Completions[std::make_pair(MaxSpecificity, I->first())] =
MatcherCompletion(TypedText, OS.str());
Completions.emplace_back(TypedText, OS.str(), MaxSpecificity);
}
}
std::vector<MatcherCompletion> RetVal;
for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end();
I != E; ++I)
RetVal.push_back(I->second);
return RetVal;
return Completions;
}
// static

View File

@ -20,6 +20,35 @@ 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_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;
}
VariantMatcher::MatcherOps::~MatcherOps() {}
VariantMatcher::Payload::~Payload() {}
@ -27,21 +56,27 @@ class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
public:
SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
return Matcher;
}
virtual std::string getTypeAsString() const {
std::string getTypeAsString() const override {
return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
.str();
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
void makeTypedMatcher(MatcherOps &Ops) const override {
bool Ignore;
if (Ops.canConstructFrom(Matcher, Ignore))
Ops.constructFrom(Matcher);
}
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const override {
return ArgKind(Matcher.getSupportedKind())
.isConvertibleTo(Kind, Specificity);
}
private:
const DynTypedMatcher Matcher;
};
@ -51,15 +86,15 @@ public:
PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
: Matchers(std::move(MatchersIn)) {}
virtual ~PolymorphicPayload() {}
~PolymorphicPayload() override {}
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
if (Matchers.size() != 1)
return llvm::Optional<DynTypedMatcher>();
return Matchers[0];
}
virtual std::string getTypeAsString() const {
std::string getTypeAsString() const override {
std::string Inner;
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
if (i != 0)
@ -69,7 +104,7 @@ public:
return (Twine("Matcher<") + Inner + ">").str();
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
void makeTypedMatcher(MatcherOps &Ops) const override {
bool FoundIsExact = false;
const DynTypedMatcher *Found = nullptr;
int NumFound = 0;
@ -92,6 +127,21 @@ public:
Ops.constructFrom(*Found);
}
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;
};
@ -101,11 +151,11 @@ public:
std::vector<VariantMatcher> Args)
: Func(Func), Args(std::move(Args)) {}
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
return llvm::Optional<DynTypedMatcher>();
}
virtual std::string getTypeAsString() const {
std::string getTypeAsString() const override {
std::string Inner;
for (size_t i = 0, e = Args.size(); i != e; ++i) {
if (i != 0)
@ -115,10 +165,19 @@ public:
return Inner;
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
void makeTypedMatcher(MatcherOps &Ops) const override {
Ops.constructVariadicOperator(Func, 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 ast_matchers::internal::VariadicOperatorFunction Func;
const std::vector<VariantMatcher> Args;
@ -251,6 +310,43 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) {
Value.Matcher = new VariantMatcher(NewValue);
}
bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
switch (Kind.getArgKind()) {
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";

View File

@ -152,6 +152,14 @@ TEST(ParserTest, ParseMatcher) {
using ast_matchers::internal::Matcher;
Parser::NamedValueMap getTestNamedValues() {
Parser::NamedValueMap Values;
Values["nameX"] = std::string("x");
Values["hasParamA"] =
VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
return Values;
}
TEST(ParserTest, FullParserTest) {
Diagnostics Error;
llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
@ -174,21 +182,11 @@ TEST(ParserTest, FullParserTest) {
EXPECT_FALSE(matches("void f(int x, int a);", M));
// Test named values.
struct NamedSema : public Parser::RegistrySema {
public:
virtual VariantValue getNamedValue(StringRef Name) {
if (Name == "nameX")
return std::string("x");
if (Name == "param0")
return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
return VariantValue();
}
};
NamedSema Sema;
auto NamedValues = getTestNamedValues();
llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
Parser::parseMatcherExpression(
"functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
&Error));
"functionDecl(hasParamA, hasParameter(1, hasName(nameX)))",
nullptr, &NamedValues, &Error));
EXPECT_EQ("", Error.toStringFull());
M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
@ -270,7 +268,7 @@ TEST(ParserTest, OverloadErrors) {
ParseWithError("callee(\"A\")"));
}
TEST(ParserTest, Completion) {
TEST(ParserTest, CompletionRegistry) {
std::vector<MatcherCompletion> Comps =
Parser::completeExpression("while", 5);
ASSERT_EQ(1u, Comps.size());
@ -284,6 +282,38 @@ TEST(ParserTest, Completion) {
EXPECT_EQ("bind", Comps[0].MatcherDecl);
}
TEST(ParserTest, CompletionNamedValues) {
// Can complete non-matcher types.
auto NamedValues = getTestNamedValues();
StringRef Code = "functionDecl(hasName(";
std::vector<MatcherCompletion> Comps =
Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
ASSERT_EQ(1u, Comps.size());
EXPECT_EQ("nameX", Comps[0].TypedText);
EXPECT_EQ("String nameX", Comps[0].MatcherDecl);
// Can complete if there are names in the expression.
Code = "methodDecl(hasName(nameX), ";
Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
EXPECT_LT(0u, Comps.size());
// Can complete names and registry together.
Code = "methodDecl(hasP";
Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
ASSERT_EQ(3u, Comps.size());
EXPECT_EQ("aramA", Comps[0].TypedText);
EXPECT_EQ("Matcher<FunctionDecl> hasParamA", Comps[0].MatcherDecl);
EXPECT_EQ("arameter(", Comps[1].TypedText);
EXPECT_EQ(
"Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)",
Comps[1].MatcherDecl);
EXPECT_EQ("arent(", Comps[2].TypedText);
EXPECT_EQ("Matcher<Decl> hasParent(Matcher<Decl|Stmt>)",
Comps[2].MatcherDecl);
}
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers

View File

@ -82,8 +82,9 @@ public:
typedef std::vector<MatcherCompletion> CompVector;
CompVector getCompletions() {
return Registry::getCompletions(
ArrayRef<std::pair<MatcherCtor, unsigned> >());
std::vector<std::pair<MatcherCtor, unsigned> > Context;
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
@ -92,7 +93,8 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo1));
return Registry::getCompletions(Context);
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
@ -106,18 +108,16 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo2));
return Registry::getCompletions(Context);
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
bool hasCompletion(const CompVector &Comps, StringRef TypedText,
StringRef MatcherDecl = StringRef(),
unsigned *Index = nullptr) {
StringRef MatcherDecl = StringRef()) {
for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
++I) {
if (I->TypedText == TypedText &&
(MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
if (Index)
*Index = I - Comps.begin();
return true;
}
}
@ -445,17 +445,12 @@ TEST_F(RegistryTest, Completion) {
CompVector WhileComps = getCompletions("whileStmt", 0);
unsigned HasBodyIndex, HasParentIndex, AllOfIndex;
EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
"Matcher<WhileStmt> hasBody(Matcher<Stmt>)",
&HasBodyIndex));
"Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
"Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)",
&HasParentIndex));
EXPECT_TRUE(hasCompletion(WhileComps, "allOf(",
"Matcher<T> allOf(Matcher<T>...)", &AllOfIndex));
EXPECT_GT(HasParentIndex, HasBodyIndex);
EXPECT_GT(AllOfIndex, HasParentIndex);
"Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)"));
EXPECT_TRUE(
hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));