@@ -1192,10 +1192,14 @@ private String typeKey(ImType type) {
11921192 private Set <String > collectDispatchSlotNames (ImClass receiverClass , List <ImMethod > groupMethods ) {
11931193 Set <String > slotNames = new TreeSet <>();
11941194 Set <String > semanticNames = new TreeSet <>();
1195+ Set <String > dispatchKeys = new TreeSet <>();
1196+ Set <String > closureRuntimeKeys = new TreeSet <>();
11951197 for (ImMethod m : groupMethods ) {
11961198 if (m == null ) {
11971199 continue ;
11981200 }
1201+ dispatchKeys .add (dispatchSignatureKey (m ));
1202+ closureRuntimeKeys .add (closureRuntimeDispatchKey (m ));
11991203 String methodName = m .getName ();
12001204 if (!methodName .isEmpty ()) {
12011205 slotNames .add (methodName );
@@ -1215,6 +1219,12 @@ private Set<String> collectDispatchSlotNames(ImClass receiverClass, List<ImMetho
12151219 slotNames .add (owner .getName () + "_" + sourceSemanticName );
12161220 }
12171221 }
1222+ if (receiverClass != null && !dispatchKeys .isEmpty () && !semanticNames .isEmpty ()) {
1223+ collectEquivalentHierarchyMethodNames (receiverClass , dispatchKeys , semanticNames , slotNames , new HashSet <>());
1224+ if (isClosureGeneratedClass (receiverClass ) && !closureRuntimeKeys .isEmpty ()) {
1225+ collectEquivalentClosureFamilyMethodNames (receiverClass , closureRuntimeKeys , semanticNames , slotNames );
1226+ }
1227+ }
12181228 if (receiverClass != null && !semanticNames .isEmpty ()) {
12191229 Set <String > classNames = new TreeSet <>();
12201230 collectClassNamesInHierarchy (receiverClass , classNames , new HashSet <>());
@@ -1227,6 +1237,105 @@ private Set<String> collectDispatchSlotNames(ImClass receiverClass, List<ImMetho
12271237 return slotNames ;
12281238 }
12291239
1240+ private void collectEquivalentHierarchyMethodNames (ImClass c , Set <String > dispatchKeys , Set <String > semanticNames ,
1241+ Set <String > slotNames , Set <ImClass > visited ) {
1242+ if (c == null || !visited .add (c )) {
1243+ return ;
1244+ }
1245+ for (ImMethod method : c .getMethods ()) {
1246+ if (method == null ) {
1247+ continue ;
1248+ }
1249+ if (!dispatchKeys .contains (dispatchSignatureKey (method ))) {
1250+ continue ;
1251+ }
1252+ String methodName = method .getName ();
1253+ String semanticName = semanticNameFromMethodName (methodName );
1254+ String sourceSemanticName = sourceSemanticName (method );
1255+ if (!semanticNames .contains (semanticName ) && !semanticNames .contains (sourceSemanticName )) {
1256+ continue ;
1257+ }
1258+ if (!methodName .isEmpty ()) {
1259+ slotNames .add (methodName );
1260+ slotNames .add (c .getName () + "_" + methodName );
1261+ }
1262+ }
1263+ for (ImClassType sc : c .getSuperClasses ()) {
1264+ collectEquivalentHierarchyMethodNames (sc .getClassDef (), dispatchKeys , semanticNames , slotNames , visited );
1265+ }
1266+ }
1267+
1268+ private void collectEquivalentClosureFamilyMethodNames (ImClass receiverClass , Set <String > closureRuntimeKeys ,
1269+ Set <String > semanticNames , Set <String > slotNames ) {
1270+ Set <ImClass > anchors = new HashSet <>();
1271+ collectClosureFamilyAnchors (receiverClass , anchors , new HashSet <>());
1272+ if (anchors .isEmpty ()) {
1273+ return ;
1274+ }
1275+ List <ImClass > classes = new ArrayList <>(prog .getClasses ());
1276+ classes .sort (Comparator .comparing (this ::classSortKey ));
1277+ for (ImClass candidateClass : classes ) {
1278+ if (!sharesClosureFamilyAnchor (candidateClass , anchors , new HashSet <>())) {
1279+ continue ;
1280+ }
1281+ List <ImMethod > methods = new ArrayList <>(candidateClass .getMethods ());
1282+ methods .sort (Comparator .comparing (this ::methodSortKey ));
1283+ for (ImMethod method : methods ) {
1284+ if (!closureRuntimeKeys .contains (closureRuntimeDispatchKey (method ))) {
1285+ continue ;
1286+ }
1287+ String methodName = method .getName ();
1288+ String semanticName = semanticNameFromMethodName (methodName );
1289+ String sourceSemanticName = sourceSemanticName (method );
1290+ if (!semanticNames .contains (semanticName ) && !semanticNames .contains (sourceSemanticName )) {
1291+ continue ;
1292+ }
1293+ if (!methodName .isEmpty ()) {
1294+ slotNames .add (methodName );
1295+ slotNames .add (candidateClass .getName () + "_" + methodName );
1296+ }
1297+ }
1298+ }
1299+ }
1300+
1301+ private String closureRuntimeDispatchKey (ImMethod method ) {
1302+ if (method == null ) {
1303+ return "<null>" ;
1304+ }
1305+ ImFunction implementation = resolveDispatchSignatureImplementation (method , new HashSet <>());
1306+ if (implementation == null ) {
1307+ return "<abstract>" ;
1308+ }
1309+ return "" + Math .max (0 , implementation .getParameters ().size () - 1 );
1310+ }
1311+
1312+ private void collectClosureFamilyAnchors (ImClass c , Set <ImClass > anchors , Set <ImClass > visited ) {
1313+ if (c == null || !visited .add (c )) {
1314+ return ;
1315+ }
1316+ if (!isClosureGeneratedClass (c )) {
1317+ anchors .add (c );
1318+ }
1319+ for (ImClassType sc : c .getSuperClasses ()) {
1320+ collectClosureFamilyAnchors (sc .getClassDef (), anchors , visited );
1321+ }
1322+ }
1323+
1324+ private boolean sharesClosureFamilyAnchor (ImClass c , Set <ImClass > anchors , Set <ImClass > visited ) {
1325+ if (c == null || !visited .add (c )) {
1326+ return false ;
1327+ }
1328+ if (anchors .contains (c )) {
1329+ return true ;
1330+ }
1331+ for (ImClassType sc : c .getSuperClasses ()) {
1332+ if (sharesClosureFamilyAnchor (sc .getClassDef (), anchors , visited )) {
1333+ return true ;
1334+ }
1335+ }
1336+ return false ;
1337+ }
1338+
12301339 private void collectClassNamesInHierarchy (ImClass c , Set <String > out , Set <ImClass > visited ) {
12311340 if (c == null || !visited .add (c )) {
12321341 return ;
0 commit comments