Index: clang-query/Query.h =================================================================== --- clang-query/Query.h +++ clang-query/Query.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H +#include "QuerySession.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" @@ -116,7 +117,7 @@ /// Query for "set VAR VALUE". template struct SetQuery : Query { SetQuery(T QuerySession::*Var, T Value) - : Query(SetQueryKind::value), Var(Var), Value(Value) {} + : Query(QK_SetBool), Var(Var), Value(Value) {} bool run(llvm::raw_ostream &OS, QuerySession &QS) const override { QS.*Var = Value; return true; @@ -130,6 +131,23 @@ T Value; }; +// Deprecated. +// Implements the old 'set output dump|diag|print' options +struct SetOutputQuery : Query { + SetOutputQuery(bool QuerySession::*Var) : Query(QK_SetOutputKind), Var(Var) {} + bool run(llvm::raw_ostream &OS, QuerySession &QS) const override { + QS.DiagOutput = false; + QS.ASTOutput = false; + QS.PrintOutput = false; + QS.*Var = true; + return true; + } + + static bool classof(const Query *Q) { return Q->Kind == QK_SetOutputKind; } + + bool QuerySession::*Var; +}; + } // namespace query } // namespace clang Index: clang-query/Query.cpp =================================================================== --- clang-query/Query.cpp +++ clang-query/Query.cpp @@ -41,10 +41,12 @@ "as part of other expressions.\n" " set bind-root (true|false) " "Set whether to bind the root matcher to \"root\".\n" - " set output (diag|print|dump) " - "Set whether to print bindings as diagnostics,\n" - " " - "AST pretty prints or AST dumps.\n" + " set diag-output (true|false) " + "Set whether to print binding diagnostic locations.\n" + " set ast-output (true|false) " + "Set whether to dump binding ASTs.\n" + " set print-output (true|false) " + "Set whether to print matched text.\n" " quit, q " "Terminates the query session.\n\n"; return true; @@ -91,8 +93,7 @@ for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE; ++BI) { - switch (QS.OutKind) { - case OK_Diag: { + if (QS.DiagOutput) { clang::SourceRange R = BI->second.getSourceRange(); if (R.isValid()) { TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), @@ -102,20 +103,16 @@ DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here", CharSourceRange::getTokenRange(R), None); } - break; } - case OK_Print: { + if (QS.PrintOutput) { OS << "Binding for \"" << BI->first << "\":\n"; BI->second.print(OS, AST->getASTContext().getPrintingPolicy()); OS << "\n"; - break; } - case OK_Dump: { + if (QS.ASTOutput) { OS << "Binding for \"" << BI->first << "\":\n"; BI->second.dump(OS, AST->getSourceManager()); OS << "\n"; - break; - } } } Index: clang-query/QueryParser.cpp =================================================================== --- clang-query/QueryParser.cpp +++ clang-query/QueryParser.cpp @@ -117,7 +117,17 @@ return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" + ValStr + "'"); } - return new SetQuery(&QuerySession::OutKind, OutputKind(OutKind)); + + switch (OutKind) { + case OK_Dump: + return new SetOutputQuery(&QuerySession::ASTOutput); + case OK_Diag: + return new SetOutputQuery(&QuerySession::DiagOutput); + case OK_Print: + return new SetOutputQuery(&QuerySession::PrintOutput); + } + + llvm_unreachable("Invalid output kind"); } QueryRef QueryParser::endQuery(QueryRef Q) { @@ -142,7 +152,14 @@ PQK_Quit }; -enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot }; +enum ParsedQueryVariable { + PQV_Invalid, + PQV_Output, + PQV_BindRoot, + PQV_ASTOutput, + PQV_DiagOutput, + PQV_PrintOutput +}; QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { std::string ErrStr; @@ -224,11 +241,14 @@ case PQK_Set: { StringRef VarStr; - ParsedQueryVariable Var = LexOrCompleteWord(this, - VarStr) - .Case("output", PQV_Output) - .Case("bind-root", PQV_BindRoot) - .Default(PQV_Invalid); + ParsedQueryVariable Var = + LexOrCompleteWord(this, VarStr) + .Case("output", PQV_Output) + .Case("bind-root", PQV_BindRoot) + .Case("ast-output", PQV_ASTOutput) + .Case("diag-output", PQV_DiagOutput) + .Case("print-output", PQV_PrintOutput) + .Default(PQV_Invalid); if (VarStr.empty()) return new InvalidQuery("expected variable name"); if (Var == PQV_Invalid) @@ -242,6 +262,15 @@ case PQV_BindRoot: Q = parseSetBool(&QuerySession::BindRoot); break; + case PQV_ASTOutput: + Q = parseSetBool(&QuerySession::ASTOutput); + break; + case PQV_DiagOutput: + Q = parseSetBool(&QuerySession::DiagOutput); + break; + case PQV_PrintOutput: + Q = parseSetBool(&QuerySession::PrintOutput); + break; case PQV_Invalid: llvm_unreachable("Invalid query kind"); } Index: clang-query/QuerySession.h =================================================================== --- clang-query/QuerySession.h +++ clang-query/QuerySession.h @@ -25,11 +25,14 @@ class QuerySession { public: QuerySession(llvm::ArrayRef> ASTs) - : ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), Terminate(false) {} + : ASTs(ASTs), BindRoot(true), DiagOutput(true), ASTOutput(false), + PrintOutput(false), Terminate(false) {} llvm::ArrayRef> ASTs; - OutputKind OutKind; bool BindRoot; + bool DiagOutput; + bool ASTOutput; + bool PrintOutput; bool Terminate; llvm::StringMap NamedValues; }; Index: unittests/clang-query/QueryEngineTest.cpp =================================================================== --- unittests/clang-query/QueryEngineTest.cpp +++ unittests/clang-query/QueryEngineTest.cpp @@ -48,6 +48,24 @@ llvm::raw_string_ostream OS; }; +TEST_F(QueryEngineTest, Deprecated) { + DynTypedMatcher FooMatcher = functionDecl(hasName("foo1")); + + EXPECT_TRUE(SetOutputQuery(&QuerySession::PrintOutput).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + + EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") != + std::string::npos); + + Str.clear(); + + EXPECT_TRUE(SetOutputQuery(&QuerySession::DumpOutput).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos); + + Str.clear(); +} + TEST_F(QueryEngineTest, Basic) { DynTypedMatcher FnMatcher = functionDecl(); DynTypedMatcher FooMatcher = functionDecl(hasName("foo1")); @@ -92,8 +110,8 @@ Str.clear(); - EXPECT_TRUE( - SetQuery(&QuerySession::OutKind, OK_Print).run(OS, S)); + EXPECT_TRUE(SetQuery(&QuerySession::DiagOutput, false).run(OS, S)); + EXPECT_TRUE(SetQuery(&QuerySession::PrintOutput, true).run(OS, S)); EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") != @@ -101,13 +119,27 @@ Str.clear(); - EXPECT_TRUE(SetQuery(&QuerySession::OutKind, OK_Dump).run(OS, S)); + EXPECT_TRUE(SetQuery(&QuerySession::PrintOutput, false).run(OS, S)); + EXPECT_TRUE(SetQuery(&QuerySession::DumpOutput, true).run(OS, S)); EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos); Str.clear(); + EXPECT_TRUE(SetQuery(&QuerySession::DiagOutput, true).run(OS, S)); + EXPECT_TRUE(SetQuery(&QuerySession::DumpOutput, true).run(OS, S)); + EXPECT_TRUE(MatchQuery(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(FooMatcher).run(OS, S)); Index: unittests/clang-query/QueryParserTest.cpp =================================================================== --- unittests/clang-query/QueryParserTest.cpp +++ unittests/clang-query/QueryParserTest.cpp @@ -59,6 +59,35 @@ EXPECT_EQ("unexpected extra input: ' me'", cast(Q)->ErrStr); } +TEST_F(QueryParserTest, Deprecated) { + QueryRef Q = parse("set output"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ("expected 'diag', 'print' or 'dump', got ''", + cast(Q)->ErrStr); + + Q = parse("set output foo"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ("expected 'diag', 'print' or 'dump', got 'foo'", + cast(Q)->ErrStr); + + Q = parse("set output dump"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ(&QuerySession::DumpOutput, cast(Q)->Var); + std::string Str; + llvm::raw_string_ostream OS(Str); + Q->run(OS, QS); + EXPECT_EQ(true, QS.DumpOutput); + EXPECT_EQ(false, QS.DiagOutput); + EXPECT_EQ(false, QS.PrintOutput); + + std::vector Comps = + QueryParser::complete("", 0, QS); + Comps = QueryParser::complete("set o", 5, QS); + ASSERT_EQ(1u, Comps.size()); + EXPECT_EQ("utput ", Comps[0].TypedText); + EXPECT_EQ("output", Comps[0].DisplayText); +} + TEST_F(QueryParserTest, Set) { QueryRef Q = parse("set"); ASSERT_TRUE(isa(Q)); @@ -68,24 +97,24 @@ ASSERT_TRUE(isa(Q)); EXPECT_EQ("unknown variable: 'foo'", cast(Q)->ErrStr); - Q = parse("set output"); + Q = parse("set dump-output"); ASSERT_TRUE(isa(Q)); - EXPECT_EQ("expected 'diag', 'print' or 'dump', got ''", + EXPECT_EQ("expected 'true' or 'false', got ''", cast(Q)->ErrStr); Q = parse("set bind-root true foo"); ASSERT_TRUE(isa(Q)); EXPECT_EQ("unexpected extra input: ' foo'", cast(Q)->ErrStr); - Q = parse("set output foo"); + Q = parse("set dump-output foo"); ASSERT_TRUE(isa(Q)); - EXPECT_EQ("expected 'diag', 'print' or 'dump', got 'foo'", + EXPECT_EQ("expected 'true' or 'false', got 'foo'", cast(Q)->ErrStr); - Q = parse("set output dump"); - ASSERT_TRUE(isa >(Q)); - EXPECT_EQ(&QuerySession::OutKind, cast >(Q)->Var); - EXPECT_EQ(OK_Dump, cast >(Q)->Value); + Q = parse("set dump-output true"); + ASSERT_TRUE(isa>(Q)); + EXPECT_EQ(&QuerySession::DumpOutput, cast>(Q)->Var); + EXPECT_EQ(true, cast>(Q)->Value); Q = parse("set bind-root foo"); ASSERT_TRUE(isa(Q)); @@ -174,10 +203,16 @@ EXPECT_EQ("unlet ", Comps[5].TypedText); EXPECT_EQ("unlet", Comps[5].DisplayText); - Comps = QueryParser::complete("set o", 5, QS); + Comps = QueryParser::complete("set d", 5, QS); + ASSERT_EQ(2u, Comps.size()); + EXPECT_EQ("ump-output ", Comps[0].TypedText); + EXPECT_EQ("dump-output", Comps[0].DisplayText); + EXPECT_EQ("iag-output ", Comps[1].TypedText); + EXPECT_EQ("diag-output", Comps[1].DisplayText); + Comps = QueryParser::complete("set du", 6, QS); ASSERT_EQ(1u, Comps.size()); - EXPECT_EQ("utput ", Comps[0].TypedText); - EXPECT_EQ("output", Comps[0].DisplayText); + EXPECT_EQ("mp-output ", Comps[0].TypedText); + EXPECT_EQ("dump-output", Comps[0].DisplayText); Comps = QueryParser::complete("match while", 11, QS); ASSERT_EQ(1u, Comps.size());