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
diff --git a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 4e3239f..860db7e 100644
--- a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -152,6 +152,14 @@
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 @@
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 @@
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 @@
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
diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index e659b3a..5552790 100644
--- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -82,8 +82,9 @@
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 @@
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 @@
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 @@
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("));