1 //===---- ClangQuery.cpp - clang-query tool -------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This tool is for interactive exploration of the Clang AST using AST matchers.
10 // It currently allows the user to enter a matcher at an interactive prompt and
11 // view the resulting bindings as diagnostics, AST pretty prints or AST dumps.
16 // $ clang-query foo.c --
17 // clang-query> match functionDecl()
21 // foo.c:1:1: note: "root" binds here
26 //===----------------------------------------------------------------------===//
29 #include "QueryParser.h"
30 #include "QuerySession.h"
31 #include "clang/Frontend/ASTUnit.h"
32 #include "clang/Tooling/CommonOptionsParser.h"
33 #include "clang/Tooling/Tooling.h"
34 #include "llvm/LineEditor/LineEditor.h"
35 #include "llvm/Support/CommandLine.h"
36 #include "llvm/Support/Error.h"
37 #include "llvm/Support/MemoryBuffer.h"
38 #include "llvm/Support/Signals.h"
39 #include "llvm/Support/WithColor.h"
43 using namespace clang
;
44 using namespace clang::ast_matchers
;
45 using namespace clang::ast_matchers::dynamic
;
46 using namespace clang::query
;
47 using namespace clang::tooling
;
50 static cl::extrahelp
CommonHelp(CommonOptionsParser::HelpMessage
);
51 static cl::OptionCategory
ClangQueryCategory("clang-query options");
56 R
"(Use colors in detailed AST output. If not set, colors
57 will be used if the terminal connected to
58 standard output supports colors.)"),
59 cl::init(false), cl::cat(ClangQueryCategory
));
61 static cl::list
<std::string
> Commands("c", cl::desc("Specify command to run"),
62 cl::value_desc("command"),
63 cl::cat(ClangQueryCategory
));
65 static cl::list
<std::string
> CommandFiles("f",
66 cl::desc("Read commands from file"),
67 cl::value_desc("file"),
68 cl::cat(ClangQueryCategory
));
70 static cl::opt
<std::string
> PreloadFile(
72 cl::desc("Preload commands from file and start interactive mode"),
73 cl::value_desc("file"), cl::cat(ClangQueryCategory
));
75 bool runCommandsInFile(const char *ExeName
, std::string
const &FileName
,
77 FileQuery
Query(FileName
, ExeName
);
78 return !Query
.run(llvm::errs(), QS
);
81 int main(int argc
, const char **argv
) {
82 llvm::sys::PrintStackTraceOnErrorSignal(argv
[0]);
84 llvm::Expected
<CommonOptionsParser
> OptionsParser
=
85 CommonOptionsParser::create(argc
, argv
, ClangQueryCategory
,
89 llvm::WithColor::error() << llvm::toString(OptionsParser
.takeError());
93 if (!Commands
.empty() && !CommandFiles
.empty()) {
94 llvm::errs() << argv
[0] << ": cannot specify both -c and -f\n";
98 if ((!Commands
.empty() || !CommandFiles
.empty()) && !PreloadFile
.empty()) {
99 llvm::errs() << argv
[0]
100 << ": cannot specify both -c or -f with --preload\n";
104 ClangTool
Tool(OptionsParser
->getCompilations(),
105 OptionsParser
->getSourcePathList());
107 if (UseColor
.getNumOccurrences() > 0) {
108 ArgumentsAdjuster colorAdjustor
= [](const CommandLineArguments
&Args
, StringRef
/*unused*/) {
109 CommandLineArguments AdjustedArgs
= Args
;
111 AdjustedArgs
.push_back("-fdiagnostics-color");
113 AdjustedArgs
.push_back("-fno-diagnostics-color");
116 Tool
.appendArgumentsAdjuster(colorAdjustor
);
119 std::vector
<std::unique_ptr
<ASTUnit
>> ASTs
;
121 switch (Tool
.buildASTs(ASTs
)) {
124 case 1: // Building ASTs failed.
128 llvm::errs() << "Failed to build AST for some of the files, "
129 << "results may be incomplete."
133 llvm_unreachable("Unexpected status returned");
136 QuerySession
QS(ASTs
);
138 if (!Commands
.empty()) {
139 for (auto &Command
: Commands
) {
140 QueryRef Q
= QueryParser::parse(Command
, QS
);
141 if (!Q
->run(llvm::outs(), QS
))
144 } else if (!CommandFiles
.empty()) {
145 for (auto &CommandFile
: CommandFiles
) {
146 if (runCommandsInFile(argv
[0], CommandFile
, QS
))
150 if (!PreloadFile
.empty()) {
151 if (runCommandsInFile(argv
[0], PreloadFile
, QS
))
154 LineEditor
LE("clang-query");
155 LE
.setListCompleter([&QS
](StringRef Line
, size_t Pos
) {
156 return QueryParser::complete(Line
, Pos
, QS
);
158 while (std::optional
<std::string
> Line
= LE
.readLine()) {
159 QueryRef Q
= QueryParser::parse(*Line
, QS
);
160 Q
->run(llvm::outs(), QS
);
161 llvm::outs().flush();