summaryrefslogtreecommitdiffstats
path: root/lib/Frontend/DocumentXML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend/DocumentXML.cpp')
-rw-r--r--lib/Frontend/DocumentXML.cpp579
1 files changed, 579 insertions, 0 deletions
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
new file mode 100644
index 0000000..7562d2a
--- /dev/null
+++ b/lib/Frontend/DocumentXML.cpp
@@ -0,0 +1,579 @@
+//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+
+//---------------------------------------------------------
+struct DocumentXML::NodeXML
+{
+ std::string Name;
+ NodeXML* Parent;
+
+ NodeXML(const std::string& name, NodeXML* parent) :
+ Name(name),
+ Parent(parent)
+ {}
+};
+
+//---------------------------------------------------------
+DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
+ Root(new NodeXML(rootName, 0)),
+ CurrentNode(Root),
+ Out(out),
+ Ctx(0),
+ CurrentIndent(0),
+ HasCurrentNodeSubNodes(false)
+{
+ Out << "<?xml version=\"1.0\"?>\n<" << rootName;
+}
+
+//---------------------------------------------------------
+DocumentXML::~DocumentXML()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+ delete Root;
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::addSubNode(const std::string& name)
+{
+ if (!HasCurrentNodeSubNodes)
+ {
+ Out << ">\n";
+ }
+ CurrentNode = new NodeXML(name, CurrentNode);
+ HasCurrentNodeSubNodes = false;
+ CurrentIndent += 2;
+ Indent();
+ Out << "<" << CurrentNode->Name;
+ return *this;
+}
+
+//---------------------------------------------------------
+void DocumentXML::Indent()
+{
+ for (int i = 0; i < CurrentIndent; ++i)
+ Out << ' ';
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::toParent()
+{
+ assert(CurrentNode != Root && "to much backtracking");
+
+ if (HasCurrentNodeSubNodes)
+ {
+ Indent();
+ Out << "</" << CurrentNode->Name << ">\n";
+ }
+ else
+ {
+ Out << "/>\n";
+ }
+ NodeXML* NodeToDelete = CurrentNode;
+ CurrentNode = CurrentNode->Parent;
+ delete NodeToDelete;
+ HasCurrentNodeSubNodes = true;
+ CurrentIndent -= 2;
+ return *this;
+}
+
+//---------------------------------------------------------
+namespace {
+
+enum tIdType { ID_NORMAL, ID_FILE, ID_LAST };
+
+unsigned getNewId(tIdType idType)
+{
+ static unsigned int idCounts[ID_LAST] = { 0 };
+ return ++idCounts[idType];
+}
+
+//---------------------------------------------------------
+inline std::string getPrefixedId(unsigned uId, tIdType idType)
+{
+ static const char idPrefix[ID_LAST] = { '_', 'f' };
+ char buffer[20];
+ char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
+ *--BufPtr = idPrefix[idType];
+ return BufPtr;
+}
+
+//---------------------------------------------------------
+template<class T, class V>
+bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL)
+{
+ typename T::iterator i = idMap.find(value);
+ bool toAdd = i == idMap.end();
+ if (toAdd)
+ {
+ idMap.insert(typename T::value_type(value, getNewId(idType)));
+ }
+ return toAdd;
+}
+
+} // anon NS
+
+//---------------------------------------------------------
+std::string DocumentXML::escapeString(const char* pStr, std::string::size_type len)
+{
+ std::string value;
+ value.reserve(len + 1);
+ char buffer[16];
+ for (unsigned i = 0; i < len; ++i) {
+ switch (char C = pStr[i]) {
+ default:
+ if (isprint(C))
+ value += C;
+ else
+ {
+ sprintf(buffer, "\\%03o", C);
+ value += buffer;
+ }
+ break;
+
+ case '\n': value += "\\n"; break;
+ case '\t': value += "\\t"; break;
+ case '\a': value += "\\a"; break;
+ case '\b': value += "\\b"; break;
+ case '\r': value += "\\r"; break;
+
+ case '&': value += "&amp;"; break;
+ case '<': value += "&lt;"; break;
+ case '>': value += "&gt;"; break;
+ case '"': value += "&quot;"; break;
+ case '\'': value += "&apos;"; break;
+
+ }
+ }
+ return value;
+}
+
+//---------------------------------------------------------
+void DocumentXML::finalize()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+
+ addSubNode("ReferenceSection");
+ addSubNode("Types");
+
+ for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i)
+ {
+ if (i->first.getCVRQualifiers() != 0)
+ {
+ addSubNode("CvQualifiedType");
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ addAttribute("type", getPrefixedId(BasicTypes[i->first.getTypePtr()], ID_NORMAL));
+ if (i->first.isConstQualified()) addAttribute("const", "1");
+ if (i->first.isVolatileQualified()) addAttribute("volatile", "1");
+ if (i->first.isRestrictQualified()) addAttribute("restrict", "1");
+ toParent();
+ }
+ }
+
+ for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i)
+ {
+ // don't use the get methods as they strip of typedef infos
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(i->first)) {
+ addSubNode("FundamentalType");
+ addAttribute("name", BT->getName(Ctx->getLangOptions().CPlusPlus));
+ }
+ else if (const PointerType *PT = dyn_cast<PointerType>(i->first)) {
+ addSubNode("PointerType");
+ addTypeAttribute(PT->getPointeeType());
+ }
+ else if (dyn_cast<FunctionType>(i->first) != 0) {
+ addSubNode("FunctionType");
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(i->first)) {
+ addSubNode("ReferenceType");
+ addTypeAttribute(RT->getPointeeType());
+ }
+ else if (const TypedefType * TT = dyn_cast<TypedefType>(i->first)) {
+ addSubNode("Typedef");
+ addAttribute("name", TT->getDecl()->getNameAsString());
+ addTypeAttribute(TT->getDecl()->getUnderlyingType());
+ addContextAttribute(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(i->first)) {
+ addSubNode("QualifiedNameType");
+ addTypeAttribute(QT->getNamedType());
+ }
+ else if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(i->first)) {
+ addSubNode("ArrayType");
+ addAttribute("min", 0);
+ addAttribute("max", (CAT->getSize() - 1).toString(10, false));
+ addTypeAttribute(CAT->getElementType());
+ }
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(i->first)) {
+ addSubNode("VariableArrayType");
+ addTypeAttribute(VAT->getElementType());
+ }
+ else if (const TagType *RET = dyn_cast<TagType>(i->first)) {
+ const TagDecl *tagDecl = RET->getDecl();
+ std::string tagKind = tagDecl->getKindName();
+ tagKind[0] = std::toupper(tagKind[0]);
+ addSubNode(tagKind);
+ addAttribute("name", tagDecl->getNameAsString());
+ addContextAttribute(tagDecl->getDeclContext());
+ }
+ else if (const VectorType* VT = dyn_cast<VectorType>(i->first)) {
+ addSubNode("VectorType");
+ addTypeAttribute(VT->getElementType());
+ addAttribute("num_elements", VT->getNumElements());
+ }
+ else
+ {
+ addSubNode("FIXMEType");
+ }
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ toParent();
+ }
+
+
+ toParent().addSubNode("Contexts");
+
+ for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), e = Contexts.end(); i != e; ++i)
+ {
+ addSubNode(i->first->getDeclKindName());
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first)) {
+ addAttribute("name", ND->getNameAsString());
+ }
+ if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) {
+ addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
+ }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first)) {
+ addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAsFunctionType()], ID_NORMAL));
+ }
+
+ if (const DeclContext* parent = i->first->getParent())
+ {
+ addContextAttribute(parent);
+ }
+ toParent();
+ }
+
+ toParent().addSubNode("Files");
+
+ for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), e = SourceFiles.end(); i != e; ++i)
+ {
+ addSubNode("File");
+ addAttribute("id", getPrefixedId(i->second, ID_FILE));
+ addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
+ toParent();
+ }
+
+ toParent().toParent();
+
+ // write the root closing node (which has always subnodes)
+ Out << "</" << CurrentNode->Name << ">\n";
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeAttribute(const QualType& pType)
+{
+ addTypeRecursively(pType);
+ addAttribute("type", getPrefixedId(Types[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeIdAttribute(const Type* pType)
+{
+ addBasicTypeRecursively(pType);
+ addAttribute("id", getPrefixedId(BasicTypes[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeRecursively(const QualType& pType)
+{
+ if (addToMap(Types, pType))
+ {
+ addBasicTypeRecursively(pType.getTypePtr());
+ // beautifier: a non-qualified type shall be transparent
+ if (pType.getCVRQualifiers() == 0)
+ {
+ Types[pType] = BasicTypes[pType.getTypePtr()];
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addBasicTypeRecursively(const Type* pType)
+{
+ if (addToMap(BasicTypes, pType))
+ {
+ if (const PointerType *PT = dyn_cast<PointerType>(pType)) {
+ addTypeRecursively(PT->getPointeeType());
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(pType)) {
+ addTypeRecursively(RT->getPointeeType());
+ }
+ else if (const TypedefType *TT = dyn_cast<TypedefType>(pType)) {
+ addTypeRecursively(TT->getDecl()->getUnderlyingType());
+ addContextsRecursively(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(pType)) {
+ addTypeRecursively(QT->getNamedType());
+ // FIXME: what to do with NestedNameSpecifier or shall this type be transparent?
+ }
+ else if (const ArrayType *AT = dyn_cast<ArrayType>(pType)) {
+ addTypeRecursively(AT->getElementType());
+ // FIXME: doesn't work in the immediate streaming approach
+ /*if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ {
+ addSubNode("VariableArraySizeExpression");
+ PrintStmt(VAT->getSizeExpr());
+ toParent();
+ }*/
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextAttribute(const DeclContext *DC, tContextUsage usage)
+{
+ addContextsRecursively(DC);
+ const char* pAttributeTags[2] = { "context", "id" };
+ addAttribute(pAttributeTags[usage], getPrefixedId(Contexts[DC], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextsRecursively(const DeclContext *DC)
+{
+ if (DC != 0 && addToMap(Contexts, DC))
+ {
+ addContextsRecursively(DC->getParent());
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addSourceFileAttribute(const std::string& fileName)
+{
+ addToMap(SourceFiles, fileName, ID_FILE);
+ addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
+}
+
+//---------------------------------------------------------
+PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
+{
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ PresumedLoc PLoc;
+ if (!SpellingLoc.isInvalid())
+ {
+ PLoc = SM.getPresumedLoc(SpellingLoc);
+ addSourceFileAttribute(PLoc.getFilename());
+ addAttribute("line", PLoc.getLine());
+ addAttribute("col", PLoc.getColumn());
+ }
+ // else there is no error in some cases (eg. CXXThisExpr)
+ return PLoc;
+}
+
+//---------------------------------------------------------
+void DocumentXML::addLocationRange(const SourceRange& R)
+{
+ PresumedLoc PStartLoc = addLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd())
+ {
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
+ if (!SpellingLoc.isInvalid())
+ {
+ PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
+ if (PStartLoc.isInvalid() ||
+ strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
+ addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
+ addAttribute("endfile", PLoc.getFilename());
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else if (PLoc.getLine() != PStartLoc.getLine()) {
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else {
+ addAttribute("endcol", PLoc.getColumn());
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintFunctionDecl(FunctionDecl *FD)
+{
+ switch (FD->getStorageClass()) {
+ default: assert(0 && "Unknown storage class");
+ case FunctionDecl::None: break;
+ case FunctionDecl::Extern: addAttribute("storage_class", "extern"); break;
+ case FunctionDecl::Static: addAttribute("storage_class", "static"); break;
+ case FunctionDecl::PrivateExtern: addAttribute("storage_class", "__private_extern__"); break;
+ }
+
+ if (FD->isInline())
+ addAttribute("inline", "1");
+
+ const FunctionType *AFT = FD->getType()->getAsFunctionType();
+ addTypeAttribute(AFT->getResultType());
+ addBasicTypeRecursively(AFT);
+
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) {
+ addAttribute("num_args", FD->getNumParams());
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ addSubNode("Argument");
+ ParmVarDecl *argDecl = FD->getParamDecl(i);
+ addAttribute("name", argDecl->getNameAsString());
+ addTypeAttribute(FT->getArgType(i));
+ addDeclIdAttribute(argDecl);
+ if (argDecl->getDefaultArg())
+ {
+ addAttribute("default_arg", "1");
+ PrintStmt(argDecl->getDefaultArg());
+ }
+ toParent();
+ }
+
+ if (FT->isVariadic()) {
+ addSubNode("Ellipsis").toParent();
+ }
+ } else {
+ assert(isa<FunctionNoProtoType>(AFT));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addRefAttribute(const NamedDecl* D)
+{
+ // FIXME: in case of CXX inline member functions referring to a member defined
+ // after the function it needs to be tested, if the ids are already there
+ // (should work, but I couldn't test it)
+ if (const DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addAttribute("ref", getPrefixedId(Contexts[DC], ID_NORMAL));
+ }
+ else
+ {
+ addAttribute("ref", getPrefixedId(Decls[D], ID_NORMAL));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addDeclIdAttribute(const NamedDecl* D)
+{
+ addToMap(Decls, D);
+ addAttribute("id", getPrefixedId(Decls[D], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintDecl(Decl *D)
+{
+ addSubNode(D->getDeclKindName());
+ addContextAttribute(D->getDeclContext());
+ addLocation(D->getLocation());
+ if (DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addContextAttribute(DC, CONTEXT_AS_ID);
+ }
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ addAttribute("name", ND->getNameAsString());
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ PrintFunctionDecl(FD);
+ if (Stmt *Body = FD->getBody(*Ctx)) {
+ addSubNode("Body");
+ PrintStmt(Body);
+ toParent();
+ }
+ } else if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ addBasicTypeRecursively(RD->getTypeForDecl());
+ addAttribute("type", getPrefixedId(BasicTypes[RD->getTypeForDecl()], ID_NORMAL));
+ if (!RD->isDefinition())
+ {
+ addAttribute("forward", "1");
+ }
+
+ for (RecordDecl::field_iterator i = RD->field_begin(*Ctx), e = RD->field_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ const QualType& enumType = ED->getIntegerType();
+ if (!enumType.isNull())
+ {
+ addTypeAttribute(enumType);
+ for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Ctx), e = ED->enumerator_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ }
+ } else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) {
+ addTypeAttribute(ECD->getType());
+ addAttribute("value", ECD->getInitVal().toString(10, true));
+ if (ECD->getInitExpr())
+ {
+ PrintStmt(ECD->getInitExpr());
+ }
+ } else if (FieldDecl *FdD = dyn_cast<FieldDecl>(D)) {
+ addTypeAttribute(FdD->getType());
+ addDeclIdAttribute(ND);
+ if (FdD->isMutable())
+ addAttribute("mutable", "1");
+ if (FdD->isBitField())
+ {
+ addAttribute("bitfield", "1");
+ PrintStmt(FdD->getBitWidth());
+ }
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ addTypeIdAttribute(Ctx->getTypedefType(TD).getTypePtr());
+ addTypeAttribute(TD->getUnderlyingType());
+ } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ addTypeAttribute(VD->getType());
+ addDeclIdAttribute(ND);
+
+ VarDecl *V = dyn_cast<VarDecl>(VD);
+ if (V && V->getStorageClass() != VarDecl::None)
+ {
+ addAttribute("storage_class", VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
+ }
+
+ if (V && V->getInit())
+ {
+ PrintStmt(V->getInit());
+ }
+ }
+ } else if (LinkageSpecDecl* LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ switch (LSD->getLanguage())
+ {
+ case LinkageSpecDecl::lang_c: addAttribute("lang", "C"); break;
+ case LinkageSpecDecl::lang_cxx: addAttribute("lang", "CXX"); break;
+ default: assert(0 && "Unexpected lang id");
+ }
+ } else if (isa<FileScopeAsmDecl>(D)) {
+ // FIXME: Implement this
+ } else {
+ assert(0 && "Unexpected decl");
+ }
+ toParent();
+}
+
+//---------------------------------------------------------
+} // NS clang
+
OpenPOWER on IntegriCloud