Index: clang-query/Query.h =================================================================== --- clang-query/Query.h +++ clang-query/Query.h @@ -84,12 +84,15 @@ /// Query for "match MATCHER". struct MatchQuery : Query { - MatchQuery(const ast_matchers::dynamic::DynTypedMatcher &Matcher) - : Query(QK_Match), Matcher(Matcher) {} + MatchQuery(StringRef Source, + const ast_matchers::dynamic::DynTypedMatcher &Matcher) + : Query(QK_Match), Matcher(Matcher), Source(Source) {} bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; ast_matchers::dynamic::DynTypedMatcher Matcher; + StringRef Source; + static bool classof(const Query *Q) { return Q->Kind == QK_Match; } }; Index: clang-query/Query.cpp =================================================================== --- clang-query/Query.cpp +++ clang-query/Query.cpp @@ -88,6 +88,12 @@ } Finder.matchAST(AST->getASTContext()); + if (QS.MatcherOutput) { + std::string prefixText = "Matcher: "; + OS << "\n " << prefixText << Source << "\n"; + OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n'; + } + for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) { OS << "\nMatch #" << ++MatchCount << ":\n\n"; Index: clang-query/QueryParser.cpp =================================================================== --- clang-query/QueryParser.cpp +++ clang-query/QueryParser.cpp @@ -158,7 +158,8 @@ PQV_BindRoot, PQV_DumpOutput, PQV_DiagOutput, - PQV_PrintOutput + PQV_PrintOutput, + PQV_MatcherOutput }; QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { @@ -231,12 +232,13 @@ return completeMatcherExpression(); Diagnostics Diag; + auto MatcherSource = StringRef(Begin, End - Begin).trim(); Optional Matcher = Parser::parseMatcherExpression( - StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag); + MatcherSource, nullptr, &QS.NamedValues, &Diag); if (!Matcher) { return makeInvalidQueryFromDiagnostics(Diag); } - return new MatchQuery(*Matcher); + return new MatchQuery(MatcherSource, *Matcher); } case PQK_Set: { @@ -248,6 +250,7 @@ .Case("dump-output", PQV_DumpOutput) .Case("diag-output", PQV_DiagOutput) .Case("print-output", PQV_PrintOutput) + .Case("matcher-output", PQV_MatcherOutput) .Default(PQV_Invalid); if (VarStr.empty()) return new InvalidQuery("expected variable name"); @@ -271,6 +274,9 @@ case PQV_PrintOutput: Q = parseSetBool(&QuerySession::PrintOutput); break; + case PQV_MatcherOutput: + Q = parseSetBool(&QuerySession::MatcherOutput); + break; case PQV_Invalid: llvm_unreachable("Invalid query kind"); } Index: clang-query/QuerySession.h =================================================================== --- clang-query/QuerySession.h +++ clang-query/QuerySession.h @@ -26,13 +26,14 @@ public: QuerySession(llvm::ArrayRef> ASTs) : ASTs(ASTs), BindRoot(true), DiagOutput(true), DumpOutput(false), - PrintOutput(false), Terminate(false) {} + PrintOutput(false), MatcherOutput(false), Terminate(false) {} llvm::ArrayRef> ASTs; bool BindRoot; bool DiagOutput; bool DumpOutput; bool PrintOutput; + bool MatcherOutput; bool Terminate; llvm::StringMap NamedValues; }; Index: unittests/clang-query/QueryEngineTest.cpp =================================================================== --- unittests/clang-query/QueryEngineTest.cpp +++ unittests/clang-query/QueryEngineTest.cpp @@ -50,9 +50,10 @@ TEST_F(QueryEngineTest, Deprecated) { DynTypedMatcher FooMatcher = functionDecl(hasName("foo1")); + std::string FooMatcherString = "functionDecl(hasName(\"foo1\"))"; EXPECT_TRUE(SetOutputQuery(&QuerySession::PrintOutput).run(OS, S)); - EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") != std::string::npos); @@ -60,7 +61,7 @@ Str.clear(); EXPECT_TRUE(SetOutputQuery(&QuerySession::DumpOutput).run(OS, S)); - EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos); Str.clear(); @@ -70,6 +71,8 @@ DynTypedMatcher FnMatcher = functionDecl(); DynTypedMatcher FooMatcher = functionDecl(hasName("foo1")); + std::string FooMatcherString = "functionDecl(hasName(\"foo1\"))"; + EXPECT_TRUE(NoOpQuery().run(OS, S)); EXPECT_EQ("", OS.str()); @@ -88,7 +91,7 @@ Str.clear(); - EXPECT_TRUE(MatchQuery(FnMatcher).run(OS, S)); + EXPECT_TRUE(MatchQuery("functionDecl()", FnMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") != std::string::npos); @@ -102,7 +105,7 @@ Str.clear(); - EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") != std::string::npos); @@ -112,7 +115,7 @@ 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(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") != std::string::npos); @@ -121,7 +124,7 @@ 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(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos); @@ -129,10 +132,12 @@ 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)); + EXPECT_TRUE(SetQuery(&QuerySession::MatcherOutput, true).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); { auto Output = OS.str(); + EXPECT_TRUE(Output.find(FooMatcherString) != std::string::npos); EXPECT_TRUE(Output.find("FunctionDecl") != std::string::npos); EXPECT_TRUE(Output.find("foo.cc:1:1: note: \"root\" binds here") != std::string::npos); @@ -141,13 +146,13 @@ Str.clear(); EXPECT_TRUE(SetQuery(&QuerySession::BindRoot, false).run(OS, S)); - EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S)); + EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos); Str.clear(); - EXPECT_FALSE(MatchQuery(isMain()).run(OS, S)); + EXPECT_FALSE(MatchQuery("isMain()", isMain()).run(OS, S)); EXPECT_EQ("Not a valid top-level matcher.\n", OS.str()); }