]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file defines the Decl::dumpXML() method, a debugging tool to | |
11 | // print a detailed graph of an AST in an unspecified XML format. | |
12 | // | |
13 | // There is no guarantee of stability for this format. | |
14 | // | |
15 | //===----------------------------------------------------------------------===// | |
16 | ||
17 | // Only pay for this in code size in assertions-enabled builds. | |
18 | ||
19 | #include "clang/AST/ASTContext.h" | |
20 | #include "clang/AST/Decl.h" | |
21 | #include "clang/AST/DeclCXX.h" | |
22 | #include "clang/AST/DeclFriend.h" | |
23 | #include "clang/AST/DeclObjC.h" | |
24 | #include "clang/AST/DeclTemplate.h" | |
25 | #include "clang/AST/DeclVisitor.h" | |
26 | #include "clang/AST/Expr.h" | |
27 | #include "clang/AST/ExprCXX.h" | |
28 | #include "clang/AST/ExprObjC.h" | |
29 | #include "clang/AST/NestedNameSpecifier.h" | |
30 | #include "clang/AST/Stmt.h" | |
31 | #include "clang/AST/StmtCXX.h" | |
32 | #include "clang/AST/StmtObjC.h" | |
33 | #include "clang/AST/StmtVisitor.h" | |
34 | #include "clang/AST/TemplateBase.h" | |
35 | #include "clang/AST/TemplateName.h" | |
36 | #include "clang/AST/Type.h" | |
37 | #include "clang/AST/TypeLoc.h" | |
38 | #include "clang/AST/TypeLocVisitor.h" | |
39 | #include "clang/AST/TypeVisitor.h" | |
40 | #include "clang/AST/Expr.h" | |
41 | #include "clang/AST/ExprCXX.h" | |
42 | #include "llvm/ADT/SmallString.h" | |
43 | ||
44 | using namespace clang; | |
45 | ||
46 | #ifndef NDEBUG | |
47 | ||
48 | namespace { | |
49 | ||
50 | enum NodeState { | |
51 | NS_Attrs, NS_LazyChildren, NS_Children | |
52 | }; | |
53 | ||
54 | struct Node { | |
55 | StringRef Name; | |
56 | NodeState State; | |
57 | Node(StringRef name) : Name(name), State(NS_Attrs) {} | |
58 | ||
59 | bool isDoneWithAttrs() const { return State != NS_Attrs; } | |
60 | }; | |
61 | ||
62 | template <class Impl> struct XMLDeclVisitor { | |
63 | #define DISPATCH(NAME, CLASS) \ | |
64 | static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) | |
65 | ||
66 | void dispatch(Decl *D) { | |
67 | switch (D->getKind()) { | |
68 | #define DECL(DERIVED, BASE) \ | |
69 | case Decl::DERIVED: \ | |
70 | DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \ | |
71 | static_cast<Impl*>(this)->completeAttrs(); \ | |
72 | DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \ | |
73 | DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \ | |
74 | break; | |
75 | #define ABSTRACT_DECL(DECL) | |
76 | #include "clang/AST/DeclNodes.inc" | |
77 | } | |
78 | } | |
79 | ||
80 | #define DECL(DERIVED, BASE) \ | |
81 | void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \ | |
82 | DISPATCH(dispatch##BASE##Attrs, BASE); \ | |
83 | DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \ | |
84 | } \ | |
85 | void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \ | |
86 | void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \ | |
87 | DISPATCH(dispatch##BASE##Children, BASE); \ | |
88 | DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \ | |
89 | } \ | |
90 | void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \ | |
91 | void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \ | |
92 | DISPATCH(dispatch##BASE##AsContext, BASE); \ | |
93 | DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \ | |
94 | } \ | |
95 | void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {} | |
96 | #include "clang/AST/DeclNodes.inc" | |
97 | ||
98 | void dispatchDeclAttrs(Decl *D) { | |
99 | DISPATCH(visitDeclAttrs, Decl); | |
100 | } | |
101 | void visitDeclAttrs(Decl *D) {} | |
102 | ||
103 | void dispatchDeclChildren(Decl *D) { | |
104 | DISPATCH(visitDeclChildren, Decl); | |
105 | } | |
106 | void visitDeclChildren(Decl *D) {} | |
107 | ||
108 | void dispatchDeclAsContext(Decl *D) { | |
109 | DISPATCH(visitDeclAsContext, Decl); | |
110 | } | |
111 | void visitDeclAsContext(Decl *D) {} | |
112 | ||
113 | #undef DISPATCH | |
114 | }; | |
115 | ||
116 | template <class Impl> struct XMLTypeVisitor { | |
117 | #define DISPATCH(NAME, CLASS) \ | |
118 | static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T)) | |
119 | ||
120 | void dispatch(Type *T) { | |
121 | switch (T->getTypeClass()) { | |
122 | #define TYPE(DERIVED, BASE) \ | |
123 | case Type::DERIVED: \ | |
124 | DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \ | |
125 | static_cast<Impl*>(this)->completeAttrs(); \ | |
126 | DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \ | |
127 | break; | |
128 | #define ABSTRACT_TYPE(DERIVED, BASE) | |
129 | #include "clang/AST/TypeNodes.def" | |
130 | } | |
131 | } | |
132 | ||
133 | #define TYPE(DERIVED, BASE) \ | |
134 | void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \ | |
135 | DISPATCH(dispatch##BASE##Attrs, BASE); \ | |
136 | DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \ | |
137 | } \ | |
138 | void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \ | |
139 | void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \ | |
140 | DISPATCH(dispatch##BASE##Children, BASE); \ | |
141 | DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \ | |
142 | } \ | |
143 | void visit##DERIVED##TypeChildren(DERIVED##Type *T) {} | |
144 | #include "clang/AST/TypeNodes.def" | |
145 | ||
146 | void dispatchTypeAttrs(Type *T) { | |
147 | DISPATCH(visitTypeAttrs, Type); | |
148 | } | |
149 | void visitTypeAttrs(Type *T) {} | |
150 | ||
151 | void dispatchTypeChildren(Type *T) { | |
152 | DISPATCH(visitTypeChildren, Type); | |
153 | } | |
154 | void visitTypeChildren(Type *T) {} | |
155 | ||
156 | #undef DISPATCH | |
157 | }; | |
158 | ||
159 | static StringRef getTypeKindName(Type *T) { | |
160 | switch (T->getTypeClass()) { | |
161 | #define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; | |
162 | #define ABSTRACT_TYPE(DERIVED, BASE) | |
163 | #include "clang/AST/TypeNodes.def" | |
164 | } | |
165 | ||
166 | llvm_unreachable("unknown type kind!"); | |
167 | } | |
168 | ||
169 | struct XMLDumper : public XMLDeclVisitor<XMLDumper>, | |
170 | public XMLTypeVisitor<XMLDumper> { | |
171 | raw_ostream &out; | |
172 | ASTContext &Context; | |
173 | SmallVector<Node, 16> Stack; | |
174 | unsigned Indent; | |
175 | explicit XMLDumper(raw_ostream &OS, ASTContext &context) | |
176 | : out(OS), Context(context), Indent(0) {} | |
177 | ||
178 | void indent() { | |
179 | for (unsigned I = Indent; I; --I) | |
180 | out << ' '; | |
181 | } | |
182 | ||
183 | /// Push a new node on the stack. | |
184 | void push(StringRef name) { | |
185 | if (!Stack.empty()) { | |
186 | assert(Stack.back().isDoneWithAttrs()); | |
187 | if (Stack.back().State == NS_LazyChildren) { | |
188 | Stack.back().State = NS_Children; | |
189 | out << ">\n"; | |
190 | } | |
191 | Indent++; | |
192 | indent(); | |
193 | } | |
194 | Stack.push_back(Node(name)); | |
195 | out << '<' << name; | |
196 | } | |
197 | ||
198 | /// Set the given attribute to the given value. | |
199 | void set(StringRef attr, StringRef value) { | |
200 | assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); | |
201 | out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation | |
202 | } | |
203 | ||
204 | /// Finish attributes. | |
205 | void completeAttrs() { | |
206 | assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); | |
207 | Stack.back().State = NS_LazyChildren; | |
208 | } | |
209 | ||
210 | /// Pop a node. | |
211 | void pop() { | |
212 | assert(!Stack.empty() && Stack.back().isDoneWithAttrs()); | |
213 | if (Stack.back().State == NS_LazyChildren) { | |
214 | out << "/>\n"; | |
215 | } else { | |
216 | indent(); | |
217 | out << "</" << Stack.back().Name << ">\n"; | |
218 | } | |
219 | if (Stack.size() > 1) Indent--; | |
220 | Stack.pop_back(); | |
221 | } | |
222 | ||
223 | //---- General utilities -------------------------------------------// | |
224 | ||
225 | void setPointer(StringRef prop, const void *p) { | |
226 | SmallString<10> buffer; | |
227 | llvm::raw_svector_ostream os(buffer); | |
228 | os << p; | |
229 | os.flush(); | |
230 | set(prop, buffer); | |
231 | } | |
232 | ||
233 | void setPointer(void *p) { | |
234 | setPointer("ptr", p); | |
235 | } | |
236 | ||
237 | void setInteger(StringRef prop, const llvm::APSInt &v) { | |
238 | set(prop, v.toString(10)); | |
239 | } | |
240 | ||
241 | void setInteger(StringRef prop, unsigned n) { | |
242 | SmallString<10> buffer; | |
243 | llvm::raw_svector_ostream os(buffer); | |
244 | os << n; | |
245 | os.flush(); | |
246 | set(prop, buffer); | |
247 | } | |
248 | ||
249 | void setFlag(StringRef prop, bool flag) { | |
250 | if (flag) set(prop, "true"); | |
251 | } | |
252 | ||
253 | void setName(DeclarationName Name) { | |
254 | if (!Name) | |
255 | return set("name", ""); | |
256 | ||
257 | // Common case. | |
258 | if (Name.isIdentifier()) | |
259 | return set("name", Name.getAsIdentifierInfo()->getName()); | |
260 | ||
261 | set("name", Name.getAsString()); | |
262 | } | |
263 | ||
264 | class TemporaryContainer { | |
265 | XMLDumper &Dumper; | |
266 | public: | |
267 | TemporaryContainer(XMLDumper &dumper, StringRef name) | |
268 | : Dumper(dumper) { | |
269 | Dumper.push(name); | |
270 | Dumper.completeAttrs(); | |
271 | } | |
272 | ||
273 | ~TemporaryContainer() { | |
274 | Dumper.pop(); | |
275 | } | |
276 | }; | |
277 | ||
278 | void visitTemplateParameters(TemplateParameterList *L) { | |
279 | push("template_parameters"); | |
280 | completeAttrs(); | |
281 | for (TemplateParameterList::iterator | |
282 | I = L->begin(), E = L->end(); I != E; ++I) | |
283 | dispatch(*I); | |
284 | pop(); | |
285 | } | |
286 | ||
287 | void visitTemplateArguments(const TemplateArgumentList &L) { | |
288 | push("template_arguments"); | |
289 | completeAttrs(); | |
290 | for (unsigned I = 0, E = L.size(); I != E; ++I) | |
291 | dispatch(L[I]); | |
292 | pop(); | |
293 | } | |
294 | ||
295 | /// Visits a reference to the given declaration. | |
296 | void visitDeclRef(Decl *D) { | |
297 | push(D->getDeclKindName()); | |
298 | setPointer("ref", D); | |
299 | completeAttrs(); | |
300 | pop(); | |
301 | } | |
302 | void visitDeclRef(StringRef Name, Decl *D) { | |
303 | TemporaryContainer C(*this, Name); | |
304 | if (D) visitDeclRef(D); | |
305 | } | |
306 | ||
307 | void dispatch(const TemplateArgument &A) { | |
308 | switch (A.getKind()) { | |
309 | case TemplateArgument::Null: { | |
310 | TemporaryContainer C(*this, "null"); | |
311 | break; | |
312 | } | |
313 | case TemplateArgument::Type: { | |
314 | dispatch(A.getAsType()); | |
315 | break; | |
316 | } | |
317 | case TemplateArgument::Template: | |
318 | case TemplateArgument::TemplateExpansion: | |
319 | case TemplateArgument::NullPtr: | |
320 | // FIXME: Implement! | |
321 | break; | |
322 | ||
323 | case TemplateArgument::Declaration: { | |
324 | visitDeclRef(A.getAsDecl()); | |
325 | break; | |
326 | } | |
327 | case TemplateArgument::Integral: { | |
328 | push("integer"); | |
329 | setInteger("value", A.getAsIntegral()); | |
330 | completeAttrs(); | |
331 | pop(); | |
332 | break; | |
333 | } | |
334 | case TemplateArgument::Expression: { | |
335 | dispatch(A.getAsExpr()); | |
336 | break; | |
337 | } | |
338 | case TemplateArgument::Pack: { | |
339 | for (TemplateArgument::pack_iterator P = A.pack_begin(), | |
340 | PEnd = A.pack_end(); | |
341 | P != PEnd; ++P) | |
342 | dispatch(*P); | |
343 | break; | |
344 | } | |
345 | } | |
346 | } | |
347 | ||
348 | void dispatch(const TemplateArgumentLoc &A) { | |
349 | dispatch(A.getArgument()); | |
350 | } | |
351 | ||
352 | //---- Declarations ------------------------------------------------// | |
353 | // Calls are made in this order: | |
354 | // # Enter a new node. | |
355 | // push("FieldDecl") | |
356 | // | |
357 | // # In this phase, attributes are set on the node. | |
358 | // visitDeclAttrs(D) | |
359 | // visitNamedDeclAttrs(D) | |
360 | // ... | |
361 | // visitFieldDeclAttrs(D) | |
362 | // | |
363 | // # No more attributes after this point. | |
364 | // completeAttrs() | |
365 | // | |
366 | // # Create "header" child nodes, i.e. those which logically | |
367 | // # belong to the declaration itself. | |
368 | // visitDeclChildren(D) | |
369 | // visitNamedDeclChildren(D) | |
370 | // ... | |
371 | // visitFieldDeclChildren(D) | |
372 | // | |
373 | // # Create nodes for the lexical children. | |
374 | // visitDeclAsContext(D) | |
375 | // visitNamedDeclAsContext(D) | |
376 | // ... | |
377 | // visitFieldDeclAsContext(D) | |
378 | // | |
379 | // # Finish the node. | |
380 | // pop(); | |
381 | void dispatch(Decl *D) { | |
382 | push(D->getDeclKindName()); | |
383 | XMLDeclVisitor<XMLDumper>::dispatch(D); | |
384 | pop(); | |
385 | } | |
386 | void visitDeclAttrs(Decl *D) { | |
387 | setPointer(D); | |
388 | } | |
389 | ||
390 | /// Visit all the lexical decls in the given context. | |
391 | void visitDeclContext(DeclContext *DC) { | |
392 | for (DeclContext::decl_iterator | |
393 | I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) | |
394 | dispatch(*I); | |
395 | ||
396 | // FIXME: point out visible declarations not in lexical context? | |
397 | } | |
398 | ||
399 | /// Set the "access" attribute on the current node according to the | |
400 | /// given specifier. | |
401 | void setAccess(AccessSpecifier AS) { | |
402 | switch (AS) { | |
403 | case AS_public: return set("access", "public"); | |
404 | case AS_protected: return set("access", "protected"); | |
405 | case AS_private: return set("access", "private"); | |
406 | case AS_none: llvm_unreachable("explicit forbidden access"); | |
407 | } | |
408 | } | |
409 | ||
410 | template <class T> void visitRedeclarableAttrs(T *D) { | |
411 | if (T *Prev = D->getPreviousDecl()) | |
412 | setPointer("previous", Prev); | |
413 | } | |
414 | ||
415 | ||
416 | // TranslationUnitDecl | |
417 | void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { | |
418 | visitDeclContext(D); | |
419 | } | |
420 | ||
421 | // LinkageSpecDecl | |
422 | void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { | |
423 | StringRef lang = ""; | |
424 | switch (D->getLanguage()) { | |
425 | case LinkageSpecDecl::lang_c: lang = "C"; break; | |
426 | case LinkageSpecDecl::lang_cxx: lang = "C++"; break; | |
427 | } | |
428 | set("lang", lang); | |
429 | } | |
430 | void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) { | |
431 | visitDeclContext(D); | |
432 | } | |
433 | ||
434 | // NamespaceDecl | |
435 | void visitNamespaceDeclAttrs(NamespaceDecl *D) { | |
436 | setFlag("inline", D->isInline()); | |
437 | if (!D->isOriginalNamespace()) | |
438 | setPointer("original", D->getOriginalNamespace()); | |
439 | } | |
440 | void visitNamespaceDeclAsContext(NamespaceDecl *D) { | |
441 | visitDeclContext(D); | |
442 | } | |
443 | ||
444 | // NamedDecl | |
445 | void visitNamedDeclAttrs(NamedDecl *D) { | |
446 | setName(D->getDeclName()); | |
447 | } | |
448 | ||
449 | // ValueDecl | |
450 | void visitValueDeclChildren(ValueDecl *D) { | |
451 | dispatch(D->getType()); | |
452 | } | |
453 | ||
454 | // DeclaratorDecl | |
455 | void visitDeclaratorDeclChildren(DeclaratorDecl *D) { | |
456 | //dispatch(D->getTypeSourceInfo()->getTypeLoc()); | |
457 | } | |
458 | ||
459 | // VarDecl | |
460 | void visitVarDeclAttrs(VarDecl *D) { | |
461 | visitRedeclarableAttrs(D); | |
462 | if (D->getStorageClass() != SC_None) | |
463 | set("storage", | |
464 | VarDecl::getStorageClassSpecifierString(D->getStorageClass())); | |
465 | StringRef initStyle = ""; | |
466 | switch (D->getInitStyle()) { | |
467 | case VarDecl::CInit: initStyle = "c"; break; | |
468 | case VarDecl::CallInit: initStyle = "call"; break; | |
469 | case VarDecl::ListInit: initStyle = "list"; break; | |
470 | } | |
471 | set("initstyle", initStyle); | |
472 | setFlag("nrvo", D->isNRVOVariable()); | |
473 | // TODO: instantiation, etc. | |
474 | } | |
475 | void visitVarDeclChildren(VarDecl *D) { | |
476 | if (D->hasInit()) dispatch(D->getInit()); | |
477 | } | |
478 | ||
479 | // ParmVarDecl? | |
480 | ||
481 | // FunctionDecl | |
482 | void visitFunctionDeclAttrs(FunctionDecl *D) { | |
483 | visitRedeclarableAttrs(D); | |
484 | setFlag("pure", D->isPure()); | |
485 | setFlag("trivial", D->isTrivial()); | |
486 | setFlag("returnzero", D->hasImplicitReturnZero()); | |
487 | setFlag("prototype", D->hasWrittenPrototype()); | |
488 | setFlag("deleted", D->isDeletedAsWritten()); | |
489 | if (D->getStorageClass() != SC_None) | |
490 | set("storage", | |
491 | VarDecl::getStorageClassSpecifierString(D->getStorageClass())); | |
492 | setFlag("inline", D->isInlineSpecified()); | |
493 | if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) | |
494 | set("asmlabel", ALA->getLabel()); | |
495 | // TODO: instantiation, etc. | |
496 | } | |
497 | void visitFunctionDeclChildren(FunctionDecl *D) { | |
498 | for (FunctionDecl::param_iterator | |
499 | I = D->param_begin(), E = D->param_end(); I != E; ++I) | |
500 | dispatch(*I); | |
501 | for (llvm::ArrayRef<NamedDecl*>::iterator | |
502 | I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end(); | |
503 | I != E; ++I) | |
504 | dispatch(*I); | |
505 | if (D->doesThisDeclarationHaveABody()) | |
506 | dispatch(D->getBody()); | |
507 | } | |
508 | ||
509 | // CXXMethodDecl ? | |
510 | // CXXConstructorDecl ? | |
511 | // CXXDestructorDecl ? | |
512 | // CXXConversionDecl ? | |
513 | ||
514 | void dispatch(CXXCtorInitializer *Init) { | |
515 | // TODO | |
516 | } | |
517 | ||
518 | // FieldDecl | |
519 | void visitFieldDeclAttrs(FieldDecl *D) { | |
520 | setFlag("mutable", D->isMutable()); | |
521 | } | |
522 | void visitFieldDeclChildren(FieldDecl *D) { | |
523 | if (D->isBitField()) { | |
524 | TemporaryContainer C(*this, "bitwidth"); | |
525 | dispatch(D->getBitWidth()); | |
526 | } | |
527 | // TODO: C++0x member initializer | |
528 | } | |
529 | ||
530 | // EnumConstantDecl | |
531 | void visitEnumConstantDeclChildren(EnumConstantDecl *D) { | |
532 | // value in any case? | |
533 | if (D->getInitExpr()) dispatch(D->getInitExpr()); | |
534 | } | |
535 | ||
536 | // IndirectFieldDecl | |
537 | void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) { | |
538 | for (IndirectFieldDecl::chain_iterator | |
539 | I = D->chain_begin(), E = D->chain_end(); I != E; ++I) { | |
540 | NamedDecl *VD = const_cast<NamedDecl*>(*I); | |
541 | push(isa<VarDecl>(VD) ? "variable" : "field"); | |
542 | setPointer("ptr", VD); | |
543 | completeAttrs(); | |
544 | pop(); | |
545 | } | |
546 | } | |
547 | ||
548 | // TypeDecl | |
549 | void visitTypeDeclAttrs(TypeDecl *D) { | |
550 | setPointer("typeptr", D->getTypeForDecl()); | |
551 | } | |
552 | ||
553 | // TypedefDecl | |
554 | void visitTypedefDeclAttrs(TypedefDecl *D) { | |
555 | visitRedeclarableAttrs<TypedefNameDecl>(D); | |
556 | } | |
557 | void visitTypedefDeclChildren(TypedefDecl *D) { | |
558 | dispatch(D->getTypeSourceInfo()->getTypeLoc()); | |
559 | } | |
560 | ||
561 | // TypeAliasDecl | |
562 | void visitTypeAliasDeclAttrs(TypeAliasDecl *D) { | |
563 | visitRedeclarableAttrs<TypedefNameDecl>(D); | |
564 | } | |
565 | void visitTypeAliasDeclChildren(TypeAliasDecl *D) { | |
566 | dispatch(D->getTypeSourceInfo()->getTypeLoc()); | |
567 | } | |
568 | ||
569 | // TagDecl | |
570 | void visitTagDeclAttrs(TagDecl *D) { | |
571 | visitRedeclarableAttrs(D); | |
572 | } | |
573 | void visitTagDeclAsContext(TagDecl *D) { | |
574 | visitDeclContext(D); | |
575 | } | |
576 | ||
577 | // EnumDecl | |
578 | void visitEnumDeclAttrs(EnumDecl *D) { | |
579 | setFlag("scoped", D->isScoped()); | |
580 | setFlag("fixed", D->isFixed()); | |
581 | } | |
582 | void visitEnumDeclChildren(EnumDecl *D) { | |
583 | { | |
584 | TemporaryContainer C(*this, "promotion_type"); | |
585 | dispatch(D->getPromotionType()); | |
586 | } | |
587 | { | |
588 | TemporaryContainer C(*this, "integer_type"); | |
589 | dispatch(D->getIntegerType()); | |
590 | } | |
591 | } | |
592 | ||
593 | // RecordDecl ? | |
594 | ||
595 | void visitCXXRecordDeclChildren(CXXRecordDecl *D) { | |
596 | if (!D->isThisDeclarationADefinition()) return; | |
597 | ||
598 | for (CXXRecordDecl::base_class_iterator | |
599 | I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { | |
600 | push("base"); | |
601 | setAccess(I->getAccessSpecifier()); | |
602 | completeAttrs(); | |
603 | dispatch(I->getTypeSourceInfo()->getTypeLoc()); | |
604 | pop(); | |
605 | } | |
606 | } | |
607 | ||
608 | // ClassTemplateSpecializationDecl ? | |
609 | ||
610 | // FileScopeAsmDecl ? | |
611 | ||
612 | // BlockDecl | |
613 | void visitBlockDeclAttrs(BlockDecl *D) { | |
614 | setFlag("variadic", D->isVariadic()); | |
615 | } | |
616 | void visitBlockDeclChildren(BlockDecl *D) { | |
617 | for (FunctionDecl::param_iterator | |
618 | I = D->param_begin(), E = D->param_end(); I != E; ++I) | |
619 | dispatch(*I); | |
620 | dispatch(D->getBody()); | |
621 | } | |
622 | ||
623 | // AccessSpecDecl | |
624 | void visitAccessSpecDeclAttrs(AccessSpecDecl *D) { | |
625 | setAccess(D->getAccess()); | |
626 | } | |
627 | ||
628 | // TemplateDecl | |
629 | void visitTemplateDeclChildren(TemplateDecl *D) { | |
630 | visitTemplateParameters(D->getTemplateParameters()); | |
631 | if (D->getTemplatedDecl()) | |
632 | dispatch(D->getTemplatedDecl()); | |
633 | } | |
634 | ||
635 | // FunctionTemplateDecl | |
636 | void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) { | |
637 | visitRedeclarableAttrs(D); | |
638 | } | |
639 | void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) { | |
640 | // Mention all the specializations which don't have explicit | |
641 | // declarations elsewhere. | |
642 | for (FunctionTemplateDecl::spec_iterator | |
643 | I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { | |
644 | FunctionTemplateSpecializationInfo *Info | |
645 | = I->getTemplateSpecializationInfo(); | |
646 | ||
647 | bool Unknown = false; | |
648 | switch (Info->getTemplateSpecializationKind()) { | |
649 | case TSK_ImplicitInstantiation: Unknown = false; break; | |
650 | case TSK_Undeclared: Unknown = true; break; | |
651 | ||
652 | // These will be covered at their respective sites. | |
653 | case TSK_ExplicitSpecialization: continue; | |
654 | case TSK_ExplicitInstantiationDeclaration: continue; | |
655 | case TSK_ExplicitInstantiationDefinition: continue; | |
656 | } | |
657 | ||
658 | TemporaryContainer C(*this, | |
659 | Unknown ? "uninstantiated" : "instantiation"); | |
660 | visitTemplateArguments(*Info->TemplateArguments); | |
661 | dispatch(Info->Function); | |
662 | } | |
663 | } | |
664 | ||
665 | // ClasTemplateDecl | |
666 | void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) { | |
667 | visitRedeclarableAttrs(D); | |
668 | } | |
669 | void visitClassTemplateDeclChildren(ClassTemplateDecl *D) { | |
670 | // Mention all the specializations which don't have explicit | |
671 | // declarations elsewhere. | |
672 | for (ClassTemplateDecl::spec_iterator | |
673 | I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { | |
674 | ||
675 | bool Unknown = false; | |
676 | switch (I->getTemplateSpecializationKind()) { | |
677 | case TSK_ImplicitInstantiation: Unknown = false; break; | |
678 | case TSK_Undeclared: Unknown = true; break; | |
679 | ||
680 | // These will be covered at their respective sites. | |
681 | case TSK_ExplicitSpecialization: continue; | |
682 | case TSK_ExplicitInstantiationDeclaration: continue; | |
683 | case TSK_ExplicitInstantiationDefinition: continue; | |
684 | } | |
685 | ||
686 | TemporaryContainer C(*this, | |
687 | Unknown ? "uninstantiated" : "instantiation"); | |
688 | visitTemplateArguments(I->getTemplateArgs()); | |
689 | dispatch(*I); | |
690 | } | |
691 | } | |
692 | ||
693 | // TemplateTypeParmDecl | |
694 | void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) { | |
695 | setInteger("depth", D->getDepth()); | |
696 | setInteger("index", D->getIndex()); | |
697 | } | |
698 | void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) { | |
699 | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | |
700 | dispatch(D->getDefaultArgumentInfo()->getTypeLoc()); | |
701 | // parameter pack? | |
702 | } | |
703 | ||
704 | // NonTypeTemplateParmDecl | |
705 | void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) { | |
706 | setInteger("depth", D->getDepth()); | |
707 | setInteger("index", D->getIndex()); | |
708 | } | |
709 | void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) { | |
710 | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | |
711 | dispatch(D->getDefaultArgument()); | |
712 | // parameter pack? | |
713 | } | |
714 | ||
715 | // TemplateTemplateParmDecl | |
716 | void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) { | |
717 | setInteger("depth", D->getDepth()); | |
718 | setInteger("index", D->getIndex()); | |
719 | } | |
720 | void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) { | |
721 | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | |
722 | dispatch(D->getDefaultArgument()); | |
723 | // parameter pack? | |
724 | } | |
725 | ||
726 | // FriendDecl | |
727 | void visitFriendDeclChildren(FriendDecl *D) { | |
728 | if (TypeSourceInfo *T = D->getFriendType()) | |
729 | dispatch(T->getTypeLoc()); | |
730 | else | |
731 | dispatch(D->getFriendDecl()); | |
732 | } | |
733 | ||
734 | // UsingDirectiveDecl ? | |
735 | // UsingDecl ? | |
736 | // UsingShadowDecl ? | |
737 | // NamespaceAliasDecl ? | |
738 | // UnresolvedUsingValueDecl ? | |
739 | // UnresolvedUsingTypenameDecl ? | |
740 | // StaticAssertDecl ? | |
741 | ||
742 | // ObjCImplDecl | |
743 | void visitObjCImplDeclChildren(ObjCImplDecl *D) { | |
744 | visitDeclRef(D->getClassInterface()); | |
745 | } | |
746 | void visitObjCImplDeclAsContext(ObjCImplDecl *D) { | |
747 | visitDeclContext(D); | |
748 | } | |
749 | ||
750 | // ObjCInterfaceDecl | |
751 | void visitCategoryList(ObjCCategoryDecl *D) { | |
752 | if (!D) return; | |
753 | ||
754 | TemporaryContainer C(*this, "categories"); | |
755 | for (; D; D = D->getNextClassCategory()) | |
756 | visitDeclRef(D); | |
757 | } | |
758 | void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { | |
759 | setPointer("typeptr", D->getTypeForDecl()); | |
760 | setFlag("forward_decl", !D->isThisDeclarationADefinition()); | |
761 | setFlag("implicit_interface", D->isImplicitInterfaceDecl()); | |
762 | } | |
763 | void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { | |
764 | visitDeclRef("super", D->getSuperClass()); | |
765 | visitDeclRef("implementation", D->getImplementation()); | |
766 | if (D->protocol_begin() != D->protocol_end()) { | |
767 | TemporaryContainer C(*this, "protocols"); | |
768 | for (ObjCInterfaceDecl::protocol_iterator | |
769 | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | |
770 | visitDeclRef(*I); | |
771 | } | |
772 | visitCategoryList(D->getCategoryList()); | |
773 | } | |
774 | void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { | |
775 | visitDeclContext(D); | |
776 | } | |
777 | ||
778 | // ObjCCategoryDecl | |
779 | void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { | |
780 | setFlag("extension", D->IsClassExtension()); | |
781 | } | |
782 | void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) { | |
783 | visitDeclRef("interface", D->getClassInterface()); | |
784 | visitDeclRef("implementation", D->getImplementation()); | |
785 | if (D->protocol_begin() != D->protocol_end()) { | |
786 | TemporaryContainer C(*this, "protocols"); | |
787 | for (ObjCCategoryDecl::protocol_iterator | |
788 | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | |
789 | visitDeclRef(*I); | |
790 | } | |
791 | } | |
792 | void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) { | |
793 | visitDeclContext(D); | |
794 | } | |
795 | ||
796 | // ObjCCategoryImplDecl | |
797 | void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) { | |
798 | set("identifier", D->getName()); | |
799 | } | |
800 | void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) { | |
801 | visitDeclRef(D->getCategoryDecl()); | |
802 | } | |
803 | ||
804 | // ObjCImplementationDecl | |
805 | void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) { | |
806 | set("identifier", D->getName()); | |
807 | } | |
808 | void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) { | |
809 | visitDeclRef("super", D->getSuperClass()); | |
810 | if (D->init_begin() != D->init_end()) { | |
811 | TemporaryContainer C(*this, "initializers"); | |
812 | for (ObjCImplementationDecl::init_iterator | |
813 | I = D->init_begin(), E = D->init_end(); I != E; ++I) | |
814 | dispatch(*I); | |
815 | } | |
816 | } | |
817 | ||
818 | // ObjCProtocolDecl | |
819 | void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { | |
820 | if (!D->isThisDeclarationADefinition()) | |
821 | return; | |
822 | ||
823 | if (D->protocol_begin() != D->protocol_end()) { | |
824 | TemporaryContainer C(*this, "protocols"); | |
825 | for (ObjCInterfaceDecl::protocol_iterator | |
826 | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | |
827 | visitDeclRef(*I); | |
828 | } | |
829 | } | |
830 | void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) { | |
831 | if (!D->isThisDeclarationADefinition()) | |
832 | return; | |
833 | ||
834 | visitDeclContext(D); | |
835 | } | |
836 | ||
837 | // ObjCMethodDecl | |
838 | void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { | |
839 | // decl qualifier? | |
840 | // implementation control? | |
841 | ||
842 | setFlag("instance", D->isInstanceMethod()); | |
843 | setFlag("variadic", D->isVariadic()); | |
844 | setFlag("synthesized", D->isSynthesized()); | |
845 | setFlag("defined", D->isDefined()); | |
846 | setFlag("related_result_type", D->hasRelatedResultType()); | |
847 | } | |
848 | void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { | |
849 | dispatch(D->getResultType()); | |
850 | for (ObjCMethodDecl::param_iterator | |
851 | I = D->param_begin(), E = D->param_end(); I != E; ++I) | |
852 | dispatch(*I); | |
853 | if (D->isThisDeclarationADefinition()) | |
854 | dispatch(D->getBody()); | |
855 | } | |
856 | ||
857 | // ObjCIvarDecl | |
858 | void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) { | |
859 | switch (AC) { | |
860 | case ObjCIvarDecl::None: return set(prop, "none"); | |
861 | case ObjCIvarDecl::Private: return set(prop, "private"); | |
862 | case ObjCIvarDecl::Protected: return set(prop, "protected"); | |
863 | case ObjCIvarDecl::Public: return set(prop, "public"); | |
864 | case ObjCIvarDecl::Package: return set(prop, "package"); | |
865 | } | |
866 | } | |
867 | void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) { | |
868 | setFlag("synthesize", D->getSynthesize()); | |
869 | setAccessControl("access", D->getAccessControl()); | |
870 | } | |
871 | ||
872 | // ObjCCompatibleAliasDecl | |
873 | void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) { | |
874 | visitDeclRef(D->getClassInterface()); | |
875 | } | |
876 | ||
877 | // FIXME: ObjCPropertyDecl | |
878 | // FIXME: ObjCPropertyImplDecl | |
879 | ||
880 | //---- Types -----------------------------------------------------// | |
881 | void dispatch(TypeLoc TL) { | |
882 | dispatch(TL.getType()); // for now | |
883 | } | |
884 | ||
885 | void dispatch(QualType T) { | |
886 | if (T.hasLocalQualifiers()) { | |
887 | push("QualType"); | |
888 | Qualifiers Qs = T.getLocalQualifiers(); | |
889 | setFlag("const", Qs.hasConst()); | |
890 | setFlag("volatile", Qs.hasVolatile()); | |
891 | setFlag("restrict", Qs.hasRestrict()); | |
892 | if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace()); | |
893 | if (Qs.hasObjCGCAttr()) { | |
894 | switch (Qs.getObjCGCAttr()) { | |
895 | case Qualifiers::Weak: set("gc", "weak"); break; | |
896 | case Qualifiers::Strong: set("gc", "strong"); break; | |
897 | case Qualifiers::GCNone: llvm_unreachable("explicit none"); | |
898 | } | |
899 | } | |
900 | ||
901 | completeAttrs(); | |
902 | dispatch(QualType(T.getTypePtr(), 0)); | |
903 | pop(); | |
904 | return; | |
905 | } | |
906 | ||
907 | Type *Ty = const_cast<Type*>(T.getTypePtr()); | |
908 | push(getTypeKindName(Ty)); | |
909 | XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr())); | |
910 | pop(); | |
911 | } | |
912 | ||
913 | void setCallingConv(CallingConv CC) { | |
914 | switch (CC) { | |
915 | case CC_Default: return; | |
916 | case CC_C: return set("cc", "cdecl"); | |
917 | case CC_X86FastCall: return set("cc", "x86_fastcall"); | |
918 | case CC_X86StdCall: return set("cc", "x86_stdcall"); | |
919 | case CC_X86ThisCall: return set("cc", "x86_thiscall"); | |
920 | case CC_X86Pascal: return set("cc", "x86_pascal"); | |
921 | case CC_AAPCS: return set("cc", "aapcs"); | |
922 | case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); | |
923 | } | |
924 | } | |
925 | ||
926 | void visitTypeAttrs(Type *D) { | |
927 | setPointer(D); | |
928 | setFlag("dependent", D->isDependentType()); | |
929 | setFlag("variably_modified", D->isVariablyModifiedType()); | |
930 | ||
931 | setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr()); | |
932 | } | |
933 | ||
934 | void visitPointerTypeChildren(PointerType *T) { | |
935 | dispatch(T->getPointeeType()); | |
936 | } | |
937 | void visitReferenceTypeChildren(ReferenceType *T) { | |
938 | dispatch(T->getPointeeType()); | |
939 | } | |
940 | void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) { | |
941 | dispatch(T->getPointeeType()); | |
942 | } | |
943 | void visitBlockPointerTypeChildren(BlockPointerType *T) { | |
944 | dispatch(T->getPointeeType()); | |
945 | } | |
946 | ||
947 | // Types that just wrap declarations. | |
948 | void visitTagTypeChildren(TagType *T) { | |
949 | visitDeclRef(T->getDecl()); | |
950 | } | |
951 | void visitTypedefTypeChildren(TypedefType *T) { | |
952 | visitDeclRef(T->getDecl()); | |
953 | } | |
954 | void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) { | |
955 | visitDeclRef(T->getDecl()); | |
956 | } | |
957 | void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) { | |
958 | visitDeclRef(T->getDecl()); | |
959 | } | |
960 | void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) { | |
961 | visitDeclRef(T->getDecl()); | |
962 | } | |
963 | ||
964 | void visitFunctionTypeAttrs(FunctionType *T) { | |
965 | setFlag("noreturn", T->getNoReturnAttr()); | |
966 | setCallingConv(T->getCallConv()); | |
967 | if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType()); | |
968 | } | |
969 | void visitFunctionTypeChildren(FunctionType *T) { | |
970 | dispatch(T->getResultType()); | |
971 | } | |
972 | ||
973 | void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { | |
974 | setFlag("const", T->isConst()); | |
975 | setFlag("volatile", T->isVolatile()); | |
976 | setFlag("restrict", T->isRestrict()); | |
977 | } | |
978 | void visitFunctionProtoTypeChildren(FunctionProtoType *T) { | |
979 | push("parameters"); | |
980 | setFlag("variadic", T->isVariadic()); | |
981 | completeAttrs(); | |
982 | for (FunctionProtoType::arg_type_iterator | |
983 | I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I) | |
984 | dispatch(*I); | |
985 | pop(); | |
986 | ||
987 | if (T->hasDynamicExceptionSpec()) { | |
988 | push("exception_specifiers"); | |
989 | setFlag("any", T->getExceptionSpecType() == EST_MSAny); | |
990 | completeAttrs(); | |
991 | for (FunctionProtoType::exception_iterator | |
992 | I = T->exception_begin(), E = T->exception_end(); I != E; ++I) | |
993 | dispatch(*I); | |
994 | pop(); | |
995 | } | |
996 | // FIXME: noexcept specifier | |
997 | } | |
998 | ||
999 | void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { | |
1000 | if (const RecordType *RT = T->getAs<RecordType>()) | |
1001 | visitDeclRef(RT->getDecl()); | |
1002 | ||
1003 | // TODO: TemplateName | |
1004 | ||
1005 | push("template_arguments"); | |
1006 | completeAttrs(); | |
1007 | for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) | |
1008 | dispatch(T->getArg(I)); | |
1009 | pop(); | |
1010 | } | |
1011 | ||
1012 | //---- Statements ------------------------------------------------// | |
1013 | void dispatch(Stmt *S) { | |
1014 | // FIXME: this is not really XML at all | |
1015 | push("Stmt"); | |
1016 | out << ">\n"; | |
1017 | Stack.back().State = NS_Children; // explicitly become non-lazy | |
1018 | S->dump(out, Context.getSourceManager()); | |
1019 | out << '\n'; | |
1020 | pop(); | |
1021 | } | |
1022 | }; | |
1023 | } | |
1024 | ||
1025 | void Decl::dumpXML() const { | |
1026 | dumpXML(llvm::errs()); | |
1027 | } | |
1028 | ||
1029 | void Decl::dumpXML(raw_ostream &out) const { | |
1030 | XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); | |
1031 | } | |
1032 | ||
1033 | #else /* ifndef NDEBUG */ | |
1034 | ||
1035 | void Decl::dumpXML() const {} | |
1036 | void Decl::dumpXML(raw_ostream &out) const {} | |
1037 | ||
1038 | #endif |