4 changes: 4 additions & 0 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
#define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H

#include "clang/AST/ASTDumperUtils.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
#include "clang/Serialization/ModuleFileExtension.h"
#include "clang/Sema/CodeCompleteOptions.h"
Expand Down Expand Up @@ -307,6 +308,9 @@ class FrontendOptions {

CodeCompleteOptions CodeCompleteOpts;

/// Specifies the output format of the AST.
ASTDumpOutputFormat ASTDumpFormat = ADOF_Default;

enum {
ARCMT_None,
ARCMT_Check,
Expand Down
19 changes: 14 additions & 5 deletions clang/lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTNodeTraverser.h"
#include "clang/AST/DeclLookups.h"
#include "clang/AST/JSONNodeDumper.h"
#include "clang/AST/TextNodeDumper.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Module.h"
Expand Down Expand Up @@ -222,13 +223,21 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {

LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }

LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const {
LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
ASTDumpOutputFormat Format) const {
const ASTContext &Ctx = getASTContext();
const SourceManager &SM = Ctx.getSourceManager();
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
P.setDeserialize(Deserialize);
P.Visit(this);

if (ADOF_JSON == Format) {
JSONDumper P(OS, SM, Ctx.getPrintingPolicy());
(void)Deserialize; // FIXME?
P.Visit(this);
} else {
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
P.setDeserialize(Deserialize);
P.Visit(this);
}
}

LLVM_DUMP_METHOD void Decl::dumpColor() const {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ add_clang_library(clangAST
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
JSONNodeDumper.cpp
Mangle.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
Expand Down
781 changes: 781 additions & 0 deletions clang/lib/AST/JSONNodeDumper.cpp

Large diffs are not rendered by default.

23 changes: 13 additions & 10 deletions clang/lib/Frontend/ASTConsumers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ namespace {

public:
enum Kind { DumpFull, Dump, Print, None };
ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, StringRef FilterString,
ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,
ASTDumpOutputFormat Format, StringRef FilterString,
bool DumpLookups = false)
: Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {}
OutputKind(K), OutputFormat(Format), FilterString(FilterString),
DumpLookups(DumpLookups) {}

void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
Expand Down Expand Up @@ -90,7 +92,7 @@ namespace {
PrintingPolicy Policy(D->getASTContext().getLangOpts());
D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true);
} else if (OutputKind != None)
D->dump(Out, OutputKind == DumpFull);
D->dump(Out, OutputKind == DumpFull, OutputFormat);
}

raw_ostream &Out;
Expand All @@ -99,6 +101,9 @@ namespace {
/// How to output individual declarations.
Kind OutputKind;

/// What format should the output take?
ASTDumpOutputFormat OutputFormat;

/// Which declarations or DeclContexts to display.
std::string FilterString;

Expand Down Expand Up @@ -135,20 +140,18 @@ std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
FilterString);
ADOF_Default, FilterString);
}

std::unique_ptr<ASTConsumer>
clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out,
StringRef FilterString,
bool DumpDecls,
bool Deserialize,
bool DumpLookups) {
clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
bool DumpDecls, bool Deserialize, bool DumpLookups,
ASTDumpOutputFormat Format) {
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
return llvm::make_unique<ASTPrinter>(std::move(Out),
Deserialize ? ASTPrinter::DumpFull :
DumpDecls ? ASTPrinter::Dump :
ASTPrinter::None,
ASTPrinter::None, Format,
FilterString, DumpLookups);
}

Expand Down
20 changes: 18 additions & 2 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
llvm_unreachable("Invalid option in group!");
case OPT_ast_list:
Opts.ProgramAction = frontend::ASTDeclList; break;
case OPT_ast_dump_all_EQ:
case OPT_ast_dump_EQ: {
unsigned Val = llvm::StringSwitch<unsigned>(A->getValue())
.CaseLower("default", ADOF_Default)
.CaseLower("json", ADOF_JSON)
.Default(std::numeric_limits<unsigned>::max());

if (Val != std::numeric_limits<unsigned>::max())
Opts.ASTDumpFormat = static_cast<ASTDumpOutputFormat>(Val);
else {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Opts.ASTDumpFormat = ADOF_Default;
}
LLVM_FALLTHROUGH;
}
case OPT_ast_dump:
case OPT_ast_dump_all:
case OPT_ast_dump_lookups:
Expand Down Expand Up @@ -1725,8 +1741,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings);
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump);
Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all);
Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump, OPT_ast_dump_EQ);
Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all, OPT_ast_dump_all_EQ);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,10 @@ ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {

std::unique_ptr<ASTConsumer>
ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTDumper(nullptr /*Dump to stdout.*/,
CI.getFrontendOpts().ASTDumpFilter,
CI.getFrontendOpts().ASTDumpDecls,
CI.getFrontendOpts().ASTDumpAll,
CI.getFrontendOpts().ASTDumpLookups);
const FrontendOptions &Opts = CI.getFrontendOpts();
return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter,
Opts.ASTDumpDecls, Opts.ASTDumpAll,
Opts.ASTDumpLookups, Opts.ASTDumpFormat);
}

std::unique_ptr<ASTConsumer>
Expand Down
484 changes: 484 additions & 0 deletions clang/test/AST/ast-dump-enum-json.cpp

Large diffs are not rendered by default.

964 changes: 964 additions & 0 deletions clang/test/AST/ast-dump-if-json.cpp

Large diffs are not rendered by default.

211 changes: 211 additions & 0 deletions clang/test/AST/ast-dump-namespace-json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++2a -ast-dump=json %s | FileCheck %s

namespace foo {
}
// CHECK: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 3
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 3
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 4
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "foo"
// CHECK-NEXT: },


namespace {
}
// CHECK: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 27
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 27
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 28
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "UsingDirectiveDecl",
// CHECK-NEXT: "loc": {},
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 27
// CHECK-NEXT: },
// CHECK-NEXT: "end": {}
// CHECK-NEXT: },
// CHECK-NEXT: "isImplicit": true,
// CHECK-NEXT: "nominatedNamespace": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "NamespaceDecl",
// CHECK-NEXT: "name": ""
// CHECK-NEXT: }
// CHECK-NEXT: },

namespace bar {
inline namespace __1 {
}
}
// CHECK: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 68
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 68
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 71
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "bar",
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 18,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 69
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 69
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 70
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "__1",
// CHECK-NEXT: "isInline": true
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: },

namespace baz::quux {
}
// CHECK: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 118
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 118
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 119
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "baz",
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 16,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 118
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 14,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 118
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 119
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "quux"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: },

namespace quux::inline frobble {
}
// CHECK: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 11,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 165
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 165
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 166
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "quux",
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "NamespaceDecl",
// CHECK-NEXT: "loc": {
// CHECK-NEXT: "col": 24,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 165
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "begin": {
// CHECK-NEXT: "col": 17,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 165
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "col": 1,
// CHECK-NEXT: "file": "{{.*}}",
// CHECK-NEXT: "line": 166
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "frobble",
// CHECK-NEXT: "isInline": true
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
6 changes: 3 additions & 3 deletions clang/tools/clang-check/ClangCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ class ClangCheckActionFactory {
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
return clang::CreateASTDumper(nullptr /*Dump to stdout.*/,
ASTDumpFilter,
return clang::CreateASTDumper(nullptr /*Dump to stdout.*/, ASTDumpFilter,
/*DumpDecls=*/true,
/*Deserialize=*/false,
/*DumpLookups=*/false);
/*DumpLookups=*/false,
clang::ADOF_Default);
if (ASTPrint)
return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
return llvm::make_unique<clang::ASTConsumer>();
Expand Down
5 changes: 3 additions & 2 deletions clang/tools/clang-import-test/clang-import-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,9 @@ llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get());

if (ShouldDumpAST)
ASTConsumers.push_back(CreateASTDumper(nullptr /*Dump to stdout.*/,
"", true, false, false));
ASTConsumers.push_back(
CreateASTDumper(nullptr /*Dump to stdout.*/, "", true, false, false,
clang::ADOF_Default));

CI.getDiagnosticClient().BeginSourceFile(
CI.getCompilerInstance().getLangOpts(),
Expand Down