Add a way to set traversal mode in clang-query

Reviewers: aaron.ballman

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D73037
This commit is contained in:
Stephen Kelly 2019-12-29 19:26:11 +00:00
parent 174322c273
commit 10f0f98eac
6 changed files with 74 additions and 2 deletions

View File

@ -43,6 +43,15 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
"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 <kind> "
"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 <feature> "
"Set whether to output only <feature> content.\n"
" enable output <feature> "
@ -98,6 +107,8 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
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 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
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";
}

View File

@ -28,6 +28,7 @@ enum QueryKind {
QK_Match,
QK_SetBool,
QK_SetOutputKind,
QK_SetTraversalKind,
QK_EnableOutputKind,
QK_DisableOutputKind,
QK_Quit
@ -119,6 +120,10 @@ template <> struct SetQueryKind<OutputKind> {
static const QueryKind value = QK_SetOutputKind;
};
template <> struct SetQueryKind<ast_type_traits::TraversalKind> {
static const QueryKind value = QK_SetTraversalKind;
};
/// Query for "set VAR VALUE".
template <typename T> struct SetQuery : Query {
SetQuery(T QuerySession::*Var, T Value)

View File

@ -128,6 +128,24 @@ template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
llvm_unreachable("Invalid output kind");
}
QueryRef QueryParser::parseSetTraversalKind(
ast_type_traits::TraversalKind QuerySession::*Var) {
StringRef ValStr;
unsigned Value =
LexOrCompleteWord<unsigned>(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<ast_type_traits::TraversalKind>(
Var, static_cast<ast_type_traits::TraversalKind>(Value));
}
QueryRef QueryParser::endQuery(QueryRef Q) {
StringRef Extra = Line;
StringRef ExtraTrimmed = Extra.drop_while(
@ -171,7 +189,8 @@ enum ParsedQueryVariable {
PQV_Invalid,
PQV_Output,
PQV_BindRoot,
PQV_PrintMatcher
PQV_PrintMatcher,
PQV_Traversal
};
QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
@ -272,6 +291,7 @@ QueryRef QueryParser::doParse() {
.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 @@ QueryRef QueryParser::doParse() {
case PQV_PrintMatcher:
Q = parseSetBool(&QuerySession::PrintMatcher);
break;
case PQV_Traversal:
Q = parseSetTraversalKind(&QuerySession::TK);
break;
case PQV_Invalid:
llvm_unreachable("Invalid query kind");
}

View File

@ -43,6 +43,8 @@ private:
template <typename T> struct LexOrCompleteWord;
QueryRef parseSetBool(bool QuerySession::*Var);
QueryRef
parseSetTraversalKind(ast_type_traits::TraversalKind QuerySession::*Var);
template <typename QueryType> QueryRef parseSetOutputKind();
QueryRef completeMatcherExpression();

View File

@ -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 @@ public:
QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> 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<std::unique_ptr<ASTUnit>> ASTs;
@ -36,6 +37,8 @@ public:
bool BindRoot;
bool PrintMatcher;
bool Terminate;
ast_type_traits::TraversalKind TK;
llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
};

View File

@ -110,6 +110,18 @@ TEST_F(QueryParserTest, Set) {
ASSERT_TRUE(isa<SetQuery<bool> >(Q));
EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);
EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);
Q = parse("set traversal AsIs");
ASSERT_TRUE(isa<SetQuery<ast_type_traits::TraversalKind>>(Q));
EXPECT_EQ(&QuerySession::TK,
cast<SetQuery<ast_type_traits::TraversalKind>>(Q)->Var);
EXPECT_EQ(ast_type_traits::TK_AsIs,
cast<SetQuery<ast_type_traits::TraversalKind>>(Q)->Value);
Q = parse("set traversal NotATraversal");
ASSERT_TRUE(isa<InvalidQuery>(Q));
EXPECT_EQ("expected traversal kind, got 'NotATraversal'",
cast<InvalidQuery>(Q)->ErrStr);
}
TEST_F(QueryParserTest, Match) {
@ -197,6 +209,11 @@ TEST_F(QueryParserTest, Complete) {
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 @@ TEST_F(QueryParserTest, Complete) {
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);