[3/3,V2] For WIP branch check-uapi-support: ir,comparison: Represent changed anonymous enums

Message ID 87cyxupshs.fsf@redhat.com
State New
Headers
Series For WIP branch check-uapi-support: Fix comparing non-reachable anonymous enums |

Commit Message

Dodji Seketeli Oct. 4, 2023, 10:54 a.m. UTC
  Hello,

Now that added/removed non-reachable anonymous enums is supported, we
want to represent changing an anonymous enum.

Strictly speaking, adding or removing an enumerator from an anonymous
enum is represented as deleting of the anonymous enum in the old
state and the addition of an anonymous enum in the new state.

This patch analyses the added/removed anonymous enums and if the old
enum has enumerators contained in the new one, then it assumes we are
looking at anonymous enum change.

	* include/abg-ir.h (is_enumerator_present_in_enum): Declare new
	public function.
	* src/abg-ir.cc (is_enumerator_present_in_enum): Turn this
	static function into a public one.
	* src/abg-comparison.cc
	(corpus_diff::priv::ensure_lookup_tables_populated): Detect that
	an removed/added anonymous enum is actually a changed anonymous
	enum and represent it as such.
	* tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v{0,1}.txt:
	New reference test output files.
	* tests/data/test-abidiff-exit/test-anonymous-enums-change-v{0,1}.c:
	Source code for the some input test binary.
	* tests/data/test-abidiff-exit/test-anonymous-enums-change-v{0,1}.o:
	New test input binaries.
	* tests/data/Makefile.am: Add the new test materials above to
	source distribution.
	* tests/test-abidiff-exit.cc (in_out_specs): Add the new test
	input to the harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-ir.h                              |   4 +
 src/abg-comparison.cc                         |  76 ++++++++++++++++++
 src/abg-ir.cc                                 |   2 +-
 tests/data/Makefile.am                        |   6 ++
 .../test-anonymous-enums-change-report-v0.txt |  16 ++++
 .../test-anonymous-enums-change-report-v1.txt |  21 +++++
 .../test-anonymous-enums-change-v0.c          |  36 +++++++++
 .../test-anonymous-enums-change-v0.o          | Bin 0 -> 3296 bytes
 .../test-anonymous-enums-change-v1.c          |  41 ++++++++++
 .../test-anonymous-enums-change-v1.o          | Bin 0 -> 3336 bytes
 tests/test-abidiff-exit.cc                    |  32 ++++++++
 11 files changed, 233 insertions(+), 1 deletion(-)
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.o

new file mode 100644
index 00000000..886dbd2b
index fb3d6fff..4c1eaea5 100644
  

Patch

diff --git a/include/abg-ir.h b/include/abg-ir.h
index 3e2cbda9..d21cd2fa 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -2828,6 +2828,10 @@  public:
   set_enum_type(enum_type_decl*);
 }; // end class enum_type_def::enumerator
 
+bool
+is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr,
+			      const enum_type_decl &enom);
+
 bool
 equals(const typedef_decl&, const typedef_decl&, change_kind*);
 
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index 228909dc..eb8e30ac 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -14,6 +14,7 @@ 
 #include <libgen.h>
 #include <algorithm>
 #include <sstream>
+#include <set>
 
 #include "abg-comparison-priv.h"
 #include "abg-reporter-priv.h"
@@ -9609,6 +9610,81 @@  corpus_diff::priv::ensure_lookup_tables_populated()
 	      added_unreachable_types_[repr] = t;
 	  }
       }
+
+    // Handle anonymous enums that got changed.  An anonymous enum is
+    // designated by its flat textual representation. So a change to
+    // any of its enumerators results in a different enum.  That is
+    // represented by a deletion of the previous anonymous enum, and
+    // the addition of a new one.  For the user however, it's the same
+    // enum that changed.  Let's massage this "added/removed" pattern
+    // to show what the user expects, namely, a changed anonymous
+    // enum.
+    {
+      std::set<enum_type_decl_sptr> deleted_anon_enums;
+      std::set<enum_type_decl_sptr> added_anon_enums;
+
+      for (auto entry : deleted_unreachable_types_)
+	if (is_enum_type(entry.second)
+	    && is_enum_type(entry.second)->get_is_anonymous())
+	  deleted_anon_enums.insert(is_enum_type(entry.second));
+
+      for (auto entry : added_unreachable_types_)
+	if (is_enum_type(entry.second)
+	    && is_enum_type(entry.second)->get_is_anonymous())
+	  added_anon_enums.insert(is_enum_type(entry.second));
+
+      string_type_base_sptr_map added_anon_enum_to_erase;
+      string_type_base_sptr_map removed_anon_enum_to_erase;
+
+      // Look for deleted anonymous enums which have enumerators
+      // present in an added anonymous enums ...
+      for (auto deleted_enum : deleted_anon_enums)
+	{
+	  // Look for any enumerator of 'deleted_enum' that is also
+	  // present in an added anonymous enum.
+	  for (auto enr : deleted_enum->get_enumerators())
+	    {
+	      bool this_enum_got_changed = false;
+	      for (auto added_enum : added_anon_enums)
+		{
+		  if (is_enumerator_present_in_enum(enr, *added_enum))
+		    {
+		      // So the enumerator 'enr' from the
+		      // 'deleted_enum' enum is also present in the
+		      // 'added_enum' enum so we assume that
+		      // 'deleted_enum' and 'added_enum' are the same
+		      // enum that got changed.  Let's represent it
+		      // using a diff node.
+		      diff_sptr d = compute_diff(deleted_enum,
+						 added_enum, ctxt);
+		      ABG_ASSERT(d->has_changes());
+		      string repr =
+			abigail::ir::get_pretty_representation(is_type(deleted_enum),
+							       /*internal=*/false);
+		      changed_unreachable_types_[repr]= d;
+		      this_enum_got_changed = true;
+		      string r1 = abigail::ir::get_pretty_representation(is_type(deleted_enum));
+		      string r2 = abigail::ir::get_pretty_representation(is_type(added_enum));
+		      removed_anon_enum_to_erase[r1] = deleted_enum;
+		      added_anon_enum_to_erase[r2] = added_enum;
+		      break;
+		    }
+		}
+	      if (this_enum_got_changed)
+		break;
+	    }
+	}
+
+      // Now remove the added/removed anonymous enums from their maps,
+      // as they are now represented as a changed enum, not an added
+      // and removed enum.
+
+      for (auto entry : added_anon_enum_to_erase)
+	added_unreachable_types_.erase(entry.first);
+
+      for (auto entry : removed_anon_enum_to_erase)
+	deleted_unreachable_types_.erase(entry.first);
+    }
   }
 }
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 06dfbe20..171267f8 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -18997,7 +18997,7 @@  enum_has_non_name_change(const enum_type_decl& l,
 ///
 /// @return true iff the enumerator @p enr is present in the enum @p
 /// enom.
-static bool
+bool
 is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr,
 			      const enum_type_decl &enom)
 {
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 0569af34..d1c05ff7 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -356,6 +356,12 @@  test-abidiff-exit/test-enumerator-changes1-v0.c \
 test-abidiff-exit/test-enumerator-changes1-v0.o \
 test-abidiff-exit/test-enumerator-changes1-v1.c \
 test-abidiff-exit/test-enumerator-changes1-v1.o \
+test-abidiff-exit/test-anonymous-enums-change-report-v0.txt \
+test-abidiff-exit/test-anonymous-enums-change-report-v1.txt \
+test-abidiff-exit/test-anonymous-enums-change-v0.c \
+test-abidiff-exit/test-anonymous-enums-change-v0.o \
+test-abidiff-exit/test-anonymous-enums-change-v1.c \
+test-abidiff-exit/test-anonymous-enums-change-v1.o \
 \
 test-diff-dwarf/test0-v0.cc		\
 test-diff-dwarf/test0-v0.o			\
diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt b/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt
new file mode 100644
index 00000000..2a408ea0
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt
@@ -0,0 +1,16 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 0 removed, 1 changed (1 filtered out), 1 added types
+
+1 changed type unreachable from any public interface:
+
+  [C] 'enum {E4_0=0, E4_1=1, E4_2=2, E4_LAST_ELEMENT=3, }' changed:
+    type size hasn't changed
+    2 enumerator deletions:
+      'E4_2' value '2'
+      'E4_LAST_ELEMENT' value '3'
+
+1 added type unreachable from any public interface:
+
+  [A] 'enum {E5_0=0, E5_1=1, }' at test-anonymous-enums-change-v1.c:26:1
+
diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt b/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt
new file mode 100644
index 00000000..8639fa44
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt
@@ -0,0 +1,21 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 0 removed, 2 changed, 1 added types
+
+2 changed types unreachable from any public interface:
+
+  [C] 'enum {E4_0=0, E4_1=1, E4_2=2, E4_LAST_ELEMENT=3, }' changed:
+    type size hasn't changed
+    2 enumerator deletions:
+      'E4_2' value '2'
+      'E4_LAST_ELEMENT' value '3'
+
+  [C] 'enum {E3_0=0, E3_1=1, }' changed:
+    type size hasn't changed
+    1 enumerator insertion:
+      'E3_2' value '2'
+
+1 added type unreachable from any public interface:
+
+  [A] 'enum {E5_0=0, E5_1=1, }' at test-anonymous-enums-change-v1.c:26:1
+
diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.c b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.c
new file mode 100644
index 00000000..443eb971
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.c
@@ -0,0 +1,36 @@ 
+/*
+ *  Compile this with:
+ *    gcc -c -g -fno-eliminate-unused-debug-types test-anonymous-enums-change-v0.c 
+ */
+
+enum
+  {
+    E1_0,
+    E1_1,
+  } v1;
+
+enum
+  {
+    E3_0,
+    E3_1,
+  };
+
+enum
+  {
+    E4_0,
+    E4_1,
+    E4_2,
+    E4_LAST_ELEMENT
+  };
+
+enum
+  {
+    E0_0,
+    E0_1,
+  } v0;
+
+enum
+  {
+    E2_0,
+    E2_1,
+  } v2;
diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.o b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..26c6df80f0d5203c520890f433cd5bba20b0bc4f
GIT binary patch
literal 3296
zcmb_e&2Jl35P$2nNn4Y&sU^Nrl6BRJ1laZ3aYJd9U=*3O5Gn*kLR_4+{p>8*>)>6R
zL<kj$3kZo5Cr%u=At5A$ggC$@C+=|I!2i$_NE~41?ToW|-Y5t$(!QDb&DYzv^Txhc
z-+m!u7=p<V8{$Y~REV83M{-SxHE~hQi{C)b2}4=4h(E53v}CS<FoR2+Q>})`WoOXA
z9GAtpMG(%Ks3NI=*$zm@0u)^MSc8>IMy+NXx$uSN0ySK*h=E#-;?L8b6>;U;W1hlT
z7UtZgJnSoLY!qkm#q90EjiPZg|7_7T3h)M1VV)r%cf0W1qnSs9$j%#A=L&gqX<_NY
z!*DuRL_WWfH|HSrC3rIM2$48WrN>JJSPpDY0yhlfuen)d_=fO+utcxClsO-#QDLJX
z^t*v<TYeCUdb#1^QWkX=B^RY?WBd8n?l$V%^_S~+?xGHsYHX>9`YNicpl;oH-P$Za
zW0lKJ)hSyQx3cQ4x!0`aS0Vc?FCv3oS+VSXGz#Q;R|azEw?OrVt=;wg>udH})gD(Y
zyKC8<U|`Fh-}eJAlJ+PVg|cn8WpmWEqk}yeih2brSD<nv!^rl6L2%F?j6z!mqkd?&
zcD<l0?Xl~$L}_=>m!<Zg{gz+q`cbLpH@&9c_55C`DWgaZRdgI!!fauw?M0pvZSZXS
zosKQ{{pf$pbn2#0br4&dn>VawIQNx*ap>x6r!UwTS#kgGG^?3<qoI4L7xfquENNsy
zg)}n718Fd1QP+IRW{R^@7y_n%o0dYRcrXP;f4o!EWQy4-@G>CtiTC0+xk@<e%$Eu0
zd&>CfjS52zX3iL|G7!g~137t0yhFtCG+u-U>0-<T;`lH<L;~YQ(jQCUTnnL<1djQ+
zUP;5b-gONpRcw)f{lz&DdXsS659Y6tzC)bxI_d9dc$xHfHGGZq_ci<`=^tu1pTlPw
z4ue<G=NgU^80o8+shg4Pq8|z8{r^Dvp@#oN`Y*)se9n`MjK4MJ$t7^?LnOrUc^eg=
zr(-t3zayQ`iT!^iTsYxDKk}NuqhZW<S&HO-BpjT6!fA$~aE7wyIcn}U{Gc-c8_wW{
z*K7{u_?X!n;>0~3((?n!Ay9%vgd0k44f=fvKRr$`h@=Cv%nl>3#c#$N{%?E%!tiYQ
zJUL5^1&yO`lCVDz(<fRj>6DQ5_$R=I_v)m0eKJkv1m(o<r{_dd4Hux_V>VfJU+fFa
zS(|vo!VWdnpA>+-hkiT*;D3msby)SBXjmlh73Fob=)P#zG4u`yv`|Tq?)wth()Rxb
z{WS1CasLSE`)>oL=LAT6N+8b*#E^8~24HFR_o)6Y6&2rIoMU?ZJ<92lAG1R$bjSd4
zuFw2Ez){xYKgz@be^4AVj${4_7}DbJQA6@PKPevPBIjZs<X`IzO-9`pb=oR<#Oxc2
p|9}E60F1v6`uX9Rrj>H3f1ireO;)}B{0Z^j)A##w5*Z76{6Aj89Torp

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.c b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.c
@@ -0,0 +1,41 @@ 
+/* 
+ * Compile this with:
+ *    gcc -c -g -fno-eliminate-unused-debug-types test-anonymous-enums-change-v1.c 
+ */
+
+enum
+  {
+    E1_0,
+    E1_1,
+  } v1;
+
+enum
+  {
+    E3_0,
+    E3_1,
+    E3_2
+  };
+
+enum
+  {
+    E4_0,
+    E4_1,
+  };
+
+enum
+  {
+    E5_0,
+    E5_1,
+  };
+
+enum
+  {
+    E0_0,
+    E0_1,
+  } v0;
+
+enum
+  {
+    E2_0,
+    E2_1,
+  } v2;
diff --git a/tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.o b/tests/data/test-abidiff-exit/test-anonymous-enums-change-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..7d0f71b47a47d0a7eb893ddd41c4515cfb4b28fa
GIT binary patch
literal 3336
zcmb_eO>7%g5T5ngq^(JsG>D(JkTtX=q3o``aY6}7YAFqA1*#Ad7cORPKRXNdI`Xbf
zB7|Cr3j&D?91s^SaN>jnhe`->=$%u!aOsH)2gHd32bg&~FWEeAFhY#9Z)U#vdprBy
z*tfP`elcelpvZs?IMfsh@cxNIxhBOLoPjy`73BgL(wZmyacSfww}QeHElEzf8c@hj
zk%Kv^z^NxtIBAkfBm<_qD5V3WoJ))ky{8!y`0Qtyu=TYLo1-#3Mb28$OFxf$da!i&
zh$k3}V9uN`;zskvMro>8%HNn@D;X~opD&rlJibyD%o7Y0Zp>eOEcYlte$Kc!GhZ|p
z&MnM7g6+Bh#o|WMoWa!R@yX!>km|40lf^?;K-)9O4a4|zW||oF10NI?lGYdtxzkA+
z88!@~pc9Ig6@)QtRqAD0DzH^1X(d^tic6K$Dp{9FT23Snwr{>>ZC0MMDix>dR4lLT
zEtglzE7szxnD@FLv%&V3EV~yEL$Tfwp%?^BRQ*A7XMOL=s=ZpZN1kPOEV~`{ZP5*S
zLFmWA9)`n6wCt8>3_Etbzbhix@~FIr<zo@WwjcJx{a$|<*&-bFBD=ZchaF*$DozvJ
zoqkWat$ypx!0iOF+YK6iBk1@+*KLS676Tcb1iF+ha$A1vOVLKpR?u$SVlRmQ$4nD9
zJ<$QSH#gU;MeO_1zi7Jr&i}B`xyZxse`UFtnKv8{FCRrc#zadNnOGr<On4v*#w_yM
zkJ(H(IffBn0$#KXGU34tl>F&Rjgtw}W8jmB%%$E-y~#z!m9F?A<La6!eDZ0<A%`Pp
zL^l~p#h*es-6gd{!l@hA@F6;rFd&>BMGv!}@Dl51Q@E-{&{7Jg{HmU-;i}#h4QCa$
zS)lW!auD=7<7)pj^NHS&YqEE$yT*E3!>_XbwuWD3{ap<&v;L8W(?BKqBw?~=R9E%q
zOAW_)Ea@u^zr^}?%;|m8r|U<}{~OltY4{!1e_>8}PP0r*odN1wA%)ZVBvRk^twe=q
znJfHT)+-wR6YJna`@Pt2Add$L-%(O5_F`~oG=kHJB5($x>pOBN*MqR#M;i_3y5DFF
z#OR3GAJ8~H8qy6yp+c~P5(%zLz1i>e1pXp9VLuiQ4mvxE{ib>|wc-E9&tVw#R`pY5
zsVPC@<eR1vDun5iu9kL6$$I?LXrudfT)aN94(12vr0=KaBvXwRq~8*Du<E{aE+}X1
zz#|cM`B2T~5}nQ-`Kj4}e@`T><ErN*gUjG6((7>1eaWt4<b8`li<A`UzAvFIYyY?T
zCqwO%_D_(${}y6;PK4ld23JW*k?vbZTUPx~x&C#IrTR2a^!mGqQBF0NP?U6!3w^Hu
z=BmEp?;xHP|1p2JKPJR~cuf2Ud?4Kk@iZ^hUed02^aIUC-IsLUYC0T#;P~4dFpF0D
f-O&3-J<Tdr<MVs@NY?Sa&K(nfpTFN16XO2{KK~tO

literal 0
HcmV?d00001

diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
--- a/tests/test-abidiff-exit.cc
+++ b/tests/test-abidiff-exit.cc
@@ -1032,6 +1032,38 @@  InOutSpec in_out_specs[] =
     "data/test-abidiff-exit/test-enumerator-changes1-report-1.txt",
     "output/test-abidiff-exit/test-enumerator-changes1-report-1.txt"
   },
+  {
+    "data/test-abidiff-exit/test-anonymous-enums-change-v0.o",
+    "data/test-abidiff-exit/test-anonymous-enums-change-v1.o",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "--no-default-suppression --non-reachable-types",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE
+    | abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
+    "data/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt",
+    "output/test-abidiff-exit/test-anonymous-enums-change-report-v0.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-anonymous-enums-change-v0.o",
+    "data/test-abidiff-exit/test-anonymous-enums-change-v1.o",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "--no-default-suppression --harmless --non-reachable-types",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE
+    | abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
+    "data/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt",
+    "output/test-abidiff-exit/test-anonymous-enums-change-report-v1.txt"
+  },
 #ifdef WITH_BTF
   {
     "data/test-abidiff-exit/btf/test0-v0.o",