sub getTypeInfo()

in src/main/abi-symbols/abi-dumper.pl [3709:4255]


sub getTypeInfo($)
{
    my $ID = $_[0];
    
    if(not defined $DWARF_Info{$ID}) {
        return;
    }
    
    if(not keys(%{$DWARF_Info{$ID}}))
    {
        delete($DWARF_Info{$ID});
        return;
    }
    
    my $Kind = $DWARF_Info{$ID}{"kind"};
    
    if(defined $Cache{"getTypeInfo"}{$ID}) {
        return;
    }
    
    if(my $N = $NameSpace{$ID})
    {
        if($DWARF_Info{$N}{"kind"} eq "prog")
        { # local code
          # template instances are declared in the subprogram (constructor)
            my $Tmpl = 0;
            if(my $ObjP = $DWARF_Info{$N}{"objptr"})
            {
                while($DWARF_Info{$ObjP}{"type"}) {
                    $ObjP = $DWARF_Info{$ObjP}{"type"};
                }
                my $CName = $DWARF_Info{$ObjP}{"name"};
                $CName=~s/<.*//g;
                if($CName eq $DWARF_Info{$N}{"name"}) {
                    $Tmpl = 1;
                }
            }
            if(not $Tmpl)
            { # local types
                $LocalType{$ID} = 1;
            }
        }
        elsif($DWARF_Info{$N}{"kind"} eq "lexical_block")
        { # local code
            return;
        }
    }
    
    $Cache{"getTypeInfo"}{$ID} = 1;
    
    my %TInfo = ();
    
    $TInfo{"Type"} = $TypeType{$Kind};
    
    if(not $TInfo{"Type"})
    {
        if($DWARF_Info{$ID}{"kind"} eq "subroutine_type") {
            $TInfo{"Type"} = "Func";
        }
    }
    
    if($DWARF_Info{$ID}{"name"} eq "__unknown__")
    { # size of such type may vary
        delete($DWARF_Info{$ID}{"size"});
    }
    
    if(defined $SYS_CLANGV
    and $TInfo{"Type"} eq "FieldPtr")
    { # support for Clang
        if(my $T = $DWARF_Info{$ID}{"type"})
        {
            if($DWARF_Info{$T}{"kind"} eq "subroutine_type")
            {
                $TInfo{"Type"} = "MethodPtr";
                $DWARF_Info{$ID}{"pfn"} = $T;
                $DWARF_Info{$T}{"objptr"} = $DWARF_Info{$ID}{"container"};
            }
        }
    }
    
    my $RealType = $TInfo{"Type"};
    
    if(defined $ClassMethods{$ID})
    {
        if($TInfo{"Type"} eq "Struct") {
            $RealType = "Class";
        }
    }
    
    if($TInfo{"Type"} ne "Enum"
    and my $BaseType = $DWARF_Info{$ID}{"type"})
    {
        $TInfo{"BaseType"} = "$BaseType";
        
        if(defined $TypeType{$DWARF_Info{$BaseType}{"kind"}})
        {
            getTypeInfo($TInfo{"BaseType"});
            
            if(not defined $TypeInfo{$TInfo{"BaseType"}}
            or not $TypeInfo{$TInfo{"BaseType"}}{"Name"})
            { # local code
                delete($TypeInfo{$ID});
                return;
            }
        }
    }
    
    if($RealType eq "Class") {
        $TInfo{"Copied"} = 1; # will be changed in getSymbolInfo()
    }
    
    if(defined $TypeMember{$ID})
    {
        my $Unnamed = 0;
        foreach my $Pos (sort {$a<=>$b} keys(%{$TypeMember{$ID}}))
        {
            my $MemId = $TypeMember{$ID}{$Pos};
            my $MInfo = $DWARF_Info{$MemId};
            
            if(my $Name = $MInfo->{"name"})
            {
                if(index($Name, "_vptr.")==0)
                { # v-table pointer
                    $Name="_vptr";
                }
                $TInfo{"Memb"}{$Pos}{"name"} = $Name;
            }
            else
            {
                $TInfo{"Memb"}{$Pos}{"name"} = "unnamed".$Unnamed;
                $Unnamed += 1;
            }
            if($TInfo{"Type"} eq "Enum") {
                $TInfo{"Memb"}{$Pos}{"value"} = $MInfo->{"cval"};
            }
            else
            {
                $TInfo{"Memb"}{$Pos}{"type"} = $MInfo->{"type"};
                if(my $Access = $MInfo->{"access"})
                {
                    if($Access ne "public")
                    { # NOTE: default access of members in the ABI dump is "public"
                        $TInfo{"Memb"}{$Pos}{"access"} = $Access;
                    }
                }
                else
                { 
                    if($DWARF_Info{$ID}{"kind"} eq "class_type")
                    { # NOTE: default access of class members in the debug info is "private"
                        $TInfo{"Memb"}{$Pos}{"access"} = "private";
                    }
                    else
                    {
                        # NOTE: default access of struct members in the debug info is "public"
                    }
                }
                if($TInfo{"Type"} eq "Union") {
                    $TInfo{"Memb"}{$Pos}{"offset"} = "0";
                }
                elsif(defined $MInfo->{"mloc"}) {
                    $TInfo{"Memb"}{$Pos}{"offset"} = $MInfo->{"mloc"};
                }
            }
            
            if((my $BitSize = $MInfo->{"bit_size"}) ne "") {
                $TInfo{"Memb"}{$Pos}{"bitfield"} = $BitSize;
            }
        }
    }
    
    my $NS = $NameSpace{$ID};
    if(not $NS)
    {
        if(my $Sp = $DWARF_Info{$ID}{"spec"}) {
            $NS = $NameSpace{$Sp};
        }
    }
    
    if($NS and $DWARF_Info{$NS}{"kind"}=~/\A(class_type|structure_type)\Z/)
    { # member class
        if(my $Access = $DWARF_Info{$ID}{"access"})
        {
            if($Access ne "public")
            { # NOTE: default access of member classes in the ABI dump is "public"
                $TInfo{ucfirst($Access)} = 1;
            }
        }
        else
        {
            if($DWARF_Info{$NS}{"kind"} eq "class_type")
            {
                # NOTE: default access of member classes in the debug info is "private"
                $TInfo{"Private"} = 1;
            }
            else
            {
                # NOTE: default access to struct member classes in the debug info is "public"
            }
        }
    }
    else
    {
        if(my $Access = $DWARF_Info{$ID}{"access"})
        {
            if($Access ne "public")
            { # NOTE: default access of classes in the ABI dump is "public"
                $TInfo{ucfirst($Access)} = 1;
            }
        }
    }
    
    my $Size = $DWARF_Info{$ID}{"size"};
    if($Size ne "") {
        $TInfo{"Size"} = $Size;
    }
    
    setSource(\%TInfo, $ID);
    
    if(not $DWARF_Info{$ID}{"name"}
    and my $Spec = $DWARF_Info{$ID}{"spec"}) {
        $DWARF_Info{$ID}{"name"} = $DWARF_Info{$Spec}{"name"};
    }
    
    if($NS)
    {
        if($DWARF_Info{$NS}{"kind"} eq "namespace")
        {
            if(my $NS_F = completeNS($ID))
            {
                $TInfo{"NameSpace"} = $NS_F;
            }
        }
        elsif($DWARF_Info{$NS}{"kind"} eq "class_type"
        or $DWARF_Info{$NS}{"kind"} eq "structure_type")
        { # class
            getTypeInfo($NS);
            
            if(my $Sp = $SpecElem{$NS}) {
                getTypeInfo($Sp);
            }
            
            if($TypeInfo{$NS}{"Name"})
            {
                $TInfo{"NameSpace"} = $TypeInfo{$NS}{"Name"};
                $TInfo{"NameSpace"}=~s/\Astruct //;
            }
        }
    }
    
    if(my $Name = $DWARF_Info{$ID}{"name"})
    {
        $TInfo{"Name"} = $Name;
        
        if($TInfo{"NameSpace"}) {
            $TInfo{"Name"} = $TInfo{"NameSpace"}."::".$TInfo{"Name"};
        }
        
        if($TInfo{"Type"}=~/\A(Struct|Enum|Union)\Z/) {
            $TInfo{"Name"} = lc($TInfo{"Type"})." ".$TInfo{"Name"};
        }
    }
    
    if($TInfo{"Type"} eq "Struct")
    {
        if(not $TInfo{"Name"})
        {
            if(defined $TInfo{"Memb"}
            and $TInfo{"Memb"}{0}{"name"} eq "__pfn")
            { # __pfn and __delta
                my $Pfn = $TInfo{"Memb"}{0}{"type"};
                if(my $Pfn_B = $DWARF_Info{$Pfn}{"type"})
                {
                    if($DWARF_Info{$Pfn_B}{"kind"} eq "subroutine_type")
                    {
                        $TInfo{"Type"} = "MethodPtr";
                    }
                }
            }
        }
    }
    
    if($TInfo{"Type"}=~/Pointer|Ptr|Ref/)
    {
        if(not $TInfo{"Size"}) {
            $TInfo{"Size"} = $SYS_WORD;
        }
    }
    
    if($TInfo{"Type"} eq "Pointer")
    {
        if($DWARF_Info{$TInfo{"BaseType"}}{"kind"} eq "subroutine_type")
        {
            initFuncType(\%TInfo, $TInfo{"BaseType"}, "FuncPtr");
        }
    }
    elsif($TInfo{"Type"}=~/Typedef|Const|Volatile/)
    {
        if($DWARF_Info{$TInfo{"BaseType"}}{"kind"} eq "subroutine_type")
        {
            getTypeInfo($TInfo{"BaseType"});
        }
    }
    elsif($TInfo{"Type"} eq "Func")
    {
        initFuncType(\%TInfo, $ID, "Func");
    }
    elsif($TInfo{"Type"} eq "MethodPtr")
    {
        my $Pfn_B = undef;
        
        if(defined $TInfo{"Memb"}
        and $TInfo{"Memb"}{0}{"name"} eq "__pfn")
        {
            if(my $Pfn = $TInfo{"Memb"}{0}{"type"}) {
                $Pfn_B = $DWARF_Info{$Pfn}{"type"};
            }
        }
        else
        { # support for Clang
            $Pfn_B = $DWARF_Info{$ID}{"pfn"};
        }
        
        if($Pfn_B)
        {
            my @Prms = ();
            my $PPos = 0;
            foreach my $Pos (sort {$a<=>$b} keys(%{$FuncParam{$Pfn_B}}))
            {
                my $ParamId = $FuncParam{$Pfn_B}{$Pos};
                my %PInfo = %{$DWARF_Info{$ParamId}};
                
                if(defined $PInfo{"art"})
                { # this
                    next;
                }
                
                if(my $PTypeId = $PInfo{"type"})
                {
                    $TInfo{"Param"}{$PPos}{"type"} = $PTypeId;
                    getTypeInfo($PTypeId);
                    push(@Prms, $TypeInfo{$PTypeId}{"Name"});
                }
                
                $PPos += 1;
            }
            
            if(my $ClassId = $DWARF_Info{$Pfn_B}{"objptr"})
            {
                while($DWARF_Info{$ClassId}{"type"}) {
                    $ClassId = $DWARF_Info{$ClassId}{"type"};
                }
                $TInfo{"Class"} = $ClassId;
                getTypeInfo($TInfo{"Class"});
            }
            
            if($TInfo{"Return"} = $DWARF_Info{$Pfn_B}{"type"}) {
                getTypeInfo($TInfo{"Return"});
            }
            else
            { # void
                $TInfo{"Return"} = "1";
            }
            
            $TInfo{"Name"} = createMethodPtrName(\%TInfo);
            
            delete($TInfo{"BaseType"});
        }
    }
    elsif($TInfo{"Type"} eq "FieldPtr")
    {
        $TInfo{"Return"} = $TInfo{"BaseType"};
        delete($TInfo{"BaseType"});
        
        if(my $Class = $DWARF_Info{$ID}{"container"})
        {
            $TInfo{"Class"} = $Class;
            getTypeInfo($TInfo{"Class"});
            
            $TInfo{"Name"} = createFieldPtrName(\%TInfo);
        }
        
        $TInfo{"Size"} = $SYS_WORD;
    }
    elsif($TInfo{"Type"} eq "String")
    {
        $TInfo{"Type"} = "Pointer";
        $TInfo{"Name"} = "char*";
        $TInfo{"BaseType"} = $TName_Tid{"Intrinsic"}{"char"};
    }
    
    if(defined $Inheritance{$ID})
    {
        foreach my $Pos (sort {$a<=>$b} keys(%{$Inheritance{$ID}}))
        {
            if(my $BaseId = $Inheritance{$ID}{$Pos}{"id"})
            {
                if(my $E = $SpecElem{$BaseId}) {
                    $BaseId = $E;
                }
                
                $TInfo{"Base"}{$BaseId}{"pos"} = "$Pos";
                if(my $Access = $Inheritance{$ID}{$Pos}{"access"}) {
                    $TInfo{"Base"}{$BaseId}{"access"} = $Access;
                }
                if($Inheritance{$ID}{$Pos}{"virtual"}) {
                    $TInfo{"Base"}{$BaseId}{"virtual"} = 1;
                }
                
                $ClassChild{$BaseId}{$ID} = 1;
            }
        }
    }
    
    if(not $TInfo{"BaseType"})
    {
        if($TInfo{"Type"} eq "Pointer")
        {
            $TInfo{"Name"} = "void*";
            $TInfo{"BaseType"} = "1";
        }
        elsif($TInfo{"Type"} eq "Const")
        {
            $TInfo{"Name"} = "const void";
            $TInfo{"BaseType"} = "1";
        }
        elsif($TInfo{"Type"} eq "Volatile")
        {
            $TInfo{"Name"} = "volatile void";
            $TInfo{"BaseType"} = "1";
        }
        elsif($TInfo{"Type"} eq "Typedef")
        {
            $TInfo{"BaseType"} = "1";
        }
    }
    
    if(not $TInfo{"Name"}
    and $TInfo{"Type"} ne "Enum")
    {
        my $ID_ = $ID;
        my $BaseID = undef;
        my $Name = "";
        
        while($BaseID = $DWARF_Info{$ID_}{"type"})
        {
            my $Kind = $DWARF_Info{$ID_}{"kind"};
            if(my $Q = $Qual{$TypeType{$Kind}})
            {
                $Name = $Q.$Name;
                if($Q=~/\A\w/) {
                    $Name = " ".$Name;
                }
            }
            if(defined $TypeInfo{$BaseID}
            and $TypeInfo{$BaseID}{"Name"})
            {
                $Name = $TypeInfo{$BaseID}{"Name"}.$Name;
                last;
            }
            elsif(defined $DWARF_Info{$BaseID}
            and $DWARF_Info{$BaseID}{"name"})
            {
                $Name = $DWARF_Info{$BaseID}{"name"}.$Name;
                $ID_ = $BaseID;
            }
            elsif(defined $Compressed
            and not defined $AllUnits)
            {
                $Name = "T#".$BaseID.$Name;
                last;
            }
            else
            { # error
                last;
            }
        }
        
        if($Name) {
            $TInfo{"Name"} = $Name;
        }
        
        if($TInfo{"Type"} eq "Array")
        {
            if(my $Count = $ArrayCount{$ID})
            {
                $TInfo{"Name"} .= "[".$Count."]";
                if(my $BType = $TInfo{"BaseType"})
                {
                    if(my $BSize = $TypeInfo{$BType}{"Size"})
                    {
                        if(my $Size = $Count*$BSize)
                        {
                            $TInfo{"Size"} = "$Size";
                        }
                    }
                }
            }
            else
            {
                $TInfo{"Name"} .= "[]";
                $TInfo{"Size"} = $SYS_WORD;
            }
        }
        elsif($TInfo{"Type"} eq "Pointer")
        {
            if(my $BType = $TInfo{"BaseType"})
            {
                if($TypeInfo{$BType}{"Type"}=~/MethodPtr|FuncPtr/)
                { # void(GTestSuite::**)()
                  # int(**)(...)
                    if($TInfo{"Name"}=~s/\*\Z//) {
                        $TInfo{"Name"}=~s/\*(\))/\*\*$1/;
                    }
                }
            }
        }
    }
    
    if(my $Bid = $TInfo{"BaseType"})
    {
        if(not $TInfo{"Size"}
        and $TypeInfo{$Bid}{"Size"}) {
            $TInfo{"Size"} = $TypeInfo{$Bid}{"Size"};
        }
    }
    if($TInfo{"Name"}) {
        $TInfo{"Name"} = formatName($TInfo{"Name"}, "T");
    }
    
    if($TInfo{"Name"}=~/>\Z/)
    {
        my ($Short, $TParams) = getTParams($ID, $TInfo{"Name"});
        
        if($TParams)
        {
            delete($TInfo{"TParam"});
            
            foreach my $Pos (0 .. $#{$TParams}) {
                $TInfo{"TParam"}{$Pos} = $TParams->[$Pos];
            }
            
            my @TKeys = getTKeys($TParams);
            @TKeys = shortTParams($Short, \@TKeys);
            
            $TInfo{"Name"} = formatName($Short."<".join(", ", @TKeys).">", "T");
        }
    }