blob: 463e52c5806f7af39293385d246bf6c498414495 [file] [log] [blame]
Peter Collingbourne8b1265b2013-11-08 00:08:231//===---- Query.cpp - clang-query query -----------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Query.h"
11#include "QuerySession.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
17using namespace clang::ast_matchers;
18using namespace clang::ast_matchers::dynamic;
19
20namespace clang {
21namespace query {
22
David Blaikiee04a3da2015-10-20 21:45:5223Query::~Query() {}
Peter Collingbourne8b1265b2013-11-08 00:08:2324
25bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
26 OS << ErrStr << "\n";
27 return false;
28}
29
30bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
31 return true;
32}
33
34bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
35 OS << "Available commands:\n\n"
Samuel Benzaquene39269e2015-02-27 17:53:2336 " match MATCHER, m MATCHER "
Peter Collingbourne8b1265b2013-11-08 00:08:2337 "Match the loaded ASTs against the given matcher.\n"
Samuel Benzaquene39269e2015-02-27 17:53:2338 " 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) "
Peter Collingbourne8b1265b2013-11-08 00:08:2343 "Set whether to bind the root matcher to \"root\".\n"
Stephen Kelly4a5b01d2018-10-20 09:13:5944 " set print-matcher (true|false) "
45 "Set whether to print the current matcher,\n"
Samuel Benzaquene39269e2015-02-27 17:53:2346 " set output (diag|print|dump) "
Peter Collingbourne8b1265b2013-11-08 00:08:2347 "Set whether to print bindings as diagnostics,\n"
Samuel Benzaquene39269e2015-02-27 17:53:2348 " "
Aaron Ballman58907172015-08-06 11:56:5749 "AST pretty prints or AST dumps.\n"
Stephen Kelly42668a42018-10-03 07:52:4450 " quit, q "
Aaron Ballman58907172015-08-06 11:56:5751 "Terminates the query session.\n\n";
52 return true;
53}
54
55bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
56 QS.Terminate = true;
Peter Collingbourne8b1265b2013-11-08 00:08:2357 return true;
58}
59
60namespace {
61
62struct CollectBoundNodes : MatchFinder::MatchCallback {
63 std::vector<BoundNodes> &Bindings;
64 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
Alexander Kornienko87638f62015-04-11 07:59:3365 void run(const MatchFinder::MatchResult &Result) override {
Peter Collingbourne8b1265b2013-11-08 00:08:2366 Bindings.push_back(Result.Nodes);
67 }
68};
69
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:1970} // namespace
Peter Collingbourne8b1265b2013-11-08 00:08:2371
72bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
73 unsigned MatchCount = 0;
74
David Blaikie35013fa2014-04-25 15:21:4375 for (auto &AST : QS.ASTs) {
Peter Collingbourne8b1265b2013-11-08 00:08:2376 MatchFinder Finder;
77 std::vector<BoundNodes> Matches;
78 DynTypedMatcher MaybeBoundMatcher = Matcher;
79 if (QS.BindRoot) {
80 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
81 if (M)
82 MaybeBoundMatcher = *M;
83 }
84 CollectBoundNodes Collect(Matches);
85 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
86 OS << "Not a valid top-level matcher.\n";
87 return false;
88 }
89 Finder.matchAST(AST->getASTContext());
90
Stephen Kelly4a5b01d2018-10-20 09:13:5991 if (QS.PrintMatcher) {
92 std::string prefixText = "Matcher: ";
93 OS << "\n " << prefixText << Source << "\n";
94 OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n';
95 }
96
Piotr Padlewski08124b12016-12-14 15:29:2397 for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
Peter Collingbourne8b1265b2013-11-08 00:08:2398 OS << "\nMatch #" << ++MatchCount << ":\n\n";
99
Piotr Padlewski08124b12016-12-14 15:29:23100 for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
101 ++BI) {
Peter Collingbourne8b1265b2013-11-08 00:08:23102 switch (QS.OutKind) {
103 case OK_Diag: {
104 clang::SourceRange R = BI->second.getSourceRange();
105 if (R.isValid()) {
106 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
107 &AST->getDiagnostics().getDiagnosticOptions());
Peter Smithd34a65d2017-06-27 10:04:04108 TD.emitDiagnostic(
109 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
110 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
111 CharSourceRange::getTokenRange(R), None);
Peter Collingbourne8b1265b2013-11-08 00:08:23112 }
113 break;
114 }
115 case OK_Print: {
116 OS << "Binding for \"" << BI->first << "\":\n";
117 BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
118 OS << "\n";
119 break;
120 }
121 case OK_Dump: {
122 OS << "Binding for \"" << BI->first << "\":\n";
123 BI->second.dump(OS, AST->getSourceManager());
124 OS << "\n";
125 break;
126 }
127 }
128 }
129
130 if (MI->getMap().empty())
131 OS << "No bindings.\n";
132 }
133 }
134
135 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
136 return true;
137}
138
Samuel Benzaquen1f6066c2014-04-23 14:04:52139bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
140 if (Value) {
141 QS.NamedValues[Name] = Value;
142 } else {
143 QS.NamedValues.erase(Name);
144 }
145 return true;
146}
147
Peter Collingbournec7ae6102013-11-08 08:54:53148#ifndef _MSC_VER
149const QueryKind SetQueryKind<bool>::value;
150const QueryKind SetQueryKind<OutputKind>::value;
151#endif
152
Peter Collingbourne8b1265b2013-11-08 00:08:23153} // namespace query
154} // namespace clang