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 " 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 47 namespace { 48 49 struct 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 57 } 58 59 bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 60 unsigned MatchCount = 0; 61 62 for (llvm::ArrayRef<ASTUnit *>::iterator I = QS.ASTs.begin(), 63 E = QS.ASTs.end(); 64 I != E; ++I) { 65 ASTUnit *AST = *I; 66 MatchFinder Finder; 67 std::vector<BoundNodes> Matches; 68 DynTypedMatcher MaybeBoundMatcher = Matcher; 69 if (QS.BindRoot) { 70 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root"); 71 if (M) 72 MaybeBoundMatcher = *M; 73 } 74 CollectBoundNodes Collect(Matches); 75 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) { 76 OS << "Not a valid top-level matcher.\n"; 77 return false; 78 } 79 Finder.matchAST(AST->getASTContext()); 80 81 for (std::vector<BoundNodes>::iterator MI = Matches.begin(), 82 ME = Matches.end(); 83 MI != ME; ++MI) { 84 OS << "\nMatch #" << ++MatchCount << ":\n\n"; 85 86 for (BoundNodes::IDToNodeMap::const_iterator BI = MI->getMap().begin(), 87 BE = MI->getMap().end(); 88 BI != BE; ++BI) { 89 switch (QS.OutKind) { 90 case OK_Diag: { 91 clang::SourceRange R = BI->second.getSourceRange(); 92 if (R.isValid()) { 93 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), 94 &AST->getDiagnostics().getDiagnosticOptions()); 95 TD.emitDiagnostic( 96 R.getBegin(), DiagnosticsEngine::Note, 97 "\"" + BI->first + "\" binds here", 98 ArrayRef<CharSourceRange>(CharSourceRange::getTokenRange(R)), 99 ArrayRef<FixItHint>(), &AST->getSourceManager()); 100 } 101 break; 102 } 103 case OK_Print: { 104 OS << "Binding for \"" << BI->first << "\":\n"; 105 BI->second.print(OS, AST->getASTContext().getPrintingPolicy()); 106 OS << "\n"; 107 break; 108 } 109 case OK_Dump: { 110 OS << "Binding for \"" << BI->first << "\":\n"; 111 BI->second.dump(OS, AST->getSourceManager()); 112 OS << "\n"; 113 break; 114 } 115 } 116 } 117 118 if (MI->getMap().empty()) 119 OS << "No bindings.\n"; 120 } 121 } 122 123 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n"); 124 return true; 125 } 126 127 #ifndef _MSC_VER 128 const QueryKind SetQueryKind<bool>::value; 129 const QueryKind SetQueryKind<OutputKind>::value; 130 #endif 131 132 } // namespace query 133 } // namespace clang 134