diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h --- a/clang-tools-extra/clang-query/Query.h +++ b/clang-tools-extra/clang-query/Query.h @@ -28,6 +28,7 @@ QK_Match, QK_SetBool, QK_SetOutputKind, + QK_SetTraversalKind, QK_EnableOutputKind, QK_DisableOutputKind, QK_Quit @@ -119,6 +120,10 @@ static const QueryKind value = QK_SetOutputKind; }; +template <> struct SetQueryKind { + static const QueryKind value = QK_SetTraversalKind; +}; + /// Query for "set VAR VALUE". template struct SetQuery : Query { SetQuery(T QuerySession::*Var, T Value) diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -43,6 +43,15 @@ "Set whether to bind the root matcher to \"root\".\n" " set print-matcher (true|false) " "Set whether to print the current matcher,\n" + " set traversal " + "Set traversal kind of clang-query session. Available kinds are:\n" + " AsIs " + "Print and match the AST as clang sees it.\n" + " IgnoreImplicitCastsAndParentheses " + "Omit implicit casts and parens in matching and dumping.\n" + " IgnoreUnlessSpelledInSource " + "Omit AST nodes unless spelled in the source. This mode is the " + "default.\n" " set output " "Set whether to output only content.\n" " enable output " @@ -98,6 +107,8 @@ OS << "Not a valid top-level matcher.\n"; return false; } + + AST->getASTContext().getParentMapContext().setTraversalKind(QS.TK); Finder.matchAST(AST->getASTContext()); if (QS.PrintMatcher) { @@ -148,6 +159,7 @@ const SourceManager &SM = Ctx.getSourceManager(); ASTDumper Dumper(OS, &Ctx.getCommentCommandTraits(), &SM, SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); + Dumper.SetTraversalKind(QS.TK); Dumper.Visit(BI->second); OS << "\n"; } diff --git a/clang-tools-extra/clang-query/QueryParser.h b/clang-tools-extra/clang-query/QueryParser.h --- a/clang-tools-extra/clang-query/QueryParser.h +++ b/clang-tools-extra/clang-query/QueryParser.h @@ -43,6 +43,8 @@ template struct LexOrCompleteWord; QueryRef parseSetBool(bool QuerySession::*Var); + QueryRef + parseSetTraversalKind(ast_type_traits::TraversalKind QuerySession::*Var); template QueryRef parseSetOutputKind(); QueryRef completeMatcherExpression(); diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp --- a/clang-tools-extra/clang-query/QueryParser.cpp +++ b/clang-tools-extra/clang-query/QueryParser.cpp @@ -128,6 +128,24 @@ llvm_unreachable("Invalid output kind"); } +QueryRef QueryParser::parseSetTraversalKind( + ast_type_traits::TraversalKind QuerySession::*Var) { + StringRef ValStr; + unsigned Value = + LexOrCompleteWord(this, ValStr) + .Case("AsIs", ast_type_traits::TK_AsIs) + .Case("IgnoreImplicitCastsAndParentheses", + ast_type_traits::TK_IgnoreImplicitCastsAndParentheses) + .Case("IgnoreUnlessSpelledInSource", + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + .Default(~0u); + if (Value == ~0u) { + return new InvalidQuery("expected traversal kind, got '" + ValStr + "'"); + } + return new SetQuery( + Var, static_cast(Value)); +} + QueryRef QueryParser::endQuery(QueryRef Q) { StringRef Extra = Line; StringRef ExtraTrimmed = Extra.drop_while( @@ -171,7 +189,8 @@ PQV_Invalid, PQV_Output, PQV_BindRoot, - PQV_PrintMatcher + PQV_PrintMatcher, + PQV_Traversal }; QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { @@ -272,6 +291,7 @@ .Case("output", PQV_Output) .Case("bind-root", PQV_BindRoot) .Case("print-matcher", PQV_PrintMatcher) + .Case("traversal", PQV_Traversal) .Default(PQV_Invalid); if (VarStr.empty()) return new InvalidQuery("expected variable name"); @@ -289,6 +309,9 @@ case PQV_PrintMatcher: Q = parseSetBool(&QuerySession::PrintMatcher); break; + case PQV_Traversal: + Q = parseSetTraversalKind(&QuerySession::TK); + break; case PQV_Invalid: llvm_unreachable("Invalid query kind"); } diff --git a/clang-tools-extra/clang-query/QuerySession.h b/clang-tools-extra/clang-query/QuerySession.h --- a/clang-tools-extra/clang-query/QuerySession.h +++ b/clang-tools-extra/clang-query/QuerySession.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H +#include "clang/AST/ASTTypeTraits.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" @@ -25,7 +26,7 @@ QuerySession(llvm::ArrayRef> ASTs) : ASTs(ASTs), PrintOutput(false), DiagOutput(true), DetailedASTOutput(false), BindRoot(true), PrintMatcher(false), - Terminate(false) {} + Terminate(false), TK(ast_type_traits::TK_IgnoreUnlessSpelledInSource) {} llvm::ArrayRef> ASTs; @@ -36,6 +37,8 @@ bool BindRoot; bool PrintMatcher; bool Terminate; + + ast_type_traits::TraversalKind TK; llvm::StringMap NamedValues; }; diff --git a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp --- a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp +++ b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp @@ -110,6 +110,18 @@ ASSERT_TRUE(isa >(Q)); EXPECT_EQ(&QuerySession::BindRoot, cast >(Q)->Var); EXPECT_EQ(true, cast >(Q)->Value); + + Q = parse("set traversal AsIs"); + ASSERT_TRUE(isa>(Q)); + EXPECT_EQ(&QuerySession::TK, + cast>(Q)->Var); + EXPECT_EQ(ast_type_traits::TK_AsIs, + cast>(Q)->Value); + + Q = parse("set traversal NotATraversal"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ("expected traversal kind, got 'NotATraversal'", + cast(Q)->ErrStr); } TEST_F(QueryParserTest, Match) { @@ -197,6 +209,11 @@ EXPECT_EQ("utput ", Comps[0].TypedText); EXPECT_EQ("output", Comps[0].DisplayText); + Comps = QueryParser::complete("set t", 5, QS); + ASSERT_EQ(1u, Comps.size()); + EXPECT_EQ("raversal ", Comps[0].TypedText); + EXPECT_EQ("traversal", Comps[0].DisplayText); + Comps = QueryParser::complete("enable ", 7, QS); ASSERT_EQ(1u, Comps.size()); EXPECT_EQ("output ", Comps[0].TypedText); @@ -214,6 +231,16 @@ EXPECT_EQ("dump ", Comps[3].TypedText); EXPECT_EQ("dump", Comps[3].DisplayText); + Comps = QueryParser::complete("set traversal ", 14, QS); + ASSERT_EQ(3u, Comps.size()); + + EXPECT_EQ("AsIs ", Comps[0].TypedText); + EXPECT_EQ("AsIs", Comps[0].DisplayText); + EXPECT_EQ("IgnoreImplicitCastsAndParentheses ", Comps[1].TypedText); + EXPECT_EQ("IgnoreImplicitCastsAndParentheses", Comps[1].DisplayText); + EXPECT_EQ("IgnoreUnlessSpelledInSource ", Comps[2].TypedText); + EXPECT_EQ("IgnoreUnlessSpelledInSource", Comps[2].DisplayText); + Comps = QueryParser::complete("match while", 11, QS); ASSERT_EQ(1u, Comps.size()); EXPECT_EQ("Stmt(", Comps[0].TypedText);