clang-tools  11.0.0
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 "QuerySession.h"
11 #include "clang/AST/ASTDumper.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/ASTUnit.h"
14 #include "clang/Frontend/TextDiagnostic.h"
15 #include "llvm/Support/raw_ostream.h"
16 
17 using namespace clang::ast_matchers;
18 using namespace clang::ast_matchers::dynamic;
19 
20 namespace clang {
21 namespace query {
22 
23 Query::~Query() {}
24 
25 bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
26  OS << ErrStr << "\n";
27  return false;
28 }
29 
30 bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
31  return true;
32 }
33 
34 bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
35  OS << "Available commands:\n\n"
36  " match MATCHER, m MATCHER "
37  "Match the loaded ASTs against the given matcher.\n"
38  " let NAME MATCHER, l NAME MATCHER "
39  "Give a matcher expression a name, to be used later\n"
40  " "
41  "as part of other expressions.\n"
42  " set bind-root (true|false) "
43  "Set whether to bind the root matcher to \"root\".\n"
44  " set print-matcher (true|false) "
45  "Set whether to print the current matcher,\n"
46  " set traversal <kind> "
47  "Set traversal kind of clang-query session. Available kinds are:\n"
48  " AsIs "
49  "Print and match the AST as clang sees it. This mode is the "
50  "default.\n"
51  " IgnoreImplicitCastsAndParentheses "
52  "Omit implicit casts and parens in matching and dumping.\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 
76 bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
77  QS.Terminate = true;
78  return true;
79 }
80 
81 namespace {
82 
83 struct 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 
93 bool 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  llvm::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  AST->getASTContext().getParentMapContext().setTraversalKind(QS.TK);
112  Finder.matchAST(AST->getASTContext());
113 
114  if (QS.PrintMatcher) {
115  SmallVector<StringRef, 4> Lines;
116  Source.split(Lines, "\n");
117  auto FirstLine = Lines[0];
118  Lines.erase(Lines.begin(), Lines.begin() + 1);
119  while (!Lines.empty() && Lines.back().empty()) {
120  Lines.resize(Lines.size() - 1);
121  }
122  unsigned MaxLength = FirstLine.size();
123  std::string PrefixText = "Matcher: ";
124  OS << "\n " << PrefixText << FirstLine;
125 
126  for (auto Line : Lines) {
127  OS << "\n" << std::string(PrefixText.size() + 2, ' ') << Line;
128  MaxLength = std::max<int>(MaxLength, Line.rtrim().size());
129  }
130 
131  OS << "\n"
132  << " " << std::string(PrefixText.size() + MaxLength, '=') << "\n\n";
133  }
134 
135  for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
136  OS << "\nMatch #" << ++MatchCount << ":\n\n";
137 
138  for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
139  ++BI) {
140  if (QS.DiagOutput) {
141  clang::SourceRange R = BI->second.getSourceRange();
142  if (R.isValid()) {
143  TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
144  &AST->getDiagnostics().getDiagnosticOptions());
145  TD.emitDiagnostic(
146  FullSourceLoc(R.getBegin(), AST->getSourceManager()),
147  DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
148  CharSourceRange::getTokenRange(R), None);
149  }
150  }
151  if (QS.PrintOutput) {
152  OS << "Binding for \"" << BI->first << "\":\n";
153  BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
154  OS << "\n";
155  }
156  if (QS.DetailedASTOutput) {
157  OS << "Binding for \"" << BI->first << "\":\n";
158  const ASTContext &Ctx = AST->getASTContext();
159  const SourceManager &SM = Ctx.getSourceManager();
160  ASTDumper Dumper(OS, Ctx, SM.getDiagnostics().getShowColors());
161  Dumper.SetTraversalKind(QS.TK);
162  Dumper.Visit(BI->second);
163  OS << "\n";
164  }
165  }
166 
167  if (MI->getMap().empty())
168  OS << "No bindings.\n";
169  }
170  }
171 
172  OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
173  return true;
174 }
175 
176 bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
177  if (Value) {
178  QS.NamedValues[Name] = Value;
179  } else {
180  QS.NamedValues.erase(Name);
181  }
182  return true;
183 }
184 
185 #ifndef _MSC_VER
188 #endif
189 
190 } // namespace query
191 } // namespace clang
clang::query::QuerySession::DiagOutput
bool DiagOutput
Definition: QuerySession.h:34
Ctx
Context Ctx
Definition: TUScheduler.cpp:324
clang::query::QuerySession::PrintMatcher
bool PrintMatcher
Definition: QuerySession.h:38
Query.h
clang::ast_matchers
Definition: AbseilMatcher.h:14
Line
int Line
Definition: PreprocessorTracker.cpp:513
clang::query::QuerySession::PrintOutput
bool PrintOutput
Definition: QuerySession.h:33
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::query::QuerySession::ASTs
llvm::ArrayRef< std::unique_ptr< ASTUnit > > ASTs
Definition: QuerySession.h:31
clang::query::QuerySession::Terminate
bool Terminate
Definition: QuerySession.h:39
clang::query::QuerySession::NamedValues
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
Definition: QuerySession.h:42
clang::query::QueryKind
QueryKind
Definition: Query.h:23
clang::query::SetQueryKind
Definition: Query.h:113
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:162
Bindings
std::vector< BoundNodes > & Bindings
Definition: Query.cpp:84
clang::query::QuerySession::DetailedASTOutput
bool DetailedASTOutput
Definition: QuerySession.h:35
clang::query::QuerySession::TK
ast_type_traits::TraversalKind TK
Definition: QuerySession.h:41
Lines
unsigned Lines
Definition: FunctionSizeCheck.cpp:113
clang::query::QuerySession
Represents the state for a particular clang-query session.
Definition: QuerySession.h:24
clang::query::QuerySession::BindRoot
bool BindRoot
Definition: QuerySession.h:37
QuerySession.h