Skip to content

Commit

Permalink
Allow lldb-test to combine -find with -dump-clang-ast
Browse files Browse the repository at this point in the history
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
  • Loading branch information
adrian-prantl committed Apr 17, 2020
1 parent dd24fb3 commit 681466f
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 76 deletions.
12 changes: 9 additions & 3 deletions lldb/include/lldb/Symbol/CompilerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,15 @@ class CompilerType {
size_t data_byte_size);

/// Dump to stdout.
void DumpTypeDescription() const;

void DumpTypeDescription(Stream *s) const;
void DumpTypeDescription(lldb::DescriptionLevel level =
lldb::eDescriptionLevelFull) 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,
Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Symbol/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ class Type : public std::enable_shared_from_this<Type>, public UserID {
// 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);

Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Symbol/TypeMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class TypeMap {

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);

Expand Down
17 changes: 12 additions & 5 deletions lldb/include/lldb/Symbol/TypeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,18 @@ class TypeSystem : public PluginInterface {
uint32_t bitfield_bit_offset,
ExecutionContextScope *exe_scope) = 0;

virtual void
DumpTypeDescription(lldb::opaque_compiler_type_t type) = 0; // Dump to stdout

virtual void DumpTypeDescription(lldb::opaque_compiler_type_t type,
Stream *s) = 0;
/// Dump the type to stdout.
virtual void DumpTypeDescription(
lldb::opaque_compiler_type_t type,
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) = 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?

Expand Down
89 changes: 53 additions & 36 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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});
Expand All @@ -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()) {
Expand All @@ -8844,39 +8853,47 @@ 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);
}
}
}
}

if (buf.size() > 0) {
s->Write(buf.data(), buf.size());
}
}
}
}

void TypeSystemClang::DumpTypeName(const CompilerType &type) {
Expand Down
8 changes: 5 additions & 3 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
Original file line number Diff line number Diff line change
Expand Up @@ -975,10 +975,12 @@ class TypeSystemClang : public TypeSystem {
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);

Expand Down
9 changes: 5 additions & 4 deletions lldb/source/Symbol/CompilerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions lldb/source/Symbol/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) << ' ';
Expand All @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions lldb/source/Symbol/TypeMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
Expand Down
21 changes: 16 additions & 5 deletions lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -29,7 +34,13 @@
// 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;
Expand Down
Loading

0 comments on commit 681466f

Please sign in to comment.