1 //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// 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 // This file implements the AST dump methods, which dump out the 10 // AST in a form that exposes type details and other fields. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/AST/ASTContext.h" 15 #include "clang/AST/ASTNodeTraverser.h" 16 #include "clang/AST/DeclLookups.h" 17 #include "clang/AST/TextNodeDumper.h" 18 #include "clang/Basic/Builtins.h" 19 #include "clang/Basic/Module.h" 20 #include "clang/Basic/SourceManager.h" 21 #include "llvm/Support/raw_ostream.h" 22 using namespace clang; 23 using namespace clang::comments; 24 25 //===----------------------------------------------------------------------===// 26 // ASTDumper Visitor 27 //===----------------------------------------------------------------------===// 28 29 namespace { 30 31 class ASTDumper : public ASTNodeTraverser<ASTDumper, TextNodeDumper> { 32 33 TextNodeDumper NodeDumper; 34 35 raw_ostream &OS; 36 37 const bool ShowColors; 38 39 public: 40 ASTDumper(raw_ostream &OS, const CommandTraits *Traits, 41 const SourceManager *SM) 42 : ASTDumper(OS, Traits, SM, SM && SM->getDiagnostics().getShowColors()) {} 43 44 ASTDumper(raw_ostream &OS, const CommandTraits *Traits, 45 const SourceManager *SM, bool ShowColors) 46 : ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {} 47 ASTDumper(raw_ostream &OS, const CommandTraits *Traits, 48 const SourceManager *SM, bool ShowColors, 49 const PrintingPolicy &PrintPolicy) 50 : NodeDumper(OS, ShowColors, SM, PrintPolicy, Traits), OS(OS), 51 ShowColors(ShowColors) {} 52 53 TextNodeDumper &doGetNodeDelegate() { return NodeDumper; } 54 55 void dumpLookups(const DeclContext *DC, bool DumpDecls); 56 57 template <typename SpecializationDecl> 58 void dumpTemplateDeclSpecialization(const SpecializationDecl *D, 59 bool DumpExplicitInst, bool DumpRefOnly); 60 template <typename TemplateDecl> 61 void dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); 62 63 void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); 64 void VisitClassTemplateDecl(const ClassTemplateDecl *D); 65 void VisitVarTemplateDecl(const VarTemplateDecl *D); 66 }; 67 } // namespace 68 69 void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { 70 NodeDumper.AddChild([=] { 71 OS << "StoredDeclsMap "; 72 NodeDumper.dumpBareDeclRef(cast<Decl>(DC)); 73 74 const DeclContext *Primary = DC->getPrimaryContext(); 75 if (Primary != DC) { 76 OS << " primary"; 77 NodeDumper.dumpPointer(cast<Decl>(Primary)); 78 } 79 80 bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); 81 82 auto Range = getDeserialize() 83 ? Primary->lookups() 84 : Primary->noload_lookups(/*PreserveInternalState=*/true); 85 for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { 86 DeclarationName Name = I.getLookupName(); 87 DeclContextLookupResult R = *I; 88 89 NodeDumper.AddChild([=] { 90 OS << "DeclarationName "; 91 { 92 ColorScope Color(OS, ShowColors, DeclNameColor); 93 OS << '\'' << Name << '\''; 94 } 95 96 for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); 97 RI != RE; ++RI) { 98 NodeDumper.AddChild([=] { 99 NodeDumper.dumpBareDeclRef(*RI); 100 101 if ((*RI)->isHidden()) 102 OS << " hidden"; 103 104 // If requested, dump the redecl chain for this lookup. 105 if (DumpDecls) { 106 // Dump earliest decl first. 107 std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { 108 if (Decl *Prev = D->getPreviousDecl()) 109 DumpWithPrev(Prev); 110 Visit(D); 111 }; 112 DumpWithPrev(*RI); 113 } 114 }); 115 } 116 }); 117 } 118 119 if (HasUndeserializedLookups) { 120 NodeDumper.AddChild([=] { 121 ColorScope Color(OS, ShowColors, UndeserializedColor); 122 OS << "<undeserialized lookups>"; 123 }); 124 } 125 }); 126 } 127 128 template <typename SpecializationDecl> 129 void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, 130 bool DumpExplicitInst, 131 bool DumpRefOnly) { 132 bool DumpedAny = false; 133 for (const auto *RedeclWithBadType : D->redecls()) { 134 // FIXME: The redecls() range sometimes has elements of a less-specific 135 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives 136 // us TagDecls, and should give CXXRecordDecls). 137 auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); 138 if (!Redecl) { 139 // Found the injected-class-name for a class template. This will be dumped 140 // as part of its surrounding class so we don't need to dump it here. 141 assert(isa<CXXRecordDecl>(RedeclWithBadType) && 142 "expected an injected-class-name"); 143 continue; 144 } 145 146 switch (Redecl->getTemplateSpecializationKind()) { 147 case TSK_ExplicitInstantiationDeclaration: 148 case TSK_ExplicitInstantiationDefinition: 149 if (!DumpExplicitInst) 150 break; 151 LLVM_FALLTHROUGH; 152 case TSK_Undeclared: 153 case TSK_ImplicitInstantiation: 154 if (DumpRefOnly) 155 NodeDumper.dumpDeclRef(Redecl); 156 else 157 Visit(Redecl); 158 DumpedAny = true; 159 break; 160 case TSK_ExplicitSpecialization: 161 break; 162 } 163 } 164 165 // Ensure we dump at least one decl for each specialization. 166 if (!DumpedAny) 167 NodeDumper.dumpDeclRef(D); 168 } 169 170 template <typename TemplateDecl> 171 void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { 172 dumpTemplateParameters(D->getTemplateParameters()); 173 174 Visit(D->getTemplatedDecl()); 175 176 for (const auto *Child : D->specializations()) 177 dumpTemplateDeclSpecialization(Child, DumpExplicitInst, 178 !D->isCanonicalDecl()); 179 } 180 181 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { 182 // FIXME: We don't add a declaration of a function template specialization 183 // to its context when it's explicitly instantiated, so dump explicit 184 // instantiations when we dump the template itself. 185 dumpTemplateDecl(D, true); 186 } 187 188 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { 189 dumpTemplateDecl(D, false); 190 } 191 192 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { 193 dumpTemplateDecl(D, false); 194 } 195 196 //===----------------------------------------------------------------------===// 197 // Type method implementations 198 //===----------------------------------------------------------------------===// 199 200 void QualType::dump(const char *msg) const { 201 if (msg) 202 llvm::errs() << msg << ": "; 203 dump(); 204 } 205 206 LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); } 207 208 LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const { 209 ASTDumper Dumper(OS, nullptr, nullptr); 210 Dumper.Visit(*this); 211 } 212 213 LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); } 214 215 LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const { 216 QualType(this, 0).dump(OS); 217 } 218 219 //===----------------------------------------------------------------------===// 220 // Decl method implementations 221 //===----------------------------------------------------------------------===// 222 223 LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } 224 225 LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const { 226 const ASTContext &Ctx = getASTContext(); 227 const SourceManager &SM = Ctx.getSourceManager(); 228 ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, 229 SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); 230 P.setDeserialize(Deserialize); 231 P.Visit(this); 232 } 233 234 LLVM_DUMP_METHOD void Decl::dumpColor() const { 235 const ASTContext &Ctx = getASTContext(); 236 ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(), 237 &Ctx.getSourceManager(), /*ShowColors*/ true, 238 Ctx.getPrintingPolicy()); 239 P.Visit(this); 240 } 241 242 LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { 243 dumpLookups(llvm::errs()); 244 } 245 246 LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, 247 bool DumpDecls, 248 bool Deserialize) const { 249 const DeclContext *DC = this; 250 while (!DC->isTranslationUnit()) 251 DC = DC->getParent(); 252 ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); 253 const SourceManager &SM = Ctx.getSourceManager(); 254 ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(), 255 SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); 256 P.setDeserialize(Deserialize); 257 P.dumpLookups(this, DumpDecls); 258 } 259 260 //===----------------------------------------------------------------------===// 261 // Stmt method implementations 262 //===----------------------------------------------------------------------===// 263 264 LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const { 265 dump(llvm::errs(), SM); 266 } 267 268 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { 269 ASTDumper P(OS, nullptr, &SM); 270 P.Visit(this); 271 } 272 273 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const { 274 ASTDumper P(OS, nullptr, nullptr); 275 P.Visit(this); 276 } 277 278 LLVM_DUMP_METHOD void Stmt::dump() const { 279 ASTDumper P(llvm::errs(), nullptr, nullptr); 280 P.Visit(this); 281 } 282 283 LLVM_DUMP_METHOD void Stmt::dumpColor() const { 284 ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); 285 P.Visit(this); 286 } 287 288 //===----------------------------------------------------------------------===// 289 // Comment method implementations 290 //===----------------------------------------------------------------------===// 291 292 LLVM_DUMP_METHOD void Comment::dump() const { 293 dump(llvm::errs(), nullptr, nullptr); 294 } 295 296 LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const { 297 dump(llvm::errs(), &Context.getCommentCommandTraits(), 298 &Context.getSourceManager()); 299 } 300 301 void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, 302 const SourceManager *SM) const { 303 const FullComment *FC = dyn_cast<FullComment>(this); 304 if (!FC) 305 return; 306 ASTDumper D(OS, Traits, SM); 307 D.Visit(FC, FC); 308 } 309 310 LLVM_DUMP_METHOD void Comment::dumpColor() const { 311 const FullComment *FC = dyn_cast<FullComment>(this); 312 if (!FC) 313 return; 314 ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); 315 D.Visit(FC, FC); 316 } 317