From adfe648216464f90ec0e10648fa2c3f0daaf80ed Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 27 Feb 2021 15:52:58 +0100 Subject: [PATCH] affect lambda instantiations when an abstract method in a SAM interface becomes non-abstract (IDEA-263109) GitOrigin-RevId: 882c034d0cd6afbc297dca1e59e940dd90f8c5a4 --- .../deleteSAMInterfaceMethod.log | 14 ++++ .../src/DerivedService.java | 2 + .../src/DerivedServiceClient.java | 5 ++ .../src/Service.java} | 1 - .../src/Service.java.new | 2 + .../src/ServiceClient.java | 5 ++ .../deleteSAMInterfaceMethod/src/Util.java | 7 ++ .../renameSAMInterfaceMethod.log | 16 +++++ .../src/DerivedService.java | 2 + .../src/DerivedServiceClient.java | 5 ++ .../renameSAMInterfaceMethod/src/Service.java | 3 + .../src/Service.java.new | 3 + .../src/ServiceClient.java | 5 ++ .../renameSAMInterfaceMethod/src/Util.java | 7 ++ .../unsetAbstractForSAMInterface.log | 14 ++++ .../src/DerivedService.java | 2 + .../src/DerivedServiceClient.java | 5 ++ .../src/Service.java | 5 ++ .../src/Service.java.new | 5 ++ .../src/ServiceClient.java | 5 ++ .../src/Util.java | 9 +++ .../java/dependencyView/Mappings.java | 66 ++++++++++--------- .../org/jetbrains/ether/MemberChangeTest.java | 8 +++ .../jetbrains/ether/MethodModifierTest.java | 5 +- 24 files changed, 169 insertions(+), 32 deletions(-) create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod.log create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedService.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedServiceClient.java rename java/java-tests/testData/compileServer/incremental/membersChange/{changeSAMInterfaceMethodToAbstract/Service.java.new => deleteSAMInterfaceMethod/src/Service.java} (64%) create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java.new create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/ServiceClient.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Util.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod.log create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedService.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedServiceClient.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java.new create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/ServiceClient.java create mode 100644 java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Util.java create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface.log create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedService.java create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedServiceClient.java create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java.new create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/ServiceClient.java create mode 100644 java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Util.java diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod.log new file mode 100644 index 000000000000..10f088dc0e01 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/DeleteSAMInterfaceMethod/Service.class +End of files +Compiling files: +src/Service.java +End of files +Cleaning output files: +out/production/DeleteSAMInterfaceMethod/DerivedServiceClient.class +out/production/DeleteSAMInterfaceMethod/ServiceClient.class +End of files +Compiling files: +src/DerivedServiceClient.java +src/ServiceClient.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedService.java b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedService.java new file mode 100644 index 000000000000..4ab428765279 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedService.java @@ -0,0 +1,2 @@ +interface DerivedService extends Service { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedServiceClient.java b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedServiceClient.java new file mode 100644 index 000000000000..3ec09d3aad1d --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/DerivedServiceClient.java @@ -0,0 +1,5 @@ +public class DerivedServiceClient { + public void execute() { + Util.invokeDerivedService(() -> System.out.println("Hello2")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/changeSAMInterfaceMethodToAbstract/Service.java.new b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java similarity index 64% rename from java/java-tests/testData/compileServer/incremental/membersChange/changeSAMInterfaceMethodToAbstract/Service.java.new rename to java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java index 7f5b0a10fa2c..97c113fd097a 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/changeSAMInterfaceMethodToAbstract/Service.java.new +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java @@ -1,4 +1,3 @@ interface Service { void foo(); - void bar(int a); } \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java.new b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java.new new file mode 100644 index 000000000000..c2a646df0bb5 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Service.java.new @@ -0,0 +1,2 @@ +interface Service { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/ServiceClient.java b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/ServiceClient.java new file mode 100644 index 000000000000..c7b2308c5145 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/ServiceClient.java @@ -0,0 +1,5 @@ +public class ServiceClient { + public void execute() { + Util.invokeService(() -> System.out.println("Hello")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Util.java b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Util.java new file mode 100644 index 000000000000..c948c1baf4a9 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteSAMInterfaceMethod/src/Util.java @@ -0,0 +1,7 @@ +public class Util { + public static void invokeService(Service s) { + } + + public static void invokeDerivedService(DerivedService s) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod.log b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod.log new file mode 100644 index 000000000000..99d1848e3253 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod.log @@ -0,0 +1,16 @@ +Cleaning output files: +out/production/RenameSAMInterfaceMethod/Service.class +End of files +Compiling files: +src/Service.java +End of files +Cleaning output files: +out/production/RenameSAMInterfaceMethod/DerivedService.class +out/production/RenameSAMInterfaceMethod/DerivedServiceClient.class +out/production/RenameSAMInterfaceMethod/ServiceClient.class +End of files +Compiling files: +src/DerivedService.java +src/DerivedServiceClient.java +src/ServiceClient.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedService.java b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedService.java new file mode 100644 index 000000000000..4ab428765279 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedService.java @@ -0,0 +1,2 @@ +interface DerivedService extends Service { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedServiceClient.java b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedServiceClient.java new file mode 100644 index 000000000000..3ec09d3aad1d --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/DerivedServiceClient.java @@ -0,0 +1,5 @@ +public class DerivedServiceClient { + public void execute() { + Util.invokeDerivedService(() -> System.out.println("Hello2")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java new file mode 100644 index 000000000000..97c113fd097a --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java @@ -0,0 +1,3 @@ +interface Service { + void foo(); +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java.new b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java.new new file mode 100644 index 000000000000..87f8f6fac0a3 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Service.java.new @@ -0,0 +1,3 @@ +interface Service { + void bar(); +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/ServiceClient.java b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/ServiceClient.java new file mode 100644 index 000000000000..c7b2308c5145 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/ServiceClient.java @@ -0,0 +1,5 @@ +public class ServiceClient { + public void execute() { + Util.invokeService(() -> System.out.println("Hello")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Util.java b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Util.java new file mode 100644 index 000000000000..c948c1baf4a9 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/membersChange/renameSAMInterfaceMethod/src/Util.java @@ -0,0 +1,7 @@ +public class Util { + public static void invokeService(Service s) { + } + + public static void invokeDerivedService(DerivedService s) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface.log b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface.log new file mode 100644 index 000000000000..dd90de60ba99 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/UnsetAbstractForSAMInterface/Service.class +End of files +Compiling files: +src/Service.java +End of files +Cleaning output files: +out/production/UnsetAbstractForSAMInterface/DerivedServiceClient.class +out/production/UnsetAbstractForSAMInterface/ServiceClient.class +End of files +Compiling files: +src/DerivedServiceClient.java +src/ServiceClient.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedService.java b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedService.java new file mode 100644 index 000000000000..4ab428765279 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedService.java @@ -0,0 +1,2 @@ +interface DerivedService extends Service { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedServiceClient.java b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedServiceClient.java new file mode 100644 index 000000000000..3ec09d3aad1d --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/DerivedServiceClient.java @@ -0,0 +1,5 @@ +public class DerivedServiceClient { + public void execute() { + Util.invokeDerivedService(() -> System.out.println("Hello2")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java new file mode 100644 index 000000000000..82a946c5d6ab --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java @@ -0,0 +1,5 @@ +interface Service { + void foo(); + + default void bar() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java.new b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java.new new file mode 100644 index 000000000000..d267748b8f6d --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Service.java.new @@ -0,0 +1,5 @@ +interface Service { + default void foo() {} + + default void bar() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/ServiceClient.java b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/ServiceClient.java new file mode 100644 index 000000000000..c7b2308c5145 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/ServiceClient.java @@ -0,0 +1,5 @@ +public class ServiceClient { + public void execute() { + Util.invokeService(() -> System.out.println("Hello")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Util.java b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Util.java new file mode 100644 index 000000000000..1311c7832dfc --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/methodModifiers/unsetAbstractForSAMInterface/src/Util.java @@ -0,0 +1,9 @@ +public class Util { + public static void invokeService(Service s) { + s.foo(); + } + + public static void invokeDerivedService(DerivedService s) { + s.foo(); + } +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java index fb8fb7272b5b..40ee94da763c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java @@ -552,8 +552,10 @@ public class Mappings { return false; } - boolean isSAMInterface(ClassRepr cls) { - if (!cls.isInterface()) { + // test if a ClassRepr is a SAM interface + boolean isLambdaTarget(int name) { + final ClassRepr cls = classReprByName(name); + if (cls == null || !cls.isInterface()) { return false; } int amFound = 0; @@ -847,6 +849,18 @@ public class Mappings { }.perform(moduleName); } + void affectLambdaInstantiations(Differential.DiffState state, final int className) { + getAllSubclasses(className).forEach(name -> { + if (isLambdaTarget(name)) { + debug("The interface could be not a SAM interface anymore or lambda target method name has changed => affecting lambda instantiations for ", name); + if (state.myAffectedUsages.add(UsageRepr.createClassNewUsage(myContext, name))) { + appendDependents(name, state.myDependants); + } + } + return true; + }); + } + public class FileFilterConstraint implements UsageConstraint { @NotNull private final DependentFilesFilter myFilter; @@ -1201,8 +1215,8 @@ public class Mappings { if (it.isInterface()) { for (final MethodRepr m : added) { if (!m.isPrivate() && m.isAbstract()) { - debug("Method: ", m.name); - affectLambdaInstantiations(state, it.name); + debug("Added non-private abstract method: ", m.name); + myPresent.affectLambdaInstantiations(state, it.name); break; } } @@ -1310,20 +1324,6 @@ public class Mappings { debug("End of added methods processing"); } - private void affectLambdaInstantiations(DiffState state, final int className) { - assert myPresent != null; - - getAllSubclasses(className).forEach(name -> { - @SuppressWarnings("ConstantConditions") - final ClassRepr cr = myPresent.classReprByName(name); - if (cr != null && myPresent.isSAMInterface(cr)) { - debug("Abstract method added to a SAM interface => affecting lambda instantiations for ", name); - state.myAffectedUsages.add(UsageRepr.createClassNewUsage(myContext, name)); - } - return true; - }); - } - private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { final Collection removed = diff.methods().removed(); if (removed.isEmpty()) { @@ -1445,9 +1445,20 @@ public class Mappings { } debug("Processing changed methods:"); + assert myPresent != null; assert myFuture != null; assert myAffectedFiles != null; + if (it.isInterface()) { + for (final Pair mr : changed) { + if ((mr.second.removedModifiers() & Opcodes.ACC_ABSTRACT) != 0) { + debug("Method became non-abstract: ", mr.first.name); + myPresent.affectLambdaInstantiations(state, it.name); + break; + } + } + } + for (final Pair mr : changed) { final MethodRepr m = mr.first; final MethodRepr.Diff d = mr.second; @@ -1550,7 +1561,7 @@ public class Mappings { debug("Added final, public or abstract specifier --- affecting subclasses"); myFuture.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false, myCompiledFiles, null); if (it.isInterface() && (d.addedModifiers() & Opcodes.ACC_ABSTRACT) != 0) { - affectLambdaInstantiations(state, it.name); + myPresent.affectLambdaInstantiations(state, it.name); } } @@ -3036,18 +3047,13 @@ public class Mappings { } } - private static boolean addAll(final TIntHashSet whereToAdd, TIntHashSet whatToAdd) { - if (whatToAdd.isEmpty()) { - return false; + private static void addAll(final TIntHashSet whereToAdd, TIntHashSet whatToAdd) { + if (!whatToAdd.isEmpty()) { + whatToAdd.forEach(value -> { + whereToAdd.add(value); + return true; + }); } - final Ref changed = new Ref<>(Boolean.FALSE); - whatToAdd.forEach(value -> { - if (whereToAdd.add(value)) { - changed.set(Boolean.TRUE); - } - return true; - }); - return changed.get(); } private static void addAllKeys(final TIntHashSet whereToAdd, final IntIntMultiMaplet maplet) { diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java index 7d3886360c5e..de599ee47f74 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java @@ -31,6 +31,14 @@ public class MemberChangeTest extends IncrementalTestCase { doTest(); } + public void testDeleteSAMInterfaceMethod() { + doTest(); + } + + public void testRenameSAMInterfaceMethod() { + doTest(); + } + public void testAddSAMInterfaceAbstractMethod() { doTest(); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/MethodModifierTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/MethodModifierTest.java index e7017cd31b77..d268ea77f9a0 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/MethodModifierTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/MethodModifierTest.java @@ -51,11 +51,14 @@ public class MethodModifierTest extends IncrementalTestCase { doTest(); } - public void testUnsetFinal() { doTest(); } + public void testUnsetAbstractForSAMInterface() { + doTest(); + } + public void testUnsetStatic() { doTest(); }