//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// AST Consumer Implementations.
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
/// ASTPrinter - Pretty-printer and dumper of ASTs
namespace {
class ASTPrinter : public ASTConsumer,
public RecursiveASTVisitor<ASTPrinter> {
typedef RecursiveASTVisitor<ASTPrinter> base;
public:
enum Kind { DumpFull, Dump, Print, None };
ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,
ASTDumpOutputFormat Format, StringRef FilterString,
bool DumpLookups = false, bool DumpDeclTypes = false)
: Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
OutputKind(K), OutputFormat(Format), FilterString(FilterString),
DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {}
void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
if (FilterString.empty())
return print(D);
TraverseDecl(D);
}
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool TraverseDecl(Decl *D) {
if (D && filterMatches(D)) {
bool ShowColors = Out.has_colors();
if (ShowColors)
Out.changeColor(raw_ostream::BLUE);
Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D)
<< ":\n";
if (ShowColors)
Out.resetColor();
print(D);
Out << "\n";
// Don't traverse child nodes to avoid output duplication.
return true;
}
return base::TraverseDecl(D);
}
private:
std::string getName(Decl *D) {
if (isa<NamedDecl>(D))
return cast<NamedDecl>(D)->getQualifiedNameAsString();
return "";
}
bool filterMatches(Decl *D) {
return getName(D).find(FilterString) != std::string::npos;
}
void print(Decl *D) {
if (DumpLookups) {
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
if (DC == DC->getPrimaryContext())
DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull);
else
Out << "Lookup map is in primary DeclContext "
<< DC->getPrimaryContext() << "\n";
} else
Out << "Not a DeclContext\n";
} else if (OutputKind == Print) {
PrintingPolicy Policy(D->getASTContext().getLangOpts());
D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true);
} else if (OutputKind != None) {
D->dump(Out, OutputKind == DumpFull, OutputFormat);
}
if (DumpDeclTypes) {
Decl *InnerD = D;
if (auto *TD = dyn_cast<TemplateDecl>(D))
InnerD = TD->getTemplatedDecl();
// FIXME: Support OutputFormat in type dumping.
// FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups.
if (auto *VD = dyn_cast<ValueDecl>(InnerD))
VD->getType().dump(Out, VD->getASTContext());
if (auto *TD = dyn_cast<TypeDecl>(InnerD))
TD->getTypeForDecl()->dump(Out, TD->getASTContext());
}
}
raw_ostream &Out;
std::unique_ptr<raw_ostream> OwnedOut;
/// How to output individual declarations.
Kind OutputKind;
/// What format should the output take?
ASTDumpOutputFormat OutputFormat;
/// Which declarations or DeclContexts to display.
std::string FilterString;
/// Whether the primary output is lookup results or declarations. Individual
/// results will be output with a format determined by OutputKind. This is
/// incompatible with OutputKind == Print.
bool DumpLookups;
/// Whether to dump the type for each declaration dumped.
bool DumpDeclTypes;
};
class ASTDeclNodeLister : public ASTConsumer,
public RecursiveASTVisitor<ASTDeclNodeLister> {
public:
ASTDeclNodeLister(raw_ostream *Out = nullptr)
: Out(Out ? *Out : llvm::outs()) {}
void HandleTranslationUnit(ASTContext &Context) override {
TraverseDecl(Context.getTranslationUnitDecl());
}
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool VisitNamedDecl(NamedDecl *D) {
D->printQualifiedName(Out);
Out << '\n';
return true;
}
private:
raw_ostream &Out;
};
} // end anonymous namespace
std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
ADOF_Default, FilterString);
}
std::unique_ptr<ASTConsumer>
clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
bool DumpDecls, bool Deserialize, bool DumpLookups,
bool DumpDeclTypes, ASTDumpOutputFormat Format) {
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
return std::make_unique<ASTPrinter>(
std::move(Out),
Deserialize ? ASTPrinter::DumpFull
: DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,
Format, FilterString, DumpLookups, DumpDeclTypes);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
return std::make_unique<ASTDeclNodeLister>(nullptr);
}
//===----------------------------------------------------------------------===//
/// ASTViewer - AST Visualization
namespace {
class ASTViewer : public ASTConsumer {
ASTContext *Context;
public:
void Initialize(ASTContext &Context) override {
this->Context = &Context;
}
bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
HandleTopLevelSingleDecl(*I);
return true;
}
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';
}
}
}
std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
return std::make_unique<ASTViewer>();
}