forked from OSchip/llvm-project
Allow lldb-test to combine -find with -dump-clang-ast
This patch threads an lldb::DescriptionLevel through the typesystem to allow dumping the full Clang AST (level=verbose) of any lldb::Type in addition to the human-readable source description (default level=full). This type dumping interface is currently not exposed through the SBAPI. The application is to let lldb-test dump the clang AST of search results. I need this to test lazy type completion of clang types in subsequent patches. Differential Revision: https://reviews.llvm.org/D78329
This commit is contained in:
parent
dd24fb388b
commit
681466f5e6
|
@ -371,9 +371,15 @@ public:
|
|||
size_t data_byte_size);
|
||||
|
||||
/// Dump to stdout.
|
||||
void DumpTypeDescription() const;
|
||||
void DumpTypeDescription(lldb::DescriptionLevel level =
|
||||
lldb::eDescriptionLevelFull) const;
|
||||
|
||||
void DumpTypeDescription(Stream *s) const;
|
||||
/// Print a description of the type to a stream. The exact implementation
|
||||
/// varies, but the expectation is that eDescriptionLevelFull returns a
|
||||
/// source-like representation of the type, whereas eDescriptionLevelVerbose
|
||||
/// does a dump of the underlying AST if applicable.
|
||||
void DumpTypeDescription(Stream *s, lldb::DescriptionLevel level =
|
||||
lldb::eDescriptionLevelFull) const;
|
||||
/// \}
|
||||
|
||||
bool GetValueAsScalar(const DataExtractor &data, lldb::offset_t data_offset,
|
||||
|
|
|
@ -103,7 +103,8 @@ public:
|
|||
// they get an error.
|
||||
Type();
|
||||
|
||||
void Dump(Stream *s, bool show_context);
|
||||
void Dump(Stream *s, bool show_context,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull);
|
||||
|
||||
void DumpTypeName(Stream *s);
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
|
||||
void Clear();
|
||||
|
||||
void Dump(Stream *s, bool show_context);
|
||||
void Dump(Stream *s, bool show_context,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull);
|
||||
|
||||
TypeMap FindTypes(ConstString name);
|
||||
|
||||
|
|
|
@ -374,11 +374,18 @@ public:
|
|||
uint32_t bitfield_bit_offset,
|
||||
ExecutionContextScope *exe_scope) = 0;
|
||||
|
||||
virtual void
|
||||
DumpTypeDescription(lldb::opaque_compiler_type_t type) = 0; // Dump to stdout
|
||||
/// Dump the type to stdout.
|
||||
virtual void DumpTypeDescription(
|
||||
lldb::opaque_compiler_type_t type,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) = 0;
|
||||
|
||||
virtual void DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
||||
Stream *s) = 0;
|
||||
/// Print a description of the type to a stream. The exact implementation
|
||||
/// varies, but the expectation is that eDescriptionLevelFull returns a
|
||||
/// source-like representation of the type, whereas eDescriptionLevelVerbose
|
||||
/// does a dump of the underlying AST if applicable.
|
||||
virtual void DumpTypeDescription(
|
||||
lldb::opaque_compiler_type_t type, Stream *s,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) = 0;
|
||||
|
||||
// TODO: These methods appear unused. Should they be removed?
|
||||
|
||||
|
|
|
@ -8787,9 +8787,10 @@ void TypeSystemClang::DumpSummary(lldb::opaque_compiler_type_t type,
|
|||
}
|
||||
}
|
||||
|
||||
void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type) {
|
||||
void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
||||
lldb::DescriptionLevel level) {
|
||||
StreamFile s(stdout, false);
|
||||
DumpTypeDescription(type, &s);
|
||||
DumpTypeDescription(type, &s, level);
|
||||
|
||||
CompilerType ct(this, type);
|
||||
const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr();
|
||||
|
@ -8800,7 +8801,8 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type) {
|
|||
}
|
||||
|
||||
void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
||||
Stream *s) {
|
||||
Stream *s,
|
||||
lldb::DescriptionLevel level) {
|
||||
if (type) {
|
||||
clang::QualType qual_type =
|
||||
RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
|
||||
|
@ -8814,24 +8816,31 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
|||
case clang::Type::ObjCInterface: {
|
||||
GetCompleteType(type);
|
||||
|
||||
const clang::ObjCObjectType *objc_class_type =
|
||||
auto *objc_class_type =
|
||||
llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
|
||||
assert(objc_class_type);
|
||||
if (objc_class_type) {
|
||||
clang::ObjCInterfaceDecl *class_interface_decl =
|
||||
if (!objc_class_type)
|
||||
break;
|
||||
clang::ObjCInterfaceDecl *class_interface_decl =
|
||||
objc_class_type->getInterface();
|
||||
if (class_interface_decl) {
|
||||
clang::PrintingPolicy policy = getASTContext().getPrintingPolicy();
|
||||
class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel());
|
||||
}
|
||||
}
|
||||
if (!class_interface_decl)
|
||||
break;
|
||||
if (level == eDescriptionLevelVerbose)
|
||||
class_interface_decl->dump(llvm_ostrm);
|
||||
else
|
||||
class_interface_decl->print(llvm_ostrm,
|
||||
getASTContext().getPrintingPolicy(),
|
||||
s->GetIndentLevel());
|
||||
} break;
|
||||
|
||||
case clang::Type::Typedef: {
|
||||
const clang::TypedefType *typedef_type =
|
||||
qual_type->getAs<clang::TypedefType>();
|
||||
if (typedef_type) {
|
||||
const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
|
||||
auto *typedef_type = qual_type->getAs<clang::TypedefType>();
|
||||
if (!typedef_type)
|
||||
break;
|
||||
const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
|
||||
if (level == eDescriptionLevelVerbose)
|
||||
typedef_decl->dump(llvm_ostrm);
|
||||
else {
|
||||
std::string clang_typedef_name(
|
||||
typedef_decl->getQualifiedNameAsString());
|
||||
if (!clang_typedef_name.empty()) {
|
||||
|
@ -8844,31 +8853,39 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
|||
case clang::Type::Record: {
|
||||
GetCompleteType(type);
|
||||
|
||||
const clang::RecordType *record_type =
|
||||
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||
auto *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||
const clang::RecordDecl *record_decl = record_type->getDecl();
|
||||
const clang::CXXRecordDecl *cxx_record_decl =
|
||||
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
|
||||
|
||||
if (cxx_record_decl)
|
||||
cxx_record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
|
||||
s->GetIndentLevel());
|
||||
else
|
||||
record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
|
||||
s->GetIndentLevel());
|
||||
if (level == eDescriptionLevelVerbose)
|
||||
record_decl->dump(llvm_ostrm);
|
||||
else {
|
||||
if (auto *cxx_record_decl =
|
||||
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl))
|
||||
cxx_record_decl->print(llvm_ostrm,
|
||||
getASTContext().getPrintingPolicy(),
|
||||
s->GetIndentLevel());
|
||||
else
|
||||
record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
|
||||
s->GetIndentLevel());
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
const clang::TagType *tag_type =
|
||||
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
|
||||
if (tag_type) {
|
||||
clang::TagDecl *tag_decl = tag_type->getDecl();
|
||||
if (tag_decl)
|
||||
tag_decl->print(llvm_ostrm, 0);
|
||||
if (auto *tag_type =
|
||||
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) {
|
||||
if (clang::TagDecl *tag_decl = tag_type->getDecl()) {
|
||||
if (level == eDescriptionLevelVerbose)
|
||||
tag_decl->dump(llvm_ostrm);
|
||||
else
|
||||
tag_decl->print(llvm_ostrm, 0);
|
||||
}
|
||||
} else {
|
||||
std::string clang_type_name(qual_type.getAsString());
|
||||
if (!clang_type_name.empty())
|
||||
s->PutCString(clang_type_name);
|
||||
if (level == eDescriptionLevelVerbose)
|
||||
qual_type->dump(llvm_ostrm);
|
||||
else {
|
||||
std::string clang_type_name(qual_type.getAsString());
|
||||
if (!clang_type_name.empty())
|
||||
s->PutCString(clang_type_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8876,7 +8893,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
|||
if (buf.size() > 0) {
|
||||
s->Write(buf.data(), buf.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TypeSystemClang::DumpTypeName(const CompilerType &type) {
|
||||
|
|
|
@ -975,10 +975,12 @@ public:
|
|||
lldb::offset_t data_offset, size_t data_byte_size) override;
|
||||
|
||||
void DumpTypeDescription(
|
||||
lldb::opaque_compiler_type_t type) override; // Dump to stdout
|
||||
lldb::opaque_compiler_type_t type,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
|
||||
|
||||
void DumpTypeDescription(lldb::opaque_compiler_type_t type,
|
||||
Stream *s) override;
|
||||
void DumpTypeDescription(
|
||||
lldb::opaque_compiler_type_t type, Stream *s,
|
||||
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
|
||||
|
||||
static void DumpTypeName(const CompilerType &type);
|
||||
|
||||
|
|
|
@ -744,14 +744,15 @@ void CompilerType::DumpSummary(ExecutionContext *exe_ctx, Stream *s,
|
|||
data_byte_size);
|
||||
}
|
||||
|
||||
void CompilerType::DumpTypeDescription() const {
|
||||
void CompilerType::DumpTypeDescription(lldb::DescriptionLevel level) const {
|
||||
if (IsValid())
|
||||
m_type_system->DumpTypeDescription(m_type);
|
||||
m_type_system->DumpTypeDescription(m_type, level);
|
||||
}
|
||||
|
||||
void CompilerType::DumpTypeDescription(Stream *s) const {
|
||||
void CompilerType::DumpTypeDescription(Stream *s,
|
||||
lldb::DescriptionLevel level) const {
|
||||
if (IsValid()) {
|
||||
m_type_system->DumpTypeDescription(m_type, s);
|
||||
m_type_system->DumpTypeDescription(m_type, s, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level,
|
|||
}
|
||||
}
|
||||
|
||||
void Type::Dump(Stream *s, bool show_context) {
|
||||
void Type::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) {
|
||||
s->Printf("%p: ", static_cast<void *>(this));
|
||||
s->Indent();
|
||||
*s << "Type" << static_cast<const UserID &>(*this) << ' ';
|
||||
|
@ -255,7 +255,7 @@ void Type::Dump(Stream *s, bool show_context) {
|
|||
|
||||
if (m_compiler_type.IsValid()) {
|
||||
*s << ", compiler_type = " << m_compiler_type.GetOpaqueQualType() << ' ';
|
||||
GetForwardCompilerType().DumpTypeDescription(s);
|
||||
GetForwardCompilerType().DumpTypeDescription(s, level);
|
||||
} else if (m_encoding_uid != LLDB_INVALID_UID) {
|
||||
s->Format(", type_data = {0:x-16}", m_encoding_uid);
|
||||
switch (m_encoding_uid_type) {
|
||||
|
|
|
@ -121,9 +121,9 @@ bool TypeMap::Remove(const lldb::TypeSP &type_sp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void TypeMap::Dump(Stream *s, bool show_context) {
|
||||
void TypeMap::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) {
|
||||
for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
|
||||
pos->second->Dump(s, show_context);
|
||||
pos->second->Dump(s, show_context, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ typedef enum Enum_e { a = 0 } Enum;
|
|||
|
||||
@interface SomeClass {
|
||||
}
|
||||
@property (readonly) int number;
|
||||
@end
|
||||
|
||||
template <typename T> struct Template { T field; };
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
// RUN: %clang --target=x86_64-apple-macosx -g -gmodules \
|
||||
// RUN: -fmodules -fmodules-cache-path=%t.cache \
|
||||
// RUN: -c -o %t.o %s -I%S/Inputs
|
||||
// RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s
|
||||
// Verify that the owning module information from DWARF is preserved in the AST.
|
||||
|
||||
@import A;
|
||||
|
||||
Typedef t1;
|
||||
// CHECK-DAG: TypedefDecl {{.*}} imported in A Typedef
|
||||
// RUN: lldb-test symbols -dump-clang-ast -find type --language=ObjC++ \
|
||||
// RUN: -compiler-context 'Module:A,Typedef:Typedef' %t.o \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-TYPEDEF
|
||||
// CHECK-TYPEDEF: TypedefDecl {{.*}} imported in A Typedef
|
||||
|
||||
TopLevelStruct s1;
|
||||
// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct TopLevelStruct
|
||||
// CHECK-DAG: -FieldDecl {{.*}} in A a 'int'
|
||||
// RUN: lldb-test symbols -dump-clang-ast -find type --language=ObjC++ \
|
||||
// RUN: -compiler-context 'Module:A,Struct:TopLevelStruct' %t.o \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-TOPLEVELSTRUCT
|
||||
// CHECK-TOPLEVELSTRUCT: CXXRecordDecl {{.*}} imported in A struct TopLevelStruct
|
||||
// CHECK-TOPLEVELSTRUCT: -FieldDecl {{.*}} in A a 'int'
|
||||
|
||||
Struct s2;
|
||||
// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct
|
||||
|
@ -29,7 +34,13 @@ Enum e1;
|
|||
// FIXME: -EnumConstantDecl {{.*}} imported in A a
|
||||
|
||||
SomeClass *obj1;
|
||||
// CHECK-DAG: ObjCInterfaceDecl {{.*}} imported in A {{.*}} SomeClass
|
||||
// RUN: lldb-test symbols -dump-clang-ast -find type --language=ObjC++ \
|
||||
// RUN: -compiler-context 'Module:A,Struct:SomeClass' %t.o \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-OBJC
|
||||
// CHECK-OBJC: ObjCInterfaceDecl {{.*}} imported in A SomeClass
|
||||
// CHECK-OBJC: |-ObjCPropertyDecl {{.*}} imported in A number 'int' readonly
|
||||
// CHECK-OBJC: | `-getter ObjCMethod {{.*}} 'number'
|
||||
// CHECK-OBJC: `-ObjCMethodDecl {{.*}} imported in A implicit - number 'int'
|
||||
|
||||
// Template specializations are not yet supported, so they lack the ownership info:
|
||||
Template<int> t2;
|
||||
|
|
|
@ -169,10 +169,13 @@ static FunctionNameType getFunctionNameFlags() {
|
|||
static cl::opt<bool> DumpAST("dump-ast",
|
||||
cl::desc("Dump AST restored from symbols."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
static cl::opt<bool>
|
||||
DumpClangAST("dump-clang-ast",
|
||||
cl::desc("Dump clang AST restored from symbols."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
static cl::opt<bool> DumpClangAST(
|
||||
"dump-clang-ast",
|
||||
cl::desc("Dump clang AST restored from symbols. When used on its own this "
|
||||
"will dump the entire AST of all loaded symbols. When combined "
|
||||
"with -find, it changes the presentation of the search results "
|
||||
"from pretty-printing the types to an AST dump."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
|
||||
static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
|
@ -192,7 +195,7 @@ static Error findTypes(lldb_private::Module &Module);
|
|||
static Error findVariables(lldb_private::Module &Module);
|
||||
static Error dumpModule(lldb_private::Module &Module);
|
||||
static Error dumpAST(lldb_private::Module &Module);
|
||||
static Error dumpClangAST(lldb_private::Module &Module);
|
||||
static Error dumpEntireClangAST(lldb_private::Module &Module);
|
||||
static Error verify(lldb_private::Module &Module);
|
||||
|
||||
static Expected<Error (*)(lldb_private::Module &)> getAction();
|
||||
|
@ -404,6 +407,10 @@ opts::symbols::getDeclContext(SymbolFile &Symfile) {
|
|||
return List.GetVariableAtIndex(0)->GetDeclContext();
|
||||
}
|
||||
|
||||
static lldb::DescriptionLevel GetDescriptionLevel() {
|
||||
return opts::symbols::DumpClangAST ? eDescriptionLevelVerbose : eDescriptionLevelFull;
|
||||
}
|
||||
|
||||
Error opts::symbols::findFunctions(lldb_private::Module &Module) {
|
||||
SymbolFile &Symfile = *Module.GetSymbolFile();
|
||||
SymbolContextList List;
|
||||
|
@ -534,7 +541,12 @@ Error opts::symbols::findTypes(lldb_private::Module &Module) {
|
|||
|
||||
outs() << formatv("Found {0} types:\n", Map.GetSize());
|
||||
StreamString Stream;
|
||||
Map.Dump(&Stream, false);
|
||||
// Resolve types to force-materialize typedef types.
|
||||
Map.ForEach([&](TypeSP &type) {
|
||||
type->GetFullCompilerType();
|
||||
return false;
|
||||
});
|
||||
Map.Dump(&Stream, false, GetDescriptionLevel());
|
||||
outs() << Stream.GetData() << "\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -615,7 +627,7 @@ Error opts::symbols::dumpAST(lldb_private::Module &Module) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error opts::symbols::dumpClangAST(lldb_private::Module &Module) {
|
||||
Error opts::symbols::dumpEntireClangAST(lldb_private::Module &Module) {
|
||||
Module.ParseAllDebugSymbols();
|
||||
|
||||
SymbolFile *symfile = Module.GetSymbolFile();
|
||||
|
@ -719,13 +731,17 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
|
|||
}
|
||||
|
||||
if (DumpClangAST) {
|
||||
if (Find != FindType::None)
|
||||
return make_string_error("Cannot both search and dump clang AST.");
|
||||
if (Regex || !Context.empty() || !File.empty() || Line != 0)
|
||||
return make_string_error(
|
||||
"-regex, -context, -name, -file and -line options are not "
|
||||
"applicable for dumping clang AST.");
|
||||
return dumpClangAST;
|
||||
if (Find == FindType::None) {
|
||||
if (Regex || !Context.empty() || !File.empty() || Line != 0)
|
||||
return make_string_error(
|
||||
"-regex, -context, -name, -file and -line options are not "
|
||||
"applicable for dumping the entire clang AST. Either combine with "
|
||||
"-find, or use -dump-clang-ast as a standalone option.");
|
||||
return dumpEntireClangAST;
|
||||
}
|
||||
if (Find != FindType::Type)
|
||||
return make_string_error("This combination of -dump-clang-ast and -find "
|
||||
"<kind> is not yet implemented.");
|
||||
}
|
||||
|
||||
if (Regex && !Context.empty())
|
||||
|
|
Loading…
Reference in New Issue