aeubanks updated this revision to Diff 471330. aeubanks added a comment. fix nested types by introducing Type::GetBaseName() add expr eval tests
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D134378/new/ https://reviews.llvm.org/D134378 Files: lldb/include/lldb/Symbol/CompilerType.h lldb/include/lldb/Symbol/Type.h lldb/include/lldb/Symbol/TypeSystem.h lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h lldb/source/Symbol/CompilerType.cpp lldb/source/Symbol/Type.cpp lldb/test/API/lang/cpp/complete-type-check/TestCppIsTypeComplete.py lldb/test/API/lang/cpp/unique-types2/Makefile lldb/test/API/lang/cpp/unique-types2/TestUniqueTypes.py lldb/test/API/lang/cpp/unique-types2/main.cpp
Index: lldb/test/API/lang/cpp/unique-types2/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/unique-types2/main.cpp @@ -0,0 +1,27 @@ +template <class T> struct Foo { + T t; + template <class U> class Nested { + U u; + }; +}; + +template <class T, class... Ss> class FooPack { + T t; +}; + +int main() { + Foo<char> t1; + Foo<int> t2; + Foo<Foo<int>> t3; + + FooPack<char> p1; + FooPack<int> p2; + FooPack<Foo<int>> p3; + FooPack<char, int> p4; + FooPack<char, float> p5; + FooPack<int, int> p6; + FooPack<int, int, int> p7; + + Foo<int>::Nested<char> n1; + // Set breakpoint here +} Index: lldb/test/API/lang/cpp/unique-types2/TestUniqueTypes.py =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/unique-types2/TestUniqueTypes.py @@ -0,0 +1,61 @@ +""" +Test that we return only the requested template instantiation. +""" + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + +class UniqueTypesTestCase(TestBase): + def do_test(self, debug_flags): + """Test that we only display the requested Foo instantiation, not all Foo instantiations.""" + self.build(dictionary=debug_flags) + lldbutil.run_to_source_breakpoint(self, "// Set breakpoint here", lldb.SBFileSpec("main.cpp")) + + self.expect("image lookup -A -t '::Foo<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<int>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<Foo<int> >'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<float>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + + self.expect("image lookup -A -t '::FooPack<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<int>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<Foo<int> >'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<char, int>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<char, float>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<int, int>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<int, int, int>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'FooPack<float>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + self.expect("image lookup -A -t 'FooPack<float, int>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + + self.expect("image lookup -A -t '::Foo<int>::Nested<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<int>::Nested<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t 'Foo<char>::Nested<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + self.expect("image lookup -A -t 'Foo<int>::Nested<int>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + self.expect("image lookup -A -t 'Nested<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["1 match found"]) + self.expect("image lookup -A -t '::Nested<char>'", DATA_TYPES_DISPLAYED_CORRECTLY, error=True) + + self.expect_expr("t1", result_type="Foo<char>") + self.expect_expr("t1", result_type="Foo<char>") + self.expect_expr("t2", result_type="Foo<int>") + self.expect_expr("t3", result_type="Foo<Foo<int> >") + self.expect_expr("p1", result_type="FooPack<char>") + self.expect_expr("p2", result_type="FooPack<int>") + self.expect_expr("p3", result_type="FooPack<Foo<int> >") + self.expect_expr("p4", result_type="FooPack<char, int>") + self.expect_expr("p5", result_type="FooPack<char, float>") + self.expect_expr("p6", result_type="FooPack<int, int>") + self.expect_expr("p7", result_type="FooPack<int, int, int>") + self.expect_expr("n1", result_type="Foo<int>::Nested<char>") + + @skipIf(compiler=no_match("clang")) + @skipIf(compiler_version=["<", "15.0"]) + def test_simple_template_name(self): + self.do_test(dict(CFLAGS_EXTRAS="-gsimple-template-names")) + + @skipIf(compiler=no_match("clang")) + @skipIf(compiler_version=["<", "15.0"]) + def test_no_simple_template_name(self): + self.do_test(dict(CFLAGS_EXTRAS="-gno-simple-template-names")) Index: lldb/test/API/lang/cpp/unique-types2/Makefile =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/unique-types2/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules Index: lldb/test/API/lang/cpp/complete-type-check/TestCppIsTypeComplete.py =================================================================== --- lldb/test/API/lang/cpp/complete-type-check/TestCppIsTypeComplete.py +++ lldb/test/API/lang/cpp/complete-type-check/TestCppIsTypeComplete.py @@ -51,7 +51,7 @@ # Record types without a defining declaration are not complete. self.assertPointeeIncomplete("FwdClass *", "fwd_class") self.assertPointeeIncomplete("FwdClassTypedef *", "fwd_class_typedef") - self.assertPointeeIncomplete("FwdTemplateClass<> *", "fwd_template_class") + self.assertPointeeIncomplete("FwdTemplateClass<int> *", "fwd_template_class") # A pointer type is complete even when it points to an incomplete type. fwd_class_ptr = self.expect_expr("fwd_class", result_type="FwdClass *") Index: lldb/source/Symbol/Type.cpp =================================================================== --- lldb/source/Symbol/Type.cpp +++ lldb/source/Symbol/Type.cpp @@ -305,6 +305,10 @@ return m_name; } +ConstString Type::GetBaseName() { + return GetForwardCompilerType().GetBaseName(); +} + void Type::DumpTypeName(Stream *s) { GetName().Dump(s, "<invalid-type-name>"); } void Type::DumpValue(ExecutionContext *exe_ctx, Stream *s, Index: lldb/source/Symbol/CompilerType.cpp =================================================================== --- lldb/source/Symbol/CompilerType.cpp +++ lldb/source/Symbol/CompilerType.cpp @@ -287,6 +287,13 @@ return ConstString("<invalid>"); } +ConstString CompilerType::GetBaseName() const { + if (IsValid()) { + return m_type_system->GetBaseName(m_type); + } + return ConstString("<invalid>"); +} + ConstString CompilerType::GetDisplayTypeName() const { if (IsValid()) return m_type_system->GetDisplayTypeName(m_type); Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -647,6 +647,8 @@ ConstString GetTypeName(lldb::opaque_compiler_type_t type) override; + ConstString GetBaseName(lldb::opaque_compiler_type_t type) override; + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override; uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -3806,6 +3806,34 @@ return ConstString(qual_type.getAsString(GetTypePrintingPolicy())); } +ConstString TypeSystemClang::GetBaseName(lldb::opaque_compiler_type_t type) { + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + + // Remove certain type sugar from the name. Sugar such as elaborated types + // or template types which only serve to improve diagnostics shouldn't + // act as their own types from the user's perspective (e.g., formatter + // shouldn't format a variable differently depending on how the ser has + // specified the type. '::Type' and 'Type' should behave the same). + // Typedefs and atomic derived types are not removed as they are actually + // useful for identifiying specific types. + qual_type = RemoveWrappingTypes(qual_type, + {clang::Type::Typedef, clang::Type::Atomic}); + + // For a typedef just return the qualified name. + if (const auto *typedef_type = qual_type->getAs<clang::TypedefType>()) { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + return ConstString(GetTypeNameForDecl(typedef_decl)); + } + + clang::PrintingPolicy printing_policy(GetTypePrintingPolicy()); + printing_policy.SuppressScope = true; + + return ConstString(qual_type.getAsString(printing_policy)); +} + ConstString TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) { if (!type) @@ -9353,7 +9381,9 @@ const TypeSystemClang::TemplateParameterInfos &template_param_infos) { if (template_param_infos.IsValid()) { std::string template_basename(parent_name); - template_basename.erase(template_basename.find('<')); + // With -gsimple-template-names we may omit template parameters in the name. + if (auto i = template_basename.find('<'); i != std::string::npos) + template_basename.erase(i); return CreateClassTemplateDecl(decl_ctx, owning_module, access_type, template_basename.c_str(), tag_decl_kind, Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2492,6 +2492,46 @@ return types.GetSize() < max_matches; }); + // With -gsimple-template-names, a templated type's DW_AT_name will not + // contain the template parameters. Try again stripping '<' and anything + // after, filtering out entries with template parameters that don't match. + if (types.GetSize() < max_matches) { + const llvm::StringRef nameRef = name.GetStringRef(); + auto it = nameRef.find('<'); + if (it != llvm::StringRef::npos) { + const llvm::StringRef nameNoTemplateParams = nameRef.slice(0, it); + const llvm::StringRef templateParams = nameRef.slice(it, nameRef.size()); + m_index->GetTypes(ConstString(nameNoTemplateParams), [&](DWARFDIE die) { + if (!DIEInDeclContext(parent_decl_ctx, die)) + return true; // The containing decl contexts don't match + + TypeSP Ty = GetTypeForDIE(die); + llvm::StringRef qualName = Ty->GetBaseName().AsCString(); + auto it = qualName.find('<'); + // If the candidate qualified name doesn't have '<', it doesn't have + // template params to compare. + if (it == llvm::StringRef::npos) + return true; + + // Filter out non-matching instantiations by comparing template params. + llvm::StringRef qualNameTemplateParams = + qualName.slice(it, qualName.size()); + + if (templateParams != qualNameTemplateParams) + return true; + + Type *matching_type = ResolveType(die, true, true); + if (!matching_type) + return true; + + // We found a type pointer, now find the shared pointer form our type + // list. + types.InsertUnique(matching_type->shared_from_this()); + return types.GetSize() < max_matches; + }); + } + } + // Next search through the reachable Clang modules. This only applies for // DWARF objects compiled with -gmodules that haven't been processed by // dsymutil. Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -127,6 +127,10 @@ lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); + /// Get the template parameters of a die as a string if the die name does not + /// already contain them. This happens with -gsimple-template-names. + std::string GetTemplateParametersString(const DWARFDIE &die); + std::string GetCPlusPlusQualifiedName(const DWARFDIE &die); bool ParseChildMembers( Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1523,6 +1523,41 @@ return type_sp; } +std::string +DWARFASTParserClang::GetTemplateParametersString(const DWARFDIE &die) { + if (llvm::StringRef(die.GetName()).contains("<")) + return std::string(); + TypeSystemClang::TemplateParameterInfos template_param_infos; + if (!ParseTemplateParameterInfos(die, template_param_infos)) + return std::string(); + std::string all_template_names; + llvm::SmallVector<clang::TemplateArgument, 2> args = + template_param_infos.args; + if (template_param_infos.hasParameterPack()) + args.append(template_param_infos.packed_args->args); + if (args.empty()) + return std::string(); + for (auto &arg : args) { + std::string template_name; + llvm::raw_string_ostream os(template_name); + arg.print(m_ast.getASTContext().getPrintingPolicy(), os, true); + + if (!template_name.empty()) { + if (all_template_names.empty()) { + all_template_names.append("<"); + } else { + all_template_names.append(", "); + } + all_template_names.append(template_name); + } + } + assert(!all_template_names.empty() && "no template parameters?"); + // Spacing doesn't matter as long as we're consistent because we're only using + // this to deduplicate C++ symbols. + all_template_names.append(">"); + return all_template_names; +} + std::string DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { if (!die.IsValid()) @@ -1534,6 +1569,9 @@ DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); // TODO: change this to get the correct decl context parent.... while (parent_decl_ctx_die) { + // The name may not contain template parameters due to simplified template + // names; we must reconstruct the full name from child template parameter + // dies via GetTemplateParametersString(). const dw_tag_t parent_tag = parent_decl_ctx_die.Tag(); switch (parent_tag) { case DW_TAG_namespace: { @@ -1551,6 +1589,8 @@ case DW_TAG_structure_type: case DW_TAG_union_type: { if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) { + qualified_name.insert(0, + GetTemplateParametersString(parent_decl_ctx_die)); qualified_name.insert(0, "::"); qualified_name.insert(0, class_union_struct_name); } @@ -1568,6 +1608,7 @@ qualified_name.append("::"); qualified_name.append(name); + qualified_name.append(GetTemplateParametersString(die)); return qualified_name; } @@ -1772,36 +1813,36 @@ metadata.SetUserID(die.GetID()); metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); - if (attrs.name.GetStringRef().contains('<')) { - TypeSystemClang::TemplateParameterInfos template_param_infos; - if (ParseTemplateParameterInfos(die, template_param_infos)) { - clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl( - decl_ctx, GetOwningClangModule(die), attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, template_param_infos); - if (!class_template_decl) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" " - "clang::ClassTemplateDecl failed to return a decl.", - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString()); - } - return TypeSP(); + TypeSystemClang::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos(die, template_param_infos) && + (!template_param_infos.args.empty() || + template_param_infos.packed_args)) { + clang::ClassTemplateDecl *class_template_decl = + m_ast.ParseClassTemplateDecl( + decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, template_param_infos); + if (!class_template_decl) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" " + "clang::ClassTemplateDecl failed to return a decl.", + static_cast<void *>(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString()); } + return TypeSP(); + } - clang::ClassTemplateSpecializationDecl *class_specialization_decl = - m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, GetOwningClangModule(die), class_template_decl, - tag_decl_kind, template_param_infos); - clang_type = m_ast.CreateClassTemplateSpecializationType( - class_specialization_decl); - clang_type_was_created = true; + clang::ClassTemplateSpecializationDecl *class_specialization_decl = + m_ast.CreateClassTemplateSpecializationDecl( + decl_ctx, GetOwningClangModule(die), class_template_decl, + tag_decl_kind, template_param_infos); + clang_type = m_ast.CreateClassTemplateSpecializationType( + class_specialization_decl); + clang_type_was_created = true; - m_ast.SetMetadata(class_template_decl, metadata); - m_ast.SetMetadata(class_specialization_decl, metadata); - } + m_ast.SetMetadata(class_template_decl, metadata); + m_ast.SetMetadata(class_specialization_decl, metadata); } if (!clang_type_was_created) { Index: lldb/include/lldb/Symbol/TypeSystem.h =================================================================== --- lldb/include/lldb/Symbol/TypeSystem.h +++ lldb/include/lldb/Symbol/TypeSystem.h @@ -210,6 +210,8 @@ virtual ConstString GetTypeName(lldb::opaque_compiler_type_t type) = 0; + virtual ConstString GetBaseName(lldb::opaque_compiler_type_t type) = 0; + virtual ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) = 0; virtual uint32_t Index: lldb/include/lldb/Symbol/Type.h =================================================================== --- lldb/include/lldb/Symbol/Type.h +++ lldb/include/lldb/Symbol/Type.h @@ -135,6 +135,8 @@ ConstString GetName(); + ConstString GetBaseName(); + llvm::Optional<uint64_t> GetByteSize(ExecutionContextScope *exe_scope); uint32_t GetNumChildren(bool omit_empty_base_classes); Index: lldb/include/lldb/Symbol/CompilerType.h =================================================================== --- lldb/include/lldb/Symbol/CompilerType.h +++ lldb/include/lldb/Symbol/CompilerType.h @@ -165,6 +165,8 @@ ConstString GetTypeName() const; + ConstString GetBaseName() const; + ConstString GetDisplayTypeName() const; uint32_t
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits