lvc / abi-compliance-checker

A tool for checking backward API/ABI compatibility of a C/C++ library
https://lvc.github.io/abi-compliance-checker/
GNU Lesser General Public License v2.1
621 stars 76 forks source link

Feature Request: Report table that shows sizes of classes #115

Open rm5248 opened 2 years ago

rm5248 commented 2 years ago

I'm using abi-compliance-checker to make sure that new code that I'm writing is ABI-stable. However, this involves converting many classes that are not ABI stable to actually be ABI stable. Since this could be an error-prone process(if I forget a class for example), it would be nice if the report that is generated could list in a big table the sizes of each class.

This data is already contained in the ABI dump file, but there's no easy way for me to see it(as I don't know perl).

rm5248 commented 1 year ago

here is a patch that seems to work to show both the size of the class and the number of members in the class. I am not 100% sure that it works correctly, but my quick tests today show it being fine.

diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index c07377d..be69015 100755
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -6371,7 +6371,7 @@ sub getCheckedHeaders($)

 sub getSourceInfo()
 {
-    my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", "");
+    my ($CheckedHeaders, $CheckedSources, $CheckedLibs, $Classes) = ("", "");

     if(my @Headers = getCheckedHeaders(1))
     {
@@ -6426,8 +6426,73 @@ sub getSourceInfo()
         $CheckedLibs .= "</div>\n";
         $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
     }
+
+    $Classes = "<a name='Classes'></a>";
+    if($In::Opt{"OldStyle"}) {
+        $Classes .= "<h2>Classes (".($#ClassNames+1).")</h2>";
+    }
+    else {
+        $Classes .= "<h2>Classes <span class='gray'>&nbsp;".($#ClassNames+1)."&nbsp;</span></h2>";
+    }
+    $Classes .= "<hr/>\n";
+    $Classes .= "<table class='summary'>\n";
+    $Classes .= "<tr><th>Class Name</th><th>Old Size</th><th>New Size</th><th>Old Number Members</th><th>New Number Members</th></tr>\n";
+    foreach my $ClassName (sort keys(%{$ClassNames{1}}))
+    {
+        my $ClassId_Old = $TName_Tid{1}{$ClassName};
+        next if(not $ClassId_Old);
+        
+        if(isPrivateABI($ClassId_Old, 1)) {
+            next;
+        }
+
+        if(index($ClassName, ">")!=-1)
+        { # skip affected template instances
+            next;
+        }
+        
+        if(not isCreatable($ClassId_Old, 1))
+        { # skip classes without public constructors (including auto-generated)
+          # example: class has only a private exported or private inline constructor
+            next;
+        }
+        
+        my %Class_Old = getType($ClassId_Old, 1);
+        my $ClassId_New = $TName_Tid{2}{$ClassName};
+        if(not $ClassId_New) {
+            next;
+        }
+        my %Class_New = getType($ClassId_New, 2);
+        if($Class_New{"Type"}!~/Class|Struct/)
+        { # became typedef
+            if($Level eq "Binary") {
+                next;
+            }
+            if($Level eq "Source")
+            {
+                %Class_New = getPureType($ClassId_New, 2);
+                if($Class_New{"Type"}!~/Class|Struct/) {
+                    next;
+                }
+                $ClassId_New = $Class_New{"Tid"};
+            }
+        }
+        
+        my $new_size = $Class_New{"Size"};
+        my $old_size = $Class_Old{"Size"};
+        my $new_num_members = keys(%{$Class_New{"Memb"}});
+        my $old_num_members = keys(%{$Class_Old{"Memb"}});
+        if(not $new_size){
+            $new_size=0;
+        }
+        if(not $old_size){
+            $old_size=0;
+        }
+        $Classes .= "<tr><td>$ClassName</td><td>$new_size</td><td>$old_size</td><td>$new_num_members</td><td>$old_num_members</td></tr>\n";
+    }
+    $Classes .= "</table>\n";

-    return $CheckedHeaders.$CheckedSources.$CheckedLibs;
+    return $CheckedHeaders.$CheckedSources.$CheckedLibs.$Classes;
 }

 sub getObjTitle()