JPS: generalize support for java17 sealed classes; supported case when permitted list gets reduced

GitOrigin-RevId: 9be5ef80b3dd00509cbe9e5dce2f9f00c4b6557a
This commit is contained in:
Eugene Zhuravlev
2024-07-05 17:52:09 +00:00
committed by intellij-monorepo-bot
parent f929629c64
commit 7ffc3f8f8b
14 changed files with 73 additions and 11 deletions
@@ -7,10 +7,8 @@ src/A.java
src/B.java
End of files
Cleaning output files:
out/production/BecameSealed/C.class
out/production/BecameSealed/D.class
End of files
Compiling files:
src/C.java
src/D.java
End of files
@@ -0,0 +1,12 @@
Cleaning output files:
out/production/DeleteSealedPermission/B.class
End of files
Compiling files:
src/B.java
End of files
Cleaning output files:
out/production/DeleteSealedPermission/A3.class
End of files
Compiling files:
src/A3.java
End of files
@@ -0,0 +1,2 @@
public final class A1 extends B {
}
@@ -0,0 +1,2 @@
public final class A2 extends B {
}
@@ -0,0 +1,2 @@
public final class A3 extends B {
}
@@ -0,0 +1,3 @@
public sealed class B permits A1, A2, A3 {
void foo(A3 param) {}
}
@@ -0,0 +1,3 @@
public sealed class B permits A1, A2 {
void foo(A3 param) {}
}
@@ -0,0 +1,27 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.jps.dependency.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.dependency.GraphDataInput;
import java.io.IOException;
public final class ClassPermitsUsage extends ClassUsage {
public ClassPermitsUsage(@NotNull String className) {
super(className);
}
public ClassPermitsUsage(@NotNull JvmNodeReferenceID clsId) {
super(clsId);
}
public ClassPermitsUsage(GraphDataInput in) throws IOException {
super(in);
}
@Override
public int hashCode() {
return super.hashCode() + 4;
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.jps.dependency.java;
import org.jetbrains.annotations.NotNull;
@@ -24,4 +24,8 @@ public class ClassUsage extends JvmElementUsage {
return getElementOwner().getNodeName();
}
@Override
public int hashCode() {
return super.hashCode() + 10;
}
}
@@ -99,7 +99,7 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp
JvmClass.Diff classDiff = change.getDiff();
debug("Processing changed class ", changedClass.getName());
if (classDiff.superClassChanged() || classDiff.signatureChanged() || classDiff.becameSealed() || !classDiff.interfaces().unchanged()) {
if (classDiff.superClassChanged() || classDiff.signatureChanged() || !classDiff.interfaces().unchanged()) {
boolean extendsChanged = classDiff.superClassChanged() && !classDiff.extendsAdded();
boolean affectUsages = classDiff.signatureChanged() || extendsChanged || !isEmpty(classDiff.interfaces().removed());
affectSubclasses(context, future, change.getNow().getReferenceID(), affectUsages);
@@ -125,6 +125,14 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp
}
}
}
else if (change.getNow().isSealed()) {
ReferenceID fromClass = change.getNow().getReferenceID();
Set<ReferenceID> permitted = collect(map(filter(change.getNow().getUsages(), u -> u instanceof ClassPermitsUsage), Usage::getElementOwner), new SmartHashSet<>());
debug("Affecting non-permitted subclasses of a sealed class: ", fromClass);
for (ReferenceID cl : filter(future.allSubclasses(fromClass), c -> !permitted.contains(c))) {
affectNodeSources(context, cl, "Affecting source file of a non-permitted subclass: ", future);
}
}
JVMFlags addedFlags = classDiff.getAddedFlags();
@@ -212,10 +212,6 @@ public final class JvmClass extends JVMClassNode<JvmClass, JvmClass.Diff> {
return (currentSuper.isEmpty() || OBJECT_CLASS_NAME.equals(currentSuper)) && superClassChanged();
}
public boolean becameSealed() {
return getAddedFlags().isSealed();
}
public boolean outerClassChanged() {
return !Objects.equals(myPast.getOuterFqName(), getOuterFqName());
}
@@ -911,6 +911,7 @@ public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuild
public void visitPermittedSubclass(String permittedSubclass) {
mySealedClassFlag.set(true);
addUsage(new ClassUsage(permittedSubclass));
addUsage(new ClassPermitsUsage(permittedSubclass));
}
private class BaseSignatureVisitor extends SignatureVisitor {
@@ -49,7 +49,7 @@ public class ClassModifierTest extends IncrementalTestCase {
}
public void testBecameSealed() {
doTest();
doTest().assertFailed();
}
public void testChangeInnerClassModifiers() {
@@ -13,7 +13,7 @@ import org.jetbrains.jps.model.module.JpsModule;
import java.util.Set;
public class CommonTest extends IncrementalTestCase {
private static final Set<String> GRAPH_ONLY_TESTS = Set.of("addClassHidingImportedClass", "addClassHidingImportedClass2", "deletePermittedClass");
private static final Set<String> GRAPH_ONLY_TESTS = Set.of("addClassHidingImportedClass", "addClassHidingImportedClass2", "deletePermittedClass", "deleteSealedPermission");
public CommonTest() {
super("common");
@@ -107,7 +107,11 @@ public class CommonTest extends IncrementalTestCase {
}
public void testDeletePermittedClass() {
doTest();
doTest().assertFailed();
}
public void testDeleteSealedPermission() {
doTest().assertFailed();
}
public void testDeleteInnerClass() {