2018-12-06 05:12:39 +08:00
|
|
|
//===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements AST dumping of components of individual AST nodes.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/TextNodeDumper.h"
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
TextNodeDumper::TextNodeDumper(raw_ostream &OS, bool ShowColors,
|
|
|
|
const SourceManager *SM,
|
2018-12-09 21:30:17 +08:00
|
|
|
const PrintingPolicy &PrintPolicy,
|
|
|
|
const comments::CommandTraits *Traits)
|
2019-01-09 06:32:48 +08:00
|
|
|
: TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors), SM(SM),
|
|
|
|
PrintPolicy(PrintPolicy), Traits(Traits) {}
|
2018-12-09 21:30:17 +08:00
|
|
|
|
|
|
|
void TextNodeDumper::Visit(const comments::Comment *C,
|
|
|
|
const comments::FullComment *FC) {
|
|
|
|
if (!C) {
|
|
|
|
ColorScope Color(OS, ShowColors, NullColor);
|
|
|
|
OS << "<<<NULL>>>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ColorScope Color(OS, ShowColors, CommentColor);
|
|
|
|
OS << C->getCommentKindName();
|
|
|
|
}
|
|
|
|
dumpPointer(C);
|
|
|
|
dumpSourceRange(C->getSourceRange());
|
|
|
|
|
|
|
|
ConstCommentVisitor<TextNodeDumper, void,
|
|
|
|
const comments::FullComment *>::visit(C, FC);
|
|
|
|
}
|
2018-12-06 05:12:39 +08:00
|
|
|
|
2019-01-12 03:16:01 +08:00
|
|
|
void TextNodeDumper::Visit(const Attr *A) {
|
|
|
|
{
|
|
|
|
ColorScope Color(OS, ShowColors, AttrColor);
|
|
|
|
|
|
|
|
switch (A->getKind()) {
|
|
|
|
#define ATTR(X) \
|
|
|
|
case attr::X: \
|
|
|
|
OS << #X; \
|
|
|
|
break;
|
|
|
|
#include "clang/Basic/AttrList.inc"
|
|
|
|
}
|
|
|
|
OS << "Attr";
|
|
|
|
}
|
|
|
|
dumpPointer(A);
|
|
|
|
dumpSourceRange(A->getRange());
|
|
|
|
if (A->isInherited())
|
|
|
|
OS << " Inherited";
|
|
|
|
if (A->isImplicit())
|
|
|
|
OS << " Implicit";
|
|
|
|
|
|
|
|
ConstAttrVisitor<TextNodeDumper>::Visit(A);
|
|
|
|
}
|
|
|
|
|
2018-12-06 05:12:39 +08:00
|
|
|
void TextNodeDumper::dumpPointer(const void *Ptr) {
|
|
|
|
ColorScope Color(OS, ShowColors, AddressColor);
|
|
|
|
OS << ' ' << Ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpLocation(SourceLocation Loc) {
|
|
|
|
if (!SM)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ColorScope Color(OS, ShowColors, LocationColor);
|
|
|
|
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
|
|
|
|
|
|
|
|
// The general format we print out is filename:line:col, but we drop pieces
|
|
|
|
// that haven't changed since the last loc printed.
|
|
|
|
PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
|
|
|
|
|
|
|
|
if (PLoc.isInvalid()) {
|
|
|
|
OS << "<invalid sloc>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
|
|
|
|
OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
|
|
|
|
<< PLoc.getColumn();
|
|
|
|
LastLocFilename = PLoc.getFilename();
|
|
|
|
LastLocLine = PLoc.getLine();
|
|
|
|
} else if (PLoc.getLine() != LastLocLine) {
|
|
|
|
OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
|
|
|
|
LastLocLine = PLoc.getLine();
|
|
|
|
} else {
|
|
|
|
OS << "col" << ':' << PLoc.getColumn();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpSourceRange(SourceRange R) {
|
|
|
|
// Can't translate locations if a SourceManager isn't available.
|
|
|
|
if (!SM)
|
|
|
|
return;
|
|
|
|
|
|
|
|
OS << " <";
|
|
|
|
dumpLocation(R.getBegin());
|
|
|
|
if (R.getBegin() != R.getEnd()) {
|
|
|
|
OS << ", ";
|
|
|
|
dumpLocation(R.getEnd());
|
|
|
|
}
|
|
|
|
OS << ">";
|
|
|
|
|
|
|
|
// <t2.c:123:421[blah], t2.c:412:321>
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpBareType(QualType T, bool Desugar) {
|
|
|
|
ColorScope Color(OS, ShowColors, TypeColor);
|
|
|
|
|
|
|
|
SplitQualType T_split = T.split();
|
|
|
|
OS << "'" << QualType::getAsString(T_split, PrintPolicy) << "'";
|
|
|
|
|
|
|
|
if (Desugar && !T.isNull()) {
|
|
|
|
// If the type is sugared, also dump a (shallow) desugared type.
|
|
|
|
SplitQualType D_split = T.getSplitDesugaredType();
|
|
|
|
if (T_split != D_split)
|
|
|
|
OS << ":'" << QualType::getAsString(D_split, PrintPolicy) << "'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpType(QualType T) {
|
|
|
|
OS << ' ';
|
|
|
|
dumpBareType(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpBareDeclRef(const Decl *D) {
|
|
|
|
if (!D) {
|
|
|
|
ColorScope Color(OS, ShowColors, NullColor);
|
|
|
|
OS << "<<<NULL>>>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ColorScope Color(OS, ShowColors, DeclKindNameColor);
|
|
|
|
OS << D->getDeclKindName();
|
|
|
|
}
|
|
|
|
dumpPointer(D);
|
|
|
|
|
|
|
|
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
|
|
|
ColorScope Color(OS, ShowColors, DeclNameColor);
|
|
|
|
OS << " '" << ND->getDeclName() << '\'';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
|
|
dumpType(VD->getType());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpName(const NamedDecl *ND) {
|
|
|
|
if (ND->getDeclName()) {
|
|
|
|
ColorScope Color(OS, ShowColors, DeclNameColor);
|
|
|
|
OS << ' ' << ND->getNameAsString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) {
|
|
|
|
switch (AS) {
|
|
|
|
case AS_none:
|
|
|
|
break;
|
|
|
|
case AS_public:
|
|
|
|
OS << "public";
|
|
|
|
break;
|
|
|
|
case AS_protected:
|
|
|
|
OS << "protected";
|
|
|
|
break;
|
|
|
|
case AS_private:
|
|
|
|
OS << "private";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
|
|
|
|
OS << "(CXXTemporary";
|
|
|
|
dumpPointer(Temporary);
|
|
|
|
OS << ")";
|
|
|
|
}
|
2018-12-09 21:30:17 +08:00
|
|
|
|
2019-01-09 07:11:24 +08:00
|
|
|
void TextNodeDumper::dumpDeclRef(const Decl *D, const char *Label) {
|
|
|
|
if (!D)
|
|
|
|
return;
|
|
|
|
|
2019-01-11 04:58:21 +08:00
|
|
|
AddChild([=] {
|
2019-01-09 07:11:24 +08:00
|
|
|
if (Label)
|
|
|
|
OS << Label << ' ';
|
|
|
|
dumpBareDeclRef(D);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-12-09 21:30:17 +08:00
|
|
|
const char *TextNodeDumper::getCommandName(unsigned CommandID) {
|
|
|
|
if (Traits)
|
|
|
|
return Traits->getCommandInfo(CommandID)->Name;
|
|
|
|
const comments::CommandInfo *Info =
|
|
|
|
comments::CommandTraits::getBuiltinCommandInfo(CommandID);
|
|
|
|
if (Info)
|
|
|
|
return Info->Name;
|
|
|
|
return "<not a builtin command>";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitTextComment(const comments::TextComment *C,
|
|
|
|
const comments::FullComment *) {
|
|
|
|
OS << " Text=\"" << C->getText() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitInlineCommandComment(
|
|
|
|
const comments::InlineCommandComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
|
|
|
|
switch (C->getRenderKind()) {
|
|
|
|
case comments::InlineCommandComment::RenderNormal:
|
|
|
|
OS << " RenderNormal";
|
|
|
|
break;
|
|
|
|
case comments::InlineCommandComment::RenderBold:
|
|
|
|
OS << " RenderBold";
|
|
|
|
break;
|
|
|
|
case comments::InlineCommandComment::RenderMonospaced:
|
|
|
|
OS << " RenderMonospaced";
|
|
|
|
break;
|
|
|
|
case comments::InlineCommandComment::RenderEmphasized:
|
|
|
|
OS << " RenderEmphasized";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
|
|
|
|
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitHTMLStartTagComment(
|
|
|
|
const comments::HTMLStartTagComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Name=\"" << C->getTagName() << "\"";
|
|
|
|
if (C->getNumAttrs() != 0) {
|
|
|
|
OS << " Attrs: ";
|
|
|
|
for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
|
|
|
|
const comments::HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
|
|
|
|
OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (C->isSelfClosing())
|
|
|
|
OS << " SelfClosing";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitHTMLEndTagComment(
|
|
|
|
const comments::HTMLEndTagComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Name=\"" << C->getTagName() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitBlockCommandComment(
|
|
|
|
const comments::BlockCommandComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
|
|
|
|
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
|
|
|
|
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitParamCommandComment(
|
|
|
|
const comments::ParamCommandComment *C, const comments::FullComment *FC) {
|
|
|
|
OS << " "
|
|
|
|
<< comments::ParamCommandComment::getDirectionAsString(C->getDirection());
|
|
|
|
|
|
|
|
if (C->isDirectionExplicit())
|
|
|
|
OS << " explicitly";
|
|
|
|
else
|
|
|
|
OS << " implicitly";
|
|
|
|
|
|
|
|
if (C->hasParamName()) {
|
|
|
|
if (C->isParamIndexValid())
|
|
|
|
OS << " Param=\"" << C->getParamName(FC) << "\"";
|
|
|
|
else
|
|
|
|
OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (C->isParamIndexValid() && !C->isVarArgParam())
|
|
|
|
OS << " ParamIndex=" << C->getParamIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitTParamCommandComment(
|
|
|
|
const comments::TParamCommandComment *C, const comments::FullComment *FC) {
|
|
|
|
if (C->hasParamName()) {
|
|
|
|
if (C->isPositionValid())
|
|
|
|
OS << " Param=\"" << C->getParamName(FC) << "\"";
|
|
|
|
else
|
|
|
|
OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (C->isPositionValid()) {
|
|
|
|
OS << " Position=<";
|
|
|
|
for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
|
|
|
|
OS << C->getIndex(i);
|
|
|
|
if (i != e - 1)
|
|
|
|
OS << ", ";
|
|
|
|
}
|
|
|
|
OS << ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitVerbatimBlockComment(
|
|
|
|
const comments::VerbatimBlockComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Name=\"" << getCommandName(C->getCommandID())
|
|
|
|
<< "\""
|
|
|
|
" CloseName=\""
|
|
|
|
<< C->getCloseName() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitVerbatimBlockLineComment(
|
|
|
|
const comments::VerbatimBlockLineComment *C,
|
|
|
|
const comments::FullComment *) {
|
|
|
|
OS << " Text=\"" << C->getText() << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextNodeDumper::visitVerbatimLineComment(
|
|
|
|
const comments::VerbatimLineComment *C, const comments::FullComment *) {
|
|
|
|
OS << " Text=\"" << C->getText() << "\"";
|
|
|
|
}
|