blob: 3733120a9cb87d877f0aadf46c6ca513165d1a30 [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
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"
36 " match MATCHER, m MATCHER "
37 "Match the loaded ASTs against the given matcher.\n"
38 " set bind-root (true|false) "
39 "Set whether to bind the root matcher to \"root\".\n"
40 " set output (diag|print|dump) "
41 "Set whether to print bindings as diagnostics,\n"
42 " "
43 "AST pretty prints or AST dumps.\n\n";
44 return true;
45}
46
47namespace {
48
49struct CollectBoundNodes : MatchFinder::MatchCallback {
50 std::vector<BoundNodes> &Bindings;
51 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
52 void run(const MatchFinder::MatchResult &Result) {
53 Bindings.push_back(Result.Nodes);
54 }
55};
56
Samuel Benzaquen1f6066c2014-04-23 14:04:52 +000057} // namespace
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000058
59bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
60 unsigned MatchCount = 0;
61
David Blaikie35013fa2014-04-25 15:21:43 +000062 for (auto &AST : QS.ASTs) {
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000063 MatchFinder Finder;
64 std::vector<BoundNodes> Matches;
65 DynTypedMatcher MaybeBoundMatcher = Matcher;
66 if (QS.BindRoot) {
67 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
68 if (M)
69 MaybeBoundMatcher = *M;
70 }
71 CollectBoundNodes Collect(Matches);
72 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
73 OS << "Not a valid top-level matcher.\n";
74 return false;
75 }
76 Finder.matchAST(AST->getASTContext());
77
78 for (std::vector<BoundNodes>::iterator MI = Matches.begin(),
79 ME = Matches.end();
80 MI != ME; ++MI) {
81 OS << "\nMatch #" << ++MatchCount << ":\n\n";
82
83 for (BoundNodes::IDToNodeMap::const_iterator BI = MI->getMap().begin(),
84 BE = MI->getMap().end();
85 BI != BE; ++BI) {
86 switch (QS.OutKind) {
87 case OK_Diag: {
88 clang::SourceRange R = BI->second.getSourceRange();
89 if (R.isValid()) {
90 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
91 &AST->getDiagnostics().getDiagnosticOptions());
92 TD.emitDiagnostic(
93 R.getBegin(), DiagnosticsEngine::Note,
94 "\"" + BI->first + "\" binds here",
Craig Topperae926ad2014-08-29 06:05:20 +000095 CharSourceRange::getTokenRange(R),
Craig Topper2f020e52014-08-27 06:29:07 +000096 None, &AST->getSourceManager());
Peter Collingbourne8b1265b2013-11-08 00:08:23 +000097 }
98 break;
99 }
100 case OK_Print: {
101 OS << "Binding for \"" << BI->first << "\":\n";
102 BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
103 OS << "\n";
104 break;
105 }
106 case OK_Dump: {
107 OS << "Binding for \"" << BI->first << "\":\n";
108 BI->second.dump(OS, AST->getSourceManager());
109 OS << "\n";
110 break;
111 }
112 }
113 }
114
115 if (MI->getMap().empty())
116 OS << "No bindings.\n";
117 }
118 }
119
120 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
121 return true;
122}
123
Samuel Benzaquen1f6066c2014-04-23 14:04:52 +0000124bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
125 if (Value) {
126 QS.NamedValues[Name] = Value;
127 } else {
128 QS.NamedValues.erase(Name);
129 }
130 return true;
131}
132
Peter Collingbournec7ae6102013-11-08 08:54:53 +0000133#ifndef _MSC_VER
134const QueryKind SetQueryKind<bool>::value;
135const QueryKind SetQueryKind<OutputKind>::value;
136#endif
137
Peter Collingbourne8b1265b2013-11-08 00:08:23 +0000138} // namespace query
139} // namespace clang