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,
// 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);
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);
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?
}
}
-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();
}
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});
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()) {
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) {
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);
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);
}
}
}
}
-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) << ' ';
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) {
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);
}
}
@interface SomeClass {
}
+@property (readonly) int number;
@end
template <typename T> struct Template { T field; };
// 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
// 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;
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));
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();
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;
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();
}
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();
}
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())