blob: 19a757303f1b190758c8617f74e19545d8fd9990 [file] [log] [blame]
Douglas Gregoree75c052009-05-21 20:55:50 +00001//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
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 the XML document class, which provides the means to
11// dump out the AST in a XML form that exposes type details and other fields.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Frontend/DocumentXML.h"
16#include "clang/AST/Decl.h"
Douglas Gregor038f75a2009-06-15 19:02:54 +000017#include "clang/AST/ASTContext.h"
Douglas Gregoree75c052009-05-21 20:55:50 +000018#include "clang/Basic/SourceManager.h"
19#include "llvm/ADT/StringExtras.h"
20
21namespace clang {
22
23//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000024DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
Douglas Gregoree75c052009-05-21 20:55:50 +000025 Out(out),
26 Ctx(0),
Douglas Gregoree75c052009-05-21 20:55:50 +000027 HasCurrentNodeSubNodes(false)
28{
Douglas Gregor038f75a2009-06-15 19:02:54 +000029 NodeStack.push(rootName);
Douglas Gregoree75c052009-05-21 20:55:50 +000030 Out << "<?xml version=\"1.0\"?>\n<" << rootName;
31}
32
33//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000034DocumentXML& DocumentXML::addSubNode(const std::string& name)
35{
36 if (!HasCurrentNodeSubNodes)
37 {
38 Out << ">\n";
39 }
Douglas Gregor038f75a2009-06-15 19:02:54 +000040 NodeStack.push(name);
Douglas Gregoree75c052009-05-21 20:55:50 +000041 HasCurrentNodeSubNodes = false;
Douglas Gregoree75c052009-05-21 20:55:50 +000042 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000043 Out << "<" << NodeStack.top();
Douglas Gregoree75c052009-05-21 20:55:50 +000044 return *this;
45}
46
47//---------------------------------------------------------
48void DocumentXML::Indent()
49{
Douglas Gregor038f75a2009-06-15 19:02:54 +000050 for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
Douglas Gregoree75c052009-05-21 20:55:50 +000051 Out << ' ';
52}
53
54//---------------------------------------------------------
55DocumentXML& DocumentXML::toParent()
56{
Douglas Gregor038f75a2009-06-15 19:02:54 +000057 assert(NodeStack.size() > 1 && "to much backtracking");
Douglas Gregoree75c052009-05-21 20:55:50 +000058
59 if (HasCurrentNodeSubNodes)
60 {
61 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000062 Out << "</" << NodeStack.top() << ">\n";
Douglas Gregoree75c052009-05-21 20:55:50 +000063 }
64 else
65 {
66 Out << "/>\n";
67 }
Douglas Gregor038f75a2009-06-15 19:02:54 +000068 NodeStack.pop();
Douglas Gregoree75c052009-05-21 20:55:50 +000069 HasCurrentNodeSubNodes = true;
Douglas Gregoree75c052009-05-21 20:55:50 +000070 return *this;
71}
72
73//---------------------------------------------------------
74namespace {
75
Douglas Gregor038f75a2009-06-15 19:02:54 +000076enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
Douglas Gregoree75c052009-05-21 20:55:50 +000077
78unsigned getNewId(tIdType idType)
79{
80 static unsigned int idCounts[ID_LAST] = { 0 };
81 return ++idCounts[idType];
82}
83
84//---------------------------------------------------------
85inline std::string getPrefixedId(unsigned uId, tIdType idType)
86{
Douglas Gregor038f75a2009-06-15 19:02:54 +000087 static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
Douglas Gregoree75c052009-05-21 20:55:50 +000088 char buffer[20];
89 char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
90 *--BufPtr = idPrefix[idType];
91 return BufPtr;
92}
93
94//---------------------------------------------------------
95template<class T, class V>
96bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL)
97{
98 typename T::iterator i = idMap.find(value);
99 bool toAdd = i == idMap.end();
100 if (toAdd)
101 {
102 idMap.insert(typename T::value_type(value, getNewId(idType)));
103 }
104 return toAdd;
105}
106
107} // anon NS
108
Douglas Gregor038f75a2009-06-15 19:02:54 +0000109
Douglas Gregoree75c052009-05-21 20:55:50 +0000110//---------------------------------------------------------
111std::string DocumentXML::escapeString(const char* pStr, std::string::size_type len)
112{
113 std::string value;
114 value.reserve(len + 1);
115 char buffer[16];
116 for (unsigned i = 0; i < len; ++i) {
117 switch (char C = pStr[i]) {
118 default:
119 if (isprint(C))
120 value += C;
121 else
122 {
123 sprintf(buffer, "\\%03o", C);
124 value += buffer;
125 }
126 break;
127
128 case '\n': value += "\\n"; break;
129 case '\t': value += "\\t"; break;
130 case '\a': value += "\\a"; break;
131 case '\b': value += "\\b"; break;
132 case '\r': value += "\\r"; break;
133
134 case '&': value += "&amp;"; break;
135 case '<': value += "&lt;"; break;
136 case '>': value += "&gt;"; break;
137 case '"': value += "&quot;"; break;
138 case '\'': value += "&apos;"; break;
139
140 }
141 }
142 return value;
143}
144
145//---------------------------------------------------------
146void DocumentXML::finalize()
147{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000148 assert(NodeStack.size() == 1 && "not completely backtracked");
Douglas Gregoree75c052009-05-21 20:55:50 +0000149
150 addSubNode("ReferenceSection");
151 addSubNode("Types");
152
153 for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i)
154 {
155 if (i->first.getCVRQualifiers() != 0)
156 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000157 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000158 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000159 toParent();
160 }
161 }
162
163 for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i)
164 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000165 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000166 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
167 toParent();
168 }
169
170
171 toParent().addSubNode("Contexts");
172
173 for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), e = Contexts.end(); i != e; ++i)
174 {
175 addSubNode(i->first->getDeclKindName());
176 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
177 if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first)) {
178 addAttribute("name", ND->getNameAsString());
179 }
180 if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) {
181 addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
182 }
183 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first)) {
184 addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAsFunctionType()], ID_NORMAL));
185 }
186
187 if (const DeclContext* parent = i->first->getParent())
188 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000189 addAttribute("context", parent);
Douglas Gregoree75c052009-05-21 20:55:50 +0000190 }
191 toParent();
192 }
193
194 toParent().addSubNode("Files");
195
196 for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), e = SourceFiles.end(); i != e; ++i)
197 {
198 addSubNode("File");
199 addAttribute("id", getPrefixedId(i->second, ID_FILE));
200 addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
201 toParent();
202 }
203
204 toParent().toParent();
205
206 // write the root closing node (which has always subnodes)
Douglas Gregor038f75a2009-06-15 19:02:54 +0000207 Out << "</" << NodeStack.top() << ">\n";
Douglas Gregoree75c052009-05-21 20:55:50 +0000208}
209
210//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000211void DocumentXML::addAttribute(const char* pAttributeName, const QualType& pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000212{
213 addTypeRecursively(pType);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000214 addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000215}
216
217//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000218void DocumentXML::addPtrAttribute(const char* pAttributeName, const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000219{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000220 addTypeRecursively(pType);
221 addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000222}
223
224//---------------------------------------------------------
225void DocumentXML::addTypeRecursively(const QualType& pType)
226{
227 if (addToMap(Types, pType))
228 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000229 addTypeRecursively(pType.getTypePtr());
Douglas Gregoree75c052009-05-21 20:55:50 +0000230 // beautifier: a non-qualified type shall be transparent
231 if (pType.getCVRQualifiers() == 0)
232 {
233 Types[pType] = BasicTypes[pType.getTypePtr()];
234 }
235 }
236}
237
238//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000239void DocumentXML::addTypeRecursively(const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000240{
241 if (addToMap(BasicTypes, pType))
242 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000243 addParentTypes(pType);
244/*
245 // FIXME: doesn't work in the immediate streaming approach
246 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
247 {
248 addSubNode("VariableArraySizeExpression");
249 PrintStmt(VAT->getSizeExpr());
250 toParent();
Douglas Gregoree75c052009-05-21 20:55:50 +0000251 }
Douglas Gregor038f75a2009-06-15 19:02:54 +0000252*/
Douglas Gregoree75c052009-05-21 20:55:50 +0000253 }
254}
255
256//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000257void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
Douglas Gregoree75c052009-05-21 20:55:50 +0000258{
259 addContextsRecursively(DC);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000260 addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
261}
262
263//---------------------------------------------------------
264void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
265{
266 if (const DeclContext* DC = dyn_cast<DeclContext>(D))
267 {
268 addContextsRecursively(DC);
269 addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
270 }
271 else
272 {
273 addToMap(Decls, D);
274 addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
275 }
276}
277
278//---------------------------------------------------------
279void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
280{
281 addPtrAttribute(pName, static_cast<const DeclContext*>(D));
Douglas Gregoree75c052009-05-21 20:55:50 +0000282}
283
284//---------------------------------------------------------
285void DocumentXML::addContextsRecursively(const DeclContext *DC)
286{
287 if (DC != 0 && addToMap(Contexts, DC))
288 {
289 addContextsRecursively(DC->getParent());
290 }
291}
292
293//---------------------------------------------------------
294void DocumentXML::addSourceFileAttribute(const std::string& fileName)
295{
296 addToMap(SourceFiles, fileName, ID_FILE);
297 addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
298}
299
Douglas Gregor038f75a2009-06-15 19:02:54 +0000300
301//---------------------------------------------------------
302void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
303{
304 addToMap(Labels, L, ID_LABEL);
305 addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
306}
307
308
Douglas Gregoree75c052009-05-21 20:55:50 +0000309//---------------------------------------------------------
310PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
311{
312 SourceManager& SM = Ctx->getSourceManager();
313 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
314 PresumedLoc PLoc;
315 if (!SpellingLoc.isInvalid())
316 {
317 PLoc = SM.getPresumedLoc(SpellingLoc);
318 addSourceFileAttribute(PLoc.getFilename());
319 addAttribute("line", PLoc.getLine());
320 addAttribute("col", PLoc.getColumn());
321 }
322 // else there is no error in some cases (eg. CXXThisExpr)
323 return PLoc;
324}
325
326//---------------------------------------------------------
327void DocumentXML::addLocationRange(const SourceRange& R)
328{
329 PresumedLoc PStartLoc = addLocation(R.getBegin());
330 if (R.getBegin() != R.getEnd())
331 {
332 SourceManager& SM = Ctx->getSourceManager();
333 SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
334 if (!SpellingLoc.isInvalid())
335 {
336 PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
337 if (PStartLoc.isInvalid() ||
338 strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
339 addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
340 addAttribute("endfile", PLoc.getFilename());
341 addAttribute("endline", PLoc.getLine());
342 addAttribute("endcol", PLoc.getColumn());
343 } else if (PLoc.getLine() != PStartLoc.getLine()) {
344 addAttribute("endline", PLoc.getLine());
345 addAttribute("endcol", PLoc.getColumn());
346 } else {
347 addAttribute("endcol", PLoc.getColumn());
348 }
349 }
350 }
351}
352
353//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000354void DocumentXML::PrintDecl(Decl *D)
355{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000356 writeDeclToXML(D);
Douglas Gregoree75c052009-05-21 20:55:50 +0000357}
358
359//---------------------------------------------------------
360} // NS clang
361