Index: llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test =================================================================== --- llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test +++ llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test @@ -30,7 +30,6 @@ ; TYPES_1: Classes ; TYPES_1: struct A { -; TYPES_1: public: ; TYPES_1: virtual void PureFunc() = 0 ; TYPES_1: virtual void VirtualFunc() ; TYPES_1: void RegularFunc() Index: llvm/test/tools/llvm-pdbdump/class-layout.test =================================================================== --- llvm/test/tools/llvm-pdbdump/class-layout.test +++ llvm/test/tools/llvm-pdbdump/class-layout.test @@ -17,9 +17,7 @@ ; MEMBERS_TEST: class MembersTest::A { ; MEMBERS_TEST-DAG: typedef int NestedTypedef ; MEMBERS_TEST-DAG: enum NestedEnum -; MEMBERS_TEST: public: -; MEMBERS_TEST-NEXT: void MemberFunc() -; MEMBERS_TEST-NEXT: private: +; MEMBERS_TEST: void MemberFunc() ; MEMBERS_TEST-DAG: int IntMemberVar ; MEMBERS_TEST-DAG: double DoubleMemberVar ; MEMBERS_TEST: } @@ -48,7 +46,6 @@ ; BITFIELD_TEST: ---TYPES--- ; BITFIELD_TEST: struct BitFieldTest::A { -; BITFIELD_TEST-NEXT: public: ; BITFIELD_TEST-NEXT: +0x00 int Bits1 : 1 ; BITFIELD_TEST-NEXT: +0x00 int Bits2 : 2 ; BITFIELD_TEST-NEXT: +0x00 int Bits3 : 3 Index: llvm/test/tools/llvm-pdbdump/regex-filter.test =================================================================== --- llvm/test/tools/llvm-pdbdump/regex-filter.test +++ llvm/test/tools/llvm-pdbdump/regex-filter.test @@ -1,9 +1,16 @@ ; RUN: llvm-pdbdump pretty -symbols -globals -types %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=NO_FILTER %s + ; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s +; RUN: llvm-pdbdump pretty -classes -enums %p/Inputs/FilterTest.pdb \ +; RUN: | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s + ; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalEnum|NestedEnum" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_ENUMS %s +; RUN: llvm-pdbdump pretty -classes -typedefs %p/Inputs/FilterTest.pdb \ +; RUN: | FileCheck --check-prefix=EXCLUDE_ENUMS %s + ; RUN: llvm-pdbdump pretty -types -symbols -globals -exclude-symbols="MemberVar|GlobalVar" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_VARS %s ; RUN: llvm-pdbdump pretty -types -exclude-types="FilterTestClass" \ @@ -36,31 +43,25 @@ ; NO_FILTER-DAG: GlobalEnum GlobalEnumVar ; EXCLUDE_TYPEDEFS: ---TYPES--- -; EXCLUDE_TYPEDEFS: Enums: -; EXCLUDE_TYPEDEFS: GlobalEnum -; EXCLUDE_TYPEDEFS: Typedefs ; EXCLUDE_TYPEDEFS-NOT: GlobalTypedef -; EXCLUDE_TYPEDEFS: Classes -; EXCLUDE_TYPEDEFS: class FilterTestClass ; EXCLUDE_TYPEDEFS-NOT: NestedTypedef -; EXCLUDE_TYPEDEFS: private: +; EXCLUDE_TYPEDEFS-DAG: GlobalEnum +; EXCLUDE_TYPEDEFS-DAG: NestedEnum +; EXCLUDE_TYPEDEFS: class FilterTestClass ; EXCLUDE_ENUMS: ---TYPES--- -; EXCLUDE_ENUMS: Enums: ; EXCLUDE_ENUMS-NOT: GlobalEnum -; EXCLUDE_ENUMS: Typedefs +; EXCLUDE_ENUMS-NOT: NestedEnum ; EXCLUDE_ENUMS: GlobalTypedef -; EXCLUDE_ENUMS: Classes ; EXCLUDE_ENUMS: class FilterTestClass -; EXCLUDE_ENUMS-NOT: NestedEnum -; EXCLUDE_ENUMS: private: ; EXCLUDE_VARS: ---TYPES--- -; EXCLUDE_VARS: Classes: -; EXCLUDE_VARS: class FilterTestClass -; EXCLUDE_VARS: private: ; EXCLUDE_VARS-NOT: IntMemberVar ; EXCLUDE_VARS-NOT: DoubleMemberVar +; EXCLUDE_VARS-DAG: GlobalEnum +; EXCLUDE_VARS-DAG: NestedEnum +; EXCLUDE_VARS: GlobalTypedef +; EXCLUDE_VARS: class FilterTestClass ; EXCLUDE_VARS: ---GLOBALS--- ; EXCLUDE_VARS-NOT: DoubleGlobalVar ; EXCLUDE_VARS-NOT: IntGlobalVar Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h +++ llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h @@ -39,24 +39,6 @@ private: LinePrinter &Printer; - - struct SymbolGroup { - SymbolGroup() {} - SymbolGroup(SymbolGroup &&Other) { - Functions = std::move(Other.Functions); - Data = std::move(Other.Data); - Unknown = std::move(Other.Unknown); - } - - std::list> Functions; - std::list> Data; - std::list> Unknown; - SymbolGroup(const SymbolGroup &other) = delete; - SymbolGroup &operator=(const SymbolGroup &other) = delete; - }; - typedef std::unordered_map SymbolGroupByAccess; - - int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group); }; } } Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp @@ -35,6 +35,9 @@ : PDBSymDumper(true), Printer(P) {} void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { + assert(opts::pretty::ClassFormat != + opts::pretty::ClassDefinitionFormat::None); + std::string Name = Class.getName(); WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); @@ -61,98 +64,36 @@ Printer << " {"; auto Children = Class.findAllChildren(); - if (Children->getChildCount() == 0) { - Printer << "}"; - return; - } - - // Try to dump symbols organized by member access level. Public members - // first, then protected, then private. This might be slow, so it's worth - // reconsidering the value of this if performance of large PDBs is a problem. - // NOTE: Access level of nested types is not recorded in the PDB, so we have - // a special case for them. - SymbolGroupByAccess Groups; - Groups.insert(std::make_pair(0, SymbolGroup())); - Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup())); - Groups.insert( - std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup())); - Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup())); - + Printer.Indent(); + int DumpedCount = 0; while (auto Child = Children->getNext()) { - PDB_MemberAccess Access = Child->getRawSymbol().getAccess(); - if (isa(*Child)) - continue; - - auto &AccessGroup = Groups.find((int)Access)->second; + if (!isa(Child.get())) { + // Only data symbols affect record layout, so skip any non-data symbols if + // we're in record layout mode. + if (opts::pretty::ClassFormat == + opts::pretty::ClassDefinitionFormat::LayoutOnly) + continue; + } if (auto Func = dyn_cast(Child.get())) { if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) continue; + if (Func->getLength() == 0 && !Func->isPureVirtual() && !Func->isIntroVirtualFunction()) continue; - Child.release(); - AccessGroup.Functions.push_back(std::unique_ptr(Func)); - } else if (auto Data = dyn_cast(Child.get())) { - Child.release(); - AccessGroup.Data.push_back(std::unique_ptr(Data)); - } else { - AccessGroup.Unknown.push_back(std::move(Child)); } + + ++DumpedCount; + Child->dump(*this); } - int Count = 0; - Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]); - Count += dumpAccessGroup(PDB_MemberAccess::Public, - Groups[(int)PDB_MemberAccess::Public]); - Count += dumpAccessGroup(PDB_MemberAccess::Protected, - Groups[(int)PDB_MemberAccess::Protected]); - Count += dumpAccessGroup(PDB_MemberAccess::Private, - Groups[(int)PDB_MemberAccess::Private]); - if (Count > 0) + Printer.Unindent(); + if (DumpedCount > 0) Printer.NewLine(); Printer << "}"; } -int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access, - const SymbolGroup &Group) { - if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty()) - return 0; - - int Count = 0; - if (Access == PDB_MemberAccess::Private) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Keyword).get() << "private"; - Printer << ":"; - } else if (Access == PDB_MemberAccess::Protected) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected"; - Printer << ":"; - } else if (Access == PDB_MemberAccess::Public) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Keyword).get() << "public"; - Printer << ":"; - } - Printer.Indent(); - for (auto iter = Group.Functions.begin(), end = Group.Functions.end(); - iter != end; ++iter) { - ++Count; - (*iter)->dump(*this); - } - for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end; - ++iter) { - ++Count; - (*iter)->dump(*this); - } - for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end(); - iter != end; ++iter) { - ++Count; - (*iter)->dump(*this); - } - Printer.Unindent(); - return Count; -} - void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {} void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) { Index: llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp @@ -100,7 +100,7 @@ Printer.NewLine(); - if (opts::pretty::NoClassDefs) { + if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } else { Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -17,6 +17,8 @@ namespace opts { namespace pretty { +enum class ClassDefinitionFormat { None, LayoutOnly, Full }; + extern llvm::cl::opt Compilands; extern llvm::cl::opt Symbols; extern llvm::cl::opt Globals; @@ -26,7 +28,7 @@ extern llvm::cl::opt All; extern llvm::cl::opt ExcludeCompilerGenerated; -extern llvm::cl::opt NoClassDefs; +extern llvm::cl::opt ClassFormat; extern llvm::cl::opt NoEnumDefs; extern llvm::cl::list ExcludeTypes; extern llvm::cl::list ExcludeSymbols; Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -170,9 +170,17 @@ ExcludeSystemLibraries("no-system-libs", cl::desc("Don't show symbols from system libraries"), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt NoClassDefs("no-class-definitions", - cl::desc("Don't display full class definitions"), - cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt ClassFormat( + "class-definitions", cl::desc("Class definition format"), + cl::init(ClassDefinitionFormat::Full), + cl::values(clEnumValN(ClassDefinitionFormat::Full, "full", + "Display complete class definition"), + clEnumValN(ClassDefinitionFormat::LayoutOnly, "layout", + "Display only members which affect record layout"), + clEnumValN(ClassDefinitionFormat::None, "none", + "Don't display class definitions")), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + cl::opt NoEnumDefs("no-enum-definitions", cl::desc("Don't display full enum definitions"), cl::cat(FilterCategory), cl::sub(PrettySubcommand));