blob: d5d755157df3aa7128d6671c8a164b23e25de3f9 [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
23Query::~Query() {}
24
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"
Samuel Benzaquene39269e2015-02-27 17:53:2344 " set output (diag|print|dump) "
Peter Collingbourne8b1265b2013-11-08 00:08:2345 "Set whether to print bindings as diagnostics,\n"
Samuel Benzaquene39269e2015-02-27 17:53:2346 " "
Peter Collingbourne8b1265b2013-11-08 00:08:2347 "AST pretty prints or AST dumps.\n\n";
48 return true;
49}
50
51namespace {
52
53struct CollectBoundNodes : MatchFinder::MatchCallback {
54 std::vector<BoundNodes> &Bindings;
55 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
Alexander Kornienko87638f62015-04-11 07:59:3356 void run(const MatchFinder::MatchResult &Result) override {
Peter Collingbourne8b1265b2013-11-08 00:08:2357 Bindings.push_back(Result.Nodes);
58 }
59};
60
Samuel Benzaquen1f6066c2014-04-23 14:04:5261} // namespace
Peter Collingbourne8b1265b2013-11-08 00:08:2362
63bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
64 unsigned MatchCount = 0;
65
David Blaikie35013fa2014-04-25 15:21:4366 for (auto &AST : QS.ASTs) {
Peter Collingbourne8b1265b2013-11-08 00:08:2367 MatchFinder Finder;
68 std::vector<BoundNodes> Matches;
69 DynTypedMatcher MaybeBoundMatcher = Matcher;
70 if (QS.BindRoot) {
71 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
72 if (M)
73 MaybeBoundMatcher = *M;
74 }
75 CollectBoundNodes Collect(Matches);
76 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
77 OS << "Not a valid top-level matcher.\n";
78 return false;
79 }
80 Finder.matchAST(AST->getASTContext());
81
82 for (std::vector<BoundNodes>::iterator MI = Matches.begin(),
83 ME = Matches.end();
84 MI != ME; ++MI) {
85 OS << "\nMatch #" << ++MatchCount << ":\n\n";
86
87 for (BoundNodes::IDToNodeMap::const_iterator BI = MI->getMap().begin(),
88 BE = MI->getMap().end();
89 BI != BE; ++BI) {
90 switch (QS.OutKind) {
91 case OK_Diag: {
92 clang::SourceRange R = BI->second.getSourceRange();
93 if (R.isValid()) {
94 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
95 &AST->getDiagnostics().getDiagnosticOptions());
96 TD.emitDiagnostic(
97 R.getBegin(), DiagnosticsEngine::Note,
98 "\"" + BI->first + "\" binds here",
Craig Topperae926ad2014-08-29 06:05:2099 CharSourceRange::getTokenRange(R),
Craig Topper2f020e52014-08-27 06:29:07100 None, &AST->getSourceManager());
Peter Collingbourne8b1265b2013-11-08 00:08:23101 }
102 break;
103 }
104 case OK_Print: {
105 OS << "Binding for \"" << BI->first << "\":\n";
106 BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
107 OS << "\n";
108 break;
109 }
110 case OK_Dump: {
111 OS << "Binding for \"" << BI->first << "\":\n";
112 BI->second.dump(OS, AST->getSourceManager());
113 OS << "\n";
114 break;
115 }
116 }
117 }
118
119 if (MI->getMap().empty())
120 OS << "No bindings.\n";
121 }
122 }
123
124 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
125 return true;
126}
127
Samuel Benzaquen1f6066c2014-04-23 14:04:52128bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
129 if (Value) {
130 QS.NamedValues[Name] = Value;
131 } else {
132 QS.NamedValues.erase(Name);
133 }
134 return true;
135}
136
Peter Collingbournec7ae6102013-11-08 08:54:53137#ifndef _MSC_VER
138const QueryKind SetQueryKind<bool>::value;
139const QueryKind SetQueryKind<OutputKind>::value;
140#endif
141
Peter Collingbourne8b1265b2013-11-08 00:08:23142} // namespace query
143} // namespace clang