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