diff --git a/jps/jps-builders/resources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker b/jps/jps-builders/resources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker deleted file mode 100644 index d71c78f81851..000000000000 --- a/jps/jps-builders/resources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -org.jetbrains.jps.dependency.kotlin.NullabilityAnnotationChangesTracker \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/GeneralJvmDifferentiateStrategy.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/GeneralJvmDifferentiateStrategy.java index 0cc84a64de82..6e0fe26e4ecb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/GeneralJvmDifferentiateStrategy.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/GeneralJvmDifferentiateStrategy.java @@ -15,7 +15,7 @@ public final class GeneralJvmDifferentiateStrategy implements DifferentiateStrat private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.dependency.java.GeneralJvmDifferentiateStrategy"); private static final Iterable ourExtensions = collect( - ServiceLoader.load(JvmDifferentiateStrategy.class, GeneralJvmDifferentiateStrategy.class.getClassLoader()), + ServiceLoader.load(JvmDifferentiateStrategy.class), new SmartList<>() ); diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JavaDifferentiateStrategy.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JavaDifferentiateStrategy.java index b9760f9e3cb4..7c4b0a2932da 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JavaDifferentiateStrategy.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JavaDifferentiateStrategy.java @@ -17,11 +17,6 @@ import static org.jetbrains.jps.javac.Iterators.*; public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImpl { - private static final Iterable ourAnnotationChangeTrackers = collect( - ServiceLoader.load(AnnotationChangesTracker.class, JavaDifferentiateStrategy.class.getClassLoader()), - new SmartList<>() - ); - @Override public boolean isIncremental(DifferentiateContext context, Node affectedNode) { if (affectedNode instanceof JvmClass && ((JvmClass)affectedNode).getFlags().isGenerated()) { @@ -295,32 +290,7 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp } } - Difference.Specifier annotationsDiff = classDiff.annotations(); - if (!annotationsDiff.unchanged()) { - EnumSet toRecompile = EnumSet.noneOf(AnnotationChangesTracker.Recompile.class); - for (AnnotationChangesTracker tracker : ourAnnotationChangeTrackers) { - if (toRecompile.containsAll(AnnotationChangesTracker.RECOMPILE_ALL)) { - break; - } - Set result = tracker.classAnnotationsChanged(changedClass, annotationsDiff); - if (result.contains(AnnotationChangesTracker.Recompile.USAGES)) { - debug("Extension ", tracker.getClass().getName(), " requested class usages recompilation because of changes in annotations list --- adding class usage to affected usages"); - } - if (result.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - debug("Extension ", tracker.getClass().getName(), " requested subclasses recompilation because of changes in annotations list --- adding subclasses to affected usages"); - } - toRecompile.addAll(result); - } - boolean affectUsages = toRecompile.contains(AnnotationChangesTracker.Recompile.USAGES); - if (affectUsages) { - context.affectUsage(new ClassUsage(changedClass.getReferenceID())); - } - if (toRecompile.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - affectSubclasses(context, future, changedClass.getReferenceID(), affectUsages); - } - } - - return true; + return super.processChangedClass(context, change, future, present); } @Override @@ -425,38 +395,6 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp } } } - - Difference.Specifier annotationsDiff = diff.annotations(); - Difference.Specifier paramAnnotationsDiff = diff.paramAnnotations(); - if (!annotationsDiff.unchanged() || !paramAnnotationsDiff.unchanged()) { - EnumSet toRecompile = EnumSet.noneOf(AnnotationChangesTracker.Recompile.class); - for (AnnotationChangesTracker tracker : ourAnnotationChangeTrackers) { - if (toRecompile.containsAll(AnnotationChangesTracker.RECOMPILE_ALL)) { - break; - } - Set result = tracker.methodAnnotationsChanged(changedMethod, annotationsDiff, paramAnnotationsDiff); - if (result.contains(AnnotationChangesTracker.Recompile.USAGES)) { - debug("Extension ", tracker.getClass().getName(), " requested recompilation because of changes in annotations list --- affecting method usages"); - } - if (result.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - debug("Extension ", tracker.getClass().getName(), " requested recompilation because of changes in method annotations or method parameter annotations list --- affecting subclasses"); - } - toRecompile.addAll(result); - } - if (toRecompile.contains(AnnotationChangesTracker.Recompile.USAGES)) { - affectMemberUsages(context, changedClass.getReferenceID(), changedMethod, propagated); - if (changedMethod.isAbstract() || toRecompile.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - for (Pair pair : recurse(Pair.create(changedClass, changedMethod), p -> p.second.isOverridable()? future.getOverridingMethods(p.first, p.second, p.second::isSameByJavaRules) : Collections.emptyList(), false)) { - JvmNodeReferenceID clsId = pair.first.getReferenceID(); - JvmMethod meth = pair.getSecond(); - affectMemberUsages(context, clsId, meth, future.collectSubclassesWithoutMethod(clsId, meth)); - } - } - } - if (toRecompile.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - affectSubclasses(context, future, changedClass.getReferenceID(), false); - } - } } Iterable> moreAccessible = collect(filter(methodChanges, ch -> ch.getDiff().accessExpanded()), new SmartList<>()); @@ -493,7 +431,7 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp } debug("End of changed methods processing"); - return true; + return super.processChangedMethods(context, clsChange, methodChanges, future, present); } @Override @@ -843,31 +781,7 @@ public final class JavaDifferentiateStrategy extends JvmDifferentiateStrategyImp } } - Difference.Specifier annotationsDiff = diff.annotations(); - if (!annotationsDiff.unchanged()) { - EnumSet toRecompile = EnumSet.noneOf(AnnotationChangesTracker.Recompile.class); - for (AnnotationChangesTracker tracker : ourAnnotationChangeTrackers) { - if (toRecompile.containsAll(AnnotationChangesTracker.RECOMPILE_ALL)) { - break; - } - Set result = tracker.fieldAnnotationsChanged(changedField, annotationsDiff); - if (result.contains(AnnotationChangesTracker.Recompile.USAGES)) { - debug("Extension ", tracker.getClass().getName(), " requested recompilation because of changes in annotations list --- affecting field usages"); - } - if (result.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - debug("Extension ", tracker.getClass().getName(), " requested recompilation because of changes in field annotations list --- affecting subclasses"); - } - toRecompile.addAll(result); - } - if (toRecompile.contains(AnnotationChangesTracker.Recompile.USAGES)) { - affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated); - } - if (toRecompile.contains(AnnotationChangesTracker.Recompile.SUBCLASSES)) { - affectSubclasses(context, future, changedClass.getReferenceID(), false); - } - } - - return true; + return super.processChangedField(context, clsChange, fieldChange, future, present); } @Override diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmClassNodeBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmClassNodeBuilder.java index a0f9dc39fbec..a38cd21e15d5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmClassNodeBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmClassNodeBuilder.java @@ -32,10 +32,7 @@ import java.util.function.Supplier; public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuilder { - private static final Iterable ourAnnotationChangeTrackers = Iterators.collect( - ServiceLoader.load(AnnotationChangesTracker.class, JvmClassNodeBuilder.class.getClassLoader()), - new SmartList<>() - ); + private static final Iterable ourDifferentiateStrategies = Iterators.collect(ServiceLoader.load(JvmDifferentiateStrategy.class), new SmartList<>()); private static final Logger LOG = Logger.getInstance(JvmClassNodeBuilder.class); public static final String LAMBDA_FACTORY_CLASS = "java/lang/invoke/LambdaMetafactory"; @@ -969,8 +966,8 @@ public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuild } private static boolean isAnnotationTracked(TypeRepr.ClassType annotationType) { - for (AnnotationChangesTracker tracker : ourAnnotationChangeTrackers) { - if (tracker.isAnnotationTracked(annotationType)) { + for (JvmDifferentiateStrategy strategy : ourDifferentiateStrategies) { + if (strategy.isAnnotationTracked(annotationType)) { return true; } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategy.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategy.java index 9aff2f3c6f18..b44e345892f4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategy.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategy.java @@ -1,6 +1,7 @@ // Copyright 2000-2025 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.DifferentiateContext; import org.jetbrains.jps.dependency.Node; import org.jetbrains.jps.dependency.diff.Difference; @@ -11,6 +12,15 @@ import org.jetbrains.jps.dependency.diff.Difference; */ public interface JvmDifferentiateStrategy { + /** + * @param annotationType the annotation class type to check. DependencyGraph will parse and store only those annotations, + * if there exists at least one registered AnnotationTracker that can track annotations of this type + * @return true if this AnnotationTracker can track annotations of this type, false otherwise. + */ + default boolean isAnnotationTracked(@NotNull TypeRepr.ClassType annotationType) { + return false; + } + default boolean isIncremental(DifferentiateContext context, Node affectedNode) { return true; } @@ -46,39 +56,47 @@ public interface JvmDifferentiateStrategy { if (!processChangedClass(context, change, future, present)) { return false; } - - JvmClass changedClass = change.getPast(); - - Difference.Specifier methodsDiff = change.getDiff().methods(); - if (!methodsDiff.unchanged()) { - if (!processRemovedMethods(context, change, methodsDiff.removed(), future, present)) { - return false; - } - if (!processAddedMethods(context, change, methodsDiff.added(), future, present)) { - return false; - } - if (!processChangedMethods(context, change, methodsDiff.changed(), future, present)) { - return false; - } - } - - Difference.Specifier fieldsDiff = change.getDiff().fields(); - if (!fieldsDiff.unchanged()) { - if (!processRemovedFields(context, change, fieldsDiff.removed(), future, present)) { - return false; - } - if (!processAddedFields(context, change, fieldsDiff.added(), future, present)) { - return false; - } - if (!processChangedFields(context, change, fieldsDiff.changed(), future, present)) { - return false; - } - } } return true; } default boolean processChangedClass(DifferentiateContext context, Difference.Change change, Utils future, Utils present) { + Difference.Specifier methodsDiff = change.getDiff().methods(); + if (!methodsDiff.unchanged()) { + if (!processRemovedMethods(context, change, methodsDiff.removed(), future, present)) { + return false; + } + if (!processAddedMethods(context, change, methodsDiff.added(), future, present)) { + return false; + } + if (!processChangedMethods(context, change, methodsDiff.changed(), future, present)) { + return false; + } + } + + Difference.Specifier fieldsDiff = change.getDiff().fields(); + if (!fieldsDiff.unchanged()) { + if (!processRemovedFields(context, change, fieldsDiff.removed(), future, present)) { + return false; + } + if (!processAddedFields(context, change, fieldsDiff.added(), future, present)) { + return false; + } + if (!processChangedFields(context, change, fieldsDiff.changed(), future, present)) { + return false; + } + } + + Difference.Specifier annotationDiff = change.getDiff().annotations(); + if (!annotationDiff.unchanged()) { + if (!processClassAnnotations(context, change, annotationDiff, future, present)) { + return false; + } + } + return true; + } + + default boolean processClassAnnotations(DifferentiateContext context, Difference.Change change, Difference.Specifier annotationDiff, Utils future, Utils present) { return true; } @@ -118,6 +136,18 @@ public interface JvmDifferentiateStrategy { } default boolean processChangedMethod(DifferentiateContext context, Difference.Change clsChange, Difference.Change methodChange, Utils future, Utils present) { + JvmMethod.Diff diff = methodChange.getDiff(); + Difference.Specifier annotationsDiff = diff.annotations(); + Difference.Specifier paramAnnotationsDiff = diff.paramAnnotations(); + if (!annotationsDiff.unchanged() || !paramAnnotationsDiff.unchanged()) { + if (!processMethodAnnotations(context, clsChange, methodChange, annotationsDiff, paramAnnotationsDiff, future, present)) { + return false; + } + } + return true; + } + + default boolean processMethodAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change methodChange, Difference.Specifier annotationsDiff, Difference.Specifier paramAnnotationsDiff, Utils future, Utils present){ return true; } @@ -157,6 +187,16 @@ public interface JvmDifferentiateStrategy { } default boolean processChangedField(DifferentiateContext context, Difference.Change clsChange, Difference.Change fieldChange, Utils future, Utils present) { + Difference.Specifier annotationDiff = fieldChange.getDiff().annotations(); + if (!annotationDiff.unchanged()) { + if (!processFieldAnnotations(context, clsChange, fieldChange, annotationDiff, future, present)) { + return false; + } + } + return true; + } + + default boolean processFieldAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change fieldChange, Difference.Specifier annotationDiff, Utils future, Utils present) { return true; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategyImpl.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategyImpl.java index 4566c7b6297d..20701414f256 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategyImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/java/JvmDifferentiateStrategyImpl.java @@ -1,10 +1,14 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 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 com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.dependency.*; +import org.jetbrains.jps.dependency.diff.Difference; +import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -12,11 +16,81 @@ import java.util.function.Predicate; import static org.jetbrains.jps.javac.Iterators.*; /** - * This class provides some common utilities for strategy implementations + * This class provides implementation common to all jvm strategies */ -public abstract class JvmDifferentiateStrategyImpl implements JvmDifferentiateStrategy { +public abstract class JvmDifferentiateStrategyImpl implements JvmDifferentiateStrategy{ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.dependency.java.JvmDifferentiateStrategyImpl"); + protected enum AnnotationAffectionKind { + added, removed, changed + } + protected final > boolean isAffectedByAnnotations( + Proto element, Difference.Specifier annotationsDiff, Set affectionKinds, Predicate annotationSelector + ) { + return !element.isPrivate() && find(getAffectedAnnotations(annotationsDiff, affectionKinds), annotationSelector::test) != null; + } + + protected final > Iterable getAffectedAnnotations( + Difference.Specifier annotationsDiff, Set affectionKinds + ) { + Iterable added = affectionKinds.contains(AnnotationAffectionKind.added)? annotationsDiff.added() : List.of(); + Iterable removed = affectionKinds.contains(AnnotationAffectionKind.removed)? annotationsDiff.removed() : List.of(); + Iterable changed = affectionKinds.contains(AnnotationAffectionKind.changed)? map(annotationsDiff.changed(), Difference.Change::getPast) : List.of(); + return map(flat(List.of(added, removed, changed)), AnnotationInstance::getAnnotationClass); + } + + protected enum AnnotationAffectionScope { + /** + * If present in the returned result set, the usages of the annotated program element (class, field, method) will be affected. + * it means that files where this program element is references, will be marked for recompilation + */ + usages, + + /** + * If present in the returned result set, the subclasses of the annotated class will be affected. + * If returned for an annotated field/method, the subclasses of the class containing this field/method will be affected. + */ + subclasses + } + + protected void affectClassAnnotationUsages(DifferentiateContext context, Set toRecompile, Difference.Change change, Utils future, Utils present) { + JvmClass changedClass = change.getPast(); + boolean affectUsages = toRecompile.contains(AnnotationAffectionScope.usages); + if (affectUsages) { + context.affectUsage(new ClassUsage(changedClass.getReferenceID())); + } + if (toRecompile.contains(AnnotationAffectionScope.subclasses)) { + affectSubclasses(context, future, changedClass.getReferenceID(), affectUsages); + } + } + + protected void affectFieldAnnotationUsages(DifferentiateContext context, Set toRecompile, Difference.Change clsChange, JvmField changedField, Utils future, Utils present) { + JvmClass changedClass = clsChange.getPast(); + if (toRecompile.contains(AnnotationAffectionScope.usages)) { + affectMemberUsages(context, changedClass.getReferenceID(), changedField, future.collectSubclassesWithoutField(changedClass.getReferenceID(), changedField)); + } + if (toRecompile.contains(AnnotationAffectionScope.subclasses)) { + affectSubclasses(context, future, changedClass.getReferenceID(), false); + } + } + + protected void affectMethodAnnotationUsages(DifferentiateContext context, Set toRecompile, Difference.Change clsChange, JvmMethod changedMethod, Utils future, Utils present) { + JvmClass changedClass = clsChange.getPast(); + if (toRecompile.contains(AnnotationAffectionScope.usages)) { + affectMemberUsages(context, changedClass.getReferenceID(), changedMethod, future.collectSubclassesWithoutMethod(changedClass.getReferenceID(), changedMethod)); + if (changedMethod.isAbstract() || toRecompile.contains(AnnotationAffectionScope.subclasses)) { + for (Pair pair : recurse(Pair.create(changedClass, changedMethod), p -> p.second.isOverridable()? future.getOverridingMethods(p.first, p.second, p.second::isSameByJavaRules) : Collections.emptyList(), false)) { + JvmNodeReferenceID clsId = pair.first.getReferenceID(); + JvmMethod meth = pair.getSecond(); + affectMemberUsages(context, clsId, meth, future.collectSubclassesWithoutMethod(clsId, meth)); + } + } + } + if (toRecompile.contains(AnnotationAffectionScope.subclasses)) { + affectSubclasses(context, future, changedClass.getReferenceID(), false); + } + } + protected void affectMemberUsages(DifferentiateContext context, JvmNodeReferenceID clsId, ProtoMember member, Iterable propagated) { affectMemberUsages(context, clsId, member, propagated, null); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/KotlinJvmDifferentiateStrategy.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/KotlinJvmDifferentiateStrategy.java index 02a3ba1f47e7..833ee29ba5ef 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/KotlinJvmDifferentiateStrategy.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/KotlinJvmDifferentiateStrategy.java @@ -23,6 +23,82 @@ import static org.jetbrains.jps.javac.Iterators.*; */ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrategyImpl { private static final TypeRepr.ClassType JVM_OVERLOADS_ANNOTATION = new TypeRepr.ClassType("kotlin/jvm/JvmOverloads"); + private static final Set ourDeprecationAnnotations = Set.of( + new TypeRepr.ClassType("kotlin/Deprecated"), + new TypeRepr.ClassType("kotlin/DeprecatedSinceKotlin") + ); + private static final Set ourNullabilityAnnotations = Set.of( + "org/jetbrains/annotations/Nullable", + "androidx/annotation/Nullable", + "android/support/annotation/Nullable", + "android/annotation/Nullable", + "com/android/annotations/Nullable", + "org/eclipse/jdt/annotation/Nullable", + "org/checkerframework/checker/nullness/qual/Nullable", + "javax/annotation/Nullable", + "javax/annotation/CheckForNull", + "edu/umd/cs/findbugs/annotations/CheckForNull", + "edu/umd/cs/findbugs/annotations/Nullable", + "edu/umd/cs/findbugs/annotations/PossiblyNull", + "io/reactivex/annotations/Nullable", + "io/reactivex/rxjava3/annotations/Nullable", + + "javax/annotation/Nonnull", + "org/jetbrains/annotations/NotNull", + "edu/umd/cs/findbugs/annotations/NonNull", + "androidx/annotation/NonNull", + "android/support/annotation/NonNull", + "android/annotation/NonNull", + "com/android/annotations/NonNull", + "org/eclipse/jdt/annotation/NonNull", + "org/checkerframework/checker/nullness/qual/NonNull", + "lombok/NonNull", + "io/reactivex/annotations/NonNull", + "io/reactivex/rxjava3/annotations/NonNull" + ); + + @Override + public boolean isAnnotationTracked(TypeRepr.@NotNull ClassType annotationType) { + return ourNullabilityAnnotations.contains(annotationType.getJvmName()) || ourDeprecationAnnotations.contains(annotationType); + } + + @Override + public boolean processClassAnnotations(DifferentiateContext context, Difference.Change change, Difference.Specifier annotationDiff, Utils future, Utils present) { + JvmClass changedClass = change.getPast(); + if (isAffectedByAnnotations(changedClass, annotationDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.changed), ourDeprecationAnnotations::contains)) { + debug("Deprecation annotations changed for ", changedClass.getName(), " --- affecting class usages"); + affectClassAnnotationUsages(context, EnumSet.of(AnnotationAffectionScope.usages), change, future, present); + } + return super.processClassAnnotations(context, change, annotationDiff, future, present); + } + + @Override + public boolean processFieldAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change fieldChange, Difference.Specifier annotationDiff, Utils future, Utils present) { + JvmField changedField = fieldChange.getPast(); + if ( + isAffectedByAnnotations(changedField, annotationDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed), t -> ourNullabilityAnnotations.contains(t.getJvmName())) || + isAffectedByAnnotations(changedField, annotationDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.changed), ourDeprecationAnnotations::contains) + ) { + debug("Nullability or Deprecation annotations changed for field ", changedField, " --- affecting field usages"); + affectFieldAnnotationUsages(context, EnumSet.of(AnnotationAffectionScope.usages), clsChange, changedField, future, present); + } + return super.processFieldAnnotations(context, clsChange, fieldChange, annotationDiff, future, present); + } + + @Override + public boolean processMethodAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change methodChange, Difference.Specifier annotationsDiff, Difference.Specifier paramAnnotationsDiff, Utils future, Utils present) { + JvmMethod changedMethod = methodChange.getPast(); + if ( + isAffectedByAnnotations(changedMethod, annotationsDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed), t -> ourNullabilityAnnotations.contains(t.getJvmName())) || + isAffectedByAnnotations(changedMethod, paramAnnotationsDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed), t -> ourNullabilityAnnotations.contains(t.getJvmName())) || + isAffectedByAnnotations(changedMethod, annotationsDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.changed), ourDeprecationAnnotations::contains) + ) { + debug("Nullability annotations/parameter annotations or Deprecation annotations changed for method ", changedMethod, " --- affecting method usages"); + EnumSet affection = changedMethod.isFinal()? EnumSet.of(AnnotationAffectionScope.usages) : EnumSet.of(AnnotationAffectionScope.usages, AnnotationAffectionScope.subclasses); + affectMethodAnnotationUsages(context, affection, clsChange, changedMethod, future, present); + } + return super.processMethodAnnotations(context, clsChange, methodChange, annotationsDiff, paramAnnotationsDiff, future, present); + } @Override public boolean processAddedClasses(DifferentiateContext context, Iterable addedClasses, Utils future, Utils present) { @@ -351,7 +427,7 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate } - return true; + return super.processChangedClass(context, change, future, present); } @Override @@ -384,7 +460,7 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate debug("Function was inlineable, or has become inlineable or a body of inline method has changed; affecting method usages ", name); affectMemberLookupUsages(context, changedClass, name, future); } - return true; + return super.processChangedMethod(context, clsChange, methodChange, future, present); } @Override @@ -422,7 +498,7 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate } } - return true; + return super.processChangedField(context, clsChange, fieldChange, future, present); } @Override @@ -474,6 +550,23 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate return true; } + @Override + protected void affectMethodAnnotationUsages(DifferentiateContext context, Set toRecompile, Difference.Change clsChange, JvmMethod changedMethod, Utils future, Utils present) { + super.affectMethodAnnotationUsages(context, toRecompile, clsChange, changedMethod, future, present); + if (toRecompile.contains(AnnotationAffectionScope.usages)) { + JvmClass changedClass = clsChange.getPast(); + affectMemberLookupUsages(context, changedClass, KJvmUtils.getMethodKotlinName(changedClass, changedMethod), present); + } + } + + @Override + protected void affectClassAnnotationUsages(DifferentiateContext context, Set toRecompile, Difference.Change change, Utils future, Utils present) { + super.affectClassAnnotationUsages(context, toRecompile, change, future, present); + if (toRecompile.contains(AnnotationAffectionScope.usages)) { + affectClassLookupUsages(context, change.getPast()); + } + } + private void affectConflictingCallExpressions(DifferentiateContext context, JvmClass cls, JvmMethod clsMethod, Utils utils, @Nullable Predicate> constraint) { if (clsMethod.isPrivate() || clsMethod.isStaticInitializer()) { return; @@ -626,7 +719,7 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate private static Iterable withJvmOverloads(JvmClass cls, JvmMethod method) { return unique(flat( asIterable(method), - filter(cls.getMethods(), m -> Objects.equals(m.getName(), method.getName()) && Objects.equals(m.getType(), method.getType()) && find(m.getAnnotations(), a -> JVM_OVERLOADS_ANNOTATION.equals(a.getAnnotationClass())) != null) + filter(cls.getMethods(), m -> Objects.equals(m.getName(), method.getName()) && Objects.equals(m.getType(), method.getType()) && contains(map(m.getAnnotations(), AnnotationInstance::getAnnotationClass), JVM_OVERLOADS_ANNOTATION)) )); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/NullabilityAnnotationChangesTracker.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/NullabilityAnnotationChangesTracker.java deleted file mode 100644 index 1843dea21da6..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/kotlin/NullabilityAnnotationChangesTracker.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package org.jetbrains.jps.dependency.kotlin; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.dependency.diff.Difference; -import org.jetbrains.jps.dependency.java.*; - -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import static org.jetbrains.jps.javac.Iterators.*; - -public final class NullabilityAnnotationChangesTracker implements AnnotationChangesTracker { - private static final Set ourTrackedAnnotations = Set.of( - "org/jetbrains/annotations/Nullable", - "androidx/annotation/Nullable", - "android/support/annotation/Nullable", - "android/annotation/Nullable", - "com/android/annotations/Nullable", - "org/eclipse/jdt/annotation/Nullable", - "org/checkerframework/checker/nullness/qual/Nullable", - "javax/annotation/Nullable", - "javax/annotation/CheckForNull", - "edu/umd/cs/findbugs/annotations/CheckForNull", - "edu/umd/cs/findbugs/annotations/Nullable", - "edu/umd/cs/findbugs/annotations/PossiblyNull", - "io/reactivex/annotations/Nullable", - "io/reactivex/rxjava3/annotations/Nullable", - - "javax/annotation/Nonnull", - "org/jetbrains/annotations/NotNull", - "edu/umd/cs/findbugs/annotations/NonNull", - "androidx/annotation/NonNull", - "android/support/annotation/NonNull", - "android/annotation/NonNull", - "com/android/annotations/NonNull", - "org/eclipse/jdt/annotation/NonNull", - "org/checkerframework/checker/nullness/qual/NonNull", - "lombok/NonNull", - "io/reactivex/annotations/NonNull", - "io/reactivex/rxjava3/annotations/NonNull" - ); - - @Override - public boolean isAnnotationTracked(@NotNull TypeRepr.ClassType annotationType) { - return ourTrackedAnnotations.contains(annotationType.getJvmName()); - } - - @Override - public @NotNull Set methodAnnotationsChanged(JvmMethod method, Difference.Specifier annotationsDiff, Difference.Specifier paramAnnotationsDiff) { - if (isAffected(map(flat(List.of(annotationsDiff.added(), annotationsDiff.removed(), paramAnnotationsDiff.added(), paramAnnotationsDiff.removed())), AnnotationInstance::getAnnotationClass))) { - return method.isFinal()? EnumSet.of(Recompile.USAGES) : EnumSet.of(Recompile.USAGES, Recompile.SUBCLASSES); - } - return RECOMPILE_NONE; - } - - @Override - public @NotNull Set fieldAnnotationsChanged(JvmField field, Difference.Specifier annotationsDiff) { - return isAffected(map(flat(annotationsDiff.added(), annotationsDiff.removed()), AnnotationInstance::getAnnotationClass))? EnumSet.of(Recompile.USAGES) : RECOMPILE_NONE; - } - - private static boolean isAffected(Iterable addedOrRemoved) { - return !isEmpty(filter(addedOrRemoved, t -> ourTrackedAnnotations.contains(t.getJvmName()))); - } -} diff --git a/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker b/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker deleted file mode 100644 index 9f3ea8b7fbd9..000000000000 --- a/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.AnnotationChangesTracker +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -org.jetbrains.jps.dependency.java.MockAnnotationsChangeTracker \ No newline at end of file diff --git a/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.JvmDifferentiateStrategy b/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.JvmDifferentiateStrategy new file mode 100644 index 000000000000..bf1bfddb6f81 --- /dev/null +++ b/jps/jps-builders/testResources/META-INF/services/org.jetbrains.jps.dependency.java.JvmDifferentiateStrategy @@ -0,0 +1,2 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +org.jetbrains.jps.dependency.java.TestJvmDifferentiateStrategy \ No newline at end of file diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/MockAnnotationsChangeTracker.java b/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/MockAnnotationsChangeTracker.java deleted file mode 100644 index dc284fe4b63e..000000000000 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/MockAnnotationsChangeTracker.java +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2000-2025 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.builders.java.dependencyView.MockAnnotation; -import org.jetbrains.jps.builders.java.dependencyView.MockHierarchyAnnotation; -import org.jetbrains.jps.dependency.diff.Difference; - -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static org.jetbrains.jps.javac.Iterators.*; - -public final class MockAnnotationsChangeTracker implements AnnotationChangesTracker { - private static final String ANOTATION_NAME = MockAnnotation.class.getName().replace('.', '/'); - private static final String HIERARCHY_ANOTATION_NAME = MockHierarchyAnnotation.class.getName().replace('.', '/'); - private static final Set KOTLIN_TESTS_ANOTATION_NAMES = Set.of("foo/Ann", "Ann"); - - @Override - public boolean isAnnotationTracked(@NotNull TypeRepr.ClassType annotationType) { - String typeName = annotationType.getJvmName(); - return KOTLIN_TESTS_ANOTATION_NAMES.contains(typeName) || Objects.equals(ANOTATION_NAME, typeName) || Objects.equals(HIERARCHY_ANOTATION_NAME, typeName); - } - - @Override - public @NotNull Set methodAnnotationsChanged(JvmMethod method, Difference.Specifier annotationsDiff, Difference.Specifier paramAnnotationsDiff) { - //return RECOMPILE_NONE; - return handleChanges( - map(flat(List.of(annotationsDiff.added(), annotationsDiff.removed(), map(annotationsDiff.changed(), Difference.Change::getPast), paramAnnotationsDiff.added(), paramAnnotationsDiff.removed(), map(paramAnnotationsDiff.changed(), Difference.Change::getPast))), AnnotationInstance::getAnnotationClass) - ); - } - - @Override - public @NotNull Set fieldAnnotationsChanged(JvmField field, Difference.Specifier annotationsDiff) { - //return RECOMPILE_NONE; - return handleChanges( - map(flat(List.of(annotationsDiff.added(), annotationsDiff.removed(), map(annotationsDiff.changed(), Difference.Change::getPast))), AnnotationInstance::getAnnotationClass) - ); - } - - @Override - public @NotNull Set classAnnotationsChanged(JvmClass aClass, Difference.Specifier annotationsDiff) { - //return RECOMPILE_NONE; - return handleChanges( - map(flat(List.of(annotationsDiff.added(), annotationsDiff.removed(), map(annotationsDiff.changed(), Difference.Change::getPast))), AnnotationInstance::getAnnotationClass) - ); - } - - @NotNull - public Set handleChanges(Iterable changes) { - final Set result = EnumSet.noneOf(Recompile.class); - if (containsAnnotation(ANOTATION_NAME, changes)) { - result.add(Recompile.USAGES); - } - if (containsAnnotation(HIERARCHY_ANOTATION_NAME, changes)) { - result.add(Recompile.SUBCLASSES); - } - if (containsAnnotation(KOTLIN_TESTS_ANOTATION_NAMES, changes)) { - result.addAll(RECOMPILE_ALL); - } - return result; - } - - private static boolean containsAnnotation(@NotNull String annotationName, Iterable classes) { - return containsAnnotation(Set.of(annotationName), classes); - } - private static boolean containsAnnotation(Set annotationNames, Iterable classes) { - return !isEmpty(filter(classes, type -> annotationNames.contains(type.getJvmName()))); - } -} diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/TestJvmDifferentiateStrategy.java b/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/TestJvmDifferentiateStrategy.java new file mode 100644 index 000000000000..79e0790f5cab --- /dev/null +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/dependency/java/TestJvmDifferentiateStrategy.java @@ -0,0 +1,75 @@ +// Copyright 2000-2025 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.builders.java.dependencyView.MockAnnotation; +import org.jetbrains.jps.builders.java.dependencyView.MockHierarchyAnnotation; +import org.jetbrains.jps.dependency.DifferentiateContext; +import org.jetbrains.jps.dependency.diff.Difference; +import org.jetbrains.jps.javac.Iterators; + +import java.util.EnumSet; +import java.util.Objects; +import java.util.Set; + +/** + * The main purpose of this class is to register the annotation tracker for mock and test annotations used in tests + */ +public class TestJvmDifferentiateStrategy extends JvmDifferentiateStrategyImpl { + + private static final String ANOTATION_NAME = MockAnnotation.class.getName().replace('.', '/'); + private static final String HIERARCHY_ANOTATION_NAME = MockHierarchyAnnotation.class.getName().replace('.', '/'); + private static final Set KOTLIN_TESTS_ANOTATION_NAMES = Set.of("foo/Ann", "Ann"); + + @Override + public boolean isAnnotationTracked(@NotNull TypeRepr.ClassType annotationType) { + String typeName = annotationType.getJvmName(); + return KOTLIN_TESTS_ANOTATION_NAMES.contains(typeName) || Objects.equals(ANOTATION_NAME, typeName) || Objects.equals(HIERARCHY_ANOTATION_NAME, typeName); + } + + @Override + public boolean processClassAnnotations(DifferentiateContext context, Difference.Change change, Difference.Specifier annotationDiff, Utils future, Utils present) { + Set affectionScope = getAffectionScope(getAffectedAnnotations(annotationDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed, AnnotationAffectionKind.changed))); + if (!affectionScope.isEmpty()) { + affectClassAnnotationUsages(context, affectionScope, change, future, present); + } + return super.processClassAnnotations(context, change, annotationDiff, future, present); + } + + @Override + public boolean processFieldAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change fieldChange, Difference.Specifier annotationDiff, Utils future, Utils present) { + Set affectionScope = getAffectionScope(getAffectedAnnotations(annotationDiff, EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed, AnnotationAffectionKind.changed))); + if (!affectionScope.isEmpty()) { + affectFieldAnnotationUsages(context, affectionScope, clsChange, fieldChange.getPast(), future, present); + } + return super.processFieldAnnotations(context, clsChange, fieldChange, annotationDiff, future, present); + } + + @Override + public boolean processMethodAnnotations(DifferentiateContext context, Difference.Change clsChange, Difference.Change methodChange, Difference.Specifier annotationsDiff, Difference.Specifier paramAnnotationsDiff, Utils future, Utils present) { + EnumSet affectionKinds = EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed, AnnotationAffectionKind.changed); + Set affectionScope = getAffectionScope( + Iterators.flat(getAffectedAnnotations(annotationsDiff, affectionKinds), getAffectedAnnotations(paramAnnotationsDiff, affectionKinds)) + ); + if (!affectionScope.isEmpty()) { + affectMethodAnnotationUsages(context, affectionScope, clsChange, methodChange.getPast(), future, present); + } + return super.processMethodAnnotations(context, clsChange, methodChange, annotationsDiff, paramAnnotationsDiff, future, present); + } + + private static Set getAffectionScope(Iterable trackedAnnotations) { + Set result = EnumSet.noneOf(AnnotationAffectionScope.class); + for (TypeRepr.ClassType annotation : trackedAnnotations) { + if (ANOTATION_NAME.equals(annotation.getJvmName())) { + result.add(AnnotationAffectionScope.usages); + } + else if (HIERARCHY_ANOTATION_NAME.equals(annotation.getJvmName())) { + result.add(AnnotationAffectionScope.subclasses); + } + else if (KOTLIN_TESTS_ANOTATION_NAMES.contains(annotation.getJvmName())) { + result.addAll(EnumSet.of(AnnotationAffectionScope.usages, AnnotationAffectionScope.subclasses)); + } + } + return result; + } +} diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/build.log b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/build.log new file mode 100644 index 000000000000..dfc387f304b1 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/build.log @@ -0,0 +1,22 @@ +================ Step #1 ================= + +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Util.class +End of files +Compiling files: + src/util.kt +End of files +Exit code: OK +------------------------------------------ +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Client.class +End of files +Compiling files: + src/client.kt +End of files +Exit code: ABORT +------------------------------------------ +COMPILATION FAILED +'fun foo(param: String): Int' is deprecated. message. \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/client.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/client.kt new file mode 100644 index 000000000000..9499c66b2749 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/client.kt @@ -0,0 +1,7 @@ +package test + +class Client { + fun test(u: Util) { + val a = u.foo("param") + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt new file mode 100644 index 000000000000..2f4e3de72f73 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt @@ -0,0 +1,6 @@ +package test + +class Util { + @Deprecated("message") + fun foo(param : String) = 10 +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt.new b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt.new new file mode 100644 index 000000000000..3b1b8fc4f52d --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateFunction/util.kt.new @@ -0,0 +1,6 @@ +package test + +class Util { + @Deprecated("message", level = DeprecationLevel.ERROR) + fun foo(param : String) = 10 +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/build.log b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/build.log new file mode 100644 index 000000000000..8907bb4a3930 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/build.log @@ -0,0 +1,22 @@ +================ Step #1 ================= + +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Util.class +End of files +Compiling files: + src/util.kt +End of files +Exit code: OK +------------------------------------------ +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Client.class +End of files +Compiling files: + src/client.kt +End of files +Exit code: ABORT +------------------------------------------ +COMPILATION FAILED +'var foo: Int' is deprecated. message. \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/client.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/client.kt new file mode 100644 index 000000000000..acf090352cbc --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/client.kt @@ -0,0 +1,7 @@ +package test + +class Client { + fun test(u: Util) { + val a = u.foo + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt new file mode 100644 index 000000000000..ea2db457d270 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt @@ -0,0 +1,8 @@ +package test + +class Util { + @Deprecated("message") + var foo = 10 + get + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt.new b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt.new new file mode 100644 index 000000000000..169d978cb48d --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecateProperty/util.kt.new @@ -0,0 +1,8 @@ +package test + +class Util { + @Deprecated("message", level = DeprecationLevel.ERROR) + var foo = 10 + get + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/build.log b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/build.log new file mode 100644 index 000000000000..5b547d5e5b0d --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/build.log @@ -0,0 +1,22 @@ +================ Step #1 ================= + +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Util.class +End of files +Compiling files: + src/util.kt +End of files +Exit code: OK +------------------------------------------ +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/ClientGet.class +End of files +Compiling files: + src/clientGet.kt +End of files +Exit code: ABORT +------------------------------------------ +COMPILATION FAILED +'var foo: Int' is deprecated. message. \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientGet.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientGet.kt new file mode 100644 index 000000000000..428b1c9fdf90 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientGet.kt @@ -0,0 +1,7 @@ +package test + +class ClientGet { + fun test(u: Util) { + val a = u.foo + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientSet.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientSet.kt new file mode 100644 index 000000000000..b5c88e622680 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/clientSet.kt @@ -0,0 +1,7 @@ +package test + +class ClientSet { + fun test(u: Util) { + u.foo = 10 + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt new file mode 100644 index 000000000000..18d14b5f6c5a --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt @@ -0,0 +1,8 @@ +package test + +class Util { + var foo = 10 + @Deprecated("message") + get + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt.new b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt.new new file mode 100644 index 000000000000..273e60d1d291 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertyGetter/util.kt.new @@ -0,0 +1,8 @@ +package test + +class Util { + var foo = 10 + @Deprecated("message", level = DeprecationLevel.ERROR) + get + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/build.log b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/build.log new file mode 100644 index 000000000000..f5ce93a15f18 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/build.log @@ -0,0 +1,22 @@ +================ Step #1 ================= + +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/Util.class +End of files +Compiling files: + src/util.kt +End of files +Exit code: OK +------------------------------------------ +Cleaning output files: + out/production/module/META-INF/module.kotlin_module + out/production/module/test/ClientSet.class +End of files +Compiling files: + src/clientSet.kt +End of files +Exit code: ABORT +------------------------------------------ +COMPILATION FAILED +'var foo: Int' is deprecated. message. \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientGet.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientGet.kt new file mode 100644 index 000000000000..428b1c9fdf90 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientGet.kt @@ -0,0 +1,7 @@ +package test + +class ClientGet { + fun test(u: Util) { + val a = u.foo + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientSet.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientSet.kt new file mode 100644 index 000000000000..b5c88e622680 --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/clientSet.kt @@ -0,0 +1,7 @@ +package test + +class ClientSet { + fun test(u: Util) { + u.foo = 10 + } +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt new file mode 100644 index 000000000000..b5a3ac95a82d --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt @@ -0,0 +1,8 @@ +package test + +class Util { + var foo = 10 + get + @Deprecated("message") + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt.new b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt.new new file mode 100644 index 000000000000..9d5f3ea8661b --- /dev/null +++ b/plugins/kotlin/jps/graphImplementationTests/testData/incremental/pureKotlin/deprecatePropertySetter/util.kt.new @@ -0,0 +1,8 @@ +package test + +class Util { + var foo = 10 + get + @Deprecated("message", level = DeprecationLevel.ERROR) + set +} \ No newline at end of file diff --git a/plugins/kotlin/jps/graphImplementationTests/tests/org/jetbrains/kotlin/jpsGraph/test/IncrementalK2JvmJpsTestGenerated.java b/plugins/kotlin/jps/graphImplementationTests/tests/org/jetbrains/kotlin/jpsGraph/test/IncrementalK2JvmJpsTestGenerated.java index 30660a546de3..4596bf678eb4 100644 --- a/plugins/kotlin/jps/graphImplementationTests/tests/org/jetbrains/kotlin/jpsGraph/test/IncrementalK2JvmJpsTestGenerated.java +++ b/plugins/kotlin/jps/graphImplementationTests/tests/org/jetbrains/kotlin/jpsGraph/test/IncrementalK2JvmJpsTestGenerated.java @@ -105,6 +105,26 @@ public class IncrementalK2JvmJpsTestGenerated extends AbstractIncrementalK2JvmJp runTest("pureKotlin/annotations/"); } + @TestMetadata("deprecateFunction") + public void testDeprecateFunction() throws Exception { + runTest("pureKotlin/deprecateFunction/"); + } + + @TestMetadata("deprecateProperty") + public void testDeprecateProperty() throws Exception { + runTest("pureKotlin/deprecateProperty/"); + } + + @TestMetadata("deprecatePropertyGetter") + public void testDeprecatePropertyGetter() throws Exception { + runTest("pureKotlin/deprecatePropertyGetter/"); + } + + @TestMetadata("deprecatePropertySetter") + public void testDeprecatePropertySetter() throws Exception { + runTest("pureKotlin/deprecatePropertySetter/"); + } + @TestMetadata("anonymousObjectChanged") public void testAnonymousObjectChanged() throws Exception { runTest("pureKotlin/anonymousObjectChanged/");