12#include "clang/AST/ASTDumper.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/TextDiagnostic.h"
16#include "llvm/Support/raw_ostream.h"
20using namespace clang::ast_matchers::dynamic;
37 OS <<
"Available commands:\n\n"
38 " match MATCHER, m MATCHER "
39 "Match the loaded ASTs against the given matcher.\n"
40 " let NAME MATCHER, l NAME MATCHER "
41 "Give a matcher expression a name, to be used later\n"
43 "as part of other expressions.\n"
44 " set bind-root (true|false) "
45 "Set whether to bind the root matcher to \"root\".\n"
46 " set print-matcher (true|false) "
47 "Set whether to print the current matcher,\n"
48 " set traversal <kind> "
49 "Set traversal kind of clang-query session. Available kinds are:\n"
51 "Print and match the AST as clang sees it. This mode is the "
53 " IgnoreUnlessSpelledInSource "
54 "Omit AST nodes unless spelled in the source.\n"
55 " set output <feature> "
56 "Set whether to output only <feature> content.\n"
57 " enable output <feature> "
58 "Enable <feature> content non-exclusively.\n"
59 " disable output <feature> "
60 "Disable <feature> content non-exclusively.\n"
62 "Terminates the query session.\n\n"
63 "Several commands accept a <feature> parameter. The available features "
66 "Pretty-print bound nodes.\n"
68 "Diagnostic location for bound nodes.\n"
70 "Detailed AST output for bound nodes.\n"
72 "Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
83struct CollectBoundNodes : MatchFinder::MatchCallback {
86 void run(
const MatchFinder::MatchResult &Result)
override {
94 unsigned MatchCount = 0;
96 for (
auto &AST : QS.
ASTs) {
98 std::vector<BoundNodes> Matches;
99 DynTypedMatcher MaybeBoundMatcher =
Matcher;
101 std::optional<DynTypedMatcher>
M =
Matcher.tryBind(
"root");
103 MaybeBoundMatcher = *
M;
105 CollectBoundNodes Collect(Matches);
106 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
107 OS <<
"Not a valid top-level matcher.\n";
111 ASTContext &Ctx = AST->getASTContext();
112 Ctx.getParentMapContext().setTraversalKind(QS.
TK);
113 Finder.matchAST(Ctx);
116 SmallVector<StringRef, 4>
Lines;
118 auto FirstLine =
Lines[0];
120 while (!
Lines.empty() &&
Lines.back().empty()) {
123 unsigned MaxLength = FirstLine.size();
124 std::string PrefixText =
"Matcher: ";
125 OS <<
"\n " << PrefixText << FirstLine;
128 OS <<
"\n" << std::string(PrefixText.size() + 2,
' ') <<
Line;
129 MaxLength = std::max<int>(MaxLength,
Line.rtrim().size());
133 <<
" " << std::string(PrefixText.size() + MaxLength,
'=') <<
"\n\n";
136 for (
auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
137 OS <<
"\nMatch #" << ++MatchCount <<
":\n\n";
139 for (
auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
142 clang::SourceRange R = BI->second.getSourceRange();
144 TextDiagnostic TD(
OS, AST->getASTContext().getLangOpts(),
145 &AST->getDiagnostics().getDiagnosticOptions());
147 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
148 DiagnosticsEngine::Note,
"\"" + BI->first +
"\" binds here",
149 CharSourceRange::getTokenRange(R), std::nullopt);
153 OS <<
"Binding for \"" << BI->first <<
"\":\n";
154 BI->second.print(
OS, AST->getASTContext().getPrintingPolicy());
158 OS <<
"Binding for \"" << BI->first <<
"\":\n";
159 ASTDumper Dumper(
OS, Ctx, AST->getDiagnostics().getShowColors());
160 Dumper.SetTraversalKind(QS.
TK);
161 Dumper.Visit(BI->second);
166 if (MI->getMap().empty())
167 OS <<
"No bindings.\n";
171 OS << MatchCount << (MatchCount == 1 ?
" match.\n" :
" matches.\n");
190 auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
192 if (Prefix.has_value())
193 llvm::errs() << *Prefix <<
": ";
194 llvm::errs() <<
"cannot open " << File <<
": "
195 << Buffer.getError().message() <<
"\n";
199 StringRef FileContentRef(Buffer.get()->getBuffer());
201 while (!FileContentRef.empty()) {
203 if (!Q->run(llvm::outs(), QS))
205 FileContentRef = Q->RemainingContent;
std::vector< BoundNodes > & Bindings
const google::protobuf::Message & M
llvm::raw_string_ostream OS
static QueryRef parse(StringRef Line, const QuerySession &QS)
Parse Line as a query.
Represents the state for a particular clang-query session.
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
llvm::ArrayRef< std::unique_ptr< ASTUnit > > ASTs
llvm::IntrusiveRefCntPtr< Query > QueryRef
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
ast_matchers::dynamic::VariantValue Value
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
ast_matchers::dynamic::DynTypedMatcher Matcher
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.