blob: 894f230216f6bd0f4a982b9e8cb8aeab7920e338 [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//
Mike Stump1eb44332009-09-09 15:08:12 +000010// This file implements the XML document class, which provides the means to
Douglas Gregoree75c052009-05-21 20:55:50 +000011// 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
Mike Stump1eb44332009-09-09 15:08:12 +000023//---------------------------------------------------------
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),
Mike Stump1eb44332009-09-09 15:08:12 +000027 HasCurrentNodeSubNodes(false) {
Douglas Gregor038f75a2009-06-15 19:02:54 +000028 NodeStack.push(rootName);
Douglas Gregoree75c052009-05-21 20:55:50 +000029 Out << "<?xml version=\"1.0\"?>\n<" << rootName;
30}
31
Mike Stump1eb44332009-09-09 15:08:12 +000032//---------------------------------------------------------
33DocumentXML& DocumentXML::addSubNode(const std::string& name) {
Douglas Gregoree75c052009-05-21 20:55:50 +000034 if (!HasCurrentNodeSubNodes)
Douglas Gregoree75c052009-05-21 20:55:50 +000035 Out << ">\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000036 NodeStack.push(name);
Douglas Gregoree75c052009-05-21 20:55:50 +000037 HasCurrentNodeSubNodes = false;
Douglas Gregoree75c052009-05-21 20:55:50 +000038 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000039 Out << "<" << NodeStack.top();
Douglas Gregoree75c052009-05-21 20:55:50 +000040 return *this;
41}
42
Mike Stump1eb44332009-09-09 15:08:12 +000043//---------------------------------------------------------
44void DocumentXML::Indent() {
Douglas Gregor038f75a2009-06-15 19:02:54 +000045 for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
Douglas Gregoree75c052009-05-21 20:55:50 +000046 Out << ' ';
47}
48
Mike Stump1eb44332009-09-09 15:08:12 +000049//---------------------------------------------------------
50DocumentXML& DocumentXML::toParent() {
Mike Stump197c8d92009-09-16 20:41:09 +000051 assert(NodeStack.size() > 1 && "too much backtracking");
Douglas Gregoree75c052009-05-21 20:55:50 +000052
Mike Stump1eb44332009-09-09 15:08:12 +000053 if (HasCurrentNodeSubNodes) {
Douglas Gregoree75c052009-05-21 20:55:50 +000054 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000055 Out << "</" << NodeStack.top() << ">\n";
Mike Stump1eb44332009-09-09 15:08:12 +000056 } else
Douglas Gregoree75c052009-05-21 20:55:50 +000057 Out << "/>\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000058 NodeStack.pop();
Douglas Gregoree75c052009-05-21 20:55:50 +000059 HasCurrentNodeSubNodes = true;
Mike Stump1eb44332009-09-09 15:08:12 +000060 return *this;
Douglas Gregoree75c052009-05-21 20:55:50 +000061}
62
Mike Stump1eb44332009-09-09 15:08:12 +000063//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000064namespace {
65
Douglas Gregor038f75a2009-06-15 19:02:54 +000066enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
Douglas Gregoree75c052009-05-21 20:55:50 +000067
Mike Stump1eb44332009-09-09 15:08:12 +000068unsigned getNewId(tIdType idType) {
Douglas Gregoree75c052009-05-21 20:55:50 +000069 static unsigned int idCounts[ID_LAST] = { 0 };
70 return ++idCounts[idType];
71}
72
Mike Stump1eb44332009-09-09 15:08:12 +000073//---------------------------------------------------------
74inline std::string getPrefixedId(unsigned uId, tIdType idType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +000075 static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
Douglas Gregoree75c052009-05-21 20:55:50 +000076 char buffer[20];
77 char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
78 *--BufPtr = idPrefix[idType];
79 return BufPtr;
80}
81
Mike Stump1eb44332009-09-09 15:08:12 +000082//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000083template<class T, class V>
Mike Stump1eb44332009-09-09 15:08:12 +000084bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
Douglas Gregoree75c052009-05-21 20:55:50 +000085 typename T::iterator i = idMap.find(value);
86 bool toAdd = i == idMap.end();
Mike Stump1eb44332009-09-09 15:08:12 +000087 if (toAdd)
Douglas Gregoree75c052009-05-21 20:55:50 +000088 idMap.insert(typename T::value_type(value, getNewId(idType)));
Douglas Gregoree75c052009-05-21 20:55:50 +000089 return toAdd;
90}
91
92} // anon NS
93
Douglas Gregor038f75a2009-06-15 19:02:54 +000094
Mike Stump1eb44332009-09-09 15:08:12 +000095//---------------------------------------------------------
96std::string DocumentXML::escapeString(const char* pStr,
97 std::string::size_type len) {
Douglas Gregoree75c052009-05-21 20:55:50 +000098 std::string value;
99 value.reserve(len + 1);
100 char buffer[16];
101 for (unsigned i = 0; i < len; ++i) {
102 switch (char C = pStr[i]) {
103 default:
104 if (isprint(C))
105 value += C;
Mike Stump1eb44332009-09-09 15:08:12 +0000106 else {
Douglas Gregoree75c052009-05-21 20:55:50 +0000107 sprintf(buffer, "\\%03o", C);
108 value += buffer;
109 }
110 break;
111
112 case '\n': value += "\\n"; break;
113 case '\t': value += "\\t"; break;
114 case '\a': value += "\\a"; break;
115 case '\b': value += "\\b"; break;
116 case '\r': value += "\\r"; break;
117
118 case '&': value += "&amp;"; break;
119 case '<': value += "&lt;"; break;
120 case '>': value += "&gt;"; break;
121 case '"': value += "&quot;"; break;
122 case '\'': value += "&apos;"; break;
123
124 }
125 }
126 return value;
127}
128
Mike Stump1eb44332009-09-09 15:08:12 +0000129//---------------------------------------------------------
130void DocumentXML::finalize() {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000131 assert(NodeStack.size() == 1 && "not completely backtracked");
Douglas Gregoree75c052009-05-21 20:55:50 +0000132
133 addSubNode("ReferenceSection");
134 addSubNode("Types");
135
Mike Stump1eb44332009-09-09 15:08:12 +0000136 for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
137 i != e; ++i) {
Douglas Gregora4923eb2009-11-16 21:35:15 +0000138 if (i->first.hasLocalQualifiers()) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000139 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000140 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000141 toParent();
142 }
143 }
144
Mike Stump1eb44332009-09-09 15:08:12 +0000145 for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
146 e = BasicTypes.end(); i != e; ++i) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000147 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000148 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
149 toParent();
150 }
151
152
153 toParent().addSubNode("Contexts");
154
Mike Stump1eb44332009-09-09 15:08:12 +0000155 for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
156 e = Contexts.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000157 addSubNode(i->first->getDeclKindName());
158 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000159 if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000160 addAttribute("name", ND->getNameAsString());
Mike Stump1eb44332009-09-09 15:08:12 +0000161 if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000162 addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000163 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
John McCall183700f2009-09-21 23:43:11 +0000164 addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000165
166 if (const DeclContext* parent = i->first->getParent())
Douglas Gregor038f75a2009-06-15 19:02:54 +0000167 addAttribute("context", parent);
Douglas Gregoree75c052009-05-21 20:55:50 +0000168 toParent();
169 }
170
171 toParent().addSubNode("Files");
172
Mike Stump1eb44332009-09-09 15:08:12 +0000173 for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
174 e = SourceFiles.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000175 addSubNode("File");
176 addAttribute("id", getPrefixedId(i->second, ID_FILE));
177 addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
178 toParent();
179 }
180
181 toParent().toParent();
Mike Stump1eb44332009-09-09 15:08:12 +0000182
Douglas Gregoree75c052009-05-21 20:55:50 +0000183 // write the root closing node (which has always subnodes)
Douglas Gregor038f75a2009-06-15 19:02:54 +0000184 Out << "</" << NodeStack.top() << ">\n";
Douglas Gregoree75c052009-05-21 20:55:50 +0000185}
186
Mike Stump1eb44332009-09-09 15:08:12 +0000187//---------------------------------------------------------
188void DocumentXML::addAttribute(const char* pAttributeName,
189 const QualType& pType) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000190 addTypeRecursively(pType);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000191 addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000192}
193
Mike Stump1eb44332009-09-09 15:08:12 +0000194//---------------------------------------------------------
195void DocumentXML::addPtrAttribute(const char* pAttributeName,
196 const Type* pType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000197 addTypeRecursively(pType);
198 addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000199}
200
Mike Stump1eb44332009-09-09 15:08:12 +0000201//---------------------------------------------------------
Douglas Gregor4bd98e82010-05-10 17:43:18 +0000202void DocumentXML::addPtrAttribute(const char* pAttributeName,
203 const NestedNameSpecifier* pNNS) {
204 switch (pNNS->getKind()) {
205 case NestedNameSpecifier::Identifier: {
206 IdentifierInfo *ii = pNNS->getAsIdentifier();
207 // FIXME how should we handle those ?
208 addPtrAttribute(pAttributeName, ii->getName().data());
209 break;
210 }
211 case NestedNameSpecifier::Namespace: {
212 addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
213 break;
214 }
215 case NestedNameSpecifier::TypeSpec: {
216 addPtrAttribute(pAttributeName, pNNS->getAsType());
217 break;
218 }
219 case NestedNameSpecifier::TypeSpecWithTemplate: {
220 addPtrAttribute(pAttributeName, pNNS->getAsType());
221 break;
222 }
223 case NestedNameSpecifier::Global: {
224 addPtrAttribute(pAttributeName, "::");
225 break;
226 }
227 }
228}
229
230//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000231void DocumentXML::addTypeRecursively(const QualType& pType)
232{
233 if (addToMap(Types, pType))
234 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000235 addTypeRecursively(pType.getTypePtr());
Douglas Gregoree75c052009-05-21 20:55:50 +0000236 // beautifier: a non-qualified type shall be transparent
Douglas Gregora4923eb2009-11-16 21:35:15 +0000237 if (!pType.hasLocalQualifiers())
Douglas Gregoree75c052009-05-21 20:55:50 +0000238 {
Mike Stump1eb44332009-09-09 15:08:12 +0000239 Types[pType] = BasicTypes[pType.getTypePtr()];
Douglas Gregoree75c052009-05-21 20:55:50 +0000240 }
241 }
242}
243
Mike Stump1eb44332009-09-09 15:08:12 +0000244//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000245void DocumentXML::addTypeRecursively(const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000246{
247 if (addToMap(BasicTypes, pType))
248 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000249 addParentTypes(pType);
250/*
251 // FIXME: doesn't work in the immediate streaming approach
Mike Stump1eb44332009-09-09 15:08:12 +0000252 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
Douglas Gregor038f75a2009-06-15 19:02:54 +0000253 {
254 addSubNode("VariableArraySizeExpression");
255 PrintStmt(VAT->getSizeExpr());
256 toParent();
Douglas Gregoree75c052009-05-21 20:55:50 +0000257 }
Douglas Gregor038f75a2009-06-15 19:02:54 +0000258*/
Douglas Gregoree75c052009-05-21 20:55:50 +0000259 }
260}
261
Mike Stump1eb44332009-09-09 15:08:12 +0000262//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000263void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
Douglas Gregoree75c052009-05-21 20:55:50 +0000264{
265 addContextsRecursively(DC);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000266 addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
267}
268
Mike Stump1eb44332009-09-09 15:08:12 +0000269//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000270void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
271{
272 if (const DeclContext* DC = dyn_cast<DeclContext>(D))
273 {
274 addContextsRecursively(DC);
275 addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
276 }
277 else
278 {
279 addToMap(Decls, D);
280 addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
281 }
282}
283
Mike Stump1eb44332009-09-09 15:08:12 +0000284//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000285void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
286{
287 addPtrAttribute(pName, static_cast<const DeclContext*>(D));
Douglas Gregoree75c052009-05-21 20:55:50 +0000288}
289
Mike Stump1eb44332009-09-09 15:08:12 +0000290//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000291void DocumentXML::addContextsRecursively(const DeclContext *DC)
292{
293 if (DC != 0 && addToMap(Contexts, DC))
294 {
295 addContextsRecursively(DC->getParent());
Mike Stump1eb44332009-09-09 15:08:12 +0000296 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000297}
298
Mike Stump1eb44332009-09-09 15:08:12 +0000299//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000300void DocumentXML::addSourceFileAttribute(const std::string& fileName)
301{
302 addToMap(SourceFiles, fileName, ID_FILE);
303 addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
304}
305
Douglas Gregor038f75a2009-06-15 19:02:54 +0000306
Mike Stump1eb44332009-09-09 15:08:12 +0000307//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000308void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
309{
310 addToMap(Labels, L, ID_LABEL);
311 addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
312}
313
314
Mike Stump1eb44332009-09-09 15:08:12 +0000315//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000316PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
317{
318 SourceManager& SM = Ctx->getSourceManager();
319 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
320 PresumedLoc PLoc;
Mike Stump1eb44332009-09-09 15:08:12 +0000321 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000322 {
323 PLoc = SM.getPresumedLoc(SpellingLoc);
324 addSourceFileAttribute(PLoc.getFilename());
325 addAttribute("line", PLoc.getLine());
326 addAttribute("col", PLoc.getColumn());
327 }
328 // else there is no error in some cases (eg. CXXThisExpr)
329 return PLoc;
330}
331
Mike Stump1eb44332009-09-09 15:08:12 +0000332//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000333void DocumentXML::addLocationRange(const SourceRange& R)
334{
335 PresumedLoc PStartLoc = addLocation(R.getBegin());
Mike Stump1eb44332009-09-09 15:08:12 +0000336 if (R.getBegin() != R.getEnd())
Douglas Gregoree75c052009-05-21 20:55:50 +0000337 {
338 SourceManager& SM = Ctx->getSourceManager();
339 SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
Mike Stump1eb44332009-09-09 15:08:12 +0000340 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000341 {
342 PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
Mike Stump1eb44332009-09-09 15:08:12 +0000343 if (PStartLoc.isInvalid() ||
Douglas Gregoree75c052009-05-21 20:55:50 +0000344 strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
345 addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
346 addAttribute("endfile", PLoc.getFilename());
347 addAttribute("endline", PLoc.getLine());
348 addAttribute("endcol", PLoc.getColumn());
349 } else if (PLoc.getLine() != PStartLoc.getLine()) {
350 addAttribute("endline", PLoc.getLine());
351 addAttribute("endcol", PLoc.getColumn());
352 } else {
353 addAttribute("endcol", PLoc.getColumn());
Mike Stump1eb44332009-09-09 15:08:12 +0000354 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000355 }
356 }
357}
358
Mike Stump1eb44332009-09-09 15:08:12 +0000359//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000360void DocumentXML::PrintDecl(Decl *D)
361{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000362 writeDeclToXML(D);
Douglas Gregoree75c052009-05-21 20:55:50 +0000363}
364
Mike Stump1eb44332009-09-09 15:08:12 +0000365//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000366} // NS clang
367