1 //===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // AST Consumer Implementations. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Frontend/ASTConsumers.h" 14 #include "clang/AST/ASTConsumer.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/PrettyPrinter.h" 17 #include "clang/AST/RecordLayout.h" 18 #include "clang/AST/RecursiveASTVisitor.h" 19 #include "clang/Basic/Diagnostic.h" 20 #include "llvm/Support/Timer.h" 21 #include "llvm/Support/raw_ostream.h" 22 using namespace clang; 23 24 //===----------------------------------------------------------------------===// 25 /// ASTPrinter - Pretty-printer and dumper of ASTs 26 27 namespace { 28 class ASTPrinter : public ASTConsumer, 29 public RecursiveASTVisitor<ASTPrinter> { 30 typedef RecursiveASTVisitor<ASTPrinter> base; 31 32 public: 33 enum Kind { DumpFull, Dump, Print, None }; 34 ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, 35 ASTDumpOutputFormat Format, StringRef FilterString, 36 bool DumpLookups = false, bool DumpDeclTypes = false) 37 : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), 38 OutputKind(K), OutputFormat(Format), FilterString(FilterString), 39 DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {} 40 41 ASTPrinter(raw_ostream &Out, Kind K, ASTDumpOutputFormat Format, 42 StringRef FilterString, bool DumpLookups = false, 43 bool DumpDeclTypes = false) 44 : Out(Out), OwnedOut(nullptr), OutputKind(K), OutputFormat(Format), 45 FilterString(FilterString), DumpLookups(DumpLookups), 46 DumpDeclTypes(DumpDeclTypes) {} 47 48 void HandleTranslationUnit(ASTContext &Context) override { 49 TranslationUnitDecl *D = Context.getTranslationUnitDecl(); 50 51 if (FilterString.empty()) 52 return print(D); 53 54 TraverseDecl(D); 55 } 56 57 bool shouldWalkTypesOfTypeLocs() const { return false; } 58 59 bool TraverseDecl(Decl *D) { 60 if (D && filterMatches(D)) { 61 bool ShowColors = Out.has_colors(); 62 if (ShowColors) 63 Out.changeColor(raw_ostream::BLUE); 64 65 if (OutputFormat == ADOF_Default) 66 Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D) 67 << ":\n"; 68 69 if (ShowColors) 70 Out.resetColor(); 71 print(D); 72 Out << "\n"; 73 // Don't traverse child nodes to avoid output duplication. 74 return true; 75 } 76 return base::TraverseDecl(D); 77 } 78 79 private: 80 std::string getName(Decl *D) { 81 if (isa<NamedDecl>(D)) 82 return cast<NamedDecl>(D)->getQualifiedNameAsString(); 83 return ""; 84 } 85 bool filterMatches(Decl *D) { 86 return getName(D).find(FilterString) != std::string::npos; 87 } 88 void print(Decl *D) { 89 if (DumpLookups) { 90 if (DeclContext *DC = dyn_cast<DeclContext>(D)) { 91 if (DC == DC->getPrimaryContext()) 92 DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull); 93 else 94 Out << "Lookup map is in primary DeclContext " 95 << DC->getPrimaryContext() << "\n"; 96 } else 97 Out << "Not a DeclContext\n"; 98 } else if (OutputKind == Print) { 99 PrintingPolicy Policy(D->getASTContext().getLangOpts()); 100 D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true); 101 } else if (OutputKind != None) { 102 D->dump(Out, OutputKind == DumpFull, OutputFormat); 103 } 104 105 if (DumpDeclTypes) { 106 Decl *InnerD = D; 107 if (auto *TD = dyn_cast<TemplateDecl>(D)) 108 if (Decl *TempD = TD->getTemplatedDecl()) 109 InnerD = TempD; 110 111 // FIXME: Support OutputFormat in type dumping. 112 // FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups. 113 if (auto *VD = dyn_cast<ValueDecl>(InnerD)) 114 VD->getType().dump(Out, VD->getASTContext()); 115 if (auto *TD = dyn_cast<TypeDecl>(InnerD)) 116 TD->getTypeForDecl()->dump(Out, TD->getASTContext()); 117 } 118 } 119 120 raw_ostream &Out; 121 std::unique_ptr<raw_ostream> OwnedOut; 122 123 /// How to output individual declarations. 124 Kind OutputKind; 125 126 /// What format should the output take? 127 ASTDumpOutputFormat OutputFormat; 128 129 /// Which declarations or DeclContexts to display. 130 std::string FilterString; 131 132 /// Whether the primary output is lookup results or declarations. Individual 133 /// results will be output with a format determined by OutputKind. This is 134 /// incompatible with OutputKind == Print. 135 bool DumpLookups; 136 137 /// Whether to dump the type for each declaration dumped. 138 bool DumpDeclTypes; 139 }; 140 141 class ASTDeclNodeLister : public ASTConsumer, 142 public RecursiveASTVisitor<ASTDeclNodeLister> { 143 public: 144 ASTDeclNodeLister(raw_ostream *Out = nullptr) 145 : Out(Out ? *Out : llvm::outs()) {} 146 147 void HandleTranslationUnit(ASTContext &Context) override { 148 TraverseDecl(Context.getTranslationUnitDecl()); 149 } 150 151 bool shouldWalkTypesOfTypeLocs() const { return false; } 152 153 bool VisitNamedDecl(NamedDecl *D) { 154 D->printQualifiedName(Out); 155 Out << '\n'; 156 return true; 157 } 158 159 private: 160 raw_ostream &Out; 161 }; 162 } // end anonymous namespace 163 164 std::unique_ptr<ASTConsumer> 165 clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out, 166 StringRef FilterString) { 167 return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print, 168 ADOF_Default, FilterString); 169 } 170 171 std::unique_ptr<ASTConsumer> 172 clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString, 173 bool DumpDecls, bool Deserialize, bool DumpLookups, 174 bool DumpDeclTypes, ASTDumpOutputFormat Format) { 175 assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); 176 return std::make_unique<ASTPrinter>( 177 std::move(Out), 178 Deserialize ? ASTPrinter::DumpFull 179 : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None, 180 Format, FilterString, DumpLookups, DumpDeclTypes); 181 } 182 183 std::unique_ptr<ASTConsumer> 184 clang::CreateASTDumper(raw_ostream &Out, StringRef FilterString, bool DumpDecls, 185 bool Deserialize, bool DumpLookups, bool DumpDeclTypes, 186 ASTDumpOutputFormat Format) { 187 assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); 188 return std::make_unique<ASTPrinter>(Out, 189 Deserialize ? ASTPrinter::DumpFull 190 : DumpDecls ? ASTPrinter::Dump 191 : ASTPrinter::None, 192 Format, FilterString, DumpLookups, 193 DumpDeclTypes); 194 } 195 196 std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() { 197 return std::make_unique<ASTDeclNodeLister>(nullptr); 198 } 199 200 //===----------------------------------------------------------------------===// 201 /// ASTViewer - AST Visualization 202 203 namespace { 204 class ASTViewer : public ASTConsumer { 205 ASTContext *Context = nullptr; 206 207 public: 208 void Initialize(ASTContext &Context) override { this->Context = &Context; } 209 210 bool HandleTopLevelDecl(DeclGroupRef D) override { 211 for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) 212 HandleTopLevelSingleDecl(*I); 213 return true; 214 } 215 216 void HandleTopLevelSingleDecl(Decl *D); 217 }; 218 } 219 220 void ASTViewer::HandleTopLevelSingleDecl(Decl *D) { 221 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 222 D->print(llvm::errs()); 223 224 if (Stmt *Body = D->getBody()) { 225 llvm::errs() << '\n'; 226 Body->viewAST(); 227 llvm::errs() << '\n'; 228 } 229 } 230 } 231 232 std::unique_ptr<ASTConsumer> clang::CreateASTViewer() { 233 return std::make_unique<ASTViewer>(); 234 } 235