public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
From: Giuliano Procida <gprocida@google.com>
To: libabigail@sourceware.org
Cc: dodji@seketeli.org, kernel-team@android.com, gprocida@google.com,
	 maennich@google.com, woodard@redhat.com
Subject: [RFC PATCH 9/9] Add pass to resolve stray forward type declarations
Date: Thu, 25 Mar 2021 21:51:46 +0000	[thread overview]
Message-ID: <20210325215146.3597963-10-gprocida@google.com> (raw)
In-Reply-To: <20210325215146.3597963-1-gprocida@google.com>

This can be used to improve the precision of ABI reporting for C++ and
Linux kernel which both have some kind of One Definition Rule when it
comes to types.

TODO: handle naming-typedef-id references as well

	* scripts/abitidy.pl (substitute_type_ids): New function to
	perform renaming of type-id attributes within XML elements.
	(resolve_forward_declarations): New function that resolves
	forward declarations of types to their definitions, assuming a
	consistent universe of type names.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 scripts/abitidy.pl | 62 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 5 deletions(-)

diff --git a/scripts/abitidy.pl b/scripts/abitidy.pl
index 67fe3a69..d45a82bb 100755
--- a/scripts/abitidy.pl
+++ b/scripts/abitidy.pl
@@ -464,11 +464,8 @@ sub eliminate_duplicate_types($dom) {
     my @losers = grep { $_ != $candidate } (0..$#$types);
     for my $ix (@losers) {
       unless (sub_tree($types->[$ix], $types->[$candidate])) {
-        warn "conflicting duplicate types with id $id\n";
         my @strs = map { $types->[$_]->toString() } ($ix, $candidate);
-        map { $_ =~ s;><;>\n<;g } @strs;
-        my @lines = map { [split("\n", $_)] } @strs;
-        warn Dumper(diff(@lines));
+        warn "conflicting duplicate types with id $id:\n", map { "  $_\n" } @strs, "\n";
         $candidate = undef;
         last;
       }
@@ -572,6 +569,55 @@ sub stabilise_types_and_declarations($dom) {
   }
 }
 
+# Substitute a set of type ids with another.
+sub substitute_type_ids($winner, $losers, $dom) {
+  for my $ref ($dom->findnodes('//*[@type-id]')) {
+    my $type_id = $ref->getAttribute('type-id');
+    $ref->setAttribute('type-id', $winner) if exists $losers->{$type_id};
+  }
+}
+
+# Find definitions and declarations for the same thing and replace
+# references to the latter with the former. naming-typedef-id may be
+# an added complication.
+sub resolve_forward_declarations($dom) {
+  for my $corpus ($dom->findnodes('//abi-corpus')) {
+    my %synonyms;
+    # Safe to extend to deeper-nested types? Need get_scopes.
+    for my $type ($corpus->findnodes('abi-instr/*[@id]')) {
+      my $kind = $type->getName();
+      my $name = $type->getAttribute('name');
+      next unless defined $name;
+      next if $name =~ m;^__anonymous_;;
+      my $key = "$kind:$name";
+      $synonyms{$key} //= [];
+      push @{$synonyms{$key}}, $type;
+    }
+
+    for my $key (keys %synonyms) {
+      my $types = $synonyms{$key};
+      next if scalar(@$types) == 1;
+      my @decls = grep { $_->hasAttribute('is-declaration-only') } @$types;
+      my @defns = grep { !$_->hasAttribute('is-declaration-only') } @$types;
+      next unless @decls and @defns;
+      # Have declarations and definitions, check that top-level ids
+      # are the only differences.
+      my ($kind, $name) = split(':', $key);
+      my @decl_strs = uniq map { my $str = $_->toString(); my $id = $_->getAttribute('id'); $str =~ s; id='$id';;g; $str } @decls;
+      my @defn_strs = uniq map { my $str = $_->toString(); my $id = $_->getAttribute('id'); $str =~ s; id='$id';;g; $str } @defns;
+      unless (scalar @decl_strs == 1 && scalar @defn_strs == 1) {
+        warn "cannot resolve duplicate $kind types with name $name\n";
+        next;
+      }
+      my $winner = $defns[0]->getAttribute('id');
+      my @losers = grep { $_ ne $winner } map { $_->getAttribute('id') } @$types;
+      warn "resolved $kind $name: substituting @losers with $winner\n";
+      substitute_type_ids($winner, {map { $_ => undef } @losers}, $dom);
+      map { remove_node($_) } (@defns[1..$#defns], @decls);
+    }
+  }
+}
+
 # Parse arguments.
 my $input_opt;
 my $output_opt;
@@ -582,18 +628,20 @@ my $prune_opt;
 my $normalise_opt;
 my $eliminate_opt;
 my $stabilise_opt;
+my $forward_opt;
 my $report_opt;
 GetOptions('i|input=s' => \$input_opt,
            'o|output=s' => \$output_opt,
            's|symbols=s' => \$symbols_opt,
            'a|all' => sub {
-             $drop_opt = $prune_opt = $normalise_opt = $eliminate_opt = $stabilise_opt = $report_opt = 1
+             $drop_opt = $prune_opt = $normalise_opt = $eliminate_opt = $stabilise_opt = $forward_opt = $report_opt = 1
            },
            'd|drop-empty!' => \$drop_opt,
            'p|prune-unreachable!' => \$prune_opt,
            'n|normalise-anonymous!' => \$normalise_opt,
            'e|eliminate-duplicates!' => \$eliminate_opt,
            't|stabilise-order!' => \$stabilise_opt,
+           'f|resolve-forward!' => \$forward_opt,
            'r|report-duplicates!' => \$report_opt,
   ) and !@ARGV or die("usage: $0",
                       map { (' ', $_) } (
@@ -606,6 +654,7 @@ GetOptions('i|input=s' => \$input_opt,
                         '[-n|--[no-]normalise-anonymous]',
                         '[-e|--[no-]eliminate-duplicates]',
                         '[-t|--[no-]stabilise-order]',
+                        '[-f|--[no-]resolve-forward]',
                         '[-r|--[no-]report-duplicates]',
                       ), "\n");
 
@@ -631,6 +680,9 @@ eliminate_duplicate_types($dom) if $eliminate_opt;
 # Check for duplicate types.
 report_duplicate_types($dom) if $report_opt;
 
+# Check for types which are both declared and defined.
+resolve_forward_declarations($dom) if $forward_opt;
+
 # Prune unreachable elements.
 prune_unreachable($dom) if $prune_opt;
 
-- 
2.31.0.291.g576ba9dcdaf-goog


      parent reply	other threads:[~2021-03-25 21:52 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-11 11:53 [RFC PATCH] Add an experimental ABI pruning utility Giuliano Procida
2021-03-11 20:39 ` Ben Woodard
2021-03-12 16:51   ` Giuliano Procida
2021-03-12 18:41     ` Ben Woodard
2021-03-15 11:08       ` Giuliano Procida
2021-03-12 16:59 ` [RFC PATCH v2] " Giuliano Procida
2021-03-16 16:55   ` [RFC PATCH v3] " Giuliano Procida
2021-03-25 21:51     ` [RFC PATCH 0/9] Utility to manipulate ABI XML Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 1/9] Add ABI tidying utility Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 2/9] Add pass to drop empty XML elements Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 3/9] Add pass to prune unreachable parts of the ABI Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 4/9] Add pass to filter symbols Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 5/9] Add pass to normalise anonymous type names Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 6/9] Add pass to report duplicate type ids Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 7/9] Add pass to eliminate duplicate member-type fragments Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 8/9] Add pass to stabilise types and declarations Giuliano Procida
2021-03-25 21:51       ` Giuliano Procida [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210325215146.3597963-10-gprocida@google.com \
    --to=gprocida@google.com \
    --cc=dodji@seketeli.org \
    --cc=kernel-team@android.com \
    --cc=libabigail@sourceware.org \
    --cc=maennich@google.com \
    --cc=woodard@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).