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     : OS(OS), ShowColors(ShowColors), SM(SM), PrintPolicy(PrintPolicy),
23       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 const char *TextNodeDumper::getCommandName(unsigned CommandID) {
165   if (Traits)
166     return Traits->getCommandInfo(CommandID)->Name;
167   const comments::CommandInfo *Info =
168       comments::CommandTraits::getBuiltinCommandInfo(CommandID);
169   if (Info)
170     return Info->Name;
171   return "<not a builtin command>";
172 }
173 
174 void TextNodeDumper::visitTextComment(const comments::TextComment *C,
175                                       const comments::FullComment *) {
176   OS << " Text=\"" << C->getText() << "\"";
177 }
178 
179 void TextNodeDumper::visitInlineCommandComment(
180     const comments::InlineCommandComment *C, const comments::FullComment *) {
181   OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
182   switch (C->getRenderKind()) {
183   case comments::InlineCommandComment::RenderNormal:
184     OS << " RenderNormal";
185     break;
186   case comments::InlineCommandComment::RenderBold:
187     OS << " RenderBold";
188     break;
189   case comments::InlineCommandComment::RenderMonospaced:
190     OS << " RenderMonospaced";
191     break;
192   case comments::InlineCommandComment::RenderEmphasized:
193     OS << " RenderEmphasized";
194     break;
195   }
196 
197   for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
198     OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
199 }
200 
201 void TextNodeDumper::visitHTMLStartTagComment(
202     const comments::HTMLStartTagComment *C, const comments::FullComment *) {
203   OS << " Name=\"" << C->getTagName() << "\"";
204   if (C->getNumAttrs() != 0) {
205     OS << " Attrs: ";
206     for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
207       const comments::HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
208       OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
209     }
210   }
211   if (C->isSelfClosing())
212     OS << " SelfClosing";
213 }
214 
215 void TextNodeDumper::visitHTMLEndTagComment(
216     const comments::HTMLEndTagComment *C, const comments::FullComment *) {
217   OS << " Name=\"" << C->getTagName() << "\"";
218 }
219 
220 void TextNodeDumper::visitBlockCommandComment(
221     const comments::BlockCommandComment *C, const comments::FullComment *) {
222   OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
223   for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
224     OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
225 }
226 
227 void TextNodeDumper::visitParamCommandComment(
228     const comments::ParamCommandComment *C, const comments::FullComment *FC) {
229   OS << " "
230      << comments::ParamCommandComment::getDirectionAsString(C->getDirection());
231 
232   if (C->isDirectionExplicit())
233     OS << " explicitly";
234   else
235     OS << " implicitly";
236 
237   if (C->hasParamName()) {
238     if (C->isParamIndexValid())
239       OS << " Param=\"" << C->getParamName(FC) << "\"";
240     else
241       OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
242   }
243 
244   if (C->isParamIndexValid() && !C->isVarArgParam())
245     OS << " ParamIndex=" << C->getParamIndex();
246 }
247 
248 void TextNodeDumper::visitTParamCommandComment(
249     const comments::TParamCommandComment *C, const comments::FullComment *FC) {
250   if (C->hasParamName()) {
251     if (C->isPositionValid())
252       OS << " Param=\"" << C->getParamName(FC) << "\"";
253     else
254       OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
255   }
256 
257   if (C->isPositionValid()) {
258     OS << " Position=<";
259     for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
260       OS << C->getIndex(i);
261       if (i != e - 1)
262         OS << ", ";
263     }
264     OS << ">";
265   }
266 }
267 
268 void TextNodeDumper::visitVerbatimBlockComment(
269     const comments::VerbatimBlockComment *C, const comments::FullComment *) {
270   OS << " Name=\"" << getCommandName(C->getCommandID())
271      << "\""
272         " CloseName=\""
273      << C->getCloseName() << "\"";
274 }
275 
276 void TextNodeDumper::visitVerbatimBlockLineComment(
277     const comments::VerbatimBlockLineComment *C,
278     const comments::FullComment *) {
279   OS << " Text=\"" << C->getText() << "\"";
280 }
281 
282 void TextNodeDumper::visitVerbatimLineComment(
283     const comments::VerbatimLineComment *C, const comments::FullComment *) {
284   OS << " Text=\"" << C->getText() << "\"";
285 }
286