| //===-- LVType.cpp --------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This implements the LVType class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/DebugInfo/LogicalView/Core/LVType.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
| |
| using namespace llvm; |
| using namespace llvm::logicalview; |
| |
| #define DEBUG_TYPE "Type" |
| |
| namespace { |
| const char *const KindBaseType = "BaseType"; |
| const char *const KindConst = "Const"; |
| const char *const KindEnumerator = "Enumerator"; |
| const char *const KindImport = "Import"; |
| const char *const KindPointer = "Pointer"; |
| const char *const KindPointerMember = "PointerMember"; |
| const char *const KindReference = "Reference"; |
| const char *const KindRestrict = "Restrict"; |
| const char *const KindRvalueReference = "RvalueReference"; |
| const char *const KindSubrange = "Subrange"; |
| const char *const KindTemplateTemplate = "TemplateTemplate"; |
| const char *const KindTemplateType = "TemplateType"; |
| const char *const KindTemplateValue = "TemplateValue"; |
| const char *const KindTypeAlias = "TypeAlias"; |
| const char *const KindUndefined = "Undefined"; |
| const char *const KindUnaligned = "Unaligned"; |
| const char *const KindUnspecified = "Unspecified"; |
| const char *const KindVolatile = "Volatile"; |
| } // end anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // DWARF Type. |
| //===----------------------------------------------------------------------===// |
| // Return a string representation for the type kind. |
| const char *LVType::kind() const { |
| const char *Kind = KindUndefined; |
| if (getIsBase()) |
| Kind = KindBaseType; |
| else if (getIsConst()) |
| Kind = KindConst; |
| else if (getIsEnumerator()) |
| Kind = KindEnumerator; |
| else if (getIsImport()) |
| Kind = KindImport; |
| else if (getIsPointerMember()) |
| Kind = KindPointerMember; |
| else if (getIsPointer()) |
| Kind = KindPointer; |
| else if (getIsReference()) |
| Kind = KindReference; |
| else if (getIsRestrict()) |
| Kind = KindRestrict; |
| else if (getIsRvalueReference()) |
| Kind = KindRvalueReference; |
| else if (getIsSubrange()) |
| Kind = KindSubrange; |
| else if (getIsTemplateTypeParam()) |
| Kind = KindTemplateType; |
| else if (getIsTemplateValueParam()) |
| Kind = KindTemplateValue; |
| else if (getIsTemplateTemplateParam()) |
| Kind = KindTemplateTemplate; |
| else if (getIsTypedef()) |
| Kind = KindTypeAlias; |
| else if (getIsUnaligned()) |
| Kind = KindUnaligned; |
| else if (getIsUnspecified()) |
| Kind = KindUnspecified; |
| else if (getIsVolatile()) |
| Kind = KindVolatile; |
| return Kind; |
| } |
| |
| LVTypeDispatch LVType::Dispatch = { |
| {LVTypeKind::IsBase, &LVType::getIsBase}, |
| {LVTypeKind::IsConst, &LVType::getIsConst}, |
| {LVTypeKind::IsEnumerator, &LVType::getIsEnumerator}, |
| {LVTypeKind::IsImport, &LVType::getIsImport}, |
| {LVTypeKind::IsImportDeclaration, &LVType::getIsImportDeclaration}, |
| {LVTypeKind::IsImportModule, &LVType::getIsImportModule}, |
| {LVTypeKind::IsPointer, &LVType::getIsPointer}, |
| {LVTypeKind::IsPointerMember, &LVType::getIsPointerMember}, |
| {LVTypeKind::IsReference, &LVType::getIsReference}, |
| {LVTypeKind::IsRestrict, &LVType::getIsRestrict}, |
| {LVTypeKind::IsRvalueReference, &LVType::getIsRvalueReference}, |
| {LVTypeKind::IsSubrange, &LVType::getIsSubrange}, |
| {LVTypeKind::IsTemplateParam, &LVType::getIsTemplateParam}, |
| {LVTypeKind::IsTemplateTemplateParam, &LVType::getIsTemplateTemplateParam}, |
| {LVTypeKind::IsTemplateTypeParam, &LVType::getIsTemplateTypeParam}, |
| {LVTypeKind::IsTemplateValueParam, &LVType::getIsTemplateValueParam}, |
| {LVTypeKind::IsTypedef, &LVType::getIsTypedef}, |
| {LVTypeKind::IsUnaligned, &LVType::getIsUnaligned}, |
| {LVTypeKind::IsUnspecified, &LVType::getIsUnspecified}, |
| {LVTypeKind::IsVolatile, &LVType::getIsVolatile}}; |
| |
| void LVType::resolveReferences() { |
| // Some DWARF tags are the representation of types. However, we associate |
| // some of them to scopes. The ones associated with types, do not have |
| // any reference tags, such as DW_AT_specification, DW_AT_abstract_origin, |
| // DW_AT_extension. |
| |
| // Set the file/line information using the Debug Information entry. |
| setFile(/*Reference=*/nullptr); |
| |
| if (LVElement *Element = getType()) |
| Element->resolve(); |
| } |
| |
| void LVType::resolveName() { |
| if (getIsResolvedName()) |
| return; |
| setIsResolvedName(); |
| |
| // The templates are recorded as normal DWARF objects relationships; |
| // the template parameters are preserved to show the types used during |
| // the instantiation; however if a compare have been requested, those |
| // parameters needs to be resolved, so no conflicts are generated. |
| // The following DWARF illustrates this issue: |
| // |
| // a) Template Parameters are preserved: |
| // {Class} 'ConstArray<AtomTable>' |
| // {Inherits} -> 'ArrayBase' |
| // {TemplateType} 'taTYPE' -> 'AtomTable' |
| // {Member} 'mData' -> '* taTYPE' |
| // |
| // b) Template Parameters are resolved: |
| // {Class} 'ConstArray<AtomTable>' |
| // {Inherits} -> 'ArrayBase' |
| // {TemplateType} 'taTYPE' -> 'AtomTable' |
| // {Member} 'mData' -> '* AtomTable' |
| // |
| // In (b), the {Member} type have been resolved to use the real type. |
| |
| LVElement *BaseType = getType(); |
| if (BaseType && options().getAttributeArgument()) |
| if (BaseType->isTemplateParam()) |
| BaseType = BaseType->getType(); |
| |
| if (BaseType && !BaseType->getIsResolvedName()) |
| BaseType->resolveName(); |
| resolveFullname(BaseType, getName()); |
| |
| // In the case of unnamed types, try to generate a name for it, using |
| // the parents name and the line information. Ignore the template parameters. |
| if (!isNamed() && !getIsTemplateParam()) |
| generateName(); |
| |
| LVElement::resolveName(); |
| |
| // Resolve any given pattern. |
| patterns().resolvePatternMatch(this); |
| } |
| |
| StringRef LVType::resolveReferencesChain() { |
| // The types do not have a DW_AT_specification or DW_AT_abstract_origin |
| // reference. Just return the type name. |
| return getName(); |
| } |
| |
| void LVType::markMissingParents(const LVTypes *References, |
| const LVTypes *Targets) { |
| if (!(References && Targets)) |
| return; |
| |
| LLVM_DEBUG({ |
| dbgs() << "\n[LVType::markMissingParents]\n"; |
| for (const LVType *Reference : *References) |
| dbgs() << "References: " |
| << "Kind = " << formattedKind(Reference->kind()) << ", " |
| << "Name = " << formattedName(Reference->getName()) << "\n"; |
| for (const LVType *Target : *Targets) |
| dbgs() << "Targets : " |
| << "Kind = " << formattedKind(Target->kind()) << ", " |
| << "Name = " << formattedName(Target->getName()) << "\n"; |
| }); |
| |
| for (LVType *Reference : *References) { |
| LLVM_DEBUG({ |
| dbgs() << "Search Reference: Name = " |
| << formattedName(Reference->getName()) << "\n"; |
| }); |
| if (!Reference->findIn(Targets)) |
| Reference->markBranchAsMissing(); |
| } |
| } |
| |
| LVType *LVType::findIn(const LVTypes *Targets) const { |
| if (!Targets) |
| return nullptr; |
| |
| LLVM_DEBUG({ |
| dbgs() << "\n[LVType::findIn]\n" |
| << "Reference: " |
| << "Level = " << getLevel() << ", " |
| << "Kind = " << formattedKind(kind()) << ", " |
| << "Name = " << formattedName(getName()) << "\n"; |
| for (const LVType *Target : *Targets) |
| dbgs() << "Target : " |
| << "Level = " << Target->getLevel() << ", " |
| << "Kind = " << formattedKind(Target->kind()) << ", " |
| << "Name = " << formattedName(Target->getName()) << "\n"; |
| }); |
| |
| for (LVType *Target : *Targets) |
| if (equals(Target)) |
| return Target; |
| |
| return nullptr; |
| } |
| |
| // Check for a match on the arguments of a function. |
| bool LVType::parametersMatch(const LVTypes *References, |
| const LVTypes *Targets) { |
| if (!References && !Targets) |
| return true; |
| if (References && Targets) { |
| LVTypes ReferenceTypes; |
| LVScopes ReferenceScopes; |
| getParameters(References, &ReferenceTypes, &ReferenceScopes); |
| LVTypes TargetTypes; |
| LVScopes TargetScopes; |
| getParameters(Targets, &TargetTypes, &TargetScopes); |
| if (!LVType::equals(&ReferenceTypes, &TargetTypes) || |
| !LVScope::equals(&ReferenceScopes, &TargetScopes)) |
| return false; |
| return true; |
| } |
| return false; |
| } |
| |
| // Return the types which are parameters. |
| void LVType::getParameters(const LVTypes *Types, LVTypes *TypesParam, |
| LVScopes *ScopesParam) { |
| if (!Types) |
| return; |
| |
| // During a compare task, the template parameters are expanded to |
| // point to their real types, to avoid compare conflicts. |
| for (LVType *Type : *Types) { |
| if (!Type->getIsTemplateParam()) |
| continue; |
| if (options().getAttributeArgument()) { |
| LVScope *Scope = nullptr; |
| if (Type->getIsKindType()) |
| Type = Type->getTypeAsType(); |
| else { |
| if (Type->getIsKindScope()) { |
| Scope = Type->getTypeAsScope(); |
| Type = nullptr; |
| } |
| } |
| Type ? TypesParam->push_back(Type) : ScopesParam->push_back(Scope); |
| } else |
| TypesParam->push_back(Type); |
| } |
| } |
| |
| bool LVType::equals(const LVType *Type) const { |
| return LVElement::equals(Type); |
| } |
| |
| bool LVType::equals(const LVTypes *References, const LVTypes *Targets) { |
| if (!References && !Targets) |
| return true; |
| if (References && Targets && References->size() == Targets->size()) { |
| for (const LVType *Reference : *References) |
| if (!Reference->findIn(Targets)) |
| return false; |
| return true; |
| } |
| return false; |
| } |
| |
| void LVType::report(LVComparePass Pass) { |
| getComparator().printItem(this, Pass); |
| } |
| |
| void LVType::print(raw_ostream &OS, bool Full) const { |
| if (getIncludeInPrint() && |
| (getIsReference() || getReader().doPrintType(this))) { |
| getReaderCompileUnit()->incrementPrintedTypes(); |
| LVElement::print(OS, Full); |
| printExtra(OS, Full); |
| } |
| } |
| |
| void LVType::printExtra(raw_ostream &OS, bool Full) const { |
| OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DWARF typedef. |
| //===----------------------------------------------------------------------===// |
| // Return the underlying type for a typedef, which can be a type or scope. |
| LVElement *LVTypeDefinition::getUnderlyingType() { |
| LVElement *BaseType = getTypeAsScope(); |
| if (BaseType) |
| // Underlying type is a scope. |
| return BaseType; |
| |
| LVType *Type = getTypeAsType(); |
| assert(Type && "Type definition does not have a type."); |
| |
| BaseType = Type; |
| while (Type->getIsTypedef()) { |
| BaseType = Type->getTypeAsScope(); |
| if (BaseType) |
| // Underlying type is a scope. |
| return BaseType; |
| |
| Type = Type->getTypeAsType(); |
| if (Type) |
| BaseType = Type; |
| } |
| |
| return BaseType; |
| } |
| |
| void LVTypeDefinition::resolveExtra() { |
| // Set the reference to the typedef type. |
| if (options().getAttributeUnderlying()) { |
| setUnderlyingType(getUnderlyingType()); |
| setIsTypedefReduced(); |
| if (LVElement *Type = getType()) { |
| Type->resolveName(); |
| resolveFullname(Type); |
| } |
| } |
| |
| // For the case of typedef'd anonymous structures: |
| // typedef struct { ... } Name; |
| // Propagate the typedef name to the anonymous structure. |
| LVScope *Aggregate = getTypeAsScope(); |
| if (Aggregate && Aggregate->getIsAnonymous()) |
| Aggregate->setName(getName()); |
| } |
| |
| bool LVTypeDefinition::equals(const LVType *Type) const { |
| return LVType::equals(Type); |
| } |
| |
| void LVTypeDefinition::printExtra(raw_ostream &OS, bool Full) const { |
| OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> " |
| << typeOffsetAsString() |
| << formattedName((getType() ? getType()->getName() : "")) << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DWARF enumerator (DW_TAG_enumerator). |
| //===----------------------------------------------------------------------===// |
| bool LVTypeEnumerator::equals(const LVType *Type) const { |
| return LVType::equals(Type); |
| } |
| |
| void LVTypeEnumerator::printExtra(raw_ostream &OS, bool Full) const { |
| OS << formattedKind(kind()) << " '" << getName() |
| << "' = " << formattedName(getValue()) << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DWARF import (DW_TAG_imported_module / DW_TAG_imported_declaration). |
| //===----------------------------------------------------------------------===// |
| bool LVTypeImport::equals(const LVType *Type) const { |
| return LVType::equals(Type); |
| } |
| |
| void LVTypeImport::printExtra(raw_ostream &OS, bool Full) const { |
| std::string Attributes = |
| formatAttributes(virtualityString(), accessibilityString()); |
| |
| OS << formattedKind(kind()) << " " << typeOffsetAsString() << Attributes |
| << formattedName((getType() ? getType()->getName() : "")) << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DWARF Template parameter holder (type or param). |
| //===----------------------------------------------------------------------===// |
| LVTypeParam::LVTypeParam() : LVType() { |
| options().getAttributeTypename() ? setIncludeInPrint() |
| : resetIncludeInPrint(); |
| } |
| |
| // Encode the specific template argument. |
| void LVTypeParam::encodeTemplateArgument(std::string &Name) const { |
| // The incoming type is a template parameter; we have 3 kinds of parameters: |
| // - type parameter: resolve the instance (type); |
| // - value parameter: resolve the constant value |
| // - template parameter: resolve the name of the template. |
| // If the parameter type is a template instance (STL sample), we need to |
| // expand the type (template template case). For the following variable |
| // declarations: |
| // std::type<float> a_float; |
| // std::type<int> a_int; |
| // We must generate names like: |
| // "std::type<float,std::less<float>,std::allocator<float>,false>" |
| // "std::type<int,std::less<int>,std::allocator<int>,false>" |
| // Instead of the incomplete names: |
| // "type<float,less,allocator,false>" |
| // "type<int,less,allocator,false>" |
| |
| if (getIsTemplateTypeParam()) { |
| // Get the type instance recorded in the template type; it can be a |
| // reference to a type or to a scope. |
| |
| if (getIsKindType()) { |
| // The argument types always are qualified. |
| Name.append(std::string(getTypeQualifiedName())); |
| |
| LVType *ArgType = getTypeAsType(); |
| // For template arguments that are typedefs, use the underlying type, |
| // which can be a type or scope. |
| if (ArgType->getIsTypedef()) { |
| LVObject *BaseType = ArgType->getUnderlyingType(); |
| Name.append(std::string(BaseType->getName())); |
| } else { |
| Name.append(std::string(ArgType->getName())); |
| } |
| } else { |
| if (getIsKindScope()) { |
| LVScope *ArgScope = getTypeAsScope(); |
| // If the scope is a template, we have to resolve that template, |
| // by recursively traversing its arguments. |
| if (ArgScope->getIsTemplate()) |
| ArgScope->encodeTemplateArguments(Name); |
| else { |
| // The argument types always are qualified. |
| Name.append(std::string(getTypeQualifiedName())); |
| Name.append(std::string(ArgScope->getName())); |
| } |
| } |
| } |
| } else |
| // Template value parameter or template template parameter. |
| Name.append(getValue()); |
| } |
| |
| bool LVTypeParam::equals(const LVType *Type) const { |
| if (!LVType::equals(Type)) |
| return false; |
| |
| // Checks the kind of template argument. |
| if (getIsTemplateTypeParam() && Type->getIsTemplateTypeParam()) |
| return getType()->equals(Type->getType()); |
| |
| if ((getIsTemplateValueParam() && Type->getIsTemplateValueParam()) || |
| (getIsTemplateTemplateParam() && Type->getIsTemplateTemplateParam())) |
| return getValueIndex() == Type->getValueIndex(); |
| |
| return false; |
| } |
| |
| void LVTypeParam::printExtra(raw_ostream &OS, bool Full) const { |
| OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> " |
| << typeOffsetAsString(); |
| |
| // Depending on the type of parameter, the print includes different |
| // information: type, value or reference to a template. |
| if (getIsTemplateTypeParam()) { |
| OS << formattedNames(getTypeQualifiedName(), getTypeName()) << "\n"; |
| return; |
| } |
| if (getIsTemplateValueParam()) { |
| OS << formattedName(getValue()) << " " << formattedName(getName()) << "\n"; |
| return; |
| } |
| if (getIsTemplateTemplateParam()) |
| OS << formattedName(getValue()) << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DW_TAG_subrange_type |
| //===----------------------------------------------------------------------===// |
| void LVTypeSubrange::resolveExtra() { |
| // There are 2 cases to represent the bounds information for an array: |
| // 1) DW_TAG_subrange_type |
| // DW_AT_type --> ref_type (type of count) |
| // DW_AT_count --> value (number of elements in subrange) |
| |
| // 2) DW_TAG_subrange_type |
| // DW_AT_lower_bound --> value |
| // DW_AT_upper_bound --> value |
| |
| // The idea is to represent the bounds as a string, depending on the format: |
| // 1) [count] |
| // 2) [lower..upper] |
| |
| // Subrange information. |
| std::string String; |
| |
| // Check if we have DW_AT_count subrange style. |
| if (getIsSubrangeCount()) |
| // Get count subrange value. Assume 0 if missing. |
| raw_string_ostream(String) << "[" << getCount() << "]"; |
| else |
| raw_string_ostream(String) |
| << "[" << getLowerBound() << ".." << getUpperBound() << "]"; |
| |
| setName(String); |
| } |
| |
| bool LVTypeSubrange::equals(const LVType *Type) const { |
| if (!LVType::equals(Type)) |
| return false; |
| |
| return getTypeName() == Type->getTypeName() && getName() == Type->getName(); |
| } |
| |
| void LVTypeSubrange::printExtra(raw_ostream &OS, bool Full) const { |
| OS << formattedKind(kind()) << " -> " << typeOffsetAsString() |
| << formattedName(getTypeName()) << " " << formattedName(getName()) << "\n"; |
| } |