Index: clang-tools-extra/trunk/clang-query/Query.h =================================================================== --- clang-tools-extra/trunk/clang-query/Query.h +++ clang-tools-extra/trunk/clang-query/Query.h @@ -29,6 +29,8 @@ QK_Match, QK_SetBool, QK_SetOutputKind, + QK_EnableOutputKind, + QK_DisableOutputKind, QK_Quit }; @@ -151,6 +153,36 @@ 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 Index: clang-tools-extra/trunk/clang-query/Query.cpp =================================================================== --- clang-tools-extra/trunk/clang-query/Query.cpp +++ clang-tools-extra/trunk/clang-query/Query.cpp @@ -45,6 +45,10 @@ "Set whether to print the current matcher,\n" " set output " "Set whether to output only content.\n" + " enable output " + "Enable content non-exclusively.\n" + " disable output " + "Disable content non-exclusively.\n" " quit, q " "Terminates the query session.\n\n" "Several commands accept a parameter. The available features " Index: clang-tools-extra/trunk/clang-query/QueryParser.h =================================================================== --- clang-tools-extra/trunk/clang-query/QueryParser.h +++ clang-tools-extra/trunk/clang-query/QueryParser.h @@ -44,7 +44,7 @@ template struct LexOrCompleteWord; QueryRef parseSetBool(bool QuerySession::*Var); - QueryRef parseSetOutputKind(); + template QueryRef parseSetOutputKind(); QueryRef completeMatcherExpression(); QueryRef endQuery(QueryRef Q); Index: clang-tools-extra/trunk/clang-query/QueryParser.cpp =================================================================== --- clang-tools-extra/trunk/clang-query/QueryParser.cpp +++ clang-tools-extra/trunk/clang-query/QueryParser.cpp @@ -106,7 +106,7 @@ return new SetQuery(Var, Value); } -QueryRef QueryParser::parseSetOutputKind() { +template QueryRef QueryParser::parseSetOutputKind() { StringRef ValStr; unsigned OutKind = LexOrCompleteWord(this, ValStr) .Case("diag", OK_Diag) @@ -122,11 +122,11 @@ 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 @@ PQK_Match, PQK_Set, PQK_Unlet, - PQK_Quit + PQK_Quit, + PQK_Enable, + PQK_Disable }; enum ParsedQueryVariable { @@ -193,6 +195,8 @@ .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 Q; switch (Var) { case PQV_Output: - Q = parseSetOutputKind(); + Q = parseSetOutputKind(); break; case PQV_BindRoot: Q = parseSetBool(&QuerySession::BindRoot); @@ -270,6 +274,28 @@ return endQuery(Q); } + case PQK_Enable: + case PQK_Disable: { + StringRef VarStr; + ParsedQueryVariable Var = + LexOrCompleteWord(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(); + else if (QKind == PQK_Disable) + Q = parseSetOutputKind(); + else + llvm_unreachable("Invalid query kind"); + return endQuery(Q); + } case PQK_Unlet: { StringRef Name = lexWord(); Index: clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp +++ clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp @@ -111,6 +111,19 @@ 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(&QuerySession::BindRoot, false).run(OS, S)); EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); Index: clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp +++ clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp @@ -90,6 +90,18 @@ ASSERT_TRUE(isa(Q)); EXPECT_EQ(&QuerySession::DetailedASTOutput, cast(Q)->Var); + Q = parse("enable output detailed-ast"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ(&QuerySession::DetailedASTOutput, cast(Q)->Var); + + Q = parse("enable"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ("expected variable name", cast(Q)->ErrStr); + + Q = parse("disable output detailed-ast"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ(&QuerySession::DetailedASTOutput, cast(Q)->Var); + Q = parse("set bind-root foo"); ASSERT_TRUE(isa(Q)); EXPECT_EQ("expected 'true' or 'false', got 'foo'", @@ -163,7 +175,7 @@ TEST_F(QueryParserTest, Complete) { std::vector 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 @@ 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);