1 //===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===//
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 implements AST dumping of components of individual AST nodes.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/TextNodeDumper.h"
15 
16 using namespace clang;
17 
18 TextNodeDumper::TextNodeDumper(raw_ostream &OS, bool ShowColors,
19                                const SourceManager *SM,
20                                const PrintingPolicy &PrintPolicy,
21                                const comments::CommandTraits *Traits)
22     : TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors), SM(SM),
23       PrintPolicy(PrintPolicy), Traits(Traits) {}
24 
25 void TextNodeDumper::Visit(const comments::Comment *C,
26                            const comments::FullComment *FC) {
27   if (!C) {
28     ColorScope Color(OS, ShowColors, NullColor);
29     OS << "<<<NULL>>>";
30     return;
31   }
32 
33   {
34     ColorScope Color(OS, ShowColors, CommentColor);
35     OS << C->getCommentKindName();
36   }
37   dumpPointer(C);
38   dumpSourceRange(C->getSourceRange());
39 
40   ConstCommentVisitor<TextNodeDumper, void,
41                       const comments::FullComment *>::visit(C, FC);
42 }
43 
44 void TextNodeDumper::dumpPointer(const void *Ptr) {
45   ColorScope Color(OS, ShowColors, AddressColor);
46   OS << ' ' << Ptr;
47 }
48 
49 void TextNodeDumper::dumpLocation(SourceLocation Loc) {
50   if (!SM)
51     return;
52 
53   ColorScope Color(OS, ShowColors, LocationColor);
54   SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
55 
56   // The general format we print out is filename:line:col, but we drop pieces
57   // that haven't changed since the last loc printed.
58   PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
59 
60   if (PLoc.isInvalid()) {
61     OS << "<invalid sloc>";
62     return;
63   }
64 
65   if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
66     OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
67        << PLoc.getColumn();
68     LastLocFilename = PLoc.getFilename();
69     LastLocLine = PLoc.getLine();
70   } else if (PLoc.getLine() != LastLocLine) {
71     OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
72     LastLocLine = PLoc.getLine();
73   } else {
74     OS << "col" << ':' << PLoc.getColumn();
75   }
76 }
77 
78 void TextNodeDumper::dumpSourceRange(SourceRange R) {
79   // Can't translate locations if a SourceManager isn't available.
80   if (!SM)
81     return;
82 
83   OS << " <";
84   dumpLocation(R.getBegin());
85   if (R.getBegin() != R.getEnd()) {
86     OS << ", ";
87     dumpLocation(R.getEnd());
88   }
89   OS << ">";
90 
91   // <t2.c:123:421[blah], t2.c:412:321>
92 }
93 
94 void TextNodeDumper::dumpBareType(QualType T, bool Desugar) {
95   ColorScope Color(OS, ShowColors, TypeColor);
96 
97   SplitQualType T_split = T.split();
98   OS << "'" << QualType::getAsString(T_split, PrintPolicy) << "'";
99 
100   if (Desugar && !T.isNull()) {
101     // If the type is sugared, also dump a (shallow) desugared type.
102     SplitQualType D_split = T.getSplitDesugaredType();
103     if (T_split != D_split)
104       OS << ":'" << QualType::getAsString(D_split, PrintPolicy) << "'";
105   }
106 }
107 
108 void TextNodeDumper::dumpType(QualType T) {
109   OS << ' ';
110   dumpBareType(T);
111 }
112 
113 void TextNodeDumper::dumpBareDeclRef(const Decl *D) {
114   if (!D) {
115     ColorScope Color(OS, ShowColors, NullColor);
116     OS << "<<<NULL>>>";
117     return;
118   }
119 
120   {
121     ColorScope Color(OS, ShowColors, DeclKindNameColor);
122     OS << D->getDeclKindName();
123   }
124   dumpPointer(D);
125 
126   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
127     ColorScope Color(OS, ShowColors, DeclNameColor);
128     OS << " '" << ND->getDeclName() << '\'';
129   }
130 
131   if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
132     dumpType(VD->getType());
133 }
134 
135 void TextNodeDumper::dumpName(const NamedDecl *ND) {
136   if (ND->getDeclName()) {
137     ColorScope Color(OS, ShowColors, DeclNameColor);
138     OS << ' ' << ND->getNameAsString();
139   }
140 }
141 
142 void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) {
143   switch (AS) {
144   case AS_none:
145     break;
146   case AS_public:
147     OS << "public";
148     break;
149   case AS_protected:
150     OS << "protected";
151     break;
152   case AS_private:
153     OS << "private";
154     break;
155   }
156 }
157 
158 void TextNodeDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
159   OS << "(CXXTemporary";
160   dumpPointer(Temporary);
161   OS << ")";
162 }
163 
164 void TextNodeDumper::dumpDeclRef(const Decl *D, const char *Label) {
165   if (!D)
166     return;
167 
168   addChild([=] {
169     if (Label)
170       OS << Label << ' ';
171     dumpBareDeclRef(D);
172   });
173 }
174 
175 const char *TextNodeDumper::getCommandName(unsigned CommandID) {
176   if (Traits)
177     return Traits->getCommandInfo(CommandID)->Name;
178   const comments::CommandInfo *Info =
179       comments::CommandTraits::getBuiltinCommandInfo(CommandID);
180   if (Info)
181     return Info->Name;
182   return "<not a builtin command>";
183 }
184 
185 void TextNodeDumper::visitTextComment(const comments::TextComment *C,
186                                       const comments::FullComment *) {
187   OS << " Text=\"" << C->getText() << "\"";
188 }
189 
190 void TextNodeDumper::visitInlineCommandComment(
191     const comments::InlineCommandComment *C, const comments::FullComment *) {
192   OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
193   switch (C->getRenderKind()) {
194   case comments::InlineCommandComment::RenderNormal:
195     OS << " RenderNormal";
196     break;
197   case comments::InlineCommandComment::RenderBold:
198     OS << " RenderBold";
199     break;
200   case comments::InlineCommandComment::RenderMonospaced:
201     OS << " RenderMonospaced";
202     break;
203   case comments::InlineCommandComment::RenderEmphasized:
204     OS << " RenderEmphasized";
205     break;
206   }
207 
208   for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
209     OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
210 }
211 
212 void TextNodeDumper::visitHTMLStartTagComment(
213     const comments::HTMLStartTagComment *C, const comments::FullComment *) {
214   OS << " Name=\"" << C->getTagName() << "\"";
215   if (C->getNumAttrs() != 0) {
216     OS << " Attrs: ";
217     for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
218       const comments::HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
219       OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
220     }
221   }
222   if (C->isSelfClosing())
223     OS << " SelfClosing";
224 }
225 
226 void TextNodeDumper::visitHTMLEndTagComment(
227     const comments::HTMLEndTagComment *C, const comments::FullComment *) {
228   OS << " Name=\"" << C->getTagName() << "\"";
229 }
230 
231 void TextNodeDumper::visitBlockCommandComment(
232     const comments::BlockCommandComment *C, const comments::FullComment *) {
233   OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
234   for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
235     OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
236 }
237 
238 void TextNodeDumper::visitParamCommandComment(
239     const comments::ParamCommandComment *C, const comments::FullComment *FC) {
240   OS << " "
241      << comments::ParamCommandComment::getDirectionAsString(C->getDirection());
242 
243   if (C->isDirectionExplicit())
244     OS << " explicitly";
245   else
246     OS << " implicitly";
247 
248   if (C->hasParamName()) {
249     if (C->isParamIndexValid())
250       OS << " Param=\"" << C->getParamName(FC) << "\"";
251     else
252       OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
253   }
254 
255   if (C->isParamIndexValid() && !C->isVarArgParam())
256     OS << " ParamIndex=" << C->getParamIndex();
257 }
258 
259 void TextNodeDumper::visitTParamCommandComment(
260     const comments::TParamCommandComment *C, const comments::FullComment *FC) {
261   if (C->hasParamName()) {
262     if (C->isPositionValid())
263       OS << " Param=\"" << C->getParamName(FC) << "\"";
264     else
265       OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
266   }
267 
268   if (C->isPositionValid()) {
269     OS << " Position=<";
270     for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
271       OS << C->getIndex(i);
272       if (i != e - 1)
273         OS << ", ";
274     }
275     OS << ">";
276   }
277 }
278 
279 void TextNodeDumper::visitVerbatimBlockComment(
280     const comments::VerbatimBlockComment *C, const comments::FullComment *) {
281   OS << " Name=\"" << getCommandName(C->getCommandID())
282      << "\""
283         " CloseName=\""
284      << C->getCloseName() << "\"";
285 }
286 
287 void TextNodeDumper::visitVerbatimBlockLineComment(
288     const comments::VerbatimBlockLineComment *C,
289     const comments::FullComment *) {
290   OS << " Text=\"" << C->getText() << "\"";
291 }
292 
293 void TextNodeDumper::visitVerbatimLineComment(
294     const comments::VerbatimLineComment *C, const comments::FullComment *) {
295   OS << " Text=\"" << C->getText() << "\"";
296 }
297