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 print-matcher (true|false) " 45 "Set whether to print the current matcher,\n" 46 " set output <feature> " 47 "Set whether to output only <feature> content.\n" 48 " quit, q " 49 "Terminates the query session.\n\n" 50 "Several commands accept a <feature> parameter. The available features " 51 "are:\n\n" 52 " print " 53 "Pretty-print bound nodes.\n" 54 " diag " 55 "Diagnostic location for bound nodes.\n" 56 " detailed-ast " 57 "Detailed AST output for bound nodes.\n" 58 " dump " 59 "Detailed AST output for bound nodes (alias of detailed-ast).\n\n"; 60 return true; 61 } 62 63 bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 64 QS.Terminate = true; 65 return true; 66 } 67 68 namespace { 69 70 struct CollectBoundNodes : MatchFinder::MatchCallback { 71 std::vector<BoundNodes> &Bindings; 72 CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {} 73 void run(const MatchFinder::MatchResult &Result) override { 74 Bindings.push_back(Result.Nodes); 75 } 76 }; 77 78 } // namespace 79 80 bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 81 unsigned MatchCount = 0; 82 83 for (auto &AST : QS.ASTs) { 84 MatchFinder Finder; 85 std::vector<BoundNodes> Matches; 86 DynTypedMatcher MaybeBoundMatcher = Matcher; 87 if (QS.BindRoot) { 88 llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root"); 89 if (M) 90 MaybeBoundMatcher = *M; 91 } 92 CollectBoundNodes Collect(Matches); 93 if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) { 94 OS << "Not a valid top-level matcher.\n"; 95 return false; 96 } 97 Finder.matchAST(AST->getASTContext()); 98 99 if (QS.PrintMatcher) { 100 std::string prefixText = "Matcher: "; 101 OS << "\n " << prefixText << Source << "\n"; 102 OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n'; 103 } 104 105 for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) { 106 OS << "\nMatch #" << ++MatchCount << ":\n\n"; 107 108 for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE; 109 ++BI) { 110 if (QS.DiagOutput) { 111 clang::SourceRange R = BI->second.getSourceRange(); 112 if (R.isValid()) { 113 TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), 114 &AST->getDiagnostics().getDiagnosticOptions()); 115 TD.emitDiagnostic( 116 FullSourceLoc(R.getBegin(), AST->getSourceManager()), 117 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here", 118 CharSourceRange::getTokenRange(R), None); 119 } 120 } 121 if (QS.PrintOutput) { 122 OS << "Binding for \"" << BI->first << "\":\n"; 123 BI->second.print(OS, AST->getASTContext().getPrintingPolicy()); 124 OS << "\n"; 125 } 126 if (QS.DetailedASTOutput) { 127 OS << "Binding for \"" << BI->first << "\":\n"; 128 BI->second.dump(OS, AST->getSourceManager()); 129 OS << "\n"; 130 } 131 } 132 133 if (MI->getMap().empty()) 134 OS << "No bindings.\n"; 135 } 136 } 137 138 OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n"); 139 return true; 140 } 141 142 bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { 143 if (Value) { 144 QS.NamedValues[Name] = Value; 145 } else { 146 QS.NamedValues.erase(Name); 147 } 148 return true; 149 } 150 151 #ifndef _MSC_VER 152 const QueryKind SetQueryKind<bool>::value; 153 const QueryKind SetQueryKind<OutputKind>::value; 154 #endif 155 156 } // namespace query 157 } // namespace clang 158