mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-03 16:06:06 +00:00

too low-level to actually be useful but is just interesting enough for people to try to use it (which won't actually work beyond toy examples). To bring back the AST printer, it needs to be: - Complete, covering all of C/C++/Objective-C - Documented, with appropriate Schema against which we can validate the output - Designed for C/C++/Objective-C, not Clang's specific ASTs - Stable across Clang versions - Well-tested llvm-svn: 127141
420 lines
11 KiB
C++
420 lines
11 KiB
C++
//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// AST Consumer Implementations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Frontend/ASTConsumers.h"
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "clang/AST/AST.h"
|
|
#include "clang/AST/ASTConsumer.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/RecordLayout.h"
|
|
#include "clang/AST/PrettyPrinter.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/Support/Timer.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Support/Path.h"
|
|
using namespace clang;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// ASTPrinter - Pretty-printer and dumper of ASTs
|
|
|
|
namespace {
|
|
class ASTPrinter : public ASTConsumer {
|
|
llvm::raw_ostream &Out;
|
|
bool Dump;
|
|
|
|
public:
|
|
ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
|
|
: Out(o? *o : llvm::outs()), Dump(Dump) { }
|
|
|
|
virtual void HandleTranslationUnit(ASTContext &Context) {
|
|
PrintingPolicy Policy = Context.PrintingPolicy;
|
|
Policy.Dump = Dump;
|
|
Context.getTranslationUnitDecl()->print(Out, Policy);
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
|
|
return new ASTPrinter(out);
|
|
}
|
|
|
|
ASTConsumer *clang::CreateASTDumper() {
|
|
return new ASTPrinter(0, true);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// ASTViewer - AST Visualization
|
|
|
|
namespace {
|
|
class ASTViewer : public ASTConsumer {
|
|
ASTContext *Context;
|
|
public:
|
|
void Initialize(ASTContext &Context) {
|
|
this->Context = &Context;
|
|
}
|
|
|
|
virtual void HandleTopLevelDecl(DeclGroupRef D) {
|
|
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
|
|
HandleTopLevelSingleDecl(*I);
|
|
}
|
|
|
|
void HandleTopLevelSingleDecl(Decl *D);
|
|
};
|
|
}
|
|
|
|
void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
|
|
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
|
|
D->print(llvm::errs());
|
|
|
|
if (Stmt *Body = D->getBody()) {
|
|
llvm::errs() << '\n';
|
|
Body->viewAST();
|
|
llvm::errs() << '\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// DeclContextPrinter - Decl and DeclContext Visualization
|
|
|
|
namespace {
|
|
|
|
class DeclContextPrinter : public ASTConsumer {
|
|
llvm::raw_ostream& Out;
|
|
public:
|
|
DeclContextPrinter() : Out(llvm::errs()) {}
|
|
|
|
void HandleTranslationUnit(ASTContext &C) {
|
|
PrintDeclContext(C.getTranslationUnitDecl(), 4);
|
|
}
|
|
|
|
void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
|
|
unsigned Indentation) {
|
|
// Print DeclContext name.
|
|
switch (DC->getDeclKind()) {
|
|
case Decl::TranslationUnit:
|
|
Out << "[translation unit] " << DC;
|
|
break;
|
|
case Decl::Namespace: {
|
|
Out << "[namespace] ";
|
|
const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
|
|
Out << ND;
|
|
break;
|
|
}
|
|
case Decl::Enum: {
|
|
const EnumDecl* ED = cast<EnumDecl>(DC);
|
|
if (ED->isDefinition())
|
|
Out << "[enum] ";
|
|
else
|
|
Out << "<enum> ";
|
|
Out << ED;
|
|
break;
|
|
}
|
|
case Decl::Record: {
|
|
const RecordDecl* RD = cast<RecordDecl>(DC);
|
|
if (RD->isDefinition())
|
|
Out << "[struct] ";
|
|
else
|
|
Out << "<struct> ";
|
|
Out << RD;
|
|
break;
|
|
}
|
|
case Decl::CXXRecord: {
|
|
const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
|
|
if (RD->isDefinition())
|
|
Out << "[class] ";
|
|
else
|
|
Out << "<class> ";
|
|
Out << RD << ' ' << DC;
|
|
break;
|
|
}
|
|
case Decl::ObjCMethod:
|
|
Out << "[objc method]";
|
|
break;
|
|
case Decl::ObjCInterface:
|
|
Out << "[objc interface]";
|
|
break;
|
|
case Decl::ObjCCategory:
|
|
Out << "[objc category]";
|
|
break;
|
|
case Decl::ObjCProtocol:
|
|
Out << "[objc protocol]";
|
|
break;
|
|
case Decl::ObjCImplementation:
|
|
Out << "[objc implementation]";
|
|
break;
|
|
case Decl::ObjCCategoryImpl:
|
|
Out << "[objc categoryimpl]";
|
|
break;
|
|
case Decl::LinkageSpec:
|
|
Out << "[linkage spec]";
|
|
break;
|
|
case Decl::Block:
|
|
Out << "[block]";
|
|
break;
|
|
case Decl::Function: {
|
|
const FunctionDecl* FD = cast<FunctionDecl>(DC);
|
|
if (FD->isThisDeclarationADefinition())
|
|
Out << "[function] ";
|
|
else
|
|
Out << "<function> ";
|
|
Out << FD;
|
|
// Print the parameters.
|
|
Out << "(";
|
|
bool PrintComma = false;
|
|
for (FunctionDecl::param_const_iterator I = FD->param_begin(),
|
|
E = FD->param_end(); I != E; ++I) {
|
|
if (PrintComma)
|
|
Out << ", ";
|
|
else
|
|
PrintComma = true;
|
|
Out << *I;
|
|
}
|
|
Out << ")";
|
|
break;
|
|
}
|
|
case Decl::CXXMethod: {
|
|
const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
|
|
if (D->isOutOfLine())
|
|
Out << "[c++ method] ";
|
|
else if (D->isImplicit())
|
|
Out << "(c++ method) ";
|
|
else
|
|
Out << "<c++ method> ";
|
|
Out << D;
|
|
// Print the parameters.
|
|
Out << "(";
|
|
bool PrintComma = false;
|
|
for (FunctionDecl::param_const_iterator I = D->param_begin(),
|
|
E = D->param_end(); I != E; ++I) {
|
|
if (PrintComma)
|
|
Out << ", ";
|
|
else
|
|
PrintComma = true;
|
|
Out << *I;
|
|
}
|
|
Out << ")";
|
|
|
|
// Check the semantic DeclContext.
|
|
const DeclContext* SemaDC = D->getDeclContext();
|
|
const DeclContext* LexicalDC = D->getLexicalDeclContext();
|
|
if (SemaDC != LexicalDC)
|
|
Out << " [[" << SemaDC << "]]";
|
|
|
|
break;
|
|
}
|
|
case Decl::CXXConstructor: {
|
|
const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC);
|
|
if (D->isOutOfLine())
|
|
Out << "[c++ ctor] ";
|
|
else if (D->isImplicit())
|
|
Out << "(c++ ctor) ";
|
|
else
|
|
Out << "<c++ ctor> ";
|
|
Out << D;
|
|
// Print the parameters.
|
|
Out << "(";
|
|
bool PrintComma = false;
|
|
for (FunctionDecl::param_const_iterator I = D->param_begin(),
|
|
E = D->param_end(); I != E; ++I) {
|
|
if (PrintComma)
|
|
Out << ", ";
|
|
else
|
|
PrintComma = true;
|
|
Out << *I;
|
|
}
|
|
Out << ")";
|
|
|
|
// Check the semantic DC.
|
|
const DeclContext* SemaDC = D->getDeclContext();
|
|
const DeclContext* LexicalDC = D->getLexicalDeclContext();
|
|
if (SemaDC != LexicalDC)
|
|
Out << " [[" << SemaDC << "]]";
|
|
break;
|
|
}
|
|
case Decl::CXXDestructor: {
|
|
const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC);
|
|
if (D->isOutOfLine())
|
|
Out << "[c++ dtor] ";
|
|
else if (D->isImplicit())
|
|
Out << "(c++ dtor) ";
|
|
else
|
|
Out << "<c++ dtor> ";
|
|
Out << D;
|
|
// Check the semantic DC.
|
|
const DeclContext* SemaDC = D->getDeclContext();
|
|
const DeclContext* LexicalDC = D->getLexicalDeclContext();
|
|
if (SemaDC != LexicalDC)
|
|
Out << " [[" << SemaDC << "]]";
|
|
break;
|
|
}
|
|
case Decl::CXXConversion: {
|
|
const CXXConversionDecl* D = cast<CXXConversionDecl>(DC);
|
|
if (D->isOutOfLine())
|
|
Out << "[c++ conversion] ";
|
|
else if (D->isImplicit())
|
|
Out << "(c++ conversion) ";
|
|
else
|
|
Out << "<c++ conversion> ";
|
|
Out << D;
|
|
// Check the semantic DC.
|
|
const DeclContext* SemaDC = D->getDeclContext();
|
|
const DeclContext* LexicalDC = D->getLexicalDeclContext();
|
|
if (SemaDC != LexicalDC)
|
|
Out << " [[" << SemaDC << "]]";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
assert(0 && "a decl that inherits DeclContext isn't handled");
|
|
}
|
|
|
|
Out << "\n";
|
|
|
|
// Print decls in the DeclContext.
|
|
for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
|
|
I != E; ++I) {
|
|
for (unsigned i = 0; i < Indentation; ++i)
|
|
Out << " ";
|
|
|
|
Decl::Kind DK = I->getKind();
|
|
switch (DK) {
|
|
case Decl::Namespace:
|
|
case Decl::Enum:
|
|
case Decl::Record:
|
|
case Decl::CXXRecord:
|
|
case Decl::ObjCMethod:
|
|
case Decl::ObjCInterface:
|
|
case Decl::ObjCCategory:
|
|
case Decl::ObjCProtocol:
|
|
case Decl::ObjCImplementation:
|
|
case Decl::ObjCCategoryImpl:
|
|
case Decl::LinkageSpec:
|
|
case Decl::Block:
|
|
case Decl::Function:
|
|
case Decl::CXXMethod:
|
|
case Decl::CXXConstructor:
|
|
case Decl::CXXDestructor:
|
|
case Decl::CXXConversion:
|
|
{
|
|
DeclContext* DC = cast<DeclContext>(*I);
|
|
PrintDeclContext(DC, Indentation+2);
|
|
break;
|
|
}
|
|
case Decl::IndirectField: {
|
|
IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I);
|
|
Out << "<IndirectField> " << IFD << '\n';
|
|
break;
|
|
}
|
|
case Decl::Label: {
|
|
LabelDecl *LD = cast<LabelDecl>(*I);
|
|
Out << "<Label> " << LD << '\n';
|
|
break;
|
|
}
|
|
case Decl::Field: {
|
|
FieldDecl *FD = cast<FieldDecl>(*I);
|
|
Out << "<field> " << FD << '\n';
|
|
break;
|
|
}
|
|
case Decl::Typedef: {
|
|
TypedefDecl* TD = cast<TypedefDecl>(*I);
|
|
Out << "<typedef> " << TD << '\n';
|
|
break;
|
|
}
|
|
case Decl::EnumConstant: {
|
|
EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
|
|
Out << "<enum constant> " << ECD << '\n';
|
|
break;
|
|
}
|
|
case Decl::Var: {
|
|
VarDecl* VD = cast<VarDecl>(*I);
|
|
Out << "<var> " << VD << '\n';
|
|
break;
|
|
}
|
|
case Decl::ImplicitParam: {
|
|
ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
|
|
Out << "<implicit parameter> " << IPD << '\n';
|
|
break;
|
|
}
|
|
case Decl::ParmVar: {
|
|
ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
|
|
Out << "<parameter> " << PVD << '\n';
|
|
break;
|
|
}
|
|
case Decl::ObjCProperty: {
|
|
ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
|
|
Out << "<objc property> " << OPD << '\n';
|
|
break;
|
|
}
|
|
case Decl::FunctionTemplate: {
|
|
FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
|
|
Out << "<function template> " << FTD << '\n';
|
|
break;
|
|
}
|
|
case Decl::FileScopeAsm: {
|
|
Out << "<file-scope asm>\n";
|
|
break;
|
|
}
|
|
case Decl::UsingDirective: {
|
|
Out << "<using directive>\n";
|
|
break;
|
|
}
|
|
case Decl::NamespaceAlias: {
|
|
NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
|
|
Out << "<namespace alias> " << NAD << '\n';
|
|
break;
|
|
}
|
|
case Decl::ClassTemplate: {
|
|
ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
|
|
Out << "<class template> " << CTD << '\n';
|
|
break;
|
|
}
|
|
default:
|
|
Out << "DeclKind: " << DK << '"' << *I << "\"\n";
|
|
assert(0 && "decl unhandled");
|
|
}
|
|
}
|
|
}
|
|
ASTConsumer *clang::CreateDeclContextPrinter() {
|
|
return new DeclContextPrinter();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// ASTDumperXML - In-depth XML dumping.
|
|
|
|
namespace {
|
|
class ASTDumpXML : public ASTConsumer {
|
|
llvm::raw_ostream &OS;
|
|
|
|
public:
|
|
ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {}
|
|
|
|
void HandleTranslationUnit(ASTContext &C) {
|
|
C.getTranslationUnitDecl()->dumpXML(OS);
|
|
}
|
|
};
|
|
}
|
|
|
|
ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) {
|
|
return new ASTDumpXML(OS);
|
|
}
|