clang-tools 20.0.0git
Query.cpp
Go to the documentation of this file.
1//===---- Query.cpp - clang-query query -----------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "Query.h"
10#include "QueryParser.h"
11#include "QuerySession.h"
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"
17#include <optional>
18
19using namespace clang::ast_matchers;
20using namespace clang::ast_matchers::dynamic;
21
22namespace clang {
23namespace query {
24
26
27bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
28 OS << ErrStr << "\n";
29 return false;
30}
31
32bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
33 return true;
34}
35
36bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
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"
42 " "
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"
50 " AsIs "
51 "Print and match the AST as clang sees it. This mode is the "
52 "default.\n"
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"
61 " quit, q "
62 "Terminates the query session.\n\n"
63 "Several commands accept a <feature> parameter. The available features "
64 "are:\n\n"
65 " print "
66 "Pretty-print bound nodes.\n"
67 " diag "
68 "Diagnostic location for bound nodes.\n"
69 " detailed-ast "
70 "Detailed AST output for bound nodes.\n"
71 " dump "
72 "Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
73 return true;
74}
75
76bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
77 QS.Terminate = true;
78 return true;
79}
80
81namespace {
82
83struct CollectBoundNodes : MatchFinder::MatchCallback {
84 std::vector<BoundNodes> &Bindings;
85 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
86 void run(const MatchFinder::MatchResult &Result) override {
87 Bindings.push_back(Result.Nodes);
88 }
89};
90
91} // namespace
92
93bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
94 unsigned MatchCount = 0;
95
96 for (auto &AST : QS.ASTs) {
97 MatchFinder Finder;
98 std::vector<BoundNodes> Matches;
99 DynTypedMatcher MaybeBoundMatcher = Matcher;
100 if (QS.BindRoot) {
101 std::optional<DynTypedMatcher> M = Matcher.tryBind("root");
102 if (M)
103 MaybeBoundMatcher = *M;
104 }
105 CollectBoundNodes Collect(Matches);
106 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
107 OS << "Not a valid top-level matcher.\n";
108 return false;
109 }
110
111 ASTContext &Ctx = AST->getASTContext();
112 Ctx.getParentMapContext().setTraversalKind(QS.TK);
113 Finder.matchAST(Ctx);
114
115 if (QS.PrintMatcher) {
116 SmallVector<StringRef, 4> Lines;
117 Source.split(Lines, "\n");
118 auto FirstLine = Lines[0];
119 Lines.erase(Lines.begin(), Lines.begin() + 1);
120 while (!Lines.empty() && Lines.back().empty()) {
121 Lines.resize(Lines.size() - 1);
122 }
123 unsigned MaxLength = FirstLine.size();
124 std::string PrefixText = "Matcher: ";
125 OS << "\n " << PrefixText << FirstLine;
126
127 for (auto Line : Lines) {
128 OS << "\n" << std::string(PrefixText.size() + 2, ' ') << Line;
129 MaxLength = std::max<int>(MaxLength, Line.rtrim().size());
130 }
131
132 OS << "\n"
133 << " " << std::string(PrefixText.size() + MaxLength, '=') << "\n\n";
134 }
135
136 for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
137 OS << "\nMatch #" << ++MatchCount << ":\n\n";
138
139 for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
140 ++BI) {
141 if (QS.DiagOutput) {
142 clang::SourceRange R = BI->second.getSourceRange();
143 if (R.isValid()) {
144 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
145 &AST->getDiagnostics().getDiagnosticOptions());
146 TD.emitDiagnostic(
147 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
148 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
149 CharSourceRange::getTokenRange(R), std::nullopt);
150 }
151 }
152 if (QS.PrintOutput) {
153 OS << "Binding for \"" << BI->first << "\":\n";
154 BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
155 OS << "\n";
156 }
157 if (QS.DetailedASTOutput) {
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);
162 OS << "\n";
163 }
164 }
165
166 if (MI->getMap().empty())
167 OS << "No bindings.\n";
168 }
169 }
170
171 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
172 return true;
173}
174
175bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
176 if (Value) {
177 QS.NamedValues[Name] = Value;
178 } else {
179 QS.NamedValues.erase(Name);
180 }
181 return true;
182}
183
184#ifndef _MSC_VER
187#endif
188
189bool FileQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
190 auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
191 if (!Buffer) {
192 if (Prefix.has_value())
193 llvm::errs() << *Prefix << ": ";
194 llvm::errs() << "cannot open " << File << ": "
195 << Buffer.getError().message() << "\n";
196 return false;
197 }
198
199 StringRef FileContentRef(Buffer.get()->getBuffer());
200
201 while (!FileContentRef.empty()) {
202 QueryRef Q = QueryParser::parse(FileContentRef, QS);
203 if (!Q->run(llvm::outs(), QS))
204 return false;
205 FileContentRef = Q->RemainingContent;
206 }
207 return true;
208}
209
210} // namespace query
211} // namespace clang
unsigned Lines
std::vector< BoundNodes > & Bindings
Definition: Query.cpp:84
const google::protobuf::Message & M
Definition: Server.cpp:309
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
static QueryRef parse(StringRef Line, const QuerySession &QS)
Parse Line as a query.
Represents the state for a particular clang-query session.
Definition: QuerySession.h:24
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
Definition: QuerySession.h:42
llvm::ArrayRef< std::unique_ptr< ASTUnit > > ASTs
Definition: QuerySession.h:31
llvm::IntrusiveRefCntPtr< Query > QueryRef
Definition: Query.h:52
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
-clang-tidy
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:189
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:36
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:27
std::string ErrStr
Definition: Query.h:59
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:175
ast_matchers::dynamic::VariantValue Value
Definition: Query.h:108
std::string Name
Definition: Query.h:107
StringRef Source
Definition: Query.h:97
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:93
ast_matchers::dynamic::DynTypedMatcher Matcher
Definition: Query.h:95
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:32
virtual ~Query()
Definition: Query.cpp:25
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override
Perform the query on QS and print output to OS.
Definition: Query.cpp:76