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 @@ -83,12 +83,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-tools-extra/trunk/clang-query/Query.cpp =================================================================== --- clang-tools-extra/trunk/clang-query/Query.cpp +++ clang-tools-extra/trunk/clang-query/Query.cpp @@ -41,6 +41,8 @@ "as part of other expressions.\n" " set bind-root (true|false) " "Set whether to bind the root matcher to \"root\".\n" + " set print-matcher (true|false) " + "Set whether to print the current matcher,\n" " set output (diag|print|dump) " "Set whether to print bindings as diagnostics,\n" " " @@ -86,6 +88,12 @@ } Finder.matchAST(AST->getASTContext()); + if (QS.PrintMatcher) { + 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-tools-extra/trunk/clang-query/QueryParser.cpp =================================================================== --- clang-tools-extra/trunk/clang-query/QueryParser.cpp +++ clang-tools-extra/trunk/clang-query/QueryParser.cpp @@ -142,7 +142,12 @@ PQK_Quit }; -enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot }; +enum ParsedQueryVariable { + PQV_Invalid, + PQV_Output, + PQV_BindRoot, + PQV_PrintMatcher +}; QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { std::string ErrStr; @@ -214,21 +219,23 @@ 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: { 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("print-matcher", PQV_PrintMatcher) + .Default(PQV_Invalid); if (VarStr.empty()) return new InvalidQuery("expected variable name"); if (Var == PQV_Invalid) @@ -242,6 +249,9 @@ case PQV_BindRoot: Q = parseSetBool(&QuerySession::BindRoot); break; + case PQV_PrintMatcher: + Q = parseSetBool(&QuerySession::PrintMatcher); + break; case PQV_Invalid: llvm_unreachable("Invalid query kind"); } Index: clang-tools-extra/trunk/clang-query/QuerySession.h =================================================================== --- clang-tools-extra/trunk/clang-query/QuerySession.h +++ clang-tools-extra/trunk/clang-query/QuerySession.h @@ -25,11 +25,13 @@ class QuerySession { public: QuerySession(llvm::ArrayRef> ASTs) - : ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), Terminate(false) {} + : ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), PrintMatcher(false), + Terminate(false) {} llvm::ArrayRef> ASTs; OutputKind OutKind; bool BindRoot; + bool PrintMatcher; bool Terminate; llvm::StringMap NamedValues; }; 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 @@ -52,6 +52,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()); @@ -70,7 +72,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); @@ -84,7 +86,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); @@ -94,7 +96,7 @@ EXPECT_TRUE( SetQuery(&QuerySession::OutKind, OK_Print).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); @@ -102,20 +104,20 @@ Str.clear(); EXPECT_TRUE(SetQuery(&QuerySession::OutKind, OK_Dump).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(); 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()); }