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