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