clang-tools  9.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/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Frontend/ASTUnit.h"
13 #include "clang/Frontend/TextDiagnostic.h"
14 #include "llvm/Support/raw_ostream.h"
15 
16 using namespace clang::ast_matchers;
17 using namespace clang::ast_matchers::dynamic;
18 
19 namespace clang {
20 namespace query {
21 
22 Query::~Query() {}
23 
24 bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
25  OS << ErrStr << "\n";
26  return false;
27 }
28 
29 bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
30  return true;
31 }
32 
33 bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
34  OS << "Available commands:\n\n"
35  " match MATCHER, m MATCHER "
36  "Match the loaded ASTs against the given matcher.\n"
37  " let NAME MATCHER, l NAME MATCHER "
38  "Give a matcher expression a name, to be used later\n"
39  " "
40  "as part of other expressions.\n"
41  " set bind-root (true|false) "
42  "Set whether to bind the root matcher to \"root\".\n"
43  " set print-matcher (true|false) "
44  "Set whether to print the current matcher,\n"
45  " set output <feature> "
46  "Set whether to output only <feature> content.\n"
47  " enable output <feature> "
48  "Enable <feature> content non-exclusively.\n"
49  " disable output <feature> "
50  "Disable <feature> content non-exclusively.\n"
51  " quit, q "
52  "Terminates the query session.\n\n"
53  "Several commands accept a <feature> parameter. The available features "
54  "are:\n\n"
55  " print "
56  "Pretty-print bound nodes.\n"
57  " diag "
58  "Diagnostic location for bound nodes.\n"
59  " detailed-ast "
60  "Detailed AST output for bound nodes.\n"
61  " dump "
62  "Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
63  return true;
64 }
65 
66 bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
67  QS.Terminate = true;
68  return true;
69 }
70 
71 namespace {
72 
73 struct CollectBoundNodes : MatchFinder::MatchCallback {
74  std::vector<BoundNodes> &Bindings;
75  CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
76  void run(const MatchFinder::MatchResult &Result) override {
77  Bindings.push_back(Result.Nodes);
78  }
79 };
80 
81 } // namespace
82 
83 bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
84  unsigned MatchCount = 0;
85 
86  for (auto &AST : QS.ASTs) {
87  MatchFinder Finder;
88  std::vector<BoundNodes> Matches;
89  DynTypedMatcher MaybeBoundMatcher = Matcher;
90  if (QS.BindRoot) {
91  llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
92  if (M)
93  MaybeBoundMatcher = *M;
94  }
95  CollectBoundNodes Collect(Matches);
96  if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
97  OS << "Not a valid top-level matcher.\n";
98  return false;
99  }
100  Finder.matchAST(AST->getASTContext());
101 
102  if (QS.PrintMatcher) {
103  std::string prefixText = "Matcher: ";
104  OS << "\n " << prefixText << Source << "\n";
105  OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n';
106  }
107 
108  for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
109  OS << "\nMatch #" << ++MatchCount << ":\n\n";
110 
111  for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
112  ++BI) {
113  if (QS.DiagOutput) {
114  clang::SourceRange R = BI->second.getSourceRange();
115  if (R.isValid()) {
116  TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
117  &AST->getDiagnostics().getDiagnosticOptions());
118  TD.emitDiagnostic(
119  FullSourceLoc(R.getBegin(), AST->getSourceManager()),
120  DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
122  }
123  }
124  if (QS.PrintOutput) {
125  OS << "Binding for \"" << BI->first << "\":\n";
126  BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
127  OS << "\n";
128  }
129  if (QS.DetailedASTOutput) {
130  OS << "Binding for \"" << BI->first << "\":\n";
131  BI->second.dump(OS, AST->getSourceManager());
132  OS << "\n";
133  }
134  }
135 
136  if (MI->getMap().empty())
137  OS << "No bindings.\n";
138  }
139  }
140 
141  OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
142  return true;
143 }
144 
145 bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
146  if (Value) {
147  QS.NamedValues[Name] = Value;
148  } else {
149  QS.NamedValues.erase(Name);
150  }
151  return true;
152 }
153 
154 #ifndef _MSC_VER
157 #endif
158 
159 } // namespace query
160 } // namespace clang
Represents the state for a particular clang-query session.
Definition: QuerySession.h:23
llvm::ArrayRef< std::unique_ptr< ASTUnit > > ASTs
Definition: QuerySession.h:30
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
Definition: QuerySession.h:39
static constexpr llvm::StringLiteral Name
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:203
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< BoundNodes > & Bindings
Definition: Query.cpp:74
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: Rename.cpp:36