blob: ffa3b4566e84c1bc2cb953911f626c4c5a76fa35 [file] [log] [blame]
Peter Collingbourne8b1265b2013-11-08 00:08:23 +00001//===---- 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:52 +000023Query::~Query() {}
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000024
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:23 +000036 " match MATCHER, m MATCHER "
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000037 "Match the loaded ASTs against the given matcher.\n"
Samuel Benzaquene39269e2015-02-27 17:53:23 +000038 " 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:23 +000043 "Set whether to bind the root matcher to \"root\".\n"
Stephen Kelly4a5b01d2018-10-20 09:13:59 +000044 " set print-matcher (true|false) "
45 "Set whether to print the current matcher,\n"
Stephen Kelly4c3d7a92018-10-24 20:33:14 +000046 " set output <feature> "
47 "Set whether to output only <feature> content.\n"
Stephen Kellya49fe5d2018-10-29 18:59:56 +000048 " enable output <feature> "
49 "Enable <feature> content non-exclusively.\n"
50 " disable output <feature> "
51 "Disable <feature> content non-exclusively.\n"
Stephen Kelly42668a42018-10-03 07:52:44 +000052 " quit, q "
Stephen Kelly4c3d7a92018-10-24 20:33:14 +000053 "Terminates the query session.\n\n"
54 "Several commands accept a <feature> parameter. The available features "
55 "are:\n\n"
56 " print "
57 "Pretty-print bound nodes.\n"
58 " diag "
59 "Diagnostic location for bound nodes.\n"
Stephen Kelly51707b22018-10-24 20:33:45 +000060 " detailed-ast "
61 "Detailed AST output for bound nodes.\n"
Stephen Kelly4c3d7a92018-10-24 20:33:14 +000062 " dump "
Stephen Kelly51707b22018-10-24 20:33:45 +000063 "Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
Aaron Ballman58907172015-08-06 11:56:57 +000064 return true;
65}
66
67bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
68 QS.Terminate = true;
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000069 return true;
70}
71
72namespace {
73
74struct CollectBoundNodes : MatchFinder::MatchCallback {
75 std::vector<BoundNodes> &Bindings;
76 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
Alexander Kornienko87638f62015-04-11 07:59:33 +000077 void run(const MatchFinder::MatchResult &Result) override {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000078 Bindings.push_back(Result.Nodes);
79 }
80};
81
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +000082} // namespace
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000083
84bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
85 unsigned MatchCount = 0;
86
David Blaikie35013fa2014-04-25 15:21:43 +000087 for (auto &AST : QS.ASTs) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000088 MatchFinder Finder;
89 std::vector<BoundNodes> Matches;
90 DynTypedMatcher MaybeBoundMatcher = Matcher;
91 if (QS.BindRoot) {
92 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
93 if (M)
94 MaybeBoundMatcher = *M;
95 }
96 CollectBoundNodes Collect(Matches);
97 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
98 OS << "Not a valid top-level matcher.\n";
99 return false;
100 }
101 Finder.matchAST(AST->getASTContext());
102
Stephen Kelly4a5b01d2018-10-20 09:13:59 +0000103 if (QS.PrintMatcher) {
104 std::string prefixText = "Matcher: ";
105 OS << "\n " << prefixText << Source << "\n";
106 OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n';
107 }
108
Piotr Padlewski08124b12016-12-14 15:29:23 +0000109 for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000110 OS << "\nMatch #" << ++MatchCount << ":\n\n";
111
Piotr Padlewski08124b12016-12-14 15:29:23 +0000112 for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
113 ++BI) {
Stephen Kelly70d77172018-10-24 20:33:55 +0000114 if (QS.DiagOutput) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000115 clang::SourceRange R = BI->second.getSourceRange();
116 if (R.isValid()) {
117 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
118 &AST->getDiagnostics().getDiagnosticOptions());
Peter Smithd34a65d2017-06-27 10:04:04 +0000119 TD.emitDiagnostic(
120 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
121 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
122 CharSourceRange::getTokenRange(R), None);
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000123 }
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000124 }
Stephen Kelly70d77172018-10-24 20:33:55 +0000125 if (QS.PrintOutput) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000126 OS << "Binding for \"" << BI->first << "\":\n";
127 BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
128 OS << "\n";
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000129 }
Stephen Kelly70d77172018-10-24 20:33:55 +0000130 if (QS.DetailedASTOutput) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000131 OS << "Binding for \"" << BI->first << "\":\n";
132 BI->second.dump(OS, AST->getSourceManager());
133 OS << "\n";
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000134 }
135 }
136
137 if (MI->getMap().empty())
138 OS << "No bindings.\n";
139 }
140 }
141
142 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
143 return true;
144}
145
Samuel Benzaquen1f6066c2014-04-23 14:04:52 +0000146bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
147 if (Value) {
148 QS.NamedValues[Name] = Value;
149 } else {
150 QS.NamedValues.erase(Name);
151 }
152 return true;
153}
154
Peter Collingbournec7ae6102013-11-08 08:54:53 +0000155#ifndef _MSC_VER
156const QueryKind SetQueryKind<bool>::value;
157const QueryKind SetQueryKind<OutputKind>::value;
158#endif
159
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000160} // namespace query
161} // namespace clang