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/ASTDumper.h" 15 #include "clang/AST/ASTConcept.h" 16 #include "clang/AST/ASTContext.h" 17 #include "clang/AST/DeclLookups.h" 18 #include "clang/AST/JSONNodeDumper.h" 19 #include "clang/Basic/SourceManager.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace clang; 23 using namespace clang::comments; 24 25 void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) { 26 NodeDumper.AddChild([=] { 27 if (!DC) { 28 ColorScope Color(OS, ShowColors, NullColor); 29 OS << "<<<NULL>>>"; 30 return; 31 } 32 // An invalid DeclContext is one for which a dyn_cast() from a DeclContext 33 // pointer to a Decl pointer would fail an assertion or otherwise fall prey 34 // to undefined behavior as a result of an invalid associated DeclKind. 35 // Such invalidity is not supposed to happen of course, but, when it does, 36 // the information provided below is intended to provide some hints about 37 // what might have gone awry. 38 { 39 ColorScope Color(OS, ShowColors, DeclKindNameColor); 40 OS << "DeclContext"; 41 } 42 NodeDumper.dumpPointer(DC); 43 OS << " <"; 44 { 45 ColorScope Color(OS, ShowColors, DeclNameColor); 46 OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind(); 47 } 48 OS << ">"; 49 }); 50 } 51 52 void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { 53 NodeDumper.AddChild([=] { 54 OS << "StoredDeclsMap "; 55 NodeDumper.dumpBareDeclRef(cast<Decl>(DC)); 56 57 const DeclContext *Primary = DC->getPrimaryContext(); 58 if (Primary != DC) { 59 OS << " primary"; 60 NodeDumper.dumpPointer(cast<Decl>(Primary)); 61 } 62 63 bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); 64 65 auto Range = getDeserialize() 66 ? Primary->lookups() 67 : Primary->noload_lookups(/*PreserveInternalState=*/true); 68 for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { 69 DeclarationName Name = I.getLookupName(); 70 DeclContextLookupResult R = *I; 71 72 NodeDumper.AddChild([=] { 73 OS << "DeclarationName "; 74 { 75 ColorScope Color(OS, ShowColors, DeclNameColor); 76 OS << '\'' << Name << '\''; 77 } 78 79 for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); 80 RI != RE; ++RI) { 81 NodeDumper.AddChild([=] { 82 NodeDumper.dumpBareDeclRef(*RI); 83 84 if (!(*RI)->isUnconditionallyVisible()) 85 OS << " hidden"; 86 87 // If requested, dump the redecl chain for this lookup. 88 if (DumpDecls) { 89 // Dump earliest decl first. 90 std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { 91 if (Decl *Prev = D->getPreviousDecl()) 92 DumpWithPrev(Prev); 93 Visit(D); 94 }; 95 DumpWithPrev(*RI); 96 } 97 }); 98 } 99 }); 100 } 101 102 if (HasUndeserializedLookups) { 103 NodeDumper.AddChild([=] { 104 ColorScope Color(OS, ShowColors, UndeserializedColor); 105 OS << "<undeserialized lookups>"; 106 }); 107 } 108 }); 109 } 110 111 template <typename SpecializationDecl> 112 void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, 113 bool DumpExplicitInst, 114 bool DumpRefOnly) { 115 bool DumpedAny = false; 116 for (const auto *RedeclWithBadType : D->redecls()) { 117 // FIXME: The redecls() range sometimes has elements of a less-specific 118 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives 119 // us TagDecls, and should give CXXRecordDecls). 120 auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType); 121 switch (Redecl->getTemplateSpecializationKind()) { 122 case TSK_ExplicitInstantiationDeclaration: 123 case TSK_ExplicitInstantiationDefinition: 124 if (!DumpExplicitInst) 125 break; 126 [[fallthrough]]; 127 case TSK_Undeclared: 128 case TSK_ImplicitInstantiation: 129 if (DumpRefOnly) 130 NodeDumper.dumpDeclRef(Redecl); 131 else 132 Visit(Redecl); 133 DumpedAny = true; 134 break; 135 case TSK_ExplicitSpecialization: 136 break; 137 } 138 } 139 140 // Ensure we dump at least one decl for each specialization. 141 if (!DumpedAny) 142 NodeDumper.dumpDeclRef(D); 143 } 144 145 template <typename TemplateDecl> 146 void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { 147 dumpTemplateParameters(D->getTemplateParameters()); 148 149 Visit(D->getTemplatedDecl()); 150 151 if (GetTraversalKind() == TK_AsIs) { 152 for (const auto *Child : D->specializations()) 153 dumpTemplateDeclSpecialization(Child, DumpExplicitInst, 154 !D->isCanonicalDecl()); 155 } 156 } 157 158 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { 159 // FIXME: We don't add a declaration of a function template specialization 160 // to its context when it's explicitly instantiated, so dump explicit 161 // instantiations when we dump the template itself. 162 dumpTemplateDecl(D, true); 163 } 164 165 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { 166 dumpTemplateDecl(D, false); 167 } 168 169 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { 170 dumpTemplateDecl(D, false); 171 } 172 173 //===----------------------------------------------------------------------===// 174 // Type method implementations 175 //===----------------------------------------------------------------------===// 176 177 void QualType::dump(const char *msg) const { 178 if (msg) 179 llvm::errs() << msg << ": "; 180 dump(); 181 } 182 183 LLVM_DUMP_METHOD void QualType::dump() const { 184 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); 185 Dumper.Visit(*this); 186 } 187 188 LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS, 189 const ASTContext &Context) const { 190 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); 191 Dumper.Visit(*this); 192 } 193 194 LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); } 195 196 LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS, 197 const ASTContext &Context) const { 198 QualType(this, 0).dump(OS, Context); 199 } 200 201 //===----------------------------------------------------------------------===// 202 // TypeLoc method implementations 203 //===----------------------------------------------------------------------===// 204 205 LLVM_DUMP_METHOD void TypeLoc::dump() const { 206 ASTDumper(llvm::errs(), /*ShowColors=*/false).Visit(*this); 207 } 208 209 LLVM_DUMP_METHOD void TypeLoc::dump(llvm::raw_ostream &OS, 210 const ASTContext &Context) const { 211 ASTDumper(OS, Context, Context.getDiagnostics().getShowColors()).Visit(*this); 212 } 213 214 //===----------------------------------------------------------------------===// 215 // Decl method implementations 216 //===----------------------------------------------------------------------===// 217 218 LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } 219 220 LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, 221 ASTDumpOutputFormat Format) const { 222 ASTContext &Ctx = getASTContext(); 223 const SourceManager &SM = Ctx.getSourceManager(); 224 225 if (ADOF_JSON == Format) { 226 JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(), 227 &Ctx.getCommentCommandTraits()); 228 (void)Deserialize; // FIXME? 229 P.Visit(this); 230 } else { 231 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); 232 P.setDeserialize(Deserialize); 233 P.Visit(this); 234 } 235 } 236 237 LLVM_DUMP_METHOD void Decl::dumpColor() const { 238 const ASTContext &Ctx = getASTContext(); 239 ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true); 240 P.Visit(this); 241 } 242 243 LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const { 244 dumpAsDecl(nullptr); 245 } 246 247 LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const { 248 // By design, DeclContext is required to be a base class of some class that 249 // derives from Decl. Thus, it should always be possible to dyn_cast() from 250 // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext() 251 // asserts that to be the case. Since this function is intended for use in a 252 // debugger, it performs an additional check in order to prevent a failed 253 // cast and assertion. If that check fails, then the (invalid) DeclContext 254 // is dumped with an indication of its invalidity. 255 if (hasValidDeclKind()) { 256 const auto *D = cast<Decl>(this); 257 D->dump(); 258 } else { 259 // If an ASTContext is not available, a less capable ASTDumper is 260 // constructed for which color diagnostics are, regrettably, disabled. 261 ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx, 262 Ctx->getDiagnostics().getShowColors()) 263 : ASTDumper(llvm::errs(), /*ShowColors*/ false); 264 P.dumpInvalidDeclContext(this); 265 } 266 } 267 268 LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { 269 dumpLookups(llvm::errs()); 270 } 271 272 LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, 273 bool DumpDecls, 274 bool Deserialize) const { 275 const DeclContext *DC = this; 276 while (!DC->isTranslationUnit()) 277 DC = DC->getParent(); 278 const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); 279 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); 280 P.setDeserialize(Deserialize); 281 P.dumpLookups(this, DumpDecls); 282 } 283 284 //===----------------------------------------------------------------------===// 285 // Stmt method implementations 286 //===----------------------------------------------------------------------===// 287 288 LLVM_DUMP_METHOD void Stmt::dump() const { 289 ASTDumper P(llvm::errs(), /*ShowColors=*/false); 290 P.Visit(this); 291 } 292 293 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, 294 const ASTContext &Context) const { 295 ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors()); 296 P.Visit(this); 297 } 298 299 LLVM_DUMP_METHOD void Stmt::dumpColor() const { 300 ASTDumper P(llvm::errs(), /*ShowColors=*/true); 301 P.Visit(this); 302 } 303 304 //===----------------------------------------------------------------------===// 305 // Comment method implementations 306 //===----------------------------------------------------------------------===// 307 308 LLVM_DUMP_METHOD void Comment::dump() const { 309 const auto *FC = dyn_cast<FullComment>(this); 310 if (!FC) 311 return; 312 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); 313 Dumper.Visit(FC, FC); 314 } 315 316 LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS, 317 const ASTContext &Context) const { 318 const auto *FC = dyn_cast<FullComment>(this); 319 if (!FC) 320 return; 321 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); 322 Dumper.Visit(FC, FC); 323 } 324 325 LLVM_DUMP_METHOD void Comment::dumpColor() const { 326 const auto *FC = dyn_cast<FullComment>(this); 327 if (!FC) 328 return; 329 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true); 330 Dumper.Visit(FC, FC); 331 } 332 333 //===----------------------------------------------------------------------===// 334 // APValue method implementations 335 //===----------------------------------------------------------------------===// 336 337 LLVM_DUMP_METHOD void APValue::dump() const { 338 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); 339 Dumper.Visit(*this, /*Ty=*/QualType()); 340 } 341 342 LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS, 343 const ASTContext &Context) const { 344 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); 345 Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy)); 346 } 347 348 //===----------------------------------------------------------------------===// 349 // ConceptReference method implementations 350 //===----------------------------------------------------------------------===// 351 352 LLVM_DUMP_METHOD void ConceptReference::dump() const { 353 dump(llvm::errs()); 354 } 355 356 LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const { 357 auto &Ctx = getNamedConcept()->getASTContext(); 358 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); 359 P.Visit(this); 360 } 361 362 //===----------------------------------------------------------------------===// 363 // TemplateName method implementations 364 //===----------------------------------------------------------------------===// 365 366 // FIXME: These are actually using the TemplateArgument dumper, through 367 // an implicit conversion. The dump will claim this is a template argument, 368 // which is misleading. 369 370 LLVM_DUMP_METHOD void TemplateName::dump() const { 371 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); 372 Dumper.Visit(*this); 373 } 374 375 LLVM_DUMP_METHOD void TemplateName::dump(llvm::raw_ostream &OS, 376 const ASTContext &Context) const { 377 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); 378 Dumper.Visit(*this); 379 } 380 381 //===----------------------------------------------------------------------===// 382 // TemplateArgument method implementations 383 //===----------------------------------------------------------------------===// 384 385 LLVM_DUMP_METHOD void TemplateArgument::dump() const { 386 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); 387 Dumper.Visit(*this); 388 } 389 390 LLVM_DUMP_METHOD void TemplateArgument::dump(llvm::raw_ostream &OS, 391 const ASTContext &Context) const { 392 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); 393 Dumper.Visit(*this); 394 } 395