1 //===---- 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 17 using namespace clang::ast_matchers; 18 using namespace clang::ast_matchers::dynamic; 19 20 namespace clang { 21 namespace query { 22 23 Query::~Query() {} 24 25 bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 26 OS << ErrStr << "\n"; 27 return false; 28 } 29 30 bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 31 return true; 32 } 33 34 bool 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 " 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) " 43 "Set whether to bind the root matcher to \"root\".\n" 44 " set output (diag|print|dump) " 45 "Set whether to print bindings as diagnostics,\n" 46 " " 47 "AST pretty prints or AST dumps.\n" 48 " quit " 49 "Terminates the query session.\n\n"; 50 return true; 51 } 52 53 bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 54 QS.Terminate = true; 55 return true; 56 } 57 58 namespace { 59 60 struct CollectBoundNodes : MatchFinder::MatchCallback { 61 std::vector<BoundNodes> &Bindings; 62 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {} 63 void run(const MatchFinder::MatchResult &Result) override { 64 Bindings.push_back(Result.Nodes); 65 } 66 }; 67 68 } // namespace 69 70 bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 71 unsigned MatchCount = 0; 72 73 for (auto &AST : QS.ASTs) { 74 MatchFinder Finder; 75 std::vector<BoundNodes> Matches; 76 DynTypedMatcher MaybeBoundMatcher = Matcher; 77 if (QS.BindRoot) { 78 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root"); 79 if (M) 80 MaybeBoundMatcher = *M; 81 } 82 CollectBoundNodes Collect(Matches); 83 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) { 84 OS << "Not a valid top-level matcher.\n"; 85 return false; 86 } 87 Finder.matchAST(AST->getASTContext()); 88 89 for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) { 90 OS << "\nMatch #" << ++MatchCount << ":\n\n"; 91 92 for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE; 93 ++BI) { 94 switch (QS.OutKind) { 95 case OK_Diag: { 96 clang::SourceRange R = BI->second.getSourceRange(); 97 if (R.isValid()) { 98 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), 99 &AST->getDiagnostics().getDiagnosticOptions()); 100 TD.emitDiagnostic(R.getBegin(), DiagnosticsEngine::Note, 101 "\"" + BI->first + "\" binds here", 102 CharSourceRange::getTokenRange(R), None, 103 &AST->getSourceManager()); 104 } 105 break; 106 } 107 case OK_Print: { 108 OS << "Binding for \"" << BI->first << "\":\n"; 109 BI->second.print(OS, AST->getASTContext().getPrintingPolicy()); 110 OS << "\n"; 111 break; 112 } 113 case OK_Dump: { 114 OS << "Binding for \"" << BI->first << "\":\n"; 115 BI->second.dump(OS, AST->getSourceManager()); 116 OS << "\n"; 117 break; 118 } 119 } 120 } 121 122 if (MI->getMap().empty()) 123 OS << "No bindings.\n"; 124 } 125 } 126 127 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n"); 128 return true; 129 } 130 131 bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 132 if (Value) { 133 QS.NamedValues[Name] = Value; 134 } else { 135 QS.NamedValues.erase(Name); 136 } 137 return true; 138 } 139 140 #ifndef _MSC_VER 141 const QueryKind SetQueryKind<bool>::value; 142 const QueryKind SetQueryKind<OutputKind>::value; 143 #endif 144 145 } // namespace query 146 } // namespace clang 147