blob: 0263c30bfd57a1bd86c56e88e9f96449edd7bd35 [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 Gregoree75c052009-05-21 20:55:50 +0000202void DocumentXML::addTypeRecursively(const QualType& pType)
203{
204 if (addToMap(Types, pType))
205 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000206 addTypeRecursively(pType.getTypePtr());
Douglas Gregoree75c052009-05-21 20:55:50 +0000207 // beautifier: a non-qualified type shall be transparent
Douglas Gregora4923eb2009-11-16 21:35:15 +0000208 if (!pType.hasLocalQualifiers())
Douglas Gregoree75c052009-05-21 20:55:50 +0000209 {
Mike Stump1eb44332009-09-09 15:08:12 +0000210 Types[pType] = BasicTypes[pType.getTypePtr()];
Douglas Gregoree75c052009-05-21 20:55:50 +0000211 }
212 }
213}
214
Mike Stump1eb44332009-09-09 15:08:12 +0000215//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000216void DocumentXML::addTypeRecursively(const Type* pType)
Douglas Gregoree75c052009-05-21 20:55:50 +0000217{
218 if (addToMap(BasicTypes, pType))
219 {
Douglas Gregor038f75a2009-06-15 19:02:54 +0000220 addParentTypes(pType);
221/*
222 // FIXME: doesn't work in the immediate streaming approach
Mike Stump1eb44332009-09-09 15:08:12 +0000223 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
Douglas Gregor038f75a2009-06-15 19:02:54 +0000224 {
225 addSubNode("VariableArraySizeExpression");
226 PrintStmt(VAT->getSizeExpr());
227 toParent();
Douglas Gregoree75c052009-05-21 20:55:50 +0000228 }
Douglas Gregor038f75a2009-06-15 19:02:54 +0000229*/
Douglas Gregoree75c052009-05-21 20:55:50 +0000230 }
231}
232
Mike Stump1eb44332009-09-09 15:08:12 +0000233//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000234void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
Douglas Gregoree75c052009-05-21 20:55:50 +0000235{
236 addContextsRecursively(DC);
Douglas Gregor038f75a2009-06-15 19:02:54 +0000237 addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
238}
239
Mike Stump1eb44332009-09-09 15:08:12 +0000240//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000241void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
242{
243 if (const DeclContext* DC = dyn_cast<DeclContext>(D))
244 {
245 addContextsRecursively(DC);
246 addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
247 }
248 else
249 {
250 addToMap(Decls, D);
251 addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
252 }
253}
254
Mike Stump1eb44332009-09-09 15:08:12 +0000255//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000256void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
257{
258 addPtrAttribute(pName, static_cast<const DeclContext*>(D));
Douglas Gregoree75c052009-05-21 20:55:50 +0000259}
260
Mike Stump1eb44332009-09-09 15:08:12 +0000261//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000262void DocumentXML::addContextsRecursively(const DeclContext *DC)
263{
264 if (DC != 0 && addToMap(Contexts, DC))
265 {
266 addContextsRecursively(DC->getParent());
Mike Stump1eb44332009-09-09 15:08:12 +0000267 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000268}
269
Mike Stump1eb44332009-09-09 15:08:12 +0000270//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000271void DocumentXML::addSourceFileAttribute(const std::string& fileName)
272{
273 addToMap(SourceFiles, fileName, ID_FILE);
274 addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
275}
276
Douglas Gregor038f75a2009-06-15 19:02:54 +0000277
Mike Stump1eb44332009-09-09 15:08:12 +0000278//---------------------------------------------------------
Douglas Gregor038f75a2009-06-15 19:02:54 +0000279void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
280{
281 addToMap(Labels, L, ID_LABEL);
282 addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
283}
284
285
Mike Stump1eb44332009-09-09 15:08:12 +0000286//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000287PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
288{
289 SourceManager& SM = Ctx->getSourceManager();
290 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
291 PresumedLoc PLoc;
Mike Stump1eb44332009-09-09 15:08:12 +0000292 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000293 {
294 PLoc = SM.getPresumedLoc(SpellingLoc);
295 addSourceFileAttribute(PLoc.getFilename());
296 addAttribute("line", PLoc.getLine());
297 addAttribute("col", PLoc.getColumn());
298 }
299 // else there is no error in some cases (eg. CXXThisExpr)
300 return PLoc;
301}
302
Mike Stump1eb44332009-09-09 15:08:12 +0000303//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000304void DocumentXML::addLocationRange(const SourceRange& R)
305{
306 PresumedLoc PStartLoc = addLocation(R.getBegin());
Mike Stump1eb44332009-09-09 15:08:12 +0000307 if (R.getBegin() != R.getEnd())
Douglas Gregoree75c052009-05-21 20:55:50 +0000308 {
309 SourceManager& SM = Ctx->getSourceManager();
310 SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
Mike Stump1eb44332009-09-09 15:08:12 +0000311 if (!SpellingLoc.isInvalid())
Douglas Gregoree75c052009-05-21 20:55:50 +0000312 {
313 PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
Mike Stump1eb44332009-09-09 15:08:12 +0000314 if (PStartLoc.isInvalid() ||
Douglas Gregoree75c052009-05-21 20:55:50 +0000315 strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
316 addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
317 addAttribute("endfile", PLoc.getFilename());
318 addAttribute("endline", PLoc.getLine());
319 addAttribute("endcol", PLoc.getColumn());
320 } else if (PLoc.getLine() != PStartLoc.getLine()) {
321 addAttribute("endline", PLoc.getLine());
322 addAttribute("endcol", PLoc.getColumn());
323 } else {
324 addAttribute("endcol", PLoc.getColumn());
Mike Stump1eb44332009-09-09 15:08:12 +0000325 }
Douglas Gregoree75c052009-05-21 20:55:50 +0000326 }
327 }
328}
329
Mike Stump1eb44332009-09-09 15:08:12 +0000330//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000331void DocumentXML::PrintDecl(Decl *D)
332{
Douglas Gregor038f75a2009-06-15 19:02:54 +0000333 writeDeclToXML(D);
Douglas Gregoree75c052009-05-21 20:55:50 +0000334}
335
Mike Stump1eb44332009-09-09 15:08:12 +0000336//---------------------------------------------------------
Douglas Gregoree75c052009-05-21 20:55:50 +0000337} // NS clang
338