mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-13 20:01:00 +00:00

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
339 lines
10 KiB
C++
339 lines
10 KiB
C++
//===--- 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/ASTContext.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
namespace clang {
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
|
|
Out(out),
|
|
Ctx(0),
|
|
HasCurrentNodeSubNodes(false) {
|
|
NodeStack.push(rootName);
|
|
Out << "<?xml version=\"1.0\"?>\n<" << rootName;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML& DocumentXML::addSubNode(const std::string& name) {
|
|
if (!HasCurrentNodeSubNodes)
|
|
Out << ">\n";
|
|
NodeStack.push(name);
|
|
HasCurrentNodeSubNodes = false;
|
|
Indent();
|
|
Out << "<" << NodeStack.top();
|
|
return *this;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::Indent() {
|
|
for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
|
|
Out << ' ';
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML& DocumentXML::toParent() {
|
|
assert(NodeStack.size() > 1 && "too much backtracking");
|
|
|
|
if (HasCurrentNodeSubNodes) {
|
|
Indent();
|
|
Out << "</" << NodeStack.top() << ">\n";
|
|
} else
|
|
Out << "/>\n";
|
|
NodeStack.pop();
|
|
HasCurrentNodeSubNodes = true;
|
|
return *this;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
namespace {
|
|
|
|
enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, 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', 'l' };
|
|
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(NodeStack.size() == 1 && "not completely backtracked");
|
|
|
|
addSubNode("ReferenceSection");
|
|
addSubNode("Types");
|
|
|
|
for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
|
|
i != e; ++i) {
|
|
if (i->first.hasLocalQualifiers()) {
|
|
writeTypeToXML(i->first);
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
toParent();
|
|
}
|
|
}
|
|
|
|
for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
|
|
e = BasicTypes.end(); i != e; ++i) {
|
|
writeTypeToXML(i->first);
|
|
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()->getAs<FunctionType>()], ID_NORMAL));
|
|
|
|
if (const DeclContext* parent = i->first->getParent())
|
|
addAttribute("context", 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 << "</" << NodeStack.top() << ">\n";
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addAttribute(const char* pAttributeName,
|
|
const QualType& pType) {
|
|
addTypeRecursively(pType);
|
|
addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName,
|
|
const Type* pType) {
|
|
addTypeRecursively(pType);
|
|
addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addTypeRecursively(const QualType& pType)
|
|
{
|
|
if (addToMap(Types, pType))
|
|
{
|
|
addTypeRecursively(pType.getTypePtr());
|
|
// beautifier: a non-qualified type shall be transparent
|
|
if (!pType.hasLocalQualifiers())
|
|
{
|
|
Types[pType] = BasicTypes[pType.getTypePtr()];
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addTypeRecursively(const Type* pType)
|
|
{
|
|
if (addToMap(BasicTypes, pType))
|
|
{
|
|
addParentTypes(pType);
|
|
/*
|
|
// FIXME: doesn't work in the immediate streaming approach
|
|
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
|
|
{
|
|
addSubNode("VariableArraySizeExpression");
|
|
PrintStmt(VAT->getSizeExpr());
|
|
toParent();
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
|
|
{
|
|
addContextsRecursively(DC);
|
|
addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
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));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
|
|
{
|
|
addPtrAttribute(pName, static_cast<const DeclContext*>(D));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
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));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
|
|
{
|
|
addToMap(Labels, L, ID_LABEL);
|
|
addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
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::PrintDecl(Decl *D)
|
|
{
|
|
writeDeclToXML(D);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
} // NS clang
|
|
|