parent
0ac904455e
commit
7f5601e55f
|
@ -38,6 +38,12 @@ class LangOptions;
|
|||
// implementation is still incomplete.
|
||||
ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS);
|
||||
|
||||
// AST XML-printer: prints out the AST in a XML format
|
||||
// The output is intended to be in a format such that
|
||||
// clang or any other tool could re-parse the output back into the same AST,
|
||||
// but the implementation is still incomplete.
|
||||
ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream* OS);
|
||||
|
||||
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
|
||||
// intended for debugging. A normal dump is done with FullDump = false;
|
||||
// with FullDump = true, the dumper waits until the end of the translation
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
//===--- DocumentXML.h - XML document for ASTs ------------------*- C++ -*-===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FRONTEND_DOCUMENTXML_H
|
||||
#define LLVM_CLANG_FRONTEND_DOCUMENTXML_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
//--------------------------------------------------------- forwards
|
||||
class DeclContext;
|
||||
class Decl;
|
||||
class NamedDecl;
|
||||
class FunctionDecl;
|
||||
class ASTContext;
|
||||
|
||||
//---------------------------------------------------------
|
||||
namespace XML
|
||||
{
|
||||
// id maps:
|
||||
template<class T>
|
||||
struct IdMap : llvm::DenseMap<T, unsigned> {};
|
||||
|
||||
template<>
|
||||
struct IdMap<QualType> : std::map<QualType, unsigned, QualTypeOrdering> {};
|
||||
|
||||
template<>
|
||||
struct IdMap<std::string> : std::map<std::string, unsigned> {};
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
class DocumentXML
|
||||
{
|
||||
public:
|
||||
DocumentXML(const std::string& rootName, llvm::raw_ostream& out);
|
||||
~DocumentXML();
|
||||
|
||||
void initialize(ASTContext &Context);
|
||||
void PrintDecl(Decl *D);
|
||||
void PrintStmt(const Stmt *S); // defined in StmtXML.cpp
|
||||
|
||||
void finalize();
|
||||
|
||||
|
||||
DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this
|
||||
DocumentXML& toParent(); // returns *this
|
||||
|
||||
template<class T>
|
||||
void addAttribute(const char* pName, const T& value);
|
||||
|
||||
void addTypeAttribute(const QualType& pType);
|
||||
void addRefAttribute(const NamedDecl* D);
|
||||
|
||||
enum tContextUsage { CONTEXT_AS_CONTEXT, CONTEXT_AS_ID };
|
||||
void addContextAttribute(const DeclContext *DC, tContextUsage usage = CONTEXT_AS_CONTEXT);
|
||||
void addSourceFileAttribute(const std::string& fileName);
|
||||
|
||||
PresumedLoc addLocation(const SourceLocation& Loc);
|
||||
void addLocationRange(const SourceRange& R);
|
||||
|
||||
static std::string escapeString(const char* pStr, std::string::size_type len);
|
||||
|
||||
private:
|
||||
DocumentXML(const DocumentXML&); // not defined
|
||||
DocumentXML& operator=(const DocumentXML&); // not defined
|
||||
|
||||
struct NodeXML;
|
||||
|
||||
NodeXML* Root;
|
||||
NodeXML* CurrentNode; // always after Root
|
||||
llvm::raw_ostream& Out;
|
||||
ASTContext *Ctx;
|
||||
int CurrentIndent;
|
||||
bool HasCurrentNodeSubNodes;
|
||||
|
||||
|
||||
XML::IdMap<QualType> Types;
|
||||
XML::IdMap<const DeclContext*> Contexts;
|
||||
XML::IdMap<const Type*> BasicTypes;
|
||||
XML::IdMap<std::string> SourceFiles;
|
||||
XML::IdMap<const NamedDecl*> Decls;
|
||||
|
||||
void addContextsRecursively(const DeclContext *DC);
|
||||
void addBasicTypeRecursively(const Type* pType);
|
||||
void addTypeRecursively(const QualType& pType);
|
||||
|
||||
void PrintFunctionDecl(FunctionDecl *FD);
|
||||
void addDeclIdAttribute(const NamedDecl* D);
|
||||
void addTypeIdAttribute(const Type* pType);
|
||||
void Indent();
|
||||
};
|
||||
|
||||
//--------------------------------------------------------- inlines
|
||||
|
||||
inline void DocumentXML::initialize(ASTContext &Context)
|
||||
{
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
template<class T>
|
||||
inline void DocumentXML::addAttribute(const char* pName, const T& value)
|
||||
{
|
||||
Out << ' ' << pName << "=\"" << value << "\"";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
||||
} //namespace clang
|
||||
|
||||
#endif //LLVM_CLANG_DOCUMENTXML_H
|
|
@ -13,6 +13,7 @@ add_clang_library(clangAST
|
|||
DeclGroup.cpp
|
||||
DeclObjC.cpp
|
||||
DeclTemplate.cpp
|
||||
DocumentXML.cpp
|
||||
ExprConstant.cpp
|
||||
Expr.cpp
|
||||
ExprCXX.cpp
|
||||
|
@ -24,6 +25,7 @@ add_clang_library(clangAST
|
|||
StmtIterator.cpp
|
||||
StmtPrinter.cpp
|
||||
StmtViz.cpp
|
||||
StmtXML.cpp
|
||||
TemplateName.cpp
|
||||
Type.cpp
|
||||
)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/ASTConsumers.h"
|
||||
#include "clang/Frontend/DocumentXML.h"
|
||||
#include "clang/Frontend/PathDiagnosticClients.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
@ -586,6 +587,41 @@ ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
|
|||
return new ASTPrinter(out);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTPrinterXML - XML-printer of ASTs
|
||||
|
||||
namespace {
|
||||
class ASTPrinterXML : public ASTConsumer {
|
||||
DocumentXML Doc;
|
||||
|
||||
public:
|
||||
ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {}
|
||||
|
||||
void Initialize(ASTContext &Context) {
|
||||
Doc.initialize(Context);
|
||||
}
|
||||
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {
|
||||
Doc.addSubNode("TranslationUnit");
|
||||
for (DeclContext::decl_iterator
|
||||
D = Ctx.getTranslationUnitDecl()->decls_begin(Ctx),
|
||||
DEnd = Ctx.getTranslationUnitDecl()->decls_end(Ctx);
|
||||
D != DEnd;
|
||||
++D)
|
||||
{
|
||||
Doc.PrintDecl(*D);
|
||||
}
|
||||
Doc.toParent();
|
||||
Doc.finalize();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
|
||||
return new ASTPrinterXML(out ? *out : llvm::outs());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTDumper - Low-level dumper of ASTs
|
||||
|
||||
|
|
|
@ -0,0 +1,577 @@
|
|||
//===--- 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 += "&"; break;
|
||||
case '<': value += "<"; break;
|
||||
case '>': value += ">"; break;
|
||||
case '"': value += """; break;
|
||||
case '\'': value += "'"; 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());
|
||||
}
|
||||
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 {
|
||||
assert(0 && "Unexpected decl");
|
||||
}
|
||||
toParent();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
} // NS clang
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
//===--- StmtXML.cpp - XML implementation for Stmt 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 Stmt::dumpXML methods, which dump out the
|
||||
// AST to an XML document.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/DocumentXML.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StmtXML Visitor
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN StmtXML : public StmtVisitor<StmtXML> {
|
||||
DocumentXML& Doc;
|
||||
|
||||
static const char *getOpcodeStr(UnaryOperator::Opcode Op);
|
||||
static const char *getOpcodeStr(BinaryOperator::Opcode Op);
|
||||
|
||||
public:
|
||||
StmtXML(DocumentXML& doc)
|
||||
: Doc(doc) {
|
||||
}
|
||||
|
||||
void DumpSubTree(Stmt *S) {
|
||||
if (S)
|
||||
{
|
||||
Doc.addSubNode(S->getStmtClassName());
|
||||
Doc.addLocationRange(S->getSourceRange());
|
||||
if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
|
||||
VisitDeclStmt(DS);
|
||||
} else {
|
||||
Visit(S);
|
||||
for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i)
|
||||
{
|
||||
DumpSubTree(*i);
|
||||
}
|
||||
}
|
||||
Doc.toParent();
|
||||
} else {
|
||||
Doc.addSubNode("NULL").toParent();
|
||||
}
|
||||
}
|
||||
|
||||
void DumpTypeExpr(const QualType& T)
|
||||
{
|
||||
Doc.addSubNode("TypeExpr");
|
||||
Doc.addTypeAttribute(T);
|
||||
Doc.toParent();
|
||||
}
|
||||
|
||||
void DumpExpr(const Expr *Node) {
|
||||
Doc.addTypeAttribute(Node->getType());
|
||||
}
|
||||
|
||||
// Stmts.
|
||||
void VisitStmt(Stmt *Node);
|
||||
void VisitDeclStmt(DeclStmt *Node);
|
||||
void VisitLabelStmt(LabelStmt *Node);
|
||||
void VisitGotoStmt(GotoStmt *Node);
|
||||
|
||||
// Exprs
|
||||
void VisitExpr(Expr *Node);
|
||||
void VisitDeclRefExpr(DeclRefExpr *Node);
|
||||
void VisitPredefinedExpr(PredefinedExpr *Node);
|
||||
void VisitCharacterLiteral(CharacterLiteral *Node);
|
||||
void VisitIntegerLiteral(IntegerLiteral *Node);
|
||||
void VisitFloatingLiteral(FloatingLiteral *Node);
|
||||
void VisitStringLiteral(StringLiteral *Str);
|
||||
void VisitUnaryOperator(UnaryOperator *Node);
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
|
||||
void VisitMemberExpr(MemberExpr *Node);
|
||||
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
|
||||
void VisitBinaryOperator(BinaryOperator *Node);
|
||||
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
|
||||
void VisitAddrLabelExpr(AddrLabelExpr *Node);
|
||||
void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
|
||||
|
||||
// C++
|
||||
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
|
||||
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
|
||||
void VisitCXXThisExpr(CXXThisExpr *Node);
|
||||
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
|
||||
|
||||
// ObjC
|
||||
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr* Node);
|
||||
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
|
||||
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
|
||||
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
|
||||
void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node);
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
|
||||
void VisitObjCSuperExpr(ObjCSuperExpr *Node);
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtXML::VisitStmt(Stmt *Node)
|
||||
{
|
||||
// nothing special to do
|
||||
}
|
||||
|
||||
void StmtXML::VisitDeclStmt(DeclStmt *Node)
|
||||
{
|
||||
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
|
||||
DI != DE; ++DI)
|
||||
{
|
||||
Doc.PrintDecl(*DI);
|
||||
}
|
||||
}
|
||||
|
||||
void StmtXML::VisitLabelStmt(LabelStmt *Node)
|
||||
{
|
||||
Doc.addAttribute("name", Node->getName());
|
||||
}
|
||||
|
||||
void StmtXML::VisitGotoStmt(GotoStmt *Node)
|
||||
{
|
||||
Doc.addAttribute("name", Node->getLabel()->getName());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expr printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtXML::VisitExpr(Expr *Node) {
|
||||
DumpExpr(Node);
|
||||
}
|
||||
|
||||
void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
const char* pKind;
|
||||
switch (Node->getDecl()->getKind()) {
|
||||
case Decl::Function: pKind = "FunctionDecl"; break;
|
||||
case Decl::Var: pKind = "Var"; break;
|
||||
case Decl::ParmVar: pKind = "ParmVar"; break;
|
||||
case Decl::EnumConstant: pKind = "EnumConstant"; break;
|
||||
case Decl::Typedef: pKind = "Typedef"; break;
|
||||
case Decl::Record: pKind = "Record"; break;
|
||||
case Decl::Enum: pKind = "Enum"; break;
|
||||
case Decl::CXXRecord: pKind = "CXXRecord"; break;
|
||||
case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
|
||||
case Decl::ObjCClass: pKind = "ObjCClass"; break;
|
||||
default: pKind = "Decl"; break;
|
||||
}
|
||||
|
||||
Doc.addAttribute("kind", pKind);
|
||||
Doc.addAttribute("name", Node->getDecl()->getNameAsString());
|
||||
Doc.addRefAttribute(Node->getDecl());
|
||||
}
|
||||
|
||||
void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
switch (Node->getIdentType()) {
|
||||
default: assert(0 && "unknown case");
|
||||
case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
|
||||
case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
|
||||
case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("value", Node->getValue());
|
||||
}
|
||||
|
||||
void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
bool isSigned = Node->getType()->isSignedIntegerType();
|
||||
Doc.addAttribute("value", Node->getValue().toString(10, isSigned));
|
||||
}
|
||||
|
||||
void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
// FIXME: output float as written in source (no approximation or the like)
|
||||
//Doc.addAttribute("value", Node->getValueAsApproximateDouble()));
|
||||
Doc.addAttribute("value", "FIXME");
|
||||
}
|
||||
|
||||
void StmtXML::VisitStringLiteral(StringLiteral *Str) {
|
||||
DumpExpr(Str);
|
||||
if (Str->isWide())
|
||||
Doc.addAttribute("is_wide", "1");
|
||||
|
||||
Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength()));
|
||||
}
|
||||
|
||||
|
||||
const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) {
|
||||
switch (Op) {
|
||||
default: assert(0 && "Unknown unary operator");
|
||||
case UnaryOperator::PostInc: return "postinc";
|
||||
case UnaryOperator::PostDec: return "postdec";
|
||||
case UnaryOperator::PreInc: return "preinc";
|
||||
case UnaryOperator::PreDec: return "predec";
|
||||
case UnaryOperator::AddrOf: return "addrof";
|
||||
case UnaryOperator::Deref: return "deref";
|
||||
case UnaryOperator::Plus: return "plus";
|
||||
case UnaryOperator::Minus: return "minus";
|
||||
case UnaryOperator::Not: return "not";
|
||||
case UnaryOperator::LNot: return "lnot";
|
||||
case UnaryOperator::Real: return "__real";
|
||||
case UnaryOperator::Imag: return "__imag";
|
||||
case UnaryOperator::Extension: return "__extension__";
|
||||
case UnaryOperator::OffsetOf: return "__builtin_offsetof";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) {
|
||||
switch (Op) {
|
||||
default: assert(0 && "Unknown binary operator");
|
||||
case BinaryOperator::PtrMemD: return "ptrmemd";
|
||||
case BinaryOperator::PtrMemI: return "ptrmemi";
|
||||
case BinaryOperator::Mul: return "mul";
|
||||
case BinaryOperator::Div: return "div";
|
||||
case BinaryOperator::Rem: return "rem";
|
||||
case BinaryOperator::Add: return "add";
|
||||
case BinaryOperator::Sub: return "sub";
|
||||
case BinaryOperator::Shl: return "shl";
|
||||
case BinaryOperator::Shr: return "shr";
|
||||
case BinaryOperator::LT: return "lt";
|
||||
case BinaryOperator::GT: return "gt";
|
||||
case BinaryOperator::LE: return "le";
|
||||
case BinaryOperator::GE: return "ge";
|
||||
case BinaryOperator::EQ: return "eq";
|
||||
case BinaryOperator::NE: return "ne";
|
||||
case BinaryOperator::And: return "and";
|
||||
case BinaryOperator::Xor: return "xor";
|
||||
case BinaryOperator::Or: return "or";
|
||||
case BinaryOperator::LAnd: return "land";
|
||||
case BinaryOperator::LOr: return "lor";
|
||||
case BinaryOperator::Assign: return "assign";
|
||||
case BinaryOperator::MulAssign: return "mulassign";
|
||||
case BinaryOperator::DivAssign: return "divassign";
|
||||
case BinaryOperator::RemAssign: return "remassign";
|
||||
case BinaryOperator::AddAssign: return "addassign";
|
||||
case BinaryOperator::SubAssign: return "subassign";
|
||||
case BinaryOperator::ShlAssign: return "shlassign";
|
||||
case BinaryOperator::ShrAssign: return "shrassign";
|
||||
case BinaryOperator::AndAssign: return "andassign";
|
||||
case BinaryOperator::XorAssign: return "xorassign";
|
||||
case BinaryOperator::OrAssign: return "orassign";
|
||||
case BinaryOperator::Comma: return "comma";
|
||||
}
|
||||
}
|
||||
|
||||
void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
|
||||
}
|
||||
|
||||
void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
|
||||
Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0");
|
||||
if (Node->isArgumentType())
|
||||
{
|
||||
DumpTypeExpr(Node->getArgumentType());
|
||||
}
|
||||
}
|
||||
|
||||
void StmtXML::VisitMemberExpr(MemberExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0");
|
||||
Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString());
|
||||
Doc.addRefAttribute(Node->getMemberDecl());
|
||||
}
|
||||
|
||||
void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("name", Node->getAccessor().getName());
|
||||
}
|
||||
|
||||
void StmtXML::VisitBinaryOperator(BinaryOperator *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
|
||||
}
|
||||
|
||||
void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
|
||||
VisitBinaryOperator(Node);
|
||||
/* FIXME: is this needed in the AST?
|
||||
DumpExpr(Node);
|
||||
CurrentNode = CurrentNode->addSubNode("ComputeLHSTy");
|
||||
DumpType(Node->getComputationLHSType());
|
||||
CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy");
|
||||
DumpType(Node->getComputationResultType());
|
||||
Doc.toParent();
|
||||
*/
|
||||
}
|
||||
|
||||
// GNU extensions.
|
||||
|
||||
void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("name", Node->getLabel()->getName());
|
||||
}
|
||||
|
||||
void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
DumpTypeExpr(Node->getArgType1());
|
||||
DumpTypeExpr(Node->getArgType2());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C++ Expressions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("kind", Node->getCastName());
|
||||
DumpTypeExpr(Node->getTypeAsWritten());
|
||||
}
|
||||
|
||||
void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("value", Node->getValue() ? "true" : "false");
|
||||
}
|
||||
|
||||
void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
}
|
||||
|
||||
void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
DumpTypeExpr(Node->getTypeAsWritten());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Obj-C Expressions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("selector", Node->getSelector().getAsString());
|
||||
IdentifierInfo* clsName = Node->getClassName();
|
||||
if (clsName)
|
||||
Doc.addAttribute("class", clsName->getName());
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
DumpTypeExpr(Node->getEncodedType());
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("selector", Node->getSelector().getAsString());
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString());
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("property", Node->getProperty()->getNameAsString());
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
ObjCMethodDecl *Getter = Node->getGetterMethod();
|
||||
ObjCMethodDecl *Setter = Node->getSetterMethod();
|
||||
Doc.addAttribute("Getter", Getter->getSelector().getAsString());
|
||||
Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("super", "1");
|
||||
}
|
||||
|
||||
void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
Doc.addAttribute("kind", Node->getDecl()->getDeclKindName());
|
||||
Doc.addAttribute("decl", Node->getDecl()->getNameAsString());
|
||||
if (Node->isFreeIvar())
|
||||
Doc.addAttribute("isFreeIvar", "1");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt method implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
||||
void DocumentXML::PrintStmt(const Stmt *S) {
|
||||
StmtXML P(*this);
|
||||
P.DumpSubTree(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// RUN: clang-cc --fsyntax-only %s &&
|
||||
// RUN: clang-cc --ast-print %s &&
|
||||
// RUN: clang-cc --ast-dump %s
|
||||
// RUN: clang-cc --ast-dump %s &&
|
||||
// RUN: clang-cc --ast-print-xml -o %t %s
|
||||
|
||||
#include "c-language-features.inc"
|
||||
|
|
|
@ -194,6 +194,7 @@ enum ProgActions {
|
|||
EmitLLVMOnly, // Generate LLVM IR, but do not
|
||||
EmitHTML, // Translate input source into HTML.
|
||||
ASTPrint, // Parse ASTs and print them.
|
||||
ASTPrintXML, // Parse ASTs and print them in XML.
|
||||
ASTDump, // Parse ASTs and dump them.
|
||||
ASTDumpFull, // Parse ASTs and dump them, including the
|
||||
// contents of a PCH file.
|
||||
|
@ -236,6 +237,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
|
|||
"Output input source as HTML"),
|
||||
clEnumValN(ASTPrint, "ast-print",
|
||||
"Build ASTs and then pretty-print them"),
|
||||
clEnumValN(ASTPrintXML, "ast-print-xml",
|
||||
"Build ASTs and then print them in XML format"),
|
||||
clEnumValN(ASTDump, "ast-dump",
|
||||
"Build ASTs and then debug dump them"),
|
||||
clEnumValN(ASTDumpFull, "ast-dump-full",
|
||||
|
@ -1755,6 +1758,11 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
|
|||
Consumer.reset(CreateASTPrinter(OS.get()));
|
||||
break;
|
||||
|
||||
case ASTPrintXML:
|
||||
OS.reset(ComputeOutFile(InFile, "xml", false, OutPath));
|
||||
Consumer.reset(CreateASTPrinterXML(OS.get()));
|
||||
break;
|
||||
|
||||
case ASTDump:
|
||||
Consumer.reset(CreateASTDumper(false));
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue