blob: 2f7e995b208f900ec338fbcb0682f540315d5857 [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 Gregor6665ffb2010-11-09 05:43:53 +000020#include "llvm/Config/config.h"
Douglas Gregor4980afd2010-11-09 04:06:42 +000021#include <cstdio>
Douglas Gregoree75c052009-05-21 20:55:50 +000022
23namespace clang {
24
Mike Stump1eb44332009-09-09 15:08:12 +000025//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000026DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
Douglas Gregoree75c052009-05-21 20:55:50 +000027 Out(out),
28 Ctx(0),
Mike Stump1eb44332009-09-09 15:08:12 +000029 HasCurrentNodeSubNodes(false) {
Douglas Gregor038f75a2009-06-15 19:02:54 +000030 NodeStack.push(rootName);
Douglas Gregoree75c052009-05-21 20:55:50 +000031 Out << "<?xml version=\"1.0\"?>\n<" << rootName;
32}
33
Mike Stump1eb44332009-09-09 15:08:12 +000034//---------------------------------------------------------
35DocumentXML& DocumentXML::addSubNode(const std::string& name) {
Douglas Gregoree75c052009-05-21 20:55:50 +000036 if (!HasCurrentNodeSubNodes)
Douglas Gregoree75c052009-05-21 20:55:50 +000037 Out << ">\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000038 NodeStack.push(name);
Douglas Gregoree75c052009-05-21 20:55:50 +000039 HasCurrentNodeSubNodes = false;
Douglas Gregoree75c052009-05-21 20:55:50 +000040 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000041 Out << "<" << NodeStack.top();
Douglas Gregoree75c052009-05-21 20:55:50 +000042 return *this;
43}
44
Mike Stump1eb44332009-09-09 15:08:12 +000045//---------------------------------------------------------
46void DocumentXML::Indent() {
Douglas Gregor038f75a2009-06-15 19:02:54 +000047 for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
Douglas Gregoree75c052009-05-21 20:55:50 +000048 Out << ' ';
49}
50
Mike Stump1eb44332009-09-09 15:08:12 +000051//---------------------------------------------------------
52DocumentXML& DocumentXML::toParent() {
Mike Stump197c8d92009-09-16 20:41:09 +000053 assert(NodeStack.size() > 1 && "too much backtracking");
Douglas Gregoree75c052009-05-21 20:55:50 +000054
Mike Stump1eb44332009-09-09 15:08:12 +000055 if (HasCurrentNodeSubNodes) {
Douglas Gregoree75c052009-05-21 20:55:50 +000056 Indent();
Douglas Gregor038f75a2009-06-15 19:02:54 +000057 Out << "</" << NodeStack.top() << ">\n";
Mike Stump1eb44332009-09-09 15:08:12 +000058 } else
Douglas Gregoree75c052009-05-21 20:55:50 +000059 Out << "/>\n";
Douglas Gregor038f75a2009-06-15 19:02:54 +000060 NodeStack.pop();
Douglas Gregoree75c052009-05-21 20:55:50 +000061 HasCurrentNodeSubNodes = true;
Mike Stump1eb44332009-09-09 15:08:12 +000062 return *this;
Douglas Gregoree75c052009-05-21 20:55:50 +000063}
64
Mike Stump1eb44332009-09-09 15:08:12 +000065//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000066namespace {
67
Douglas Gregor038f75a2009-06-15 19:02:54 +000068enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
Douglas Gregoree75c052009-05-21 20:55:50 +000069
Mike Stump1eb44332009-09-09 15:08:12 +000070unsigned getNewId(tIdType idType) {
Douglas Gregoree75c052009-05-21 20:55:50 +000071 static unsigned int idCounts[ID_LAST] = { 0 };
72 return ++idCounts[idType];
73}
74
Mike Stump1eb44332009-09-09 15:08:12 +000075//---------------------------------------------------------
76inline std::string getPrefixedId(unsigned uId, tIdType idType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +000077 static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
Douglas Gregoree75c052009-05-21 20:55:50 +000078 char buffer[20];
79 char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
80 *--BufPtr = idPrefix[idType];
81 return BufPtr;
82}
83
Mike Stump1eb44332009-09-09 15:08:12 +000084//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +000085template<class T, class V>
Mike Stump1eb44332009-09-09 15:08:12 +000086bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
Douglas Gregoree75c052009-05-21 20:55:50 +000087 typename T::iterator i = idMap.find(value);
88 bool toAdd = i == idMap.end();
Mike Stump1eb44332009-09-09 15:08:12 +000089 if (toAdd)
Douglas Gregoree75c052009-05-21 20:55:50 +000090 idMap.insert(typename T::value_type(value, getNewId(idType)));
Douglas Gregoree75c052009-05-21 20:55:50 +000091 return toAdd;
92}
93
94} // anon NS
95
Douglas Gregor038f75a2009-06-15 19:02:54 +000096
Mike Stump1eb44332009-09-09 15:08:12 +000097//---------------------------------------------------------
98std::string DocumentXML::escapeString(const char* pStr,
99 std::string::size_type len) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000100 std::string value;
101 value.reserve(len + 1);
102 char buffer[16];
103 for (unsigned i = 0; i < len; ++i) {
104 switch (char C = pStr[i]) {
105 default:
106 if (isprint(C))
107 value += C;
Mike Stump1eb44332009-09-09 15:08:12 +0000108 else {
Douglas Gregorb87b29e2010-11-09 04:38:09 +0000109#ifdef LLVM_ON_WIN32
110 sprintf(buffer, "\\%03o", C);
111#else
Douglas Gregor5e0fb352010-11-09 03:20:07 +0000112 snprintf(buffer, sizeof(buffer), "\\%03o", C);
Douglas Gregorb87b29e2010-11-09 04:38:09 +0000113#endif
Douglas Gregoree75c052009-05-21 20:55:50 +0000114 value += buffer;
115 }
116 break;
117
118 case '\n': value += "\\n"; break;
119 case '\t': value += "\\t"; break;
120 case '\a': value += "\\a"; break;
121 case '\b': value += "\\b"; break;
122 case '\r': value += "\\r"; break;
123
124 case '&': value += "&amp;"; break;
125 case '<': value += "&lt;"; break;
126 case '>': value += "&gt;"; break;
127 case '"': value += "&quot;"; break;
128 case '\'': value += "&apos;"; break;
129
130 }
131 }
132 return value;
133}
134
Mike Stump1eb44332009-09-09 15:08:12 +0000135//---------------------------------------------------------
136void DocumentXML::finalize() {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000137 assert(NodeStack.size() == 1 && "not completely backtracked");
Douglas Gregoree75c052009-05-21 20:55:50 +0000138
139 addSubNode("ReferenceSection");
140 addSubNode("Types");
141
Mike Stump1eb44332009-09-09 15:08:12 +0000142 for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
143 i != e; ++i) {
Douglas Gregora4923eb2009-11-16 21:35:15 +0000144 if (i->first.hasLocalQualifiers()) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000145 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000146 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000147 toParent();
148 }
149 }
150
Mike Stump1eb44332009-09-09 15:08:12 +0000151 for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
152 e = BasicTypes.end(); i != e; ++i) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000153 writeTypeToXML(i->first);
Douglas Gregoree75c052009-05-21 20:55:50 +0000154 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
155 toParent();
156 }
157
158
159 toParent().addSubNode("Contexts");
160
Mike Stump1eb44332009-09-09 15:08:12 +0000161 for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
162 e = Contexts.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000163 addSubNode(i->first->getDeclKindName());
164 addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000165 if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000166 addAttribute("name", ND->getNameAsString());
Mike Stump1eb44332009-09-09 15:08:12 +0000167 if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
Douglas Gregoree75c052009-05-21 20:55:50 +0000168 addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
Mike Stump1eb44332009-09-09 15:08:12 +0000169 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
John McCall183700f2009-09-21 23:43:11 +0000170 addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000171
172 if (const DeclContext* parent = i->first->getParent())
Douglas Gregor038f75a2009-06-15 19:02:54 +0000173 addAttribute("context", parent);
Douglas Gregoree75c052009-05-21 20:55:50 +0000174 toParent();
175 }
176
177 toParent().addSubNode("Files");
178
Mike Stump1eb44332009-09-09 15:08:12 +0000179 for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
180 e = SourceFiles.end(); i != e; ++i) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000181 addSubNode("File");
182 addAttribute("id", getPrefixedId(i->second, ID_FILE));
183 addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
184 toParent();
185 }
186
187 toParent().toParent();
Mike Stump1eb44332009-09-09 15:08:12 +0000188
Douglas Gregoree75c052009-05-21 20:55:50 +0000189 // write the root closing node (which has always subnodes)
Douglas Gregor038f75a2009-06-15 19:02:54 +0000190 Out << "</" << NodeStack.top() << ">\n";
Douglas Gregoree75c052009-05-21 20:55:50 +0000191}
192
Mike Stump1eb44332009-09-09 15:08:12 +0000193//---------------------------------------------------------
194void DocumentXML::addAttribute(const char* pAttributeName,
195 const QualType& pType) {
Douglas Gregoree75c052009-05-21 20:55:50 +0000196 addTypeRecursively(pType);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000197 addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000198}
199
Mike Stump1eb44332009-09-09 15:08:12 +0000200//---------------------------------------------------------
201void DocumentXML::addPtrAttribute(const char* pAttributeName,
202 const Type* pType) {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000203 addTypeRecursively(pType);
204 addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
Douglas Gregoree75c052009-05-21 20:55:50 +0000205}
206
Mike Stump1eb44332009-09-09 15:08:12 +0000207//---------------------------------------------------------
Douglas Gregor4bd98e82010-05-10 17:43:18 +0000208void DocumentXML::addPtrAttribute(const char* pAttributeName,
209 const NestedNameSpecifier* pNNS) {
210 switch (pNNS->getKind()) {
211 case NestedNameSpecifier::Identifier: {
212 IdentifierInfo *ii = pNNS->getAsIdentifier();
213 // FIXME how should we handle those ?
214 addPtrAttribute(pAttributeName, ii->getName().data());
215 break;
216 }
217 case NestedNameSpecifier::Namespace: {
218 addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
219 break;
220 }
221 case NestedNameSpecifier::TypeSpec: {
222 addPtrAttribute(pAttributeName, pNNS->getAsType());
223 break;
224 }
225 case NestedNameSpecifier::TypeSpecWithTemplate: {
226 addPtrAttribute(pAttributeName, pNNS->getAsType());
227 break;
228 }
229 case NestedNameSpecifier::Global: {
230 addPtrAttribute(pAttributeName, "::");
231 break;
232 }
233 }
234}
235
236//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000237void DocumentXML::addTypeRecursively(const QualType& pType)
238{
239 if (addToMap(Types, pType))
240 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000241 addTypeRecursively(pType.getTypePtr());
Douglas Gregoree75c052009-05-21 20:55:50 +0000242 // beautifier: a non-qualified type shall be transparent
Douglas Gregora4923eb2009-11-16 21:35:15 +0000243 if (!pType.hasLocalQualifiers())
Douglas Gregoree75c052009-05-21 20:55:50 +0000244 {
Mike Stump1eb44332009-09-09 15:08:12 +0000245 Types[pType] = BasicTypes[pType.getTypePtr()];
Douglas Gregoree75c052009-05-21 20:55:50 +0000246 }
247 }
248}
249
Mike Stump1eb44332009-09-09 15:08:12 +0000250//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000251void DocumentXML::addTypeRecursively(const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000252{
253 if (addToMap(BasicTypes, pType))
254 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000255 addParentTypes(pType);
256/*
257 // FIXME: doesn't work in the immediate streaming approach
Mike Stump1eb44332009-09-09 15:08:12 +0000258 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
Douglas Gregor038f75a2009-06-15 19:02:54 +0000259 {
260 addSubNode("VariableArraySizeExpression");
261 PrintStmt(VAT->getSizeExpr());
262 toParent();
Douglas Gregoree75c052009-05-21 20:55:50 +0000263 }
Douglas Gregor038f75a2009-06-15 19:02:54 +0000264*/
Douglas Gregoree75c052009-05-21 20:55:50 +0000265 }
266}
267
Mike Stump1eb44332009-09-09 15:08:12 +0000268//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000269void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
Douglas Gregoree75c052009-05-21 20:55:50 +0000270{
271 addContextsRecursively(DC);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000272 addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
273}
274
Mike Stump1eb44332009-09-09 15:08:12 +0000275//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000276void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
277{
278 if (const DeclContext* DC = dyn_cast<DeclContext>(D))
279 {
280 addContextsRecursively(DC);
281 addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
282 }
283 else
284 {
285 addToMap(Decls, D);
286 addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
287 }
288}
289
Mike Stump1eb44332009-09-09 15:08:12 +0000290//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000291void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
292{
293 addPtrAttribute(pName, static_cast<const DeclContext*>(D));
Douglas Gregoree75c052009-05-21 20:55:50 +0000294}
295
Mike Stump1eb44332009-09-09 15:08:12 +0000296//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000297void DocumentXML::addContextsRecursively(const DeclContext *DC)
298{
299 if (DC != 0 && addToMap(Contexts, DC))
300 {
301 addContextsRecursively(DC->getParent());
Mike Stump1eb44332009-09-09 15:08:12 +0000302 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000303}
304
Mike Stump1eb44332009-09-09 15:08:12 +0000305//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000306void DocumentXML::addSourceFileAttribute(const std::string& fileName)
307{
308 addToMap(SourceFiles, fileName, ID_FILE);
309 addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
310}
311
Douglas Gregor038f75a2009-06-15 19:02:54 +0000312
Mike Stump1eb44332009-09-09 15:08:12 +0000313//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000314void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
315{
316 addToMap(Labels, L, ID_LABEL);
317 addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
318}
319
320
Mike Stump1eb44332009-09-09 15:08:12 +0000321//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000322PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
323{
324 SourceManager& SM = Ctx->getSourceManager();
325 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
326 PresumedLoc PLoc;
Mike Stump1eb44332009-09-09 15:08:12 +0000327 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000328 {
329 PLoc = SM.getPresumedLoc(SpellingLoc);
330 addSourceFileAttribute(PLoc.getFilename());
331 addAttribute("line", PLoc.getLine());
332 addAttribute("col", PLoc.getColumn());
333 }
334 // else there is no error in some cases (eg. CXXThisExpr)
335 return PLoc;
336}
337
Mike Stump1eb44332009-09-09 15:08:12 +0000338//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000339void DocumentXML::addLocationRange(const SourceRange& R)
340{
341 PresumedLoc PStartLoc = addLocation(R.getBegin());
Mike Stump1eb44332009-09-09 15:08:12 +0000342 if (R.getBegin() != R.getEnd())
Douglas Gregoree75c052009-05-21 20:55:50 +0000343 {
344 SourceManager& SM = Ctx->getSourceManager();
345 SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
Mike Stump1eb44332009-09-09 15:08:12 +0000346 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000347 {
348 PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
Mike Stump1eb44332009-09-09 15:08:12 +0000349 if (PStartLoc.isInvalid() ||
Douglas Gregoree75c052009-05-21 20:55:50 +0000350 strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
351 addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
352 addAttribute("endfile", PLoc.getFilename());
353 addAttribute("endline", PLoc.getLine());
354 addAttribute("endcol", PLoc.getColumn());
355 } else if (PLoc.getLine() != PStartLoc.getLine()) {
356 addAttribute("endline", PLoc.getLine());
357 addAttribute("endcol", PLoc.getColumn());
358 } else {
359 addAttribute("endcol", PLoc.getColumn());
Mike Stump1eb44332009-09-09 15:08:12 +0000360 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000361 }
362 }
363}
364
Mike Stump1eb44332009-09-09 15:08:12 +0000365//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000366void DocumentXML::PrintDecl(Decl *D)
367{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000368 writeDeclToXML(D);
Douglas Gregoree75c052009-05-21 20:55:50 +0000369}
370
Mike Stump1eb44332009-09-09 15:08:12 +0000371//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000372} // NS clang
373