blob: 9ed10c8b4e89a620cd9e7f6a617f0c2559cfd3a9 [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"
Douglas Gregor4980afd2010-11-09 04:06:42 +000020#include <cstdio>
Douglas Gregoree75c052009-05-21 20:55:50 +000021
22namespace clang {
23
Mike Stump1eb44332009-09-09 15:08:12 +000024//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000025DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
Douglas Gregoree75c052009-05-21 20:55:50 +000026 Out(out),
27 Ctx(0),
Mike Stump1eb44332009-09-09 15:08:12 +000028 HasCurrentNodeSubNodes(false) {
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
Mike Stump1eb44332009-09-09 15:08:12 +000033//---------------------------------------------------------
34DocumentXML& DocumentXML::addSubNode(const std::string& name) {
Douglas Gregoree75c052009-05-21 20:55:50 +000035 if (!HasCurrentNodeSubNodes)
Douglas Gregoree75c052009-05-21 20:55:50 +000036 Out << ">\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000037 NodeStack.push(name);
Douglas Gregoree75c052009-05-21 20:55:50 +000038 HasCurrentNodeSubNodes = false;
Douglas Gregoree75c052009-05-21 20:55:50 +000039 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000040 Out << "<" << NodeStack.top();
Douglas Gregoree75c052009-05-21 20:55:50 +000041 return *this;
42}
43
Mike Stump1eb44332009-09-09 15:08:12 +000044//---------------------------------------------------------
45void DocumentXML::Indent() {
Douglas Gregor038f75a2009-06-15 19:02:54 +000046 for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
Douglas Gregoree75c052009-05-21 20:55:50 +000047 Out << ' ';
48}
49
Mike Stump1eb44332009-09-09 15:08:12 +000050//---------------------------------------------------------
51DocumentXML& DocumentXML::toParent() {
Mike Stump197c8d92009-09-16 20:41:09 +000052 assert(NodeStack.size() > 1 && "too much backtracking");
Douglas Gregoree75c052009-05-21 20:55:50 +000053
Mike Stump1eb44332009-09-09 15:08:12 +000054 if (HasCurrentNodeSubNodes) {
Douglas Gregoree75c052009-05-21 20:55:50 +000055 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000056 Out << "</" << NodeStack.top() << ">\n";
Mike Stump1eb44332009-09-09 15:08:12 +000057 } else
Douglas Gregoree75c052009-05-21 20:55:50 +000058 Out << "/>\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000059 NodeStack.pop();
Douglas Gregoree75c052009-05-21 20:55:50 +000060 HasCurrentNodeSubNodes = true;
Mike Stump1eb44332009-09-09 15:08:12 +000061 return *this;
Douglas Gregoree75c052009-05-21 20:55:50 +000062}
63
Mike Stump1eb44332009-09-09 15:08:12 +000064//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000065namespace {
66
Douglas Gregor038f75a2009-06-15 19:02:54 +000067enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
Douglas Gregoree75c052009-05-21 20:55:50 +000068
Mike Stump1eb44332009-09-09 15:08:12 +000069unsigned getNewId(tIdType idType) {
Douglas Gregoree75c052009-05-21 20:55:50 +000070 static unsigned int idCounts[ID_LAST] = { 0 };
71 return ++idCounts[idType];
72}
73
Mike Stump1eb44332009-09-09 15:08:12 +000074//---------------------------------------------------------
75inline std::string getPrefixedId(unsigned uId, tIdType idType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +000076 static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
Douglas Gregoree75c052009-05-21 20:55:50 +000077 char buffer[20];
78 char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
79 *--BufPtr = idPrefix[idType];
80 return BufPtr;
81}
82
Mike Stump1eb44332009-09-09 15:08:12 +000083//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000084template<class T, class V>
Mike Stump1eb44332009-09-09 15:08:12 +000085bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
Douglas Gregoree75c052009-05-21 20:55:50 +000086 typename T::iterator i = idMap.find(value);
87 bool toAdd = i == idMap.end();
Mike Stump1eb44332009-09-09 15:08:12 +000088 if (toAdd)
Douglas Gregoree75c052009-05-21 20:55:50 +000089 idMap.insert(typename T::value_type(value, getNewId(idType)));
Douglas Gregoree75c052009-05-21 20:55:50 +000090 return toAdd;
91}
92
93} // anon NS
94
Douglas Gregor038f75a2009-06-15 19:02:54 +000095
Mike Stump1eb44332009-09-09 15:08:12 +000096//---------------------------------------------------------
97std::string DocumentXML::escapeString(const char* pStr,
98 std::string::size_type len) {
Douglas Gregoree75c052009-05-21 20:55:50 +000099 std::string value;
100 value.reserve(len + 1);
101 char buffer[16];
102 for (unsigned i = 0; i < len; ++i) {
103 switch (char C = pStr[i]) {
104 default:
105 if (isprint(C))
106 value += C;
Mike Stump1eb44332009-09-09 15:08:12 +0000107 else {
Douglas Gregorb87b29e2010-11-09 04:38:09 +0000108#ifdef LLVM_ON_WIN32
109 sprintf(buffer, "\\%03o", C);
110#else
Douglas Gregor5e0fb352010-11-09 03:20:07 +0000111 snprintf(buffer, sizeof(buffer), "\\%03o", C);
Douglas Gregorb87b29e2010-11-09 04:38:09 +0000112#endif
Douglas Gregoree75c052009-05-21 20:55:50 +0000113 value += buffer;
114 }
115 break;
116
117 case '\n': value += "\\n"; break;
118 case '\t': value += "\\t"; break;
119 case '\a': value += "\\a"; break;
120 case '\b': value += "\\b"; break;
121 case '\r': value += "\\r"; break;
122
123 case '&': value += "&amp;"; break;
124 case '<': value += "&lt;"; break;
125 case '>': value += "&gt;"; break;
126 case '"': value += "&quot;"; break;
127 case '\'': value += "&apos;"; break;
128
129 }
130 }
131 return value;
132}
133
Mike Stump1eb44332009-09-09 15:08:12 +0000134//---------------------------------------------------------
135void DocumentXML::finalize() {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000136 assert(NodeStack.size() == 1 && "not completely backtracked");
Douglas Gregoree75c052009-05-21 20:55:50 +0000137
138 addSubNode("ReferenceSection");
139 addSubNode("Types");
140
Mike Stump1eb44332009-09-09 15:08:12 +0000141 for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
142 i != e; ++i) {
Douglas Gregora4923eb2009-11-16 21:35:15 +0000143 if (i->first.hasLocalQualifiers()) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000144 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000145 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000146 toParent();
147 }
148 }
149
Mike Stump1eb44332009-09-09 15:08:12 +0000150 for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
151 e = BasicTypes.end(); i != e; ++i) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000152 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000153 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
154 toParent();
155 }
156
157
158 toParent().addSubNode("Contexts");
159
Mike Stump1eb44332009-09-09 15:08:12 +0000160 for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
161 e = Contexts.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000162 addSubNode(i->first->getDeclKindName());
163 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000164 if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000165 addAttribute("name", ND->getNameAsString());
Mike Stump1eb44332009-09-09 15:08:12 +0000166 if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000167 addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000168 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
John McCall183700f2009-09-21 23:43:11 +0000169 addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000170
171 if (const DeclContext* parent = i->first->getParent())
Douglas Gregor038f75a2009-06-15 19:02:54 +0000172 addAttribute("context", parent);
Douglas Gregoree75c052009-05-21 20:55:50 +0000173 toParent();
174 }
175
176 toParent().addSubNode("Files");
177
Mike Stump1eb44332009-09-09 15:08:12 +0000178 for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
179 e = SourceFiles.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000180 addSubNode("File");
181 addAttribute("id", getPrefixedId(i->second, ID_FILE));
182 addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
183 toParent();
184 }
185
186 toParent().toParent();
Mike Stump1eb44332009-09-09 15:08:12 +0000187
Douglas Gregoree75c052009-05-21 20:55:50 +0000188 // write the root closing node (which has always subnodes)
Douglas Gregor038f75a2009-06-15 19:02:54 +0000189 Out << "</" << NodeStack.top() << ">\n";
Douglas Gregoree75c052009-05-21 20:55:50 +0000190}
191
Mike Stump1eb44332009-09-09 15:08:12 +0000192//---------------------------------------------------------
193void DocumentXML::addAttribute(const char* pAttributeName,
194 const QualType& pType) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000195 addTypeRecursively(pType);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000196 addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000197}
198
Mike Stump1eb44332009-09-09 15:08:12 +0000199//---------------------------------------------------------
200void DocumentXML::addPtrAttribute(const char* pAttributeName,
201 const Type* pType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000202 addTypeRecursively(pType);
203 addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000204}
205
Mike Stump1eb44332009-09-09 15:08:12 +0000206//---------------------------------------------------------
Douglas Gregor4bd98e82010-05-10 17:43:18 +0000207void DocumentXML::addPtrAttribute(const char* pAttributeName,
208 const NestedNameSpecifier* pNNS) {
209 switch (pNNS->getKind()) {
210 case NestedNameSpecifier::Identifier: {
211 IdentifierInfo *ii = pNNS->getAsIdentifier();
212 // FIXME how should we handle those ?
213 addPtrAttribute(pAttributeName, ii->getName().data());
214 break;
215 }
216 case NestedNameSpecifier::Namespace: {
217 addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
218 break;
219 }
220 case NestedNameSpecifier::TypeSpec: {
221 addPtrAttribute(pAttributeName, pNNS->getAsType());
222 break;
223 }
224 case NestedNameSpecifier::TypeSpecWithTemplate: {
225 addPtrAttribute(pAttributeName, pNNS->getAsType());
226 break;
227 }
228 case NestedNameSpecifier::Global: {
229 addPtrAttribute(pAttributeName, "::");
230 break;
231 }
232 }
233}
234
235//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000236void DocumentXML::addTypeRecursively(const QualType& pType)
237{
238 if (addToMap(Types, pType))
239 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000240 addTypeRecursively(pType.getTypePtr());
Douglas Gregoree75c052009-05-21 20:55:50 +0000241 // beautifier: a non-qualified type shall be transparent
Douglas Gregora4923eb2009-11-16 21:35:15 +0000242 if (!pType.hasLocalQualifiers())
Douglas Gregoree75c052009-05-21 20:55:50 +0000243 {
Mike Stump1eb44332009-09-09 15:08:12 +0000244 Types[pType] = BasicTypes[pType.getTypePtr()];
Douglas Gregoree75c052009-05-21 20:55:50 +0000245 }
246 }
247}
248
Mike Stump1eb44332009-09-09 15:08:12 +0000249//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000250void DocumentXML::addTypeRecursively(const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000251{
252 if (addToMap(BasicTypes, pType))
253 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000254 addParentTypes(pType);
255/*
256 // FIXME: doesn't work in the immediate streaming approach
Mike Stump1eb44332009-09-09 15:08:12 +0000257 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
Douglas Gregor038f75a2009-06-15 19:02:54 +0000258 {
259 addSubNode("VariableArraySizeExpression");
260 PrintStmt(VAT->getSizeExpr());
261 toParent();
Douglas Gregoree75c052009-05-21 20:55:50 +0000262 }
Douglas Gregor038f75a2009-06-15 19:02:54 +0000263*/
Douglas Gregoree75c052009-05-21 20:55:50 +0000264 }
265}
266
Mike Stump1eb44332009-09-09 15:08:12 +0000267//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000268void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
Douglas Gregoree75c052009-05-21 20:55:50 +0000269{
270 addContextsRecursively(DC);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000271 addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
272}
273
Mike Stump1eb44332009-09-09 15:08:12 +0000274//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000275void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
276{
277 if (const DeclContext* DC = dyn_cast<DeclContext>(D))
278 {
279 addContextsRecursively(DC);
280 addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
281 }
282 else
283 {
284 addToMap(Decls, D);
285 addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
286 }
287}
288
Mike Stump1eb44332009-09-09 15:08:12 +0000289//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000290void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
291{
292 addPtrAttribute(pName, static_cast<const DeclContext*>(D));
Douglas Gregoree75c052009-05-21 20:55:50 +0000293}
294
Mike Stump1eb44332009-09-09 15:08:12 +0000295//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000296void DocumentXML::addContextsRecursively(const DeclContext *DC)
297{
298 if (DC != 0 && addToMap(Contexts, DC))
299 {
300 addContextsRecursively(DC->getParent());
Mike Stump1eb44332009-09-09 15:08:12 +0000301 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000302}
303
Mike Stump1eb44332009-09-09 15:08:12 +0000304//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000305void DocumentXML::addSourceFileAttribute(const std::string& fileName)
306{
307 addToMap(SourceFiles, fileName, ID_FILE);
308 addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
309}
310
Douglas Gregor038f75a2009-06-15 19:02:54 +0000311
Mike Stump1eb44332009-09-09 15:08:12 +0000312//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000313void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
314{
315 addToMap(Labels, L, ID_LABEL);
316 addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
317}
318
319
Mike Stump1eb44332009-09-09 15:08:12 +0000320//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000321PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
322{
323 SourceManager& SM = Ctx->getSourceManager();
324 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
325 PresumedLoc PLoc;
Mike Stump1eb44332009-09-09 15:08:12 +0000326 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000327 {
328 PLoc = SM.getPresumedLoc(SpellingLoc);
329 addSourceFileAttribute(PLoc.getFilename());
330 addAttribute("line", PLoc.getLine());
331 addAttribute("col", PLoc.getColumn());
332 }
333 // else there is no error in some cases (eg. CXXThisExpr)
334 return PLoc;
335}
336
Mike Stump1eb44332009-09-09 15:08:12 +0000337//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000338void DocumentXML::addLocationRange(const SourceRange& R)
339{
340 PresumedLoc PStartLoc = addLocation(R.getBegin());
Mike Stump1eb44332009-09-09 15:08:12 +0000341 if (R.getBegin() != R.getEnd())
Douglas Gregoree75c052009-05-21 20:55:50 +0000342 {
343 SourceManager& SM = Ctx->getSourceManager();
344 SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
Mike Stump1eb44332009-09-09 15:08:12 +0000345 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000346 {
347 PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
Mike Stump1eb44332009-09-09 15:08:12 +0000348 if (PStartLoc.isInvalid() ||
Douglas Gregoree75c052009-05-21 20:55:50 +0000349 strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
350 addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
351 addAttribute("endfile", PLoc.getFilename());
352 addAttribute("endline", PLoc.getLine());
353 addAttribute("endcol", PLoc.getColumn());
354 } else if (PLoc.getLine() != PStartLoc.getLine()) {
355 addAttribute("endline", PLoc.getLine());
356 addAttribute("endcol", PLoc.getColumn());
357 } else {
358 addAttribute("endcol", PLoc.getColumn());
Mike Stump1eb44332009-09-09 15:08:12 +0000359 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000360 }
361 }
362}
363
Mike Stump1eb44332009-09-09 15:08:12 +0000364//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000365void DocumentXML::PrintDecl(Decl *D)
366{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000367 writeDeclToXML(D);
Douglas Gregoree75c052009-05-21 20:55:50 +0000368}
369
Mike Stump1eb44332009-09-09 15:08:12 +0000370//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000371} // NS clang
372