java make: recompile method usages of deleted method when it is replaced with equivalent bridge method (IDEA-185494)

This commit is contained in:
Eugene Zhuravlev
2018-01-26 16:05:43 +01:00
parent e67f0a842f
commit 3d4b4c53b2
9 changed files with 68 additions and 5 deletions
@@ -0,0 +1,12 @@
Cleaning output files:
out/production/ReplaceMethodWithBridge/stubs/StubBase.class
End of files
Compiling files:
src/stubs/StubBase.java
End of files
Cleaning output files:
out/production/ReplaceMethodWithBridge/ppp/Util.class
End of files
Compiling files:
src/ppp/Util.java
End of files
@@ -0,0 +1,11 @@
package ppp;
import stubs.StubBase;
import stubs.StubElement;
public class Util {
public void calcParent(StubBase stub) { // using raw type 'StubBase', this is important!
final StubElement parent = stub.getParentStub();
}
}
@@ -0,0 +1,9 @@
package stubs;
public class ObjectStubBase<T extends Stub> implements Stub {
protected T myParent;
public T getParentStub() {
return myParent;
}
}
@@ -0,0 +1,5 @@
package stubs;
public interface Stub {
Stub getParentStub();
}
@@ -0,0 +1,7 @@
package stubs;
public class StubBase<T> extends ObjectStubBase<StubElement> implements StubElement{
public StubElement getParentStub() {
return myParent;
}
}
@@ -0,0 +1,4 @@
package stubs;
public class StubBase<T> extends ObjectStubBase<StubElement> implements StubElement{
}
@@ -0,0 +1,5 @@
package stubs;
public interface StubElement extends Stub{
StubElement getParentStub();
}
@@ -327,7 +327,7 @@ public class Mappings {
final MethodRepr memberMethod = (MethodRepr)member;
return memberMethod.name == m.name && Arrays.equals(memberMethod.myArgumentTypes, m.myArgumentTypes);
}
return member.name == m.name;
return false;
}
}, className);
}
@@ -1482,11 +1482,17 @@ public class Mappings {
}
}
else if ((d.base() & Difference.ACCESS) != 0) {
if ((d.addedModifiers() & Opcodes.ACC_STATIC) != 0 ||
(d.removedModifiers() & Opcodes.ACC_STATIC) != 0 ||
(d.addedModifiers() & Opcodes.ACC_PRIVATE) != 0) {
if ((d.addedModifiers() & (Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE)) != 0 ||
(d.removedModifiers() & Opcodes.ACC_STATIC) != 0) {
// When synthetic or bridge flags are added, this effectively means that explicitly written in the code
// method with the same signature and return type has been removed and a bridge method has been generated instead.
// In some cases (e.g. using raw types) the presence of such synthetic methods in the bytecode is ignored by the compiler
// so that the code that called such method via raw type reference might not compile anymore => to be on the safe side
// we should recompile all places where the method was used
if (!affected) {
debug("Added static or private specifier or removed static specifier --- affecting method usages");
debug("Added {static | private | synthetic | bridge} specifier or removed static specifier --- affecting method usages");
myFuture.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
affected = true;
@@ -210,4 +210,8 @@ public class MemberChangeTest extends IncrementalTestCase {
public void testAddVarargMethod() {
doTest();
}
public void testReplaceMethodWithBridge() {
doTest();
}
}