397 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the AST dump methods, which dump out the10// 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 22using namespace clang;23using namespace clang::comments;24 25void 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 DeclContext33 // pointer to a Decl pointer would fail an assertion or otherwise fall prey34 // 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 about37 // 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 52void 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 111template <typename SpecializationDecl>112void 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-specific118 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives119 // us TagDecls, and should give CXXRecordDecls).120 auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);121 if (!Redecl)122 continue;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 else134 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 147template <typename TemplateDecl>148void 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 160void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {161 // FIXME: We don't add a declaration of a function template specialization162 // to its context when it's explicitly instantiated, so dump explicit163 // instantiations when we dump the template itself.164 dumpTemplateDecl(D, true);165}166 167void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {168 dumpTemplateDecl(D, false);169}170 171void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {172 dumpTemplateDecl(D, false);173}174 175//===----------------------------------------------------------------------===//176// Type method implementations177//===----------------------------------------------------------------------===//178 179void QualType::dump(const char *msg) const {180 if (msg)181 llvm::errs() << msg << ": ";182 dump();183}184 185LLVM_DUMP_METHOD void QualType::dump() const {186 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);187 Dumper.Visit(*this);188}189 190LLVM_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 196LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }197 198LLVM_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// TypeLoc method implementations205//===----------------------------------------------------------------------===//206 207LLVM_DUMP_METHOD void TypeLoc::dump() const {208 ASTDumper(llvm::errs(), /*ShowColors=*/false).Visit(*this);209}210 211LLVM_DUMP_METHOD void TypeLoc::dump(llvm::raw_ostream &OS,212 const ASTContext &Context) const {213 ASTDumper(OS, Context, Context.getDiagnostics().getShowColors()).Visit(*this);214}215 216//===----------------------------------------------------------------------===//217// Decl method implementations218//===----------------------------------------------------------------------===//219 220LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }221 222LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,223 ASTDumpOutputFormat Format) const {224 ASTContext &Ctx = getASTContext();225 const SourceManager &SM = Ctx.getSourceManager();226 227 if (ADOF_JSON == Format) {228 JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),229 &Ctx.getCommentCommandTraits());230 (void)Deserialize; // FIXME?231 P.Visit(this);232 } else {233 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());234 P.setDeserialize(Deserialize);235 P.Visit(this);236 }237}238 239LLVM_DUMP_METHOD void Decl::dumpColor() const {240 const ASTContext &Ctx = getASTContext();241 ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true);242 P.Visit(this);243}244 245LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {246 dumpAsDecl(nullptr);247}248 249LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {250 // By design, DeclContext is required to be a base class of some class that251 // derives from Decl. Thus, it should always be possible to dyn_cast() from252 // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext()253 // asserts that to be the case. Since this function is intended for use in a254 // debugger, it performs an additional check in order to prevent a failed255 // cast and assertion. If that check fails, then the (invalid) DeclContext256 // is dumped with an indication of its invalidity.257 if (hasValidDeclKind()) {258 const auto *D = cast<Decl>(this);259 D->dump();260 } else {261 // If an ASTContext is not available, a less capable ASTDumper is262 // constructed for which color diagnostics are, regrettably, disabled.263 ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx,264 Ctx->getDiagnostics().getShowColors())265 : ASTDumper(llvm::errs(), /*ShowColors*/ false);266 P.dumpInvalidDeclContext(this);267 }268}269 270LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {271 dumpLookups(llvm::errs());272}273 274LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,275 bool DumpDecls,276 bool Deserialize) const {277 const DeclContext *DC = this;278 while (!DC->isTranslationUnit())279 DC = DC->getParent();280 const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();281 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());282 P.setDeserialize(Deserialize);283 P.dumpLookups(this, DumpDecls);284}285 286//===----------------------------------------------------------------------===//287// Stmt method implementations288//===----------------------------------------------------------------------===//289 290LLVM_DUMP_METHOD void Stmt::dump() const {291 ASTDumper P(llvm::errs(), /*ShowColors=*/false);292 P.Visit(this);293}294 295LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS,296 const ASTContext &Context) const {297 ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors());298 P.Visit(this);299}300 301LLVM_DUMP_METHOD void Stmt::dumpColor() const {302 ASTDumper P(llvm::errs(), /*ShowColors=*/true);303 P.Visit(this);304}305 306//===----------------------------------------------------------------------===//307// Comment method implementations308//===----------------------------------------------------------------------===//309 310LLVM_DUMP_METHOD void Comment::dump() const {311 const auto *FC = dyn_cast<FullComment>(this);312 if (!FC)313 return;314 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);315 Dumper.Visit(FC, FC);316}317 318LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS,319 const ASTContext &Context) const {320 const auto *FC = dyn_cast<FullComment>(this);321 if (!FC)322 return;323 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());324 Dumper.Visit(FC, FC);325}326 327LLVM_DUMP_METHOD void Comment::dumpColor() const {328 const auto *FC = dyn_cast<FullComment>(this);329 if (!FC)330 return;331 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true);332 Dumper.Visit(FC, FC);333}334 335//===----------------------------------------------------------------------===//336// APValue method implementations337//===----------------------------------------------------------------------===//338 339LLVM_DUMP_METHOD void APValue::dump() const {340 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);341 Dumper.Visit(*this, /*Ty=*/QualType());342}343 344LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS,345 const ASTContext &Context) const {346 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());347 Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy));348}349 350//===----------------------------------------------------------------------===//351// ConceptReference method implementations352//===----------------------------------------------------------------------===//353 354LLVM_DUMP_METHOD void ConceptReference::dump() const {355 dump(llvm::errs());356}357 358LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const {359 auto &Ctx = getNamedConcept()->getASTContext();360 ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());361 P.Visit(this);362}363 364//===----------------------------------------------------------------------===//365// TemplateName method implementations366//===----------------------------------------------------------------------===//367 368// FIXME: These are actually using the TemplateArgument dumper, through369// an implicit conversion. The dump will claim this is a template argument,370// which is misleading.371 372LLVM_DUMP_METHOD void TemplateName::dump() const {373 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);374 Dumper.Visit(*this);375}376 377LLVM_DUMP_METHOD void TemplateName::dump(llvm::raw_ostream &OS,378 const ASTContext &Context) const {379 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());380 Dumper.Visit(*this);381}382 383//===----------------------------------------------------------------------===//384// TemplateArgument method implementations385//===----------------------------------------------------------------------===//386 387LLVM_DUMP_METHOD void TemplateArgument::dump() const {388 ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);389 Dumper.Visit(*this);390}391 392LLVM_DUMP_METHOD void TemplateArgument::dump(llvm::raw_ostream &OS,393 const ASTContext &Context) const {394 ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());395 Dumper.Visit(*this);396}397