forked from OSchip/llvm-project
[clang-query] Add non-exclusive output API
Summary: Add granular options for AST dumping, text printing and diagnostics. This makes it possible to * Have both diag and dump active at once * Extend the output with other queryable content in the future. Reviewers: aaron.ballman, pcc, ioeric, ilya-biryukov, klimek, sammccall Reviewed By: aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D52857 llvm-svn: 345522
This commit is contained in:
parent
eb15d00193
commit
a49fe5d878
|
@ -45,6 +45,10 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
|||
"Set whether to print the current matcher,\n"
|
||||
" set output <feature> "
|
||||
"Set whether to output only <feature> content.\n"
|
||||
" enable output <feature> "
|
||||
"Enable <feature> content non-exclusively.\n"
|
||||
" disable output <feature> "
|
||||
"Disable <feature> content non-exclusively.\n"
|
||||
" quit, q "
|
||||
"Terminates the query session.\n\n"
|
||||
"Several commands accept a <feature> parameter. The available features "
|
||||
|
|
|
@ -29,6 +29,8 @@ enum QueryKind {
|
|||
QK_Match,
|
||||
QK_SetBool,
|
||||
QK_SetOutputKind,
|
||||
QK_EnableOutputKind,
|
||||
QK_DisableOutputKind,
|
||||
QK_Quit
|
||||
};
|
||||
|
||||
|
@ -151,6 +153,36 @@ struct SetExclusiveOutputQuery : Query {
|
|||
bool QuerySession::*Var;
|
||||
};
|
||||
|
||||
// Implements the non-exclusive 'set output dump|diag|print' options.
|
||||
struct SetNonExclusiveOutputQuery : Query {
|
||||
SetNonExclusiveOutputQuery(QueryKind Kind, bool QuerySession::*Var,
|
||||
bool Value)
|
||||
: Query(Kind), Var(Var), Value(Value) {}
|
||||
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override {
|
||||
QS.*Var = Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuerySession::*Var;
|
||||
bool Value;
|
||||
};
|
||||
|
||||
struct EnableOutputQuery : SetNonExclusiveOutputQuery {
|
||||
EnableOutputQuery(bool QuerySession::*Var)
|
||||
: SetNonExclusiveOutputQuery(QK_EnableOutputKind, Var, true) {}
|
||||
|
||||
static bool classof(const Query *Q) { return Q->Kind == QK_EnableOutputKind; }
|
||||
};
|
||||
|
||||
struct DisableOutputQuery : SetNonExclusiveOutputQuery {
|
||||
DisableOutputQuery(bool QuerySession::*Var)
|
||||
: SetNonExclusiveOutputQuery(QK_DisableOutputKind, Var, false) {}
|
||||
|
||||
static bool classof(const Query *Q) {
|
||||
return Q->Kind == QK_DisableOutputKind;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace query
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
|
|||
return new SetQuery<bool>(Var, Value);
|
||||
}
|
||||
|
||||
QueryRef QueryParser::parseSetOutputKind() {
|
||||
template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
|
||||
StringRef ValStr;
|
||||
unsigned OutKind = LexOrCompleteWord<unsigned>(this, ValStr)
|
||||
.Case("diag", OK_Diag)
|
||||
|
@ -122,11 +122,11 @@ QueryRef QueryParser::parseSetOutputKind() {
|
|||
|
||||
switch (OutKind) {
|
||||
case OK_DetailedAST:
|
||||
return new SetExclusiveOutputQuery(&QuerySession::DetailedASTOutput);
|
||||
return new QueryType(&QuerySession::DetailedASTOutput);
|
||||
case OK_Diag:
|
||||
return new SetExclusiveOutputQuery(&QuerySession::DiagOutput);
|
||||
return new QueryType(&QuerySession::DiagOutput);
|
||||
case OK_Print:
|
||||
return new SetExclusiveOutputQuery(&QuerySession::PrintOutput);
|
||||
return new QueryType(&QuerySession::PrintOutput);
|
||||
}
|
||||
|
||||
llvm_unreachable("Invalid output kind");
|
||||
|
@ -151,7 +151,9 @@ enum ParsedQueryKind {
|
|||
PQK_Match,
|
||||
PQK_Set,
|
||||
PQK_Unlet,
|
||||
PQK_Quit
|
||||
PQK_Quit,
|
||||
PQK_Enable,
|
||||
PQK_Disable
|
||||
};
|
||||
|
||||
enum ParsedQueryVariable {
|
||||
|
@ -193,6 +195,8 @@ QueryRef QueryParser::doParse() {
|
|||
.Case("q", PQK_Quit, /*IsCompletion=*/false)
|
||||
.Case("quit", PQK_Quit)
|
||||
.Case("set", PQK_Set)
|
||||
.Case("enable", PQK_Enable)
|
||||
.Case("disable", PQK_Disable)
|
||||
.Case("unlet", PQK_Unlet)
|
||||
.Default(PQK_Invalid);
|
||||
|
||||
|
@ -256,7 +260,7 @@ QueryRef QueryParser::doParse() {
|
|||
QueryRef Q;
|
||||
switch (Var) {
|
||||
case PQV_Output:
|
||||
Q = parseSetOutputKind();
|
||||
Q = parseSetOutputKind<SetExclusiveOutputQuery>();
|
||||
break;
|
||||
case PQV_BindRoot:
|
||||
Q = parseSetBool(&QuerySession::BindRoot);
|
||||
|
@ -270,6 +274,28 @@ QueryRef QueryParser::doParse() {
|
|||
|
||||
return endQuery(Q);
|
||||
}
|
||||
case PQK_Enable:
|
||||
case PQK_Disable: {
|
||||
StringRef VarStr;
|
||||
ParsedQueryVariable Var =
|
||||
LexOrCompleteWord<ParsedQueryVariable>(this, VarStr)
|
||||
.Case("output", PQV_Output)
|
||||
.Default(PQV_Invalid);
|
||||
if (VarStr.empty())
|
||||
return new InvalidQuery("expected variable name");
|
||||
if (Var == PQV_Invalid)
|
||||
return new InvalidQuery("unknown variable: '" + VarStr + "'");
|
||||
|
||||
QueryRef Q;
|
||||
|
||||
if (QKind == PQK_Enable)
|
||||
Q = parseSetOutputKind<EnableOutputQuery>();
|
||||
else if (QKind == PQK_Disable)
|
||||
Q = parseSetOutputKind<DisableOutputQuery>();
|
||||
else
|
||||
llvm_unreachable("Invalid query kind");
|
||||
return endQuery(Q);
|
||||
}
|
||||
|
||||
case PQK_Unlet: {
|
||||
StringRef Name = lexWord();
|
||||
|
|
|
@ -44,7 +44,7 @@ private:
|
|||
template <typename T> struct LexOrCompleteWord;
|
||||
|
||||
QueryRef parseSetBool(bool QuerySession::*Var);
|
||||
QueryRef parseSetOutputKind();
|
||||
template <typename QueryType> QueryRef parseSetOutputKind();
|
||||
QueryRef completeMatcherExpression();
|
||||
|
||||
QueryRef endQuery(QueryRef Q);
|
||||
|
|
|
@ -111,6 +111,19 @@ TEST_F(QueryEngineTest, Basic) {
|
|||
|
||||
Str.clear();
|
||||
|
||||
EXPECT_TRUE(EnableOutputQuery(&QuerySession::DiagOutput).run(OS, S));
|
||||
EXPECT_TRUE(EnableOutputQuery(&QuerySession::DetailedASTOutput).run(OS, S));
|
||||
EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
|
||||
|
||||
{
|
||||
auto Output = OS.str();
|
||||
EXPECT_TRUE(Output.find("FunctionDecl") != std::string::npos);
|
||||
EXPECT_TRUE(Output.find("foo.cc:1:1: note: \"root\" binds here") !=
|
||||
std::string::npos);
|
||||
}
|
||||
|
||||
Str.clear();
|
||||
|
||||
EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S));
|
||||
EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
|
||||
|
||||
|
|
|
@ -90,6 +90,18 @@ TEST_F(QueryParserTest, Set) {
|
|||
ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
|
||||
EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var);
|
||||
|
||||
Q = parse("enable output detailed-ast");
|
||||
ASSERT_TRUE(isa<EnableOutputQuery>(Q));
|
||||
EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<EnableOutputQuery>(Q)->Var);
|
||||
|
||||
Q = parse("enable");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = parse("disable output detailed-ast");
|
||||
ASSERT_TRUE(isa<DisableOutputQuery>(Q));
|
||||
EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<DisableOutputQuery>(Q)->Var);
|
||||
|
||||
Q = parse("set bind-root foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected 'true' or 'false', got 'foo'",
|
||||
|
@ -163,7 +175,7 @@ TEST_F(QueryParserTest, Comment) {
|
|||
TEST_F(QueryParserTest, Complete) {
|
||||
std::vector<llvm::LineEditor::Completion> Comps =
|
||||
QueryParser::complete("", 0, QS);
|
||||
ASSERT_EQ(6u, Comps.size());
|
||||
ASSERT_EQ(8u, Comps.size());
|
||||
EXPECT_EQ("help ", Comps[0].TypedText);
|
||||
EXPECT_EQ("help", Comps[0].DisplayText);
|
||||
EXPECT_EQ("let ", Comps[1].TypedText);
|
||||
|
@ -174,14 +186,35 @@ TEST_F(QueryParserTest, Complete) {
|
|||
EXPECT_EQ("quit", Comps[3].DisplayText);
|
||||
EXPECT_EQ("set ", Comps[4].TypedText);
|
||||
EXPECT_EQ("set", Comps[4].DisplayText);
|
||||
EXPECT_EQ("unlet ", Comps[5].TypedText);
|
||||
EXPECT_EQ("unlet", Comps[5].DisplayText);
|
||||
EXPECT_EQ("enable ", Comps[5].TypedText);
|
||||
EXPECT_EQ("enable", Comps[5].DisplayText);
|
||||
EXPECT_EQ("disable ", Comps[6].TypedText);
|
||||
EXPECT_EQ("disable", Comps[6].DisplayText);
|
||||
EXPECT_EQ("unlet ", Comps[7].TypedText);
|
||||
EXPECT_EQ("unlet", Comps[7].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("set o", 5, QS);
|
||||
ASSERT_EQ(1u, Comps.size());
|
||||
EXPECT_EQ("utput ", Comps[0].TypedText);
|
||||
EXPECT_EQ("output", Comps[0].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("enable ", 7, QS);
|
||||
ASSERT_EQ(1u, Comps.size());
|
||||
EXPECT_EQ("output ", Comps[0].TypedText);
|
||||
EXPECT_EQ("output", Comps[0].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("enable output ", 14, QS);
|
||||
ASSERT_EQ(4u, Comps.size());
|
||||
|
||||
EXPECT_EQ("diag ", Comps[0].TypedText);
|
||||
EXPECT_EQ("diag", Comps[0].DisplayText);
|
||||
EXPECT_EQ("print ", Comps[1].TypedText);
|
||||
EXPECT_EQ("print", Comps[1].DisplayText);
|
||||
EXPECT_EQ("detailed-ast ", Comps[2].TypedText);
|
||||
EXPECT_EQ("detailed-ast", Comps[2].DisplayText);
|
||||
EXPECT_EQ("dump ", Comps[3].TypedText);
|
||||
EXPECT_EQ("dump", Comps[3].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("match while", 11, QS);
|
||||
ASSERT_EQ(1u, Comps.size());
|
||||
EXPECT_EQ("Stmt(", Comps[0].TypedText);
|
||||
|
|
Loading…
Reference in New Issue