diff -Nru abi-compliance-checker-1.99.1/INSTALL abi-compliance-checker-1.99.8/INSTALL --- abi-compliance-checker-1.99.1/INSTALL 2013-06-07 12:19:02.000000000 +0000 +++ abi-compliance-checker-1.99.8/INSTALL 2013-07-30 15:08:11.000000000 +0000 @@ -9,8 +9,8 @@ RELEASE INFORMATION Project: ABI Compliance Checker (ACC) -Version: 1.99.1 -Date: 2013-06-07 +Version: 1.99.8 +Date: 2013-07-30 This file explains how to install and setup environment diff -Nru abi-compliance-checker-1.99.1/README abi-compliance-checker-1.99.8/README --- abi-compliance-checker-1.99.1/README 2013-06-07 12:19:02.000000000 +0000 +++ abi-compliance-checker-1.99.8/README 2013-07-30 15:08:11.000000000 +0000 @@ -25,7 +25,7 @@ For advanced usage, see doc/Readme.html or output of --help option. COMPATIBILITY: - ABI Dumper >= 0.97 (https://github.com/lvc/abi-dumper) + ABI Dumper >= 0.98 (https://github.com/lvc/abi-dumper) USAGE WITH ABI DUMPER: diff -Nru abi-compliance-checker-1.99.1/abi-compliance-checker.pl abi-compliance-checker-1.99.8/abi-compliance-checker.pl --- abi-compliance-checker-1.99.1/abi-compliance-checker.pl 2013-06-07 12:19:02.000000000 +0000 +++ abi-compliance-checker-1.99.8/abi-compliance-checker.pl 2013-07-30 15:08:11.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/perl ########################################################################### -# ABI Compliance Checker (ACC) 1.99.1 +# ABI Compliance Checker (ACC) 1.99.8 # A tool for checking backward compatibility of a C/C++ library API # # Copyright (C) 2009-2010 The Linux Foundation @@ -38,7 +38,7 @@ # # COMPATIBILITY # ============= -# ABI Dumper >= 0.97 +# ABI Dumper >= 0.98 # # # This program is free software: you can redistribute it and/or modify @@ -60,11 +60,12 @@ use File::Temp qw(tempdir); use File::Copy qw(copy move); use Cwd qw(abs_path cwd realpath); +use Storable qw(dclone); use Data::Dumper; use Config; -my $TOOL_VERSION = "1.99.1"; -my $ABI_DUMP_VERSION = "3.1"; +my $TOOL_VERSION = "1.99.8"; +my $ABI_DUMP_VERSION = "3.2"; my $OLDEST_SUPPORTED_VERSION = "1.18"; my $XML_REPORT_VERSION = "1.1"; my $XML_ABI_DUMP_VERSION = "1.2"; @@ -91,7 +92,8 @@ $SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, $SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat, -$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath); +$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, +$CheckInfo, $Quick, $AffectLimit, $AllAffected); my $CmdName = get_filename($0); my %OS_LibExt = ( @@ -244,6 +246,7 @@ "lang=s" => \$UserLang, "binary|bin|abi!" => \$BinaryOnly, "source|src|api!" => \$SourceOnly, + "affected-limit=s" => \$AffectLimit, # other options "test!" => \$TestTool, "test-dump!" => \$TestDump, @@ -270,7 +273,10 @@ "extra-dump!" => \$ExtraDump, "force!" => \$Force, "tolerance=s" => \$Tolerance, - "tolerant!" => \$Tolerant + "tolerant!" => \$Tolerant, + "check!" => \$CheckInfo, + "quick!" => \$Quick, + "all-affected!" => \$AllAffected ) or ERR_MESSAGE(); sub ERR_MESSAGE() @@ -633,6 +639,10 @@ Show \"Source\" compatibility problems only. Generate report to: compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html + + -affected-limit LIMIT + The maximum number of affected symbols listed under the description + of the changed type in the report. OTHER OPTIONS: -test @@ -765,6 +775,12 @@ -tolerant Enable highest tolerance level [1234]. + + -check + Check completeness of the ABI dump. + + -quick + Quick analysis. Disable check of some template instances. REPORT: Compatibility report will be generated to: @@ -972,6 +988,7 @@ "identifier_node" => "Other", "integer_cst" => "Other", "integer_type" => "Intrinsic", + "vector_type" => "Vector", "method_type" => "MethodType", "namespace_decl" => "Other", "parm_decl" => "Other", @@ -982,7 +999,9 @@ "reference_type" => "Ref", "string_cst" => "Other", "template_decl" => "Other", - "template_type_parm" => "Other", + "template_type_parm" => "TemplateParam", + "typename_type" => "TypeName", + "sizeof_expr" => "SizeOf", "tree_list" => "Other", "tree_vec" => "Other", "type_decl" => "Other", @@ -1094,6 +1113,8 @@ "..." => "z" ); +my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); + my %StdcxxMangling = ( "3std"=>"St", "3std9allocator"=>"Sa", @@ -1105,6 +1126,10 @@ ); my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; +my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); + +my $ADD_TMPL_INSTANCES = 1; +my $EMERGENCY_MODE_48 = 0; my %ConstantSuffix = ( "unsigned int"=>"u", @@ -1399,10 +1424,15 @@ my %SymbolHeader; my %KnownLibs; -# Types -my %TypeInfo; +# Templates my %TemplateInstance; +my %BasicTemplate; +my %TemplateArg; my %TemplateDecl; +my %TemplateMap; + +# Types +my %TypeInfo; my %SkipTypes = ( "1"=>{}, "2"=>{} ); @@ -1412,7 +1442,6 @@ my %NestedNameSpaces = ( "1"=>{}, "2"=>{} ); -my %UsedType; my %VirtualTable; my %VirtualTable_Model; my %ClassVTable; @@ -1426,6 +1455,8 @@ my %TypedefToAnon; my $MAX_ID = 0; +my %CheckedTypeInfo; + # Typedefs my %Typedef_BaseName; my %Typedef_Tr; @@ -1569,6 +1600,7 @@ my %SourceAlternative; my %SourceAlternative_B; my %SourceReplacement; +my $CurrentSymbol; # for debugging # Calling Conventions my %UseConv_Real = ( @@ -2157,10 +2189,10 @@ getVarInfo_All(); getSymbolInfo_All(); - # clean memory %LibInfo = (); %TemplateInstance = (); + %BasicTemplate = (); %MangledNames = (); %TemplateDecl = (); %StdCxxTypedef = (); @@ -2175,21 +2207,27 @@ if($ExtraDump) { - foreach (keys(%{$TypeInfo{$Version}})) - { - if($TypeInfo{$Version}{$_}{"Artificial"}) { - delete($TypeInfo{$Version}{$_}); - } - } + remove_Unused($Version, "Extra"); } else { # remove unused types if($BinaryOnly and not $ExtendedCheck) { # --binary - removeUnused($Version, "All"); + remove_Unused($Version, "All"); } else { - removeUnused($Version, "Extended"); + remove_Unused($Version, "Extended"); + } + } + + if($CheckInfo) + { + foreach my $Tid (keys(%{$TypeInfo{$Version}})) { + check_Completeness($TypeInfo{$Version}{$Tid}, $Version); + } + + foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { + check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); } } @@ -2215,7 +2253,7 @@ # clean memory undef $Content; - $MAX_ID = $#Lines+1; + $MAX_ID = $#Lines+1; # number of lines == number of nodes foreach (0 .. $#Lines) { @@ -2340,14 +2378,41 @@ sub setTemplateParams($) { + my $Tid = getTypeId($_[0]); if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) { my $TmplInst_Id = $2; - setTemplateInstParams($TmplInst_Id); + setTemplateInstParams($_[0], $TmplInst_Id); while($TmplInst_Id = getNextElem($TmplInst_Id)) { - setTemplateInstParams($TmplInst_Id); + setTemplateInstParams($_[0], $TmplInst_Id); + } + } + + $BasicTemplate{$Version}{$Tid} = $_[0]; + + if(my $Prms = getTreeAttr_Prms($_[0])) + { + if(my $Valu = getTreeAttr_Valu($Prms)) + { + my $Vector = getTreeVec($Valu); + foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) + { + if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) + { + if(my $Name = getNameByInfo($Val)) + { + $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; + if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { + $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; + } + else { + $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); + } + } + } + } } } } @@ -2356,15 +2421,17 @@ if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) { if($IType eq "record_type") { - $TemplateDecl{$Version}{$TypeId}=1; + $TemplateDecl{$Version}{$TypeId} = 1; } } } } -sub setTemplateInstParams($) +sub setTemplateInstParams($$) { - if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) + my ($Tmpl, $Inst) = @_; + + if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) { my ($Params_InfoId, $ElemId) = (); if($Info=~/purp[ ]*:[ ]*@(\d+) /) { @@ -2381,19 +2448,19 @@ my ($PPos, $PTypeId) = ($1, $2); if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) { - if($PType eq "template_type_parm") - { - $TemplateDecl{$Version}{$ElemId}=1; - return; + if($PType eq "template_type_parm") { + $TemplateDecl{$Version}{$ElemId} = 1; } } if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") { # functions $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; + $BasicTemplate{$Version}{$ElemId} = $Tmpl; } else { # types $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; + $BasicTemplate{$Version}{$ElemId} = $Tmpl; } } } @@ -2448,6 +2515,181 @@ { # support for GCC < 4.5 addMissedTypes_Post(); } + + if($ADD_TMPL_INSTANCES) + { + # templates + foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) + { + if(defined $TemplateMap{$Version}{$Tid} + and not defined $TypeInfo{$Version}{$Tid}{"Template"}) + { + if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) + { + foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) + { + if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) + { + if(my %MAttr = getTypeAttr($MembTypeId)) + { + $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; + $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); + } + } + } + } + if(defined $TypeInfo{$Version}{$Tid}{"Base"}) + { + foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) + { + my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); + + if($NBid ne $Bid) + { + %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; + delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); + } + } + } + } + } + } +} + +sub createType($$) +{ + my ($Attr, $LibVersion) = @_; + my $NewId = ++$MAX_ID; + + $Attr->{"Tid"} = $NewId; + $TypeInfo{$Version}{$NewId} = $Attr; + $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; + + return "$NewId"; +} + +sub instType($$$) +{ # create template instances + my ($Map, $Tid, $LibVersion) = @_; + + if(not $TypeInfo{$LibVersion}{$Tid}) { + return undef; + } + my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); + + foreach my $Key (sort keys(%{$Map})) + { + if(my $Val = $Map->{$Key}) + { + $Attr->{"Name"}=~s/\b$Key\b/$Val/g; + + if(defined $Attr->{"NameSpace"}) { + $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; + } + foreach (keys(%{$Attr->{"TParam"}})) { + $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; + } + } + else + { # remove absent + # _Traits, etc. + $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; + if(defined $Attr->{"NameSpace"}) { + $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; + } + foreach (keys(%{$Attr->{"TParam"}})) + { + if($Attr->{"TParam"}{$_}{"name"} eq $Key) { + delete($Attr->{"TParam"}{$_}); + } + else { + $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; + } + } + } + } + + my $Tmpl = 0; + + if(defined $Attr->{"TParam"}) + { + foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) + { + my $PName = $Attr->{"TParam"}{$_}{"name"}; + + if(my $PTid = $TName_Tid{$LibVersion}{$PName}) + { + my %Base = get_BaseType($PTid, $LibVersion); + + if($Base{"Type"} eq "TemplateParam" + or defined $Base{"Template"}) + { + $Tmpl = 1; + last + } + } + } + } + + if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { + return "$Id"; + } + else + { + if(not $Tmpl) { + delete($Attr->{"Template"}); + } + + my $New = createType($Attr, $LibVersion); + + my %EMap = (); + if(defined $TemplateMap{$LibVersion}{$Tid}) { + %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; + } + foreach (keys(%{$Map})) { + $EMap{$_} = $Map->{$_}; + } + + if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { + $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); + } + if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) + { + foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) + { + my $NBid = instType(\%EMap, $Bid, $LibVersion); + + if($NBid ne $Bid) + { + %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; + delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); + } + } + } + + if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) + { + foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) + { + if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { + $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); + } + } + } + + if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) + { + foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { + $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); + } + } + + if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { + $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); + } + + return $New; + } } sub addMissedTypes_Pre() @@ -2488,13 +2730,13 @@ if(not $TypedefName) { next; } - $MAX_ID++; + my $NewId = ++$MAX_ID; my %MissedInfo = ( # typedef info "Name" => $TypedefName, "NameSpace" => $TypedefNS, "BaseType" => $Tid, "Type" => "Typedef", - "Tid" => "$MAX_ID" ); + "Tid" => "$NewId" ); my ($H, $L) = getLocation($MissedTDid); $MissedInfo{"Header"} = $H; $MissedInfo{"Line"} = $L; @@ -2642,13 +2884,12 @@ { if($Info=~/qual[ ]*:/) { - if(my $NID = ++$MAX_ID) - { - $MissedBase{$Version}{$TypeId}="$NID"; - $MissedBase_R{$Version}{$NID}=$TypeId; - $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId}; - $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId}; - } + my $NewId = ++$MAX_ID; + + $MissedBase{$Version}{$TypeId} = "$NewId"; + $MissedBase_R{$Version}{$NewId} = $TypeId; + $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; + $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; } } $TypeAttr{"Type"} = "Typedef"; @@ -2657,6 +2898,14 @@ $TypeAttr{"Type"} = getTypeType($TypeId); } + if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) + { + if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") + { # local code + return (); + } + } + if($TypeAttr{"Type"} eq "Unknown") { return (); } @@ -2720,13 +2969,15 @@ } return (); } - elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) + elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) { %TypeAttr = getTrivialTypeAttr($TypeId); if($TypeAttr{"Name"}) { %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; - if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"})) + + if(not defined $IntrinsicNames{$TypeAttr{"Name"}} + or getTypeDeclId($TypeAttr{"Tid"})) { # NOTE: register only one int: with built-in decl if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; @@ -2738,6 +2989,35 @@ return (); } } + elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) + { + %TypeAttr = getTrivialTypeAttr($TypeId); + if($TypeAttr{"Name"}) + { + %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; + if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { + $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; + } + return %TypeAttr; + } + else { + return (); + } + } + elsif($TypeAttr{"Type"} eq "SizeOf") + { + $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); + my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); + $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; + if($TypeAttr{"Name"}) + { + %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; + return %TypeAttr; + } + else { + return (); + } + } else { # derived types my ($BTid, $BTSpec) = selectBaseType($TypeId); @@ -2924,6 +3204,10 @@ } return @Params; } + elsif($NodeType eq "parm_decl") + { + (getNameByInfo($Type_Id)); + } else { my %ParamAttr = getTypeAttr($Type_Id); @@ -3319,13 +3603,24 @@ sub isTypedef($) { - if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) + if($_[0]) { - my $TDid = getTypeDeclId($_[0]); - if(getNameByInfo($TDid) - and $Info=~/unql[ ]*:[ ]*\@(\d+) / - and getTypeId($TDid) eq $_[0]) { - return $1; + if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") + { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); + return 0; + } + if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) + { + if(my $TDid = getTypeDeclId($_[0])) + { + if(getTypeId($TDid) eq $_[0] + and getNameByInfo($TDid)) + { + if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { + return $1; + } + } + } } } return 0; @@ -3370,31 +3665,21 @@ if($Info=~/refd[ ]*:[ ]*@(\d+) /) { return ($1, "&"); } - else { - return (0, ""); - } } elsif($InfoType eq "array_type") { if($Info=~/elts[ ]*:[ ]*@(\d+) /) { return ($1, ""); } - else { - return (0, ""); - } } elsif($InfoType eq "pointer_type") { if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { return ($1, "*"); } - else { - return (0, ""); - } - } - else { - return (0, ""); } + + return (0, ""); } sub getSymbolInfo_All() @@ -3405,6 +3690,44 @@ getSymbolInfo($_); } } + + if($ADD_TMPL_INSTANCES) + { + # templates + foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) + { + my %Map = (); + + if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) + { + if(defined $TemplateMap{$Version}{$ClassId}) + { + foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { + $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; + } + } + } + + if(defined $TemplateMap{$Version}{$Sid}) + { + foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { + $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; + } + } + + if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) + { + foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) + { + my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; + $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); + } + } + if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { + $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); + } + } + } } sub getVarInfo_All() @@ -3474,8 +3797,9 @@ $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; if(my $Rid = getTypeId($InfoId)) { - if(not $TypeInfo{$Version}{$Rid}{"Name"}) - { # typename_type + if(not defined $TypeInfo{$Version}{$Rid} + or not $TypeInfo{$Version}{$Rid}{"Name"}) + { delete($SymbolInfo{$Version}{$InfoId}); return; } @@ -3488,8 +3812,9 @@ set_Class_And_Namespace($InfoId); if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { - if(not $TypeInfo{$Version}{$ClassId}{"Name"}) - { # templates + if(not defined $TypeInfo{$Version}{$ClassId} + or not $TypeInfo{$Version}{$ClassId}{"Name"}) + { delete($SymbolInfo{$Version}{$InfoId}); return; } @@ -3608,7 +3933,7 @@ last; } } - $NameSpaceId=$NSId; + $NameSpaceId = $NSId; } } else @@ -3636,10 +3961,6 @@ and getTypeDeclId($TypeId) eq $TypeInfoId) { my @TParams = getTParams($TypeId, "Type"); - if(not @TParams) - { # template declarations with abstract params - return ("", ""); - } $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); } return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); @@ -3650,22 +3971,13 @@ my $TypeId = $_[0]; my $TypeInfoId = getTypeDeclId($_[0]); + my %TypeAttr = (); + if($TemplateDecl{$Version}{$TypeId}) { # template_decl - return (); - } - if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId)) - { - if($TemplateDecl{$Version}{$ScopeId}) - { # template_decl - return (); - } + $TypeAttr{"Template"} = 1; } - my %TypeAttr = (); - if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) { - return (); - } setTypeAccess($TypeId, \%TypeAttr); ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); if(isBuiltIn($TypeAttr{"Header"})) @@ -3681,27 +3993,98 @@ if(not $TypeAttr{"NameSpace"}) { delete($TypeAttr{"NameSpace"}); } + + my $Tmpl = undef; + if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) { + $Tmpl = $BasicTemplate{$Version}{$TypeId}; + if(my @TParams = getTParams($TypeId, "Type")) { - foreach my $Pos (0 .. $#TParams) { - $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos]; + foreach my $Pos (0 .. $#TParams) + { + my $Val = $TParams[$Pos]; + $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; + + if(not defined $TypeAttr{"Template"}) + { + my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); + + if($Base{"Type"} eq "TemplateParam" + or defined $Base{"Template"}) { + $TypeAttr{"Template"} = 1; + } + } + + if($Tmpl) + { + if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) + { + $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; + + if($Val eq $Arg) { + $TypeAttr{"Template"} = 1; + } + } + } + } + + if($Tmpl) + { + foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) + { + if($Pos>$#TParams) + { + my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; + $TemplateMap{$Version}{$TypeId}{$Arg} = ""; + } + } + } + } + + if($ADD_TMPL_INSTANCES) + { + if($Tmpl) + { + if(my $MainInst = getTreeAttr_Type($Tmpl)) + { + if(not getTreeAttr_Flds($TypeId)) + { + if(my $Flds = getTreeAttr_Flds($MainInst)) { + $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; + } + } + if(not getTreeAttr_Binf($TypeId)) + { + if(my $Binf = getTreeAttr_Binf($MainInst)) { + $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; + } + } + } } } } + + my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); + if(my $Size = getSize($TypeId)) { $Size = $Size/$BYTE_SIZE; $TypeAttr{"Size"} = "$Size"; } else - { # declaration only - $TypeAttr{"Forward"} = 1; + { + if($ExtraDump) + { + if(not defined $TypeAttr{"Memb"} + and not $Tmpl) + { # declaration only + $TypeAttr{"Forward"} = 1; + } + } } - my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); - if($TypeAttr{"Type"} eq "Struct" and ($StaticFields or detect_lang($TypeId))) { @@ -3724,7 +4107,7 @@ if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) { if(not $TypedefToAnon{$TypeId} - and not keys(%{$TemplateInstance{$Version}{"Type"}{$TypeId}})) + and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) { if(not isAnon($TypeAttr{"Name"})) { $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; @@ -3740,7 +4123,7 @@ { my $Entry = $Entries[$_]; if($Entry=~/\A(\d+)\s+(.+)\Z/) { - $TypeAttr{"VTable"}{$1} = $2; + $TypeAttr{"VTable"}{$1} = simplifyVTable($2); } } } @@ -3759,10 +4142,14 @@ }; if(isAnon($TypeAttr{"Name"})) { - %{$Constants{$Version}{$MName}} = ( - "Value" => $MVal, - "Header" => $TypeAttr{"Header"} - ); + if($ExtraDump + or is_target_header($TypeAttr{"Header"}, $Version)) + { + %{$Constants{$Version}{$MName}} = ( + "Value" => $MVal, + "Header" => $TypeAttr{"Header"} + ); + } } } } @@ -3774,7 +4161,34 @@ } } - return %TypeAttr; + return %TypeAttr; +} + +sub simplifyVTable($) +{ + my $Content = $_[0]; + if($Content=~s/ \[with (.+)]//) + { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits] + if(my @Elems = separate_Params($1, 0, 0)) + { + foreach my $Elem (@Elems) + { + if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) + { + my ($Arg, $Val) = ($1, $2); + + if(defined $DEFAULT_STD_ARGS{$Arg}) { + $Content=~s/,\s*$Arg\b//g; + } + else { + $Content=~s/\b$Arg\b/$Val/g; + } + } + } + } + } + + return $Content; } sub detect_lang($) @@ -3812,9 +4226,9 @@ { my ($TypeId, $TypeAttr) = @_; my $Info = $LibInfo{$Version}{"info"}{$TypeId}; - if($Info=~/binf[ ]*:[ ]*@(\d+) /) + if(my $Binf = getTreeAttr_Binf($TypeId)) { - $Info = $LibInfo{$Version}{"info"}{$1}; + my $Info = $LibInfo{$Version}{"info"}{$Binf}; my $Pos = 0; while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) { @@ -3824,7 +4238,7 @@ if(not $CType or $CType eq "template_type_parm" or $CType eq "typename_type") { # skip - return 1; + # return 1; } my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; if($Access=~/prot/) { @@ -3881,8 +4295,16 @@ foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) { # checking parameters my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; + my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; my %PType = get_PureType($PId, $TypeInfo{$Version}); my $PTName = unmangledFormat($PType{"Name"}, $Version); + + if($PName eq "this" + and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") + { + next; + } + $PTName=~s/\b(restrict|register)\b//g; if($Compiler eq "MSVC") { $PTName=~s/\blong long\b/__int64/; @@ -4093,16 +4515,16 @@ if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { if($MangledNames{$LibVersion}{$Mangled}) { - $Mangled=~s/C1E/C2E/; + $Mangled=~s/C1([EI])/C2$1/; } } elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { if($MangledNames{$LibVersion}{$Mangled}) { - $Mangled=~s/D0E/D1E/; + $Mangled=~s/D0([EI])/D1$1/; } if($MangledNames{$LibVersion}{$Mangled}) { - $Mangled=~s/D1E/D2E/; + $Mangled=~s/D1([EI])/D2$1/; } } return $Mangled; @@ -4624,9 +5046,11 @@ my $InfoId = $_[0]; # try to mangle symbol if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"}) - or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"})) - { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) - # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions + or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}) + or $EMERGENCY_MODE_48) + { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) + # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions + # GCC 4.8 doesn't mangle anything if(not $CheckHeadersOnly) { if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) { @@ -4634,7 +5058,8 @@ } } if($CheckHeadersOnly - or not $BinaryOnly) + or not $BinaryOnly + or $EMERGENCY_MODE_48) { # 1. --headers-only mode # 2. not mangled src-only symbols if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) { @@ -4675,13 +5100,15 @@ } $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId); - if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId)) + if(my $Return = getFuncReturn($InfoId)) { - if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"}) - { # templates + if(not defined $TypeInfo{$Version}{$Return} + or not $TypeInfo{$Version}{$Return}{"Name"}) + { delete($SymbolInfo{$Version}{$InfoId}); return; } + $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return; } if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) { @@ -4711,15 +5138,40 @@ if(defined $TemplateInstance{$Version}{"Func"}{$Orig}) { + my $Tmpl = $BasicTemplate{$Version}{$InfoId}; + my @TParams = getTParams($Orig, "Func"); if(not @TParams) { delete($SymbolInfo{$Version}{$InfoId}); return; } - foreach my $Pos (0 .. $#TParams) { - $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos]; + foreach my $Pos (0 .. $#TParams) + { + my $Val = $TParams[$Pos]; + $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val; + + if($Tmpl) + { + if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) + { + $TemplateMap{$Version}{$InfoId}{$Arg} = $Val; + } + } + } + + if($Tmpl) + { + foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) + { + if($Pos>$#TParams) + { + my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; + $TemplateMap{$Version}{$InfoId}{$Arg} = ""; + } + } } + my $PrmsInLine = join(", ", @TParams); if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/) { # operator<< , operator>> @@ -4772,8 +5224,9 @@ if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { - if(not $TypeInfo{$Version}{$ClassId}{"Name"}) - { # templates + if(not defined $TypeInfo{$Version}{$ClassId} + or not $TypeInfo{$Version}{$ClassId}{"Name"}) + { delete($SymbolInfo{$Version}{$InfoId}); return; } @@ -4936,7 +5389,7 @@ } } } - delete($SymbolInfo{$Version}{$InfoId}{"Type"}); + if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) { $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; } @@ -5074,6 +5527,7 @@ $MembTypeId = $AddedTid; } } + $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId; $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName; if((my $Access = getTreeAccess($MInfoId)) ne "public") @@ -5093,7 +5547,13 @@ } else { # in bytes - $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; + if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1) + { # template + delete($TypeAttr->{"Memb"}{$Pos}{"algn"}); + } + else { + $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; + } } $MInfoId = getNextElem($MInfoId); @@ -5108,7 +5568,10 @@ { my $InfoId = $_[0]; my $ParamInfoId = getTreeAttr_Args($InfoId); - if(getFuncType($InfoId) eq "Method") + + my $FType = getFuncType($InfoId); + + if($FType eq "Method") { # check type of "this" pointer my $ObjectTypeId = getTreeAttr_Type($ParamInfoId); if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"}) @@ -5127,14 +5590,14 @@ # skip "this"-parameter # $ParamInfoId = getNextElem($ParamInfoId); } - my ($Pos, $Vtt_Pos) = (0, -1); + my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1); while($ParamInfoId) { # formal args my $ParamTypeId = getTreeAttr_Type($ParamInfoId); my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId)); if(not $ParamName) { # unnamed - $ParamName = "p".($Pos+1); + $ParamName = "p".($PPos+1); } if(defined $MissedTypedef{$Version}{$ParamTypeId}) { @@ -5161,19 +5624,27 @@ next; } $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; + + if(my %Base = get_BaseType($ParamTypeId, $Version)) + { + if(defined $Base{"Template"}) { + return 1; + } + } + $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName; if(my $Algn = getAlgn($ParamInfoId)) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE; } - if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) { - $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1); - } if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /) { # foo(register type arg) $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1; } $ParamInfoId = getNextElem($ParamInfoId); $Pos += 1; + if($ParamName ne "this" or $FType ne "Method") { + $PPos += 1; + } } if(setFuncArgs($InfoId, $Vtt_Pos)) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1"; @@ -5186,15 +5657,19 @@ my ($InfoId, $Vtt_Pos) = @_; my $FuncTypeId = getFuncTypeId($InfoId); my $ParamListElemId = getTreeAttr_Prms($FuncTypeId); - if(getFuncType($InfoId) eq "Method") { - $ParamListElemId = getNextElem($ParamListElemId); + my $FType = getFuncType($InfoId); + + if($FType eq "Method") + { + # skip "this"-parameter + # $ParamListElemId = getNextElem($ParamListElemId); } if(not $ParamListElemId) { # foo(...) return 1; } my $HaveVoid = 0; - my $Pos = 0; + my ($Pos, $PPos) = (0, 0); while($ParamListElemId) { # actual params: may differ from formal args # formal int*const @@ -5211,12 +5686,30 @@ $HaveVoid = 1; last; } - elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) + else { - $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; - if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) - { # unnamed - $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1); + if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) + { + $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; + if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) + { # unnamed + $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1); + } + } + elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) + { + if($Pos>0 or getFuncType($InfoId) ne "Method") + { # params + if($OldId ne $ParamTypeId) + { + my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version}); + my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version}); + + if($Old_Pure{"Name"} ne $New_Pure{"Name"}) { + $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; + } + } + } } } if(my $PurpId = getTreeAttr_Purp($ParamListElemId)) @@ -5234,6 +5727,9 @@ } } $ParamListElemId = getNextElem($ParamListElemId); + if($Pos!=0 or $FType ne "Method") { + $PPos += 1; + } $Pos += 1; } return ($Pos>=1 and not $HaveVoid); @@ -5393,6 +5889,17 @@ return ""; } +sub getTreeAttr_Binf($) +{ + if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) + { + if($Info=~/binf[ ]*:[ ]*@(\d+) /) { + return $1; + } + } + return ""; +} + sub getTreeAttr_Args($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) @@ -5594,7 +6101,7 @@ return ""; } } - elsif($InfoType eq "record_type") + elsif($InfoType ne "function_decl") { # inside data type my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId); return $Name; @@ -5745,6 +6252,7 @@ $Dir=~s/[\/\\]+\Z//g; return if(not $LibVersion or not $Dir or not -d $Dir); $Dir = get_abs_path($Dir); + my $Mode = "All"; if($WithDeps) { @@ -6697,9 +7205,9 @@ return join_P($Path,$Header); } } - if(not keys(%SystemHeaders)) + if(not defined $Cache{"checkSystemFiles"}) { # register all headers in system include dirs - detectSystemHeaders(); + checkSystemFiles(); } foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)} sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion)) @@ -7031,41 +7539,41 @@ { if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}) { - if($Symbol=~/C1E/) { + if($Symbol=~/C1[EI]/) { return "[in-charge]"; } - elsif($Symbol=~/C2E/) { + elsif($Symbol=~/C2[EI]/) { return "[not-in-charge]"; } } elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { - if($Symbol=~/D1E/) { + if($Symbol=~/D1[EI]/) { return "[in-charge]"; } - elsif($Symbol=~/D2E/) { + elsif($Symbol=~/D2[EI]/) { return "[not-in-charge]"; } - elsif($Symbol=~/D0E/) { + elsif($Symbol=~/D0[EI]/) { return "[in-charge-deleting]"; } } } else { - if($Symbol=~/C1E/) { + if($Symbol=~/C1[EI]/) { return "[in-charge]"; } - elsif($Symbol=~/C2E/) { + elsif($Symbol=~/C2[EI]/) { return "[not-in-charge]"; } - elsif($Symbol=~/D1E/) { + elsif($Symbol=~/D1[EI]/) { return "[in-charge]"; } - elsif($Symbol=~/D2E/) { + elsif($Symbol=~/D2[EI]/) { return "[not-in-charge]"; } - elsif($Symbol=~/D0E/) { + elsif($Symbol=~/D0[EI]/) { return "[in-charge-deleting]"; } } @@ -7135,7 +7643,13 @@ $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g; } } - if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) { + if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) + { + if($ParamName eq "this" + and $Symbol=~/\A(_Z|\?)/) + { # do NOT show first hidded "this"-parameter + next; + } push(@ParamArray, create_member_decl($ParamTypeName, $ParamName)); } else { @@ -7597,7 +8111,12 @@ if($OSgroup eq "macos") { $GccCall .= "objective-"; } - if(check_gcc($GCC_PATH, "4")) + + if($EMERGENCY_MODE_48) + { # workaround for GCC 4.8 (C only) + $GccCall .= "c++"; + } + elsif(check_gcc($GCC_PATH, "4")) { # compile as "C++" header # to obtain complete dump using GCC 4.0 $GccCall .= "c++-header"; @@ -8594,7 +9113,7 @@ foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}})) { my $RegDir = get_dirname($RegHeader); - $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1; + $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1; if(not $INC_PATH_AUTODETECT{$LibVersion}) { detect_recursive_includes($RegHeader, $LibVersion); @@ -8604,10 +9123,10 @@ { my $Dir = get_dirname($RecInc); - if(familiarDirs($Dir, $RegDir) + if(familiarDirs($RegDir, $Dir) or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1) { # in the same directory or included by #include "..." - $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1; + $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1; } } } @@ -8619,14 +9138,48 @@ if($D1 eq $D2) { return 1; } - while($D1=~s/[\/\\]+.*?\Z//) + + my $U1 = index($D1, "/usr/"); + my $U2 = index($D2, "/usr/"); + + if($U1==0 and $U2!=0) { + return 0; + } + + if($U2==0 and $U1!=0) { + return 0; + } + + if(index($D2, $D1."/")==0) { + return 1; + } + + # /usr/include/DIR + # /home/user/DIR + + my $DL = get_depth($D1); + + my @Dirs1 = ($D1); + while($DL - get_depth($D1)<=2 + and get_depth($D1)>=4 + and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { + push(@Dirs1, $D1); + } + + my @Dirs2 = ($D2); + while(get_depth($D2)>=4 + and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { + push(@Dirs2, $D2); + } + + foreach my $P1 (@Dirs1) { - $D2=~s/[\/\\]+.*?\Z//; - if($D1 eq "/usr/include") { - return 0; - } - if($D1 eq $D2) { - return 1; + foreach my $P2 (@Dirs2) + { + + if($P1 eq $P2) { + return 1; + } } } return 0; @@ -8777,7 +9330,7 @@ { if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}) - and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"}) + and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg) # + support for old ABI dumps next; @@ -9017,70 +9570,153 @@ } } -sub register_TypeUsage($$) +sub getFirst($$) { - my ($TypeId, $LibVersion) = @_; + my ($Tid, $LibVersion) = @_; + if(not $Tid) { + return $Tid; + } + + if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}) + { + if($TName_Tid{$LibVersion}{$Name}) { + return $TName_Tid{$LibVersion}{$Name}; + } + } + + return $Tid; +} + +sub register_SymbolUsage($$$) +{ + my ($InfoId, $UsedType, $LibVersion) = @_; + + my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; + if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion)) + { + register_TypeUsage($RTid, $UsedType, $LibVersion); + $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid; + } + if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion)) + { + register_TypeUsage($FCid, $UsedType, $LibVersion); + $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid; + + if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) + { # register "this" pointer + register_TypeUsage($ThisId, $UsedType, $LibVersion); + } + if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion)) + { # register "this" pointer (const method) + register_TypeUsage($ThisId_C, $UsedType, $LibVersion); + } + } + foreach my $PPos (keys(%{$FuncInfo{"Param"}})) + { + if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion)) + { + register_TypeUsage($PTid, $UsedType, $LibVersion); + $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; + } + } + foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) + { + my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; + if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { + register_TypeUsage($TTid, $UsedType, $LibVersion); + } + } +} + +sub register_TypeUsage($$$) +{ + my ($TypeId, $UsedType, $LibVersion) = @_; if(not $TypeId) { - return 0; + return; } - if($UsedType{$LibVersion}{$TypeId}) + if($UsedType->{$TypeId}) { # already registered - return 1; + return; } + my %TInfo = get_Type($TypeId, $LibVersion); if($TInfo{"Type"}) { - if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/) + if(my $NS = $TInfo{"NameSpace"}) + { + if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) { + register_TypeUsage($NSTid, $UsedType, $LibVersion); + } + } + + if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) { - $UsedType{$LibVersion}{$TypeId} = 1; + $UsedType->{$TypeId} = 1; if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) { - foreach my $BaseId (keys(%{$TInfo{"Base"}})) - { # register base classes - register_TypeUsage($BaseId, $LibVersion); + foreach my $BaseId (keys(%{$TInfo{"Base"}})) { + register_TypeUsage($BaseId, $UsedType, $LibVersion); } foreach my $TPos (keys(%{$TInfo{"TParam"}})) { my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { - register_TypeUsage($TTid, $LibVersion); + register_TypeUsage($TTid, $UsedType, $LibVersion); } } } foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}})) { - if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) { - register_TypeUsage($MTid, $LibVersion); + if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion)) + { + register_TypeUsage($MTid, $UsedType, $LibVersion); + $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; } } if($TInfo{"Type"} eq "FuncPtr" - or $TInfo{"Type"} eq "MethodPtr") + or $TInfo{"Type"} eq "MethodPtr" + or $TInfo{"Type"} eq "Func") { if(my $RTid = $TInfo{"Return"}) { - register_TypeUsage($RTid, $LibVersion); + register_TypeUsage($RTid, $UsedType, $LibVersion); } - foreach my $Memb_Pos (keys(%{$TInfo{"Param"}})) + foreach my $PPos (keys(%{$TInfo{"Param"}})) { - if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) { - register_TypeUsage($MTid, $LibVersion); + if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { + register_TypeUsage($PTid, $UsedType, $LibVersion); } } } - return 1; + if($TInfo{"Type"} eq "FieldPtr") + { + if(my $RTid = $TInfo{"Return"}) { + register_TypeUsage($RTid, $UsedType, $LibVersion); + } + if(my $CTid = $TInfo{"Class"}) { + register_TypeUsage($CTid, $UsedType, $LibVersion); + } + } + if($TInfo{"Type"} eq "MethodPtr") + { + if(my $CTid = $TInfo{"Class"}) { + register_TypeUsage($CTid, $UsedType, $LibVersion); + } + } } elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) { - $UsedType{$LibVersion}{$TypeId} = 1; - register_TypeUsage($TInfo{"BaseType"}, $LibVersion); - return 1; + $UsedType->{$TypeId} = 1; + if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion)) + { + register_TypeUsage($BTid, $UsedType, $LibVersion); + $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid; + } } - elsif($TInfo{"Type"} eq "Intrinsic") - { - $UsedType{$LibVersion}{$TypeId} = 1; - return 1; + else + { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. + $UsedType->{$TypeId} = 1; } } - return 0; } sub selectSymbol($$$$) @@ -9111,7 +9747,7 @@ $Target = 1; } } - if($CheckHeadersOnly) + if($CheckHeadersOnly or $Level eq "Source") { if($Target) { @@ -9192,13 +9828,20 @@ my $LibVersion = $_[0]; foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { + if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}})) + { + delete($SymbolInfo{$LibVersion}{$InfoId}); + next; + } my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; - if(not $MnglName) { + if(not $MnglName) + { delete($SymbolInfo{$LibVersion}{$InfoId}); next; } my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; - if(not $ShortName) { + if(not $ShortName) + { delete($SymbolInfo{$LibVersion}{$InfoId}); next; } @@ -9212,9 +9855,15 @@ if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"}); } + delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"}); } foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) { + if(not keys(%{$TypeInfo{$LibVersion}{$Tid}})) + { + delete($TypeInfo{$LibVersion}{$Tid}); + next; + } delete($TypeInfo{$LibVersion}{$Tid}{"Tid"}); foreach my $Attr ("Header", "Line", "Size", "NameSpace") { @@ -9264,66 +9913,190 @@ return 0; } -sub removeUnused($$) +sub remove_Unused($$) { # remove unused data types from the ABI dump my ($LibVersion, $Kind) = @_; - foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) + + my %UsedType = (); + + foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}})) + { + register_SymbolUsage($InfoId, \%UsedType, $LibVersion); + } + foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { - my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; - if(my $RTid = $FuncInfo{"Return"}) { - register_TypeUsage($RTid, $LibVersion); + if($UsedType{$Tid}) + { # All & Extended + next; + } + + if($Kind eq "Extended") + { + if(selectType($Tid, $LibVersion)) + { + my %Tree = (); + register_TypeUsage($Tid, \%Tree, $LibVersion); + + my $Tmpl = 0; + foreach (sort {int($a)<=>int($b)} keys(%Tree)) + { + if(defined $TypeInfo{$LibVersion}{$_}{"Template"} + or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") + { + $Tmpl = 1; + last; + } + } + if(not $Tmpl) + { + foreach (keys(%Tree)) { + $UsedType{$_} = 1; + } + } + } + } + } + + my %Delete = (); + + foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) + { # remove unused types + if($UsedType{$Tid}) + { # All & Extended + next; } - if(my $FCid = $FuncInfo{"Class"}) + + if($Kind eq "Extra") { - register_TypeUsage($FCid, $LibVersion); - if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) - { # register "this" pointer - $UsedType{$LibVersion}{$ThisId} = 1; - if(my %ThisType = get_Type($ThisId, $LibVersion)) { - register_TypeUsage($ThisType{"BaseType"}, $LibVersion); + my %Tree = (); + register_TypeUsage($Tid, \%Tree, $LibVersion); + + foreach (sort {int($a)<=>int($b)} keys(%Tree)) + { + if(defined $TypeInfo{$LibVersion}{$_}{"Template"} + or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") + { + $Delete{$Tid} = 1; + last; } } } - foreach my $PPos (keys(%{$FuncInfo{"Param"}})) + else + { + # remove type + delete($TypeInfo{$LibVersion}{$Tid}); + } + } + + if($Kind eq "Extra") + { # remove duplicates + foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) + { + if($UsedType{$Tid}) + { # All & Extended + next; + } + + my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}; + + if($TName_Tid{$LibVersion}{$Name} ne $Tid) { + delete($TypeInfo{$LibVersion}{$Tid}); + } + } + } + + foreach my $Tid (keys(%Delete)) + { + delete($TypeInfo{$LibVersion}{$Tid}); + } +} + +sub check_Completeness($$) +{ + my ($Info, $LibVersion) = @_; + + # data types + if(defined $Info->{"Memb"}) + { + foreach my $Pos (keys(%{$Info->{"Memb"}})) + { + if(defined $Info->{"Memb"}{$Pos}{"type"}) { + check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion); + } + } + } + if(defined $Info->{"Base"}) + { + foreach my $Bid (keys(%{$Info->{"Base"}})) { + check_TypeInfo($Bid, $LibVersion); + } + } + if(defined $Info->{"BaseType"}) { + check_TypeInfo($Info->{"BaseType"}, $LibVersion); + } + if(defined $Info->{"TParam"}) + { + foreach my $Pos (keys(%{$Info->{"TParam"}})) { - if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) { - register_TypeUsage($PTid, $LibVersion); + my $TName = $Info->{"TParam"}{$Pos}{"name"}; + if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) { + next; + } + if($TName eq "_BoolType") { + next; + } + if($TName=~/\Asizeof\(/) { + next; + } + if(my $Tid = $TName_Tid{$LibVersion}{$TName}) { + check_TypeInfo($Tid, $LibVersion); + } + else + { + if(defined $Debug) { + printMsg("WARNING", "missed type $TName"); + } } } - foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) + } + + # symbols + if(defined $Info->{"Param"}) + { + foreach my $Pos (keys(%{$Info->{"Param"}})) { - my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; - if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { - register_TypeUsage($TTid, $LibVersion); + if(defined $Info->{"Param"}{$Pos}{"type"}) { + check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion); } } } - foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) + if(defined $Info->{"Return"}) { + check_TypeInfo($Info->{"Return"}, $LibVersion); + } + if(defined $Info->{"Class"}) { + check_TypeInfo($Info->{"Class"}, $LibVersion); + } +} + +sub check_TypeInfo($$) +{ + my ($Tid, $LibVersion) = @_; + + if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) { + return; + } + $CheckedTypeInfo{$LibVersion}{$Tid} = 1; + + if(defined $TypeInfo{$LibVersion}{$Tid}) { - if($UsedType{$LibVersion}{$Tid}) - { # All & Extended - next; - } - - if($Kind eq "Extended") - { - if(selectType($Tid, $LibVersion)) { - register_TypeUsage($Tid, $LibVersion); - } + if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) { + printMsg("ERROR", "missed type name ($Tid)"); } + check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion); } - foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) - { # remove unused types - if($UsedType{$LibVersion}{$Tid}) - { # All & Extended - next; - } - # remove type - delete($TypeInfo{$LibVersion}{$Tid}); + else { + printMsg("ERROR", "missed type id $Tid"); } - - # clean memory - %UsedType = (); } sub selfTypedef($$) @@ -10579,17 +11352,6 @@ "Safe"=>-1 ); -sub maxSeverity($$) -{ - my ($S1, $S2) = @_; - if(cmpSeverities($S1, $S2)) { - return $S1; - } - else { - return $S2; - } -} - sub cmpSeverities($$) { my ($S1, $S2) = @_; @@ -10602,12 +11364,6 @@ return ($Severity_Val{$S1}>$Severity_Val{$S2}); } -sub getProblemSeverity($$) -{ - my ($Level, $Kind) = @_; - return $CompatRules{$Level}{$Kind}{"Severity"}; -} - sub isRecurType($$$) { foreach (@{$_[2]}) @@ -10760,23 +11516,27 @@ sub mergeTypes($$$) { my ($Type1_Id, $Type2_Id, $Level) = @_; - return () if(not $Type1_Id or not $Type2_Id); - my (%Sub_SubProblems, %SubProblems) = (); + return {} if(not $Type1_Id or not $Type2_Id); + if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}) { # already merged - return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}}; + return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}; } + my %Type1 = get_Type($Type1_Id, 1); my %Type2 = get_Type($Type2_Id, 2); if(not $Type1{"Name"} or not $Type2{"Name"}) { - return (); + return {}; } $CheckedTypes{$Level}{$Type1{"Name"}} = 1; my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); + $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1; + my %SubProblems = (); + if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) { if($Type1_Pure{"Type"}=~/Struct|Union/ @@ -10788,23 +11548,27 @@ "Target"=>$Type1_Pure{"Name"}, "Type_Name"=>$Type1_Pure{"Name"} ); - %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems; - return %SubProblems; + return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } } } - if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"}) + if(not $Type1_Pure{"Size"} + or not $Type2_Pure{"Size"}) { # including a case when "class Class { ... };" changed to "class Class;" - return (); + if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"} + or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1) + { # NOTE: template instances have no size + return {}; + } } if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes)) { # skip recursive declarations - return (); + return {}; } - return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); - return () if($SkipTypes{1}{$Type1_Pure{"Name"}}); - return () if($SkipTypes{1}{$Type1{"Name"}}); + return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); + return {} if($SkipTypes{1}{$Type1_Pure{"Name"}}); + return {} if($SkipTypes{1}{$Type1{"Name"}}); if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/) { # support for old ABI dumps @@ -10918,8 +11682,7 @@ "New_Value"=>lc($Type2_Pure{"Type"}) ); } } - %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems; - return %SubProblems; + return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes); if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"} @@ -10952,22 +11715,17 @@ "Target"=>$Type1_Pure{"Name"}, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"} ); + "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE); } } if(defined $Type1_Pure{"BaseType"} and defined $Type2_Pure{"BaseType"}) { # checking base types - %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); - foreach my $Sub_SubProblemType (keys(%Sub_SubProblems)) + my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); + foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) { - foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}})) - { - foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) { - $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr}; - } - $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"}; + foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { + $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; } } } @@ -10992,12 +11750,12 @@ } if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2)) { # renamed - $RenamedField{$Member_Pos}=$RenamedTo; - $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name; + $RenamedField{$Member_Pos} = $RenamedTo; + $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; } else { # removed - $RemovedField{$Member_Pos}=1; + $RemovedField{$Member_Pos} = 1; } } elsif($Type1_Pure{"Type"} eq "Enum") @@ -11011,16 +11769,16 @@ my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure); if($MemberPair_Pos_Rev eq "lost") { - $RenamedField{$Member_Pos}=$RenamedTo; - $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name; + $RenamedField{$Member_Pos} = $RenamedTo; + $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; } else { - $RemovedField{$Member_Pos}=1; + $RemovedField{$Member_Pos} = 1; } } else { # removed - $RemovedField{$Member_Pos}=1; + $RemovedField{$Member_Pos} = 1; } } } @@ -11063,7 +11821,7 @@ next if(not $Member_Name); if(not $RemovedField{$Member_Pos}) { # old type without removed fields - $RelPos{1}{$Member_Name}=$Pos; + $RelPos{1}{$Member_Name} = $Pos; $RelPosName{1}{$Pos} = $Member_Name; $AbsPos{1}{$Pos++} = $Member_Pos; } @@ -11075,7 +11833,7 @@ next if(not $Member_Name); if(not $AddedField{$Member_Pos}) { # new type without added fields - $RelPos{2}{$Member_Name}=$Pos; + $RelPos{2}{$Member_Name} = $Pos; $RelPosName{2}{$Pos} = $Member_Name; $AbsPos{2}{$Pos++} = $Member_Pos; } @@ -11129,6 +11887,7 @@ { # check older fields, public and private my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); + next if($Member_Name eq "_vptr"); if(my $RenamedTo = $RenamedField{$Member_Pos}) { # renamed if(defined $Constants{2}{$Member_Name}) @@ -11318,6 +12077,13 @@ { # private field size with no effect $ProblemType = ""; } + if($ProblemType eq "Field_Size") + { + if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2) + { # Low severity + $ProblemType = "Struct_Field_Size_Increased"; + } + } if($ProblemType) { # register a problem %{$SubProblems{$ProblemType}{$Member_Name}}=( @@ -11350,11 +12116,11 @@ "Type_Name"=>$Type1_Pure{"Name"}); } } - %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); - foreach my $ProblemType (keys(%Sub_SubProblems)) + my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); + foreach my $ProblemType (keys(%Sub_SubChanges)) { - my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"}; - my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"}; + my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; + my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; # quals if($ProblemType eq "Field_Type" @@ -11364,28 +12130,28 @@ if(checkDump(1, "2.6") and checkDump(2, "2.6")) { if(addedQual($Old_Value, $New_Value, "volatile")) { - %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; } elsif(removedQual($Old_Value, $New_Value, "volatile")) { - %{$Sub_SubProblems{"Field_Became_Non_Volatile"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; } } if(my $RA = addedQual($Old_Value, $New_Value, "const")) { if($RA==2) { - %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } else { - %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } } elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) { if($RR==2) { - %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } else { - %{$Sub_SubProblems{"Field_Became_Non_Const"}} = %{$Sub_SubProblems{$ProblemType}}; + %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } } } @@ -11393,21 +12159,21 @@ if($Level eq "Source") { - foreach my $ProblemType (keys(%Sub_SubProblems)) + foreach my $ProblemType (keys(%Sub_SubChanges)) { - my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"}; - my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"}; + my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; + my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; if($ProblemType eq "Field_Type") { if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { - delete($Sub_SubProblems{$ProblemType}); + delete($Sub_SubChanges{$ProblemType}); } } } } - foreach my $ProblemType (keys(%Sub_SubProblems)) + foreach my $ProblemType (keys(%Sub_SubChanges)) { my $ProblemType_Init = $ProblemType; if($ProblemType eq "Field_Type_And_Size") @@ -11446,9 +12212,9 @@ "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); - foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}})) + foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}})) { # other properties - $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr}; + $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr}; } } if(not isPublic(\%Type1_Pure, $Member_Pos)) @@ -11456,22 +12222,33 @@ next; } if($MemberType1_Id and $MemberType2_Id) - {# checking member type changes (replace) - %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); - foreach my $Sub_SubProblemType (keys(%Sub_SubProblems)) + { # checking member type changes + my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); + + my %DupProblems = (); + + foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) { - foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}})) + foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { - my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; - $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1; - foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) { - $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr}; + if(not defined $AllAffected) + { + if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) { + next; + } } - if($Sub_SubLocation!~/\-\>/) { - $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name; + + my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; + $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; + + if(not defined $AllAffected) + { + $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1; } } } + + %DupProblems = (); } } } @@ -11480,6 +12257,7 @@ { # checking added members, public and private my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); + next if($Member_Name eq "_vptr"); if($AddedField{$Member_Pos}) { # added if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) @@ -11542,9 +12320,9 @@ } } } - %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems; + pop(@RecurTypes); - return %SubProblems; + return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } sub isUnnamed($) { @@ -12275,7 +13053,7 @@ and $CompleteSignature{1}{$Symbol}{"Const"}) { my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; - %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=( + %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=( "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"}, "Target"=>get_Signature($Alt, 1)); } @@ -12432,7 +13210,7 @@ { my $Level = $_[0]; my %SubProblems = (); - + mergeBases($Level); my %AddedOverloads = (); @@ -12582,18 +13360,18 @@ my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]}; if($CompleteSignature{1}{$Symbol}{"Constructor"}) { - if($Symbol=~/(C1E|C2E)/) + if($Symbol=~/(C[1-2][EI])/) { my $CtorType = $1; - $NewSym=~s/(C1E|C2E)/$CtorType/g; + $NewSym=~s/(C[1-2][EI])/$CtorType/g; } } elsif($CompleteSignature{1}{$Symbol}{"Destructor"}) { - if($Symbol=~/(D0E|D1E|D2E)/) + if($Symbol=~/(D[0-2][EI])/) { my $DtorType = $1; - $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g; + $NewSym=~s/(D[0-2][EI])/$DtorType/g; } } my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"}; @@ -12652,6 +13430,8 @@ } foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) { # checking symbols + $CurrentSymbol = $Symbol; + my ($SN, $SS, $SV) = separate_symbol($Symbol); if($Level eq "Source") { # remove symbol version @@ -12880,7 +13660,7 @@ } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } @@ -12896,7 +13676,7 @@ { %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName_Old, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "Old_Value"=>$PName_Old, "New_Value"=>$PName, @@ -12911,7 +13691,7 @@ } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } @@ -12962,7 +13742,7 @@ } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } @@ -12978,7 +13758,7 @@ { %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "Old_Value"=>$PName, "New_Value"=>$PName_New, @@ -12993,7 +13773,7 @@ } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, - "Param_Pos"=>$ParamPos, + "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } @@ -13004,12 +13784,12 @@ # checking return type my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"}; my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"}; - %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); + my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); - foreach my $SubProblemType (keys(%SubProblems)) + foreach my $SubProblemType (keys(%RC_SubProblems)) { - my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; - my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; + my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"}; + my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"}; my %ProblemTypes = (); if($CompleteSignature{1}{$Symbol}{"Data"}) @@ -13171,13 +13951,15 @@ foreach my $ProblemType (keys(%ProblemTypes)) { # additional - @{$CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; + $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType}; } } if($ReturnType1_Id and $ReturnType2_Id) { @RecurTypes = (); - %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); + my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); + + my $AddProblems = {}; if($CompleteSignature{1}{$Symbol}{"Data"}) { @@ -13185,17 +13967,17 @@ { if(get_PLevel($ReturnType1_Id, 1)==0) { - foreach my $SubProblemType (keys(%SubProblems)) + foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { # add "Global_Data_Size" problem - my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; - my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; + my $New_Value = $Sub_SubProblems->{$SubProblemType}{"New_Value"}; + my $Old_Value = $Sub_SubProblems->{$SubProblemType}{"Old_Value"}; if($SubProblemType eq "DataType_Size") { # add a new problem - %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}}; + $AddProblems->{"Global_Data_Size"} = $Sub_SubProblems->{$SubProblemType}; } } } - if(not defined $SubProblems{"Global_Data_Size"}) + if(not defined $AddProblems->{"Global_Data_Size"}) { if(defined $GlobalDataObject{1}{$Symbol} and defined $GlobalDataObject{2}{$Symbol}) @@ -13204,25 +13986,30 @@ my $New_Size = $GlobalDataObject{2}{$Symbol}; if($Old_Size!=$New_Size) { - %{$SubProblems{"Global_Data_Size"}{"retval"}} = ( + $AddProblems->{"Global_Data_Size"}{"retval"} = { "Old_Size"=>$Old_Size*$BYTE_SIZE, - "New_Size"=>$New_Size*$BYTE_SIZE ); + "New_Size"=>$New_Size*$BYTE_SIZE }; } } } } } - foreach my $SubProblemType (keys(%SubProblems)) + + foreach my $SubProblemType (keys(%{$AddProblems})) { - foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}})) + foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}})) { my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval"; - %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=( - "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} ); - @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}}; - if($SubLocation!~/\-\>/) { - $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"}; - } + $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation}; + } + } + + foreach my $SubProblemType (keys(%{$Sub_SubProblems})) + { + foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) + { + my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval"; + $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } @@ -13238,18 +14025,13 @@ if($ThisPtr1_Id and $ThisPtr2_Id) { @RecurTypes = (); - %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); - foreach my $SubProblemType (keys(%SubProblems)) + my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); + foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { - foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}})) + foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) { my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this"; - %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=( - "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} ); - @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}}; - if($SubLocation!~/\-\>/) { - $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"}; - } + $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } @@ -13437,11 +14219,11 @@ return; } - if(index($Symbol, "_Z")==0) - { # do not merge this - if($PName1 eq "this" or $PName2 eq "this") { - return; - } + if($Symbol=~/\A(_Z|\?)/) + { # do not merge "this" + if($PName1 eq "this" or $PName2 eq "this") { + return; + } } my %Type1 = get_Type($PType1_Id, 1); @@ -13459,14 +14241,14 @@ { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1 ); + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); } elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1 ); + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); } } @@ -13483,7 +14265,7 @@ { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Old_Regs, "New_Value"=>$New_Regs ); } @@ -13492,14 +14274,14 @@ { %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Old_Regs ); } elsif(not $Old_Regs and $New_Regs) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Value"=>$New_Regs ); } if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne "" @@ -13507,18 +14289,29 @@ { if($Old_Offset ne $New_Offset) { - %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( - "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, - "Old_Value"=>$Old_Offset, - "New_Value"=>$New_Offset ); + my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"}; + my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"}; + + $Old_Offset = $Old_Offset - $Start1; + $New_Offset = $New_Offset - $Start2; + + if($Old_Offset ne $New_Offset) + { + %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( + "Target"=>$PName1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), + "Old_Value"=>$Old_Offset, + "New_Value"=>$New_Offset ); + } } } } } } - if(checkDump(1, "2.0") and checkDump(2, "2.0")) + if(checkDump(1, "2.0") and checkDump(2, "2.0") + and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1") { # "default" attribute added in ACC 1.22 (dump 2.0 format) + # broken in 3.1, fixed in 3.2 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"}; my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"}; if(not checkDump(1, "2.13") @@ -13553,7 +14346,7 @@ { # FIXME: how to distinguish "0" and 0 (NULL) %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Value_Old, "New_Value"=>$Value_New ); } @@ -13562,7 +14355,7 @@ { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Value_Old ); } } @@ -13571,7 +14364,7 @@ $Value_New = showVal($Value_New, $PType2_Id, 2); %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Value"=>$Value_New ); } } @@ -13584,7 +14377,7 @@ { # except unnamed "..." value list (Id=-1) %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, "Old_Value"=>$PName1, "New_Value"=>$PName2, @@ -13594,6 +14387,7 @@ # checking type change (replace) my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level); + foreach my $SubProblemType (keys(%SubProblems)) { # add new problems, remove false alarms my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; @@ -13731,35 +14525,29 @@ } %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=( "Target"=>$PName1, - "Param_Pos"=>$ParamPos1, + "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Signature"=>get_Signature($Symbol, 2) ); @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; } + @RecurTypes = (); + # checking type definition changes - my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level); - foreach my $SubProblemType (keys(%SubProblems_Merge)) + my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level); + foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { - foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}})) + foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) { my $NewProblemType = $SubProblemType; if($SubProblemType eq "DataType_Size") { - my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"}; - if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) + if($Type1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) { # stack has been affected $NewProblemType = "DataType_Size_And_Stack"; } } my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location; - %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=( - "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, - "Param_Pos"=>$ParamPos1, - "Param_Name"=>$PName1 ); - @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}}; - if($SubLocation!~/\-\>/) { - $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"}; - } + $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } @@ -13797,8 +14585,8 @@ sub getTypeIdByName($$) { - my ($TypeName, $Version) = @_; - return $TName_Tid{$Version}{formatName($TypeName, "T")}; + my ($TypeName, $LibVersion) = @_; + return $TName_Tid{$LibVersion}{formatName($TypeName, "T")}; } sub diffTypes($$$) @@ -14015,8 +14803,7 @@ "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } else { @@ -14026,8 +14813,7 @@ "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"})) { @@ -14035,8 +14821,7 @@ "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } } } @@ -14050,16 +14835,14 @@ { %{$LocalProblems{"Return_Type_From_Void"}}=( "New_Value"=>$Type2{"Name"}, - "New_Size"=>$Type2{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } elsif($Prefix eq "Return" and $Type2_Pure{"Name"} eq "void") { %{$LocalProblems{"Return_Type_Became_Void"}}=( "Old_Value"=>$Type1{"Name"}, - "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE); } else { @@ -14071,8 +14854,7 @@ "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } else { @@ -14082,8 +14864,7 @@ "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } elsif(tNameLock($Type1_Id, $Type2_Id)) { # FIXME: correct this condition @@ -14091,8 +14872,7 @@ "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, - "New_Size"=>$Type2{"Size"}*$BYTE_SIZE, - "InitialType_Type"=>$Type1_Pure{"Type"}); + "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } } } @@ -14718,7 +15498,8 @@ if($Arch=~/\A([\w]{3,})(-|\Z)/) { $Arch = $1; } - $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/); + $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/i); + $Arch = "x86_64" if($Arch=~/\Aamd64\Z/i); if($OSgroup eq "windows") { $Arch = "x86" if($Arch=~/win32|mingw32/i); @@ -14829,7 +15610,7 @@ foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}})) { my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"}; - my $Priority = getProblemSeverity($Level, $Kind); + my $Priority = $CompatRules{$Level}{$Kind}{"Severity"}; next if($Priority ne $TargetPriority); if($Kinds_Target{$Kind}{$Target}) { next; @@ -14894,7 +15675,7 @@ { foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { - my $Priority = getProblemSeverity($Level, $Kind); + my $Priority = $CompatRules{$Level}{$Kind}{"Severity"}; if($Kind eq "Added_Symbol") { $Added += 1; } @@ -14933,21 +15714,43 @@ { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { - foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) + foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; - my $Priority = getProblemSeverity($Level, $Kind); - if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority)) + my $Priority = $CompatRules{$Level}{$Kind}{"Severity"}; + my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}; + + if($MaxSeverity and $Severity_Val{$MaxSeverity}>$Severity_Val{$Priority}) { # select a problem with the highest priority next; } + if(($Priority ne "Low" or $StrictCompat) - and $Priority ne "Safe") { - $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority); + and $Priority ne "Safe") + { + if(defined $TotalAffected{$Level}{$Interface}) + { + if($Severity_Val{$Priority}>$Severity_Val{$TotalAffected{$Level}{$Interface}}) { + $TotalAffected{$Level}{$Interface} = $Priority; + } + } + else { + $TotalAffected{$Level}{$Interface} = $Priority; + } + } + + $TypeChanges{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; + + if($MaxSeverity) + { + if($Severity_Val{$Priority}>$Severity_Val{$MaxSeverity}) { + $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Priority; + } + } + else { + $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Priority; } - %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}}; - $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority); } } } @@ -14958,6 +15761,8 @@ $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level); $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level); + %TypeChanges = (); # free memory + if($CheckObjectsOnly) { # only removed exported symbols $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}}); @@ -15004,7 +15809,7 @@ { foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) { - my $Severity = getProblemSeverity($Level, $Kind); + my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity eq "Safe") { $C_Other+=1; @@ -15437,7 +16242,7 @@ if(not defined $CompatRules{$Level}{$Kind}) { next; } - if($TargetSeverity ne getProblemSeverity($Level, $Kind)) { + if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) { next; } $ReportMap{$Header}{$Constant}{$Kind} = 1; @@ -15933,7 +16738,7 @@ %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}}; foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) { - my $Priority = getProblemSeverity($Level, $Kind); + my $Priority = $CompatRules{$Level}{$Kind}{"Severity"}; if($Priority ne $TargetSeverity) { delete($SymbolChanges{$Symbol}{$Kind}{$Location}); } @@ -15967,6 +16772,7 @@ { my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); + $INTERFACE_PROBLEMS .= " \n"; my $Change = $CompatRules{$Level}{$Kind}{"Change"}; $INTERFACE_PROBLEMS .= " $Change\n"; @@ -16078,11 +16884,11 @@ { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { - foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) + foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; - my $Severity = getProblemSeverity($Level, $Kind); + my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity eq "Safe" and $TargetSeverity ne "Safe") { next; @@ -16103,9 +16909,9 @@ my %Kinds_Target = (); foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}})) { - foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) + foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { - my $Severity = getProblemSeverity($Level, $Kind); + my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity ne $TargetSeverity) { # other priority delete($TypeChanges{$TypeName}{$Kind}{$Location}); @@ -16141,7 +16947,7 @@ $TYPE_PROBLEMS .= " \n"; foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) { - foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) + foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; $TYPE_PROBLEMS .= " \n"; @@ -16183,7 +16989,7 @@ my $TYPE_REPORT = ""; foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) { - foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) + foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) @@ -16355,34 +17161,69 @@ $VEntry=~s/\A0u\Z/(int (*)(...))0/; $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/; $VEntry=~s/\A&_Z\Z/& _Z/; - # templates - if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g) - { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits] - # become std::basic_streambuf::imbue - my ($Pname, $Pval) = ($1, $2); - if($Pname eq "_CharT" and $VEntry=~/\Astd::/) - { # stdc++ typedefs - $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g; - # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef) - # The typedef info should be added to ABI dumps + $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors + return $VEntry; +} + +sub adjustParamPos($$$) +{ + my ($Pos, $Symbol, $LibVersion) = @_; + if(defined $CompleteSignature{$LibVersion}{$Symbol}) + { + if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"} + and $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) + { + return $Pos-1; } - else + + return $Pos; + } + + return undef; +} + +sub getParamPos($$$) +{ + my ($Name, $Symbol, $LibVersion) = @_; + + if(defined $CompleteSignature{$LibVersion}{$Symbol} + and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}) + { + my $Info = $CompleteSignature{$LibVersion}{$Symbol}; + foreach (keys(%{$Info->{"Param"}})) { - $VEntry=~s/<$Pname>/<$Pval>/g; - $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g; + if($Info->{"Param"}{$_}{"name"} eq $Name) + { + return $_; + } } } - $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors - return $VEntry; + + return undef; +} + +sub getParamName($) +{ + my $Loc = $_[0]; + $Loc=~s/\->.*//g; + return $Loc; } sub getAffectedSymbols($$$$) { my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_; my $LIMIT = 1000; - if($#{$Syms}>=10000) - { # reduce size of the report - $LIMIT = 10; + + if(defined $AffectLimit) + { + $LIMIT = $AffectLimit; + } + else + { + if($#{$Syms}>=10000) + { # reduce size of the report + $LIMIT = 10; + } } my %SProblems = (); foreach my $Symbol (@{$Syms}) @@ -16390,7 +17231,7 @@ if(keys(%SProblems)>$LIMIT) { last; } - if(($Symbol=~/C2E|D2E|D0E/)) + if(($Symbol=~/(C2|D2|D0)[EI]/)) { # duplicated problems for C2 constructors, D2 and D0 destructors next; } @@ -16418,9 +17259,10 @@ my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"}; next if($Type_Name ne $Target_TypeName); - my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"}; - my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"}; - my $Severity = getProblemSeverity($Level, $Kind); + my $PName = getParamName($Location); + my $PPos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1); + + my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; my $Path_Length = 0; my $ProblemLocation = $Location; if($Type_Name) { @@ -16430,17 +17272,17 @@ $Path_Length += 1; } if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max) - or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max)) + or (cmpLocations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max)) { $MinPath_Length = $Path_Length; $Severity_Max = $Severity_Val{$Severity}; $ProblemLocation_Last = $ProblemLocation; %{$SProblems{$Symbol}} = ( - "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location), + "Descr"=>getAffectDesc($Level, $Symbol, $Kind, $Location), "Severity_Max"=>$Severity_Max, "Signature"=>$Signature, - "Position"=>$Position, - "Param_Name"=>$Param_Name, + "Position"=>$PPos, + "Param_Name"=>$PName, "Location"=>$Location ); } @@ -16501,37 +17343,46 @@ return $Affected; } -sub cmp_locations($$) +sub cmpLocations($$) { my ($L1, $L2) = @_; - if($L2=~/\b(retval|this)\b/ - and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) { - return 1; - } - if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/ - and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) { - return 1; + if($L2=~/\A(retval|this)\b/ + and $L1!~/\A(retval|this)\b/) + { + if($L1!~/\-\>/) { + return 1; + } + elsif($L2=~/\-\>/) { + return 1; + } } return 0; } -sub getAffectDescription($$$$) +sub getAffectDesc($$$$) { my ($Level, $Symbol, $Kind, $Location) = @_; + my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}}; - my $PPos = showPos($Problem{"Param_Pos"}); + + my $Location_I = $Location; + $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field + my @Sentence = (); - $Location=~s/\A(.*)\-\>.+?\Z/$1/; + if($Kind eq "Overridden_Virtual_Method" or $Kind eq "Overridden_Virtual_Method_B") { push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method."); } elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { + my %SymInfo = %{$CompleteSignature{1}{$Symbol}}; + if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/) { - my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method"; - my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"}; + my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method"; + my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"}; + if($ClassName eq $Problem{"Type_Name"}) { push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class."); } @@ -16541,63 +17392,81 @@ } else { + my $TypeID = undef; + if($Location=~/retval/) { # return value - if($Location=~/\-\>/) { + if(index($Location, "->")!=-1) { push(@Sentence, "Field \'".$Location."\' in return value"); } else { push(@Sentence, "Return value"); } - if(my $Init = $Problem{"InitialType_Type"}) - { - if($Init eq "Pointer") { - push(@Sentence, "(pointer)"); - } - elsif($Init eq "Ref") { - push(@Sentence, "(reference)"); - } - } + + $TypeID = $SymInfo{"Return"}; } elsif($Location=~/this/) { # "this" pointer - if($Location=~/\-\>/) { + if(index($Location, "->")!=-1) { push(@Sentence, "Field \'".$Location."\' in the object of this method"); } else { push(@Sentence, "\'this\' pointer"); } + + $TypeID = $SymInfo{"Class"}; } else { # parameters - if($Location=~/\-\>/) { - push(@Sentence, "Field \'".$Location."\' in $PPos parameter"); + + my $PName = getParamName($Location); + my $PPos = getParamPos($PName, $Symbol, 1); + + if(index($Location, "->")!=-1) { + push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); } else { - push(@Sentence, "$PPos parameter"); + push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); } - if($Problem{"Param_Name"}) { - push(@Sentence, "\'".$Problem{"Param_Name"}."\'"); + if($PName) { + push(@Sentence, "\'".$PName."\'"); } - if(my $Init = $Problem{"InitialType_Type"}) + + $TypeID = $SymInfo{"Param"}{$PPos}{"type"}; + } + + if($Location!~/this/) + { + if(my %PureType = get_PureType($TypeID, $TypeInfo{1})) { - if($Init eq "Pointer") { + if($PureType{"Type"} eq "Pointer") { push(@Sentence, "(pointer)"); } - elsif($Init eq "Ref") { + elsif($PureType{"Type"} eq "Ref") { push(@Sentence, "(reference)"); } } } + if($Location eq "this") { push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); } - elsif(defined $Problem{"Start_Type_Name"} - and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) { - push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); - } - else { - push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); + else + { + my $Location_T = $Location; + $Location_T=~s/\A\w+(\->|\Z)//; # location in type + + my $TypeID_Problem = $TypeID; + if($Location_T) { + $TypeID_Problem = getFieldType($Location_T, $TypeID, 1); + } + + if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) { + push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); + } + else { + push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); + } } } } @@ -16607,6 +17476,29 @@ return join(" ", @Sentence); } +sub getFieldType($$$) +{ + my ($Location, $TypeId, $LibVersion) = @_; + + my @Fields = split("->", $Location); + + foreach my $Name (@Fields) + { + my %Info = get_BaseType($TypeId, $LibVersion); + + foreach my $Pos (keys(%{$Info{"Memb"}})) + { + if($Info{"Memb"}{$Pos}{"name"} eq $Name) + { + $TypeId = $Info{"Memb"}{$Pos}{"type"}; + last; + } + } + } + + return $TypeId; +} + sub get_XmlSign($$) { my ($Symbol, $LibVersion) = @_; @@ -17085,7 +17977,8 @@ delete($Constants{$Version}{$Constant}); next; } - if(not $ExtraDump and ($Constant=~/_h\Z/i or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) + if(not $ExtraDump and ($Constant=~/_h\Z/i + or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) { # skip delete($Constants{$Version}{$Constant}); } @@ -17922,7 +18815,7 @@ if(not $ReadelfCmd) { exitStatus("Not_Found", "can't find \"readelf\""); } - open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |"); + open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |"); my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output while() { @@ -18053,7 +18946,9 @@ return join_P($Dir,$Name); } } - detectSystemObjects() if(not keys(%SystemObjects)); + if(not defined $Cache{"checkSystemFiles"}) { + checkSystemFiles(); + } if(my @AllObjects = keys(%{$SystemObjects{$Name}})) { return $AllObjects[0]; } @@ -18265,6 +19160,7 @@ } } close(LIB); + if($Deps) { if($LIB_TYPE eq "dynamic") @@ -18288,16 +19184,16 @@ if(not $ReadelfCmd) { exitStatus("Not_Found", "can't find \"readelf\""); } - $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\""; + my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\""; if($DebugPath) { # debug mode # write to file - system($ReadelfCmd." >\"$DebugPath\""); + system($Cmd." >\"$DebugPath\""); open(LIB, $DebugPath); } else { # write to pipe - open(LIB, $ReadelfCmd." |"); + open(LIB, $Cmd." |"); } my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output while() @@ -18378,19 +19274,25 @@ } } } - elsif($LIB_TYPE eq "dynamic") - { # dynamic library specifics - if($Deps) - { - if(/NEEDED.+\[([^\[\]]+)\]/) - { # dependencies: - # 0x00000001 (NEEDED) Shared library: [libc.so.6] - $NeededLib{$1} = 1; - } + } + close(LIB); + + if($Deps and $LIB_TYPE eq "dynamic") + { # dynamic library specifics + $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\""; + open(LIB, $Cmd." |"); + + while() + { + if(/NEEDED.+\[([^\[\]]+)\]/) + { # dependencies: + # 0x00000001 (NEEDED) Shared library: [libc.so.6] + $NeededLib{$1} = 1; } } + + close(LIB); } - close(LIB); } if($Vers) { @@ -18486,46 +19388,52 @@ } } -sub detectSystemHeaders() +sub checkSystemFiles() { + $Cache{"checkSystemFiles"} = 1; + my @SysHeaders = (); - foreach my $DevelPath (@{$SystemPaths{"include"}}) + + foreach my $DevelPath (@{$SystemPaths{"lib"}}) { next if(not -d $DevelPath); - # search for all header files in the /usr/include - # with or without extension (ncurses.h, QtCore, ...) - push(@SysHeaders, cmd_find($DevelPath,"f")); - foreach my $Link (cmd_find($DevelPath,"l")) - { # add symbolic links - if(-f $Link) { - push(@SysHeaders, $Link); - } + + my @Files = cmd_find($DevelPath); + + if(not $CheckObjectsOnly) + { + # search for headers in /usr/lib + my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; + @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; + push(@SysHeaders, @Headers); } - } - foreach my $DevelPath (@{$SystemPaths{"lib"}}) - { # search for config headers in the /usr/lib - next if(not -d $DevelPath); - foreach (cmd_find($DevelPath,"f",'\.h(pp|xx)?\Z|\/include\/',"",1)) + + # search for libraries in /usr/lib (including symbolic links) + my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files; + foreach my $Path (@Libs) { - if(/\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/) - { # skip useless headers - next; - } - push(@SysHeaders, $_); + my $N = get_filename($Path); + $SystemObjects{$N}{$Path} = 1; + $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1; } } - get_prefixes_I(\@SysHeaders, \%SystemHeaders); -} - -sub detectSystemObjects() -{ - foreach my $DevelPath (@{$SystemPaths{"lib"}}) + + if(not $CheckObjectsOnly) { - next if(not -d $DevelPath); - foreach my $Path (find_libs($DevelPath,"","")) - { # search for shared libraries in the /usr/lib (including symbolic links) - $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1; + foreach my $DevelPath (@{$SystemPaths{"include"}}) + { + next if(not -d $DevelPath); + # search for all header files in the /usr/include + # with or without extension (ncurses.h, QtCore, ...) + push(@SysHeaders, cmd_find($DevelPath,"f")); + foreach my $Link (cmd_find($DevelPath,"l")) + { # add symbolic links + if(-f $Link) { + push(@SysHeaders, $Link); + } + } } + get_prefixes_I(\@SysHeaders, \%SystemHeaders); } } @@ -18705,7 +19613,8 @@ if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) { return $Kind; } - foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}})) + foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}} + keys(%{$SkipHeaders{$LibVersion}{"Path"}})) { if(index($Path, $D)!=-1) { @@ -18714,7 +19623,8 @@ } } } - foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) + foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}} + keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) { if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P}) { @@ -19057,7 +19967,7 @@ { $MAX_ID = $Tid if($Tid>$MAX_ID); $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID); - $Tid_TDid{$Tid}{$TDid}=1; + $Tid_TDid{$Tid}{$TDid} = 1; } } my %NewID = (); @@ -19073,12 +19983,11 @@ } else { - if(my $ID = ++$MAX_ID) - { - $NewID{$TDid}{$Tid} = $ID; - %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; - $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; - } + my $ID = ++$MAX_ID; + + $NewID{$TDid}{$Tid} = $ID; + %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; + $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; } } } @@ -19165,10 +20074,10 @@ or not $TargetHeaders{$LibVersion}) { # support for old ABI dumps: added target headers foreach (keys(%{$Registered_Headers{$LibVersion}})) { - $TargetHeaders{$LibVersion}{get_filename($_)}=1; + $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } foreach (keys(%{$Registered_Sources{$LibVersion}})) { - $TargetHeaders{$LibVersion}{get_filename($_)}=1; + $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } } $Constants{$LibVersion} = $ABI->{"Constants"}; @@ -19245,6 +20154,38 @@ } } + if(not checkDump($LibVersion, "3.2")) + { # support for old ABI dumps + foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) + { + if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) + { + foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) { + $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset}); + } + } + } + + # repair target headers list + delete($TargetHeaders{$LibVersion}); + foreach (keys(%{$Registered_Headers{$LibVersion}})) { + $TargetHeaders{$LibVersion}{get_filename($_)} = 1; + } + foreach (keys(%{$Registered_Sources{$LibVersion}})) { + $TargetHeaders{$LibVersion}{get_filename($_)} = 1; + } + + # non-target constants from anon enums + foreach my $Name (keys(%{$Constants{$LibVersion}})) + { + if(not $ExtraDump + and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion)) + { + delete($Constants{$LibVersion}{$Name}); + } + } + } + if(not checkDump($LibVersion, "2.20")) { # support for old ABI dumps foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) @@ -19862,6 +20803,7 @@ if(not $GCC_PATH) { exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); } + if(not $CheckObjectsOnly_Opt) { if(my $GCC_Ver = get_dumpversion($GCC_PATH)) @@ -19873,6 +20815,13 @@ $OStarget = "symbian"; $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; } + + # check GCC version + if($GCC_Ver=~/\A4\.8(|\.0|\.1)\Z/) + { # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 + printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update or downgrade GCC or use a local installation by --gcc-path=PATH option."); + $EMERGENCY_MODE_48 = 1; + } } else { exitStatus("Error", "something is going wrong with the GCC compiler"); @@ -20979,9 +21928,6 @@ { # enable --extra-info $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info"; } - - # enable --extra-dump - $ExtraDump = 1; } resetLogging($LibVersion); } @@ -21489,6 +22435,9 @@ mergeConstants($Level); } } + + $Cache{"mergeTypes"} = (); # free memory + if($CheckHeadersOnly or $Level eq "Source") { # added/removed in headers @@ -21560,6 +22509,9 @@ $COMMON_LOG_PATH = $LoggingPath; } } + if($Quick) { + $ADD_TMPL_INSTANCES = 0; + } if($OutputDumpPath) { # validate if(not isDump($OutputDumpPath)) { diff -Nru abi-compliance-checker-1.99.1/debian/abi-compliance-checker.1 abi-compliance-checker-1.99.8/debian/abi-compliance-checker.1 --- abi-compliance-checker-1.99.1/debian/abi-compliance-checker.1 2013-06-11 08:53:17.000000000 +0000 +++ abi-compliance-checker-1.99.8/debian/abi-compliance-checker.1 2013-07-29 20:03:04.000000000 +0000 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. -.TH ABI-COMPLIANCE-CHECKER "1" "June 2013" "abi-compliance-checker Compliance Checker (ACC) 1.99.1" "User Commands" +.TH ABI-COMPLIANCE-CHECKER "1" "July 2013" "abi-compliance-checker Compliance Checker (ACC) 1.99.7" "User Commands" .SH NAME abi-compliance-checker \- tool to compare ABI compatibility of shared C/C++ library versions .SH DESCRIPTION @@ -78,7 +78,7 @@ .HP \fB\-dumpversion\fR .IP -Print the tool version (1.99.1) and don't do anything else. +Print the tool version (1.99.7) and don't do anything else. .SS "GENERAL OPTIONS:" .HP \fB\-l\fR|\-lib|\-library NAME @@ -143,7 +143,7 @@ transfer it anywhere and pass instead of the descriptor. Also it can be used for debugging the tool. .IP -Supported ABI dump versions: 2.0<=V<=3.1 +Supported ABI dump versions: 2.0<=V<=3.2 .HP \fB\-old\-dumps\fR .IP @@ -611,6 +611,14 @@ \fB\-tolerant\fR .IP Enable highest tolerance level [1234]. +.HP +\fB\-check\fR +.IP +Check completeness of the ABI dump. +.HP +\fB\-quick\fR +.IP +Quick analysis. Disable check of some template instances. .SS "REPORT:" .IP Compatibility report will be generated to: diff -Nru abi-compliance-checker-1.99.1/debian/changelog abi-compliance-checker-1.99.8/debian/changelog --- abi-compliance-checker-1.99.1/debian/changelog 2013-06-11 08:49:13.000000000 +0000 +++ abi-compliance-checker-1.99.8/debian/changelog 2013-08-01 09:54:52.000000000 +0000 @@ -1,3 +1,18 @@ +abi-compliance-checker (1.99.8-1) unstable; urgency=low + + * New upstream release + - Fixed compatibility with gcc-4.8 + * Update watch file to point at github + + -- Dmitrijs Ledkovs Thu, 01 Aug 2013 10:52:43 +0100 + +abi-compliance-checker (1.99.7-1) unstable; urgency=low + + * New upstream + - Fixed default arguments of methods (broken in 1.99.1) + + -- Mathieu Malaterre Mon, 29 Jul 2013 21:56:09 +0200 + abi-compliance-checker (1.99.1-1) unstable; urgency=low [ James Hunt ] @@ -7,11 +22,10 @@ * New upstream, upload to sid * Update man page, suggests icheck * Recommends ctags. Closes: #711503 - * Make sure dh_acc pulls a-c-c (= ${binary:Version}) * Remove patches applied upstream: - d/p/allow-suffix-on-dumps.patch - -- Mathieu Malaterre Tue, 11 Jun 2013 10:48:45 +0200 + -- Mathieu Malaterre Tue, 11 Jun 2013 10:45:46 +0200 abi-compliance-checker (1.98.8-1~exp1) experimental; urgency=low diff -Nru abi-compliance-checker-1.99.1/debian/control abi-compliance-checker-1.99.8/debian/control --- abi-compliance-checker-1.99.1/debian/control 2013-06-11 08:48:32.000000000 +0000 +++ abi-compliance-checker-1.99.8/debian/control 2013-06-11 08:46:52.000000000 +0000 @@ -33,7 +33,7 @@ Package: dh-acc Architecture: all -Depends: ${perl:Depends}, ${misc:Depends}, abi-compliance-checker (= ${binary:Version}) +Depends: ${perl:Depends}, ${misc:Depends}, abi-compliance-checker Description: debhelper addon to compare ABI compatibility of shared C/C++ library versions dh-acc is an addon to facilitate generating ABI compatibility reports by comparing known ABI dumps with newly build ABI at Debian package diff -Nru abi-compliance-checker-1.99.1/debian/patches/allow-suffix-on-dumps.patch abi-compliance-checker-1.99.8/debian/patches/allow-suffix-on-dumps.patch --- abi-compliance-checker-1.99.1/debian/patches/allow-suffix-on-dumps.patch 1970-01-01 00:00:00.000000000 +0000 +++ abi-compliance-checker-1.99.8/debian/patches/allow-suffix-on-dumps.patch 2013-04-19 13:08:55.000000000 +0000 @@ -0,0 +1,27 @@ +Description: allow suffix on dumps + Since ABI/API dumps can be arch specific, we need to be able to store + a dump per arch for comparison using dh_acc. Debhelper already + supports .ARCH and .OS suffixes, hence allow suffixes on the dump in + abi-compliance-checker. Other ways to solve this are welcome. +Author: Dmitrijs Ledkovs + +--- abi-compliance-checker-1.98.8.orig/abi-compliance-checker.pl ++++ abi-compliance-checker-1.98.8/abi-compliance-checker.pl +@@ -8362,7 +8362,7 @@ sub unpackDump($) + } + return $Contents[0]; + } +- elsif($FileName=~s/\Q.tar.gz\E\Z//g) ++ elsif($FileName=~s/\Q.tar.gz\E.*\Z//g) + { # *.tar.gz + if($OSgroup eq "windows") + { # -xvzf option is not implemented in tar.exe (2003) +@@ -20326,7 +20326,7 @@ sub printErrorLog($) + + sub isDump($) + { +- if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz|\.zip|\.xml|)\Z/) { ++ if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz|\.zip|\.xml|)(.+)\Z/) { + return $1; + } + return 0; diff -Nru abi-compliance-checker-1.99.1/debian/watch abi-compliance-checker-1.99.8/debian/watch --- abi-compliance-checker-1.99.1/debian/watch 2011-12-21 08:43:54.000000000 +0000 +++ abi-compliance-checker-1.99.8/debian/watch 2013-08-01 09:54:42.000000000 +0000 @@ -1,2 +1,3 @@ version=3 -http://forge.ispras.ru/projects/abi-compliance-checker/files /attachments/download/[0-9]+/abi-compliance-checker-(.*).tar.gz +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/-$1.tar.gz/ \ + https://github.com/lvc/abi-compliance-checker/tags .*/v?(\d\S*)\.tar\.gz diff -Nru abi-compliance-checker-1.99.1/doc/Changes.html abi-compliance-checker-1.99.8/doc/Changes.html --- abi-compliance-checker-1.99.1/doc/Changes.html 2013-06-07 12:19:02.000000000 +0000 +++ abi-compliance-checker-1.99.8/doc/Changes.html 2013-07-30 15:08:11.000000000 +0000 @@ -21,7 +21,7 @@