2009-05-22 04:55:50 +08:00
|
|
|
//===--- 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2009-09-09 23:08:12 +08:00
|
|
|
// This file implements the XML document class, which provides the means to
|
2009-05-22 04:55:50 +08:00
|
|
|
// 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"
|
2009-06-16 03:02:54 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-05-22 04:55:50 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
|
|
|
|
Out(out),
|
|
|
|
Ctx(0),
|
2009-09-09 23:08:12 +08:00
|
|
|
HasCurrentNodeSubNodes(false) {
|
2009-06-16 03:02:54 +08:00
|
|
|
NodeStack.push(rootName);
|
2009-05-22 04:55:50 +08:00
|
|
|
Out << "<?xml version=\"1.0\"?>\n<" << rootName;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
DocumentXML& DocumentXML::addSubNode(const std::string& name) {
|
2009-05-22 04:55:50 +08:00
|
|
|
if (!HasCurrentNodeSubNodes)
|
|
|
|
Out << ">\n";
|
2009-06-16 03:02:54 +08:00
|
|
|
NodeStack.push(name);
|
2009-05-22 04:55:50 +08:00
|
|
|
HasCurrentNodeSubNodes = false;
|
|
|
|
Indent();
|
2009-06-16 03:02:54 +08:00
|
|
|
Out << "<" << NodeStack.top();
|
2009-05-22 04:55:50 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
void DocumentXML::Indent() {
|
2009-06-16 03:02:54 +08:00
|
|
|
for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
|
2009-05-22 04:55:50 +08:00
|
|
|
Out << ' ';
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
DocumentXML& DocumentXML::toParent() {
|
2009-09-17 04:41:09 +08:00
|
|
|
assert(NodeStack.size() > 1 && "too much backtracking");
|
2009-05-22 04:55:50 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (HasCurrentNodeSubNodes) {
|
2009-05-22 04:55:50 +08:00
|
|
|
Indent();
|
2009-06-16 03:02:54 +08:00
|
|
|
Out << "</" << NodeStack.top() << ">\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
} else
|
2009-05-22 04:55:50 +08:00
|
|
|
Out << "/>\n";
|
2009-06-16 03:02:54 +08:00
|
|
|
NodeStack.pop();
|
2009-05-22 04:55:50 +08:00
|
|
|
HasCurrentNodeSubNodes = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
return *this;
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
namespace {
|
|
|
|
|
2009-06-16 03:02:54 +08:00
|
|
|
enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
|
2009-05-22 04:55:50 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned getNewId(tIdType idType) {
|
2009-05-22 04:55:50 +08:00
|
|
|
static unsigned int idCounts[ID_LAST] = { 0 };
|
|
|
|
return ++idCounts[idType];
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
inline std::string getPrefixedId(unsigned uId, tIdType idType) {
|
2009-06-16 03:02:54 +08:00
|
|
|
static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
|
2009-05-22 04:55:50 +08:00
|
|
|
char buffer[20];
|
|
|
|
char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
|
|
|
|
*--BufPtr = idPrefix[idType];
|
|
|
|
return BufPtr;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
template<class T, class V>
|
2009-09-09 23:08:12 +08:00
|
|
|
bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
|
2009-05-22 04:55:50 +08:00
|
|
|
typename T::iterator i = idMap.find(value);
|
|
|
|
bool toAdd = i == idMap.end();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (toAdd)
|
2009-05-22 04:55:50 +08:00
|
|
|
idMap.insert(typename T::value_type(value, getNewId(idType)));
|
|
|
|
return toAdd;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anon NS
|
|
|
|
|
2009-06-16 03:02:54 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
std::string DocumentXML::escapeString(const char* pStr,
|
|
|
|
std::string::size_type len) {
|
2009-05-22 04:55:50 +08:00
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
else {
|
2009-05-22 04:55:50 +08:00
|
|
|
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 += "&"; break;
|
|
|
|
case '<': value += "<"; break;
|
|
|
|
case '>': value += ">"; break;
|
|
|
|
case '"': value += """; break;
|
|
|
|
case '\'': value += "'"; break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
void DocumentXML::finalize() {
|
2009-06-16 03:02:54 +08:00
|
|
|
assert(NodeStack.size() == 1 && "not completely backtracked");
|
2009-05-22 04:55:50 +08:00
|
|
|
|
|
|
|
addSubNode("ReferenceSection");
|
|
|
|
addSubNode("Types");
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
|
|
|
|
i != e; ++i) {
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (i->first.hasLocalQualifiers()) {
|
2009-06-16 03:02:54 +08:00
|
|
|
writeTypeToXML(i->first);
|
2009-05-22 04:55:50 +08:00
|
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
|
|
toParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
|
|
|
|
e = BasicTypes.end(); i != e; ++i) {
|
2009-06-16 03:02:54 +08:00
|
|
|
writeTypeToXML(i->first);
|
2009-05-22 04:55:50 +08:00
|
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
|
|
toParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
toParent().addSubNode("Contexts");
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
|
|
|
|
e = Contexts.end(); i != e; ++i) {
|
2009-05-22 04:55:50 +08:00
|
|
|
addSubNode(i->first->getDeclKindName());
|
|
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
|
2009-05-22 04:55:50 +08:00
|
|
|
addAttribute("name", ND->getNameAsString());
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
|
2009-05-22 04:55:50 +08:00
|
|
|
addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
|
2009-09-09 23:08:12 +08:00
|
|
|
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
|
2009-09-22 07:43:11 +08:00
|
|
|
addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
|
2009-05-22 04:55:50 +08:00
|
|
|
|
|
|
|
if (const DeclContext* parent = i->first->getParent())
|
2009-06-16 03:02:54 +08:00
|
|
|
addAttribute("context", parent);
|
2009-05-22 04:55:50 +08:00
|
|
|
toParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
toParent().addSubNode("Files");
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
|
|
|
|
e = SourceFiles.end(); i != e; ++i) {
|
2009-05-22 04:55:50 +08:00
|
|
|
addSubNode("File");
|
|
|
|
addAttribute("id", getPrefixedId(i->second, ID_FILE));
|
|
|
|
addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
|
|
|
|
toParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
toParent().toParent();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-22 04:55:50 +08:00
|
|
|
// write the root closing node (which has always subnodes)
|
2009-06-16 03:02:54 +08:00
|
|
|
Out << "</" << NodeStack.top() << ">\n";
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
void DocumentXML::addAttribute(const char* pAttributeName,
|
|
|
|
const QualType& pType) {
|
2009-05-22 04:55:50 +08:00
|
|
|
addTypeRecursively(pType);
|
2009-06-16 03:02:54 +08:00
|
|
|
addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName,
|
|
|
|
const Type* pType) {
|
2009-06-16 03:02:54 +08:00
|
|
|
addTypeRecursively(pType);
|
|
|
|
addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
void DocumentXML::addTypeRecursively(const QualType& pType)
|
|
|
|
{
|
|
|
|
if (addToMap(Types, pType))
|
|
|
|
{
|
2009-06-16 03:02:54 +08:00
|
|
|
addTypeRecursively(pType.getTypePtr());
|
2009-05-22 04:55:50 +08:00
|
|
|
// beautifier: a non-qualified type shall be transparent
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (!pType.hasLocalQualifiers())
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
2009-09-09 23:08:12 +08:00
|
|
|
Types[pType] = BasicTypes[pType.getTypePtr()];
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-06-16 03:02:54 +08:00
|
|
|
void DocumentXML::addTypeRecursively(const Type* pType)
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
|
|
|
if (addToMap(BasicTypes, pType))
|
|
|
|
{
|
2009-06-16 03:02:54 +08:00
|
|
|
addParentTypes(pType);
|
|
|
|
/*
|
|
|
|
// FIXME: doesn't work in the immediate streaming approach
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
|
2009-06-16 03:02:54 +08:00
|
|
|
{
|
|
|
|
addSubNode("VariableArraySizeExpression");
|
|
|
|
PrintStmt(VAT->getSizeExpr());
|
|
|
|
toParent();
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
2009-06-16 03:02:54 +08:00
|
|
|
*/
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-06-16 03:02:54 +08:00
|
|
|
void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
|
|
|
addContextsRecursively(DC);
|
2009-06-16 03:02:54 +08:00
|
|
|
addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-06-16 03:02:54 +08:00
|
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
|
|
|
|
{
|
|
|
|
if (const DeclContext* DC = dyn_cast<DeclContext>(D))
|
|
|
|
{
|
|
|
|
addContextsRecursively(DC);
|
|
|
|
addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
addToMap(Decls, D);
|
|
|
|
addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-06-16 03:02:54 +08:00
|
|
|
void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
|
|
|
|
{
|
|
|
|
addPtrAttribute(pName, static_cast<const DeclContext*>(D));
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
void DocumentXML::addContextsRecursively(const DeclContext *DC)
|
|
|
|
{
|
|
|
|
if (DC != 0 && addToMap(Contexts, DC))
|
|
|
|
{
|
|
|
|
addContextsRecursively(DC->getParent());
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
void DocumentXML::addSourceFileAttribute(const std::string& fileName)
|
|
|
|
{
|
|
|
|
addToMap(SourceFiles, fileName, ID_FILE);
|
|
|
|
addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
|
|
|
|
}
|
|
|
|
|
2009-06-16 03:02:54 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-06-16 03:02:54 +08:00
|
|
|
void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
|
|
|
|
{
|
|
|
|
addToMap(Labels, L, ID_LABEL);
|
|
|
|
addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
|
|
|
|
{
|
|
|
|
SourceManager& SM = Ctx->getSourceManager();
|
|
|
|
SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
|
|
|
|
PresumedLoc PLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!SpellingLoc.isInvalid())
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
void DocumentXML::addLocationRange(const SourceRange& R)
|
|
|
|
{
|
|
|
|
PresumedLoc PStartLoc = addLocation(R.getBegin());
|
2009-09-09 23:08:12 +08:00
|
|
|
if (R.getBegin() != R.getEnd())
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
|
|
|
SourceManager& SM = Ctx->getSourceManager();
|
|
|
|
SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!SpellingLoc.isInvalid())
|
2009-05-22 04:55:50 +08:00
|
|
|
{
|
|
|
|
PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
if (PStartLoc.isInvalid() ||
|
2009-05-22 04:55:50 +08:00
|
|
|
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());
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
void DocumentXML::PrintDecl(Decl *D)
|
|
|
|
{
|
2009-06-16 03:02:54 +08:00
|
|
|
writeDeclToXML(D);
|
2009-05-22 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
//---------------------------------------------------------
|
2009-05-22 04:55:50 +08:00
|
|
|
} // NS clang
|
|
|
|
|