mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
declarative style for specifying tracked annotations
GitOrigin-RevId: 94bc427ed465cecc0cf2885e2a2cad749338848b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4b4d12c3fb
commit
3bb6012069
@@ -36,6 +36,7 @@ out/production/AnnotationsTracker/D3Sub.class
|
||||
out/production/AnnotationsTracker/D3Sub2.class
|
||||
out/production/AnnotationsTracker/D4Sub.class
|
||||
out/production/AnnotationsTracker/D4Sub2.class
|
||||
out/production/AnnotationsTracker/D5Sub.class
|
||||
out/production/AnnotationsTracker/D5Sub2.class
|
||||
End of files
|
||||
Compiling files:
|
||||
@@ -56,5 +57,6 @@ src/D3Sub.java
|
||||
src/D3Sub2.java
|
||||
src/D4Sub.java
|
||||
src/D4Sub2.java
|
||||
src/D5Sub.java
|
||||
src/D5Sub2.java
|
||||
End of files
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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 java.util.Set;
|
||||
|
||||
public class AnnotationGroup {
|
||||
public enum AffectionKind {
|
||||
added, removed, changed
|
||||
}
|
||||
|
||||
public enum AnnTarget {
|
||||
type, field, method, method_parameter
|
||||
}
|
||||
|
||||
public enum AffectionScope {
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
public final String name;
|
||||
public final Set<AffectionKind> affectionKind;
|
||||
public final Set<AffectionScope> affectionScope;
|
||||
public final Set<AnnTarget> targets;
|
||||
public final Set<TypeRepr.ClassType> types;
|
||||
|
||||
private AnnotationGroup(String name, Set<AffectionKind> affectionKind, Set<AffectionScope> affectionScope, Set<AnnTarget> targets, Set<TypeRepr.ClassType> types) {
|
||||
this.name = name;
|
||||
this.affectionKind = affectionKind;
|
||||
this.affectionScope = affectionScope;
|
||||
this.targets = targets;
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
public static AnnotationGroup of(String name, Set<AnnTarget> targets, Set<AffectionKind> affectionKind, Set<AffectionScope> affectionScope, Set<TypeRepr.ClassType> annotationTypes) {
|
||||
return new AnnotationGroup(name, affectionKind, affectionScope, targets, annotationTypes);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,13 @@ package org.jetbrains.jps.dependency.java;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.dependency.diff.Difference;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
@@ -21,64 +23,165 @@ import static org.jetbrains.jps.javac.Iterators.*;
|
||||
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 <T extends AnnotationInstance, D extends AnnotationInstance.Diff<T>> boolean isAffectedByAnnotations(
|
||||
Proto element, Difference.Specifier<T, D> annotationsDiff, Set<AnnotationAffectionKind> affectionKinds, Predicate<? super TypeRepr.ClassType> annotationSelector
|
||||
Proto element, Difference.Specifier<T, D> annotationsDiff, Set<AnnotationGroup.AffectionKind> affectionKinds, Predicate<? super TypeRepr.ClassType> annotationSelector
|
||||
) {
|
||||
return !element.isPrivate() && find(getAffectedAnnotations(annotationsDiff, affectionKinds), annotationSelector::test) != null;
|
||||
}
|
||||
|
||||
protected final <T extends AnnotationInstance, D extends AnnotationInstance.Diff<T>> Iterable<TypeRepr.ClassType> getAffectedAnnotations(
|
||||
Difference.Specifier<T, D> annotationsDiff, Set<AnnotationAffectionKind> affectionKinds
|
||||
Difference.Specifier<T, D> annotationsDiff, Set<AnnotationGroup.AffectionKind> affectionKinds
|
||||
) {
|
||||
Iterable<? extends T> added = affectionKinds.contains(AnnotationAffectionKind.added)? annotationsDiff.added() : List.of();
|
||||
Iterable<? extends T> removed = affectionKinds.contains(AnnotationAffectionKind.removed)? annotationsDiff.removed() : List.of();
|
||||
Iterable<? extends T> changed = affectionKinds.contains(AnnotationAffectionKind.changed)? map(annotationsDiff.changed(), Difference.Change::getPast) : List.of();
|
||||
Iterable<? extends T> added = affectionKinds.contains(AnnotationGroup.AffectionKind.added)? annotationsDiff.added() : List.of();
|
||||
Iterable<? extends T> removed = affectionKinds.contains(AnnotationGroup.AffectionKind.removed)? annotationsDiff.removed() : List.of();
|
||||
Iterable<? extends T> changed = affectionKinds.contains(AnnotationGroup.AffectionKind.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 Iterable<AnnotationGroup> getTrackedAnnotations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected void affectClassAnnotationUsages(DifferentiateContext context, Set<AnnotationAffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> change, Utils future, Utils present) {
|
||||
@Override
|
||||
public boolean isAnnotationTracked(TypeRepr.@NotNull ClassType annotationType) {
|
||||
return find(getTrackedAnnotations(), gr -> gr.types.contains(annotationType)) != null;
|
||||
}
|
||||
|
||||
private Set<AnnotationGroup.AffectionScope> getMaxPossibleScope() {
|
||||
Set<AnnotationGroup.AffectionScope> result = EnumSet.noneOf(AnnotationGroup.AffectionScope.class);
|
||||
for (AnnotationGroup group : getTrackedAnnotations()) {
|
||||
result.addAll(group.affectionScope);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processClassAnnotations(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> change, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationDiff, Utils future, Utils present) {
|
||||
Set<AnnotationGroup.AffectionScope> maxScope = getMaxPossibleScope();
|
||||
if (maxScope.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
JvmClass changedClass = change.getPast();
|
||||
boolean affectUsages = toRecompile.contains(AnnotationAffectionScope.usages);
|
||||
Set<AnnotationGroup.AffectionScope> affectionScope = EnumSet.noneOf(AnnotationGroup.AffectionScope.class);
|
||||
for (AnnotationGroup group : filter(getTrackedAnnotations(), gr -> gr.targets.contains(AnnotationGroup.AnnTarget.type))) {
|
||||
if (isAffectedByAnnotations(changedClass, annotationDiff, group.affectionKind, group.types::contains)) {
|
||||
debug(group.name, " changed for ", changedClass.getName(), " --- affecting class usages");
|
||||
affectionScope.addAll(group.affectionScope);
|
||||
if (affectionScope.equals(maxScope)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!affectionScope.isEmpty()) {
|
||||
affectClassAnnotationUsages(context, affectionScope, change, future, present);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processFieldAnnotations(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmField, JvmField.Diff> fieldChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationDiff, Utils future, Utils present) {
|
||||
Set<AnnotationGroup.AffectionScope> maxScope = getMaxPossibleScope();
|
||||
if (maxScope.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
JvmField changedField = fieldChange.getPast();
|
||||
Set<AnnotationGroup.AffectionScope> affectionScope = EnumSet.noneOf(AnnotationGroup.AffectionScope.class);
|
||||
for (AnnotationGroup group : filter(getTrackedAnnotations(), gr -> gr.targets.contains(AnnotationGroup.AnnTarget.field))) {
|
||||
if (isAffectedByAnnotations(changedField, annotationDiff, group.affectionKind, group.types::contains) ) {
|
||||
debug(group.name, " changed for field ", changedField, " --- affecting field usages");
|
||||
affectionScope.addAll(group.affectionScope);
|
||||
if (affectionScope.equals(maxScope)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!affectionScope.isEmpty()) {
|
||||
affectFieldAnnotationUsages(context, affectionScope, clsChange, changedField, future, present);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processMethodAnnotations(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmMethod, JvmMethod.Diff> methodChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationsDiff, Difference.Specifier<ParamAnnotation, ParamAnnotation.Diff> paramAnnotationsDiff, Utils future, Utils present) {
|
||||
Set<AnnotationGroup.AffectionScope> maxScope = getMaxPossibleScope();
|
||||
JvmMethod changedMethod = methodChange.getPast();
|
||||
if (!changedMethod.isFinal()) {
|
||||
maxScope.add(AnnotationGroup.AffectionScope.subclasses);
|
||||
}
|
||||
|
||||
Set<AnnotationGroup.AffectionScope> affectionScope = EnumSet.noneOf(AnnotationGroup.AffectionScope.class);
|
||||
|
||||
for (AnnotationGroup group : filter(getTrackedAnnotations(), gr -> gr.targets.contains(AnnotationGroup.AnnTarget.method))) {
|
||||
if (isAffectedByAnnotations(changedMethod, annotationsDiff, group.affectionKind, group.types::contains)) {
|
||||
affectionScope.addAll(group.affectionScope);
|
||||
if (!changedMethod.isFinal()) {
|
||||
// ensure the affection scope is expanded for subclasses
|
||||
affectionScope.add(AnnotationGroup.AffectionScope.subclasses);
|
||||
debug(group.name, " changed for non-final method ", changedMethod, " --- affecting method usages and subclasses");
|
||||
}
|
||||
else {
|
||||
debug(group.name, " changed for method ", changedMethod, " --- affecting method usages");
|
||||
}
|
||||
if (affectionScope.equals(maxScope)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!affectionScope.equals(maxScope)) {
|
||||
for (AnnotationGroup group : filter(getTrackedAnnotations(), gr -> gr.targets.contains(AnnotationGroup.AnnTarget.method_parameter))) {
|
||||
if (isAffectedByAnnotations(changedMethod, paramAnnotationsDiff, group.affectionKind, group.types::contains)) {
|
||||
affectionScope.addAll(group.affectionScope);
|
||||
if (!changedMethod.isFinal()) {
|
||||
// ensure the affection scope is expanded for subclasses
|
||||
affectionScope.add(AnnotationGroup.AffectionScope.subclasses);
|
||||
debug(group.name, " changed for non-final method parameters ", changedMethod, " --- affecting method usages and subclasses");
|
||||
}
|
||||
else {
|
||||
debug(group.name, " changed for method parameters ", changedMethod, " --- affecting method usages");
|
||||
}
|
||||
if (affectionScope.equals(maxScope)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!affectionScope.isEmpty()) {
|
||||
affectMethodAnnotationUsages(context, affectionScope, clsChange, changedMethod, future, present);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void affectClassAnnotationUsages(DifferentiateContext context, Set<AnnotationGroup.AffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> change, Utils future, Utils present) {
|
||||
JvmClass changedClass = change.getPast();
|
||||
boolean affectUsages = toRecompile.contains(AnnotationGroup.AffectionScope.usages);
|
||||
if (affectUsages) {
|
||||
context.affectUsage(new ClassUsage(changedClass.getReferenceID()));
|
||||
}
|
||||
if (toRecompile.contains(AnnotationAffectionScope.subclasses)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.subclasses)) {
|
||||
affectSubclasses(context, future, changedClass.getReferenceID(), affectUsages);
|
||||
}
|
||||
}
|
||||
|
||||
protected void affectFieldAnnotationUsages(DifferentiateContext context, Set<AnnotationAffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmField changedField, Utils future, Utils present) {
|
||||
protected void affectFieldAnnotationUsages(DifferentiateContext context, Set<AnnotationGroup.AffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmField changedField, Utils future, Utils present) {
|
||||
JvmClass changedClass = clsChange.getPast();
|
||||
if (toRecompile.contains(AnnotationAffectionScope.usages)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.usages)) {
|
||||
affectMemberUsages(context, changedClass.getReferenceID(), changedField, future.collectSubclassesWithoutField(changedClass.getReferenceID(), changedField));
|
||||
}
|
||||
if (toRecompile.contains(AnnotationAffectionScope.subclasses)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.subclasses)) {
|
||||
affectSubclasses(context, future, changedClass.getReferenceID(), false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void affectMethodAnnotationUsages(DifferentiateContext context, Set<AnnotationAffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmMethod changedMethod, Utils future, Utils present) {
|
||||
protected void affectMethodAnnotationUsages(DifferentiateContext context, Set<AnnotationGroup.AffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmMethod changedMethod, Utils future, Utils present) {
|
||||
JvmClass changedClass = clsChange.getPast();
|
||||
if (toRecompile.contains(AnnotationAffectionScope.usages)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.usages)) {
|
||||
affectMemberUsages(context, changedClass.getReferenceID(), changedMethod, future.collectSubclassesWithoutMethod(changedClass.getReferenceID(), changedMethod));
|
||||
if (changedMethod.isAbstract() || toRecompile.contains(AnnotationAffectionScope.subclasses)) {
|
||||
if (changedMethod.isAbstract() || toRecompile.contains(AnnotationGroup.AffectionScope.subclasses)) {
|
||||
for (Pair<JvmClass, JvmMethod> 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();
|
||||
@@ -86,7 +189,7 @@ public abstract class JvmDifferentiateStrategyImpl implements JvmDifferentiateSt
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRecompile.contains(AnnotationAffectionScope.subclasses)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.subclasses)) {
|
||||
affectSubclasses(context, future, changedClass.getReferenceID(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,81 +23,59 @@ 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<TypeRepr.ClassType> ourDeprecationAnnotations = Set.of(
|
||||
new TypeRepr.ClassType("kotlin/Deprecated"),
|
||||
new TypeRepr.ClassType("kotlin/DeprecatedSinceKotlin")
|
||||
);
|
||||
private static final Set<String> 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"
|
||||
private static final List<AnnotationGroup> ourTrackedAnnotations = List.of(
|
||||
AnnotationGroup.of(
|
||||
"Nullability annotations",
|
||||
EnumSet.of(AnnotationGroup.AnnTarget.field, AnnotationGroup.AnnTarget.method, AnnotationGroup.AnnTarget.method_parameter),
|
||||
EnumSet.of(AnnotationGroup.AffectionKind.added, AnnotationGroup.AffectionKind.removed),
|
||||
EnumSet.of(AnnotationGroup.AffectionScope.usages),
|
||||
Set.of(
|
||||
new TypeRepr.ClassType("org/jetbrains/annotations/Nullable"),
|
||||
new TypeRepr.ClassType("androidx/annotation/Nullable"),
|
||||
new TypeRepr.ClassType("android/support/annotation/Nullable"),
|
||||
new TypeRepr.ClassType("android/annotation/Nullable"),
|
||||
new TypeRepr.ClassType("com/android/annotations/Nullable"),
|
||||
new TypeRepr.ClassType("org/eclipse/jdt/annotation/Nullable"),
|
||||
new TypeRepr.ClassType("org/checkerframework/checker/nullness/qual/Nullable"),
|
||||
new TypeRepr.ClassType("javax/annotation/Nullable"),
|
||||
new TypeRepr.ClassType("javax/annotation/CheckForNull"),
|
||||
new TypeRepr.ClassType("edu/umd/cs/findbugs/annotations/CheckForNull"),
|
||||
new TypeRepr.ClassType("edu/umd/cs/findbugs/annotations/Nullable"),
|
||||
new TypeRepr.ClassType("edu/umd/cs/findbugs/annotations/PossiblyNull"),
|
||||
new TypeRepr.ClassType("io/reactivex/annotations/Nullable"),
|
||||
new TypeRepr.ClassType("io/reactivex/rxjava3/annotations/Nullable"),
|
||||
|
||||
new TypeRepr.ClassType("javax/annotation/Nonnull"),
|
||||
new TypeRepr.ClassType("org/jetbrains/annotations/NotNull"),
|
||||
new TypeRepr.ClassType("edu/umd/cs/findbugs/annotations/NonNull"),
|
||||
new TypeRepr.ClassType("androidx/annotation/NonNull"),
|
||||
new TypeRepr.ClassType("android/support/annotation/NonNull"),
|
||||
new TypeRepr.ClassType("android/annotation/NonNull"),
|
||||
new TypeRepr.ClassType("com/android/annotations/NonNull"),
|
||||
new TypeRepr.ClassType("org/eclipse/jdt/annotation/NonNull"),
|
||||
new TypeRepr.ClassType("org/checkerframework/checker/nullness/qual/NonNull"),
|
||||
new TypeRepr.ClassType("lombok/NonNull"),
|
||||
new TypeRepr.ClassType("io/reactivex/annotations/NonNull"),
|
||||
new TypeRepr.ClassType("io/reactivex/rxjava3/annotations/NonNull")
|
||||
)
|
||||
),
|
||||
|
||||
AnnotationGroup.of(
|
||||
"Deprecation annotations",
|
||||
EnumSet.of(AnnotationGroup.AnnTarget.type, AnnotationGroup.AnnTarget.field, AnnotationGroup.AnnTarget.method),
|
||||
EnumSet.of(AnnotationGroup.AffectionKind.added, AnnotationGroup.AffectionKind.changed),
|
||||
EnumSet.of(AnnotationGroup.AffectionScope.usages),
|
||||
Set.of(
|
||||
new TypeRepr.ClassType("kotlin/Deprecated"),
|
||||
new TypeRepr.ClassType("kotlin/DeprecatedSinceKotlin")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationTracked(TypeRepr.@NotNull ClassType annotationType) {
|
||||
return ourNullabilityAnnotations.contains(annotationType.getJvmName()) || ourDeprecationAnnotations.contains(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processClassAnnotations(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> change, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> 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<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmField, JvmField.Diff> fieldChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> 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<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmMethod, JvmMethod.Diff> methodChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationsDiff, Difference.Specifier<ParamAnnotation, ParamAnnotation.Diff> 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<AnnotationAffectionScope> 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);
|
||||
protected Iterable<AnnotationGroup> getTrackedAnnotations() {
|
||||
return ourTrackedAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -555,18 +533,18 @@ public final class KotlinJvmDifferentiateStrategy extends JvmDifferentiateStrate
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void affectMethodAnnotationUsages(DifferentiateContext context, Set<AnnotationAffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmMethod changedMethod, Utils future, Utils present) {
|
||||
protected void affectMethodAnnotationUsages(DifferentiateContext context, Set<AnnotationGroup.AffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> clsChange, JvmMethod changedMethod, Utils future, Utils present) {
|
||||
super.affectMethodAnnotationUsages(context, toRecompile, clsChange, changedMethod, future, present);
|
||||
if (toRecompile.contains(AnnotationAffectionScope.usages)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.usages)) {
|
||||
JvmClass changedClass = clsChange.getPast();
|
||||
affectMemberLookupUsages(context, changedClass, KJvmUtils.getMethodKotlinName(changedClass, changedMethod), present);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void affectClassAnnotationUsages(DifferentiateContext context, Set<AnnotationAffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> change, Utils future, Utils present) {
|
||||
protected void affectClassAnnotationUsages(DifferentiateContext context, Set<AnnotationGroup.AffectionScope> toRecompile, Difference.Change<JvmClass, JvmClass.Diff> change, Utils future, Utils present) {
|
||||
super.affectClassAnnotationUsages(context, toRecompile, change, future, present);
|
||||
if (toRecompile.contains(AnnotationAffectionScope.usages)) {
|
||||
if (toRecompile.contains(AnnotationGroup.AffectionScope.usages)) {
|
||||
affectClassLookupUsages(context, change.getPast());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
// 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.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -19,57 +15,42 @@ 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<String> KOTLIN_TESTS_ANOTATION_NAMES = Set.of("foo/Ann", "Ann");
|
||||
|
||||
private static final List<AnnotationGroup> ourTrackedAnnotations = List.of(
|
||||
AnnotationGroup.of(
|
||||
"Test annotation",
|
||||
EnumSet.allOf(AnnotationGroup.AnnTarget.class),
|
||||
EnumSet.allOf(AnnotationGroup.AffectionKind.class),
|
||||
EnumSet.of(AnnotationGroup.AffectionScope.usages),
|
||||
Set.of(
|
||||
new TypeRepr.ClassType(ANOTATION_NAME)
|
||||
)
|
||||
),
|
||||
|
||||
AnnotationGroup.of(
|
||||
"Test hierarchy annotation",
|
||||
EnumSet.allOf(AnnotationGroup.AnnTarget.class),
|
||||
EnumSet.allOf(AnnotationGroup.AffectionKind.class),
|
||||
EnumSet.of(AnnotationGroup.AffectionScope.subclasses),
|
||||
Set.of(
|
||||
new TypeRepr.ClassType(HIERARCHY_ANOTATION_NAME)
|
||||
)
|
||||
),
|
||||
|
||||
AnnotationGroup.of(
|
||||
"Kotlin test annotations",
|
||||
EnumSet.of(AnnotationGroup.AnnTarget.type, AnnotationGroup.AnnTarget.field, AnnotationGroup.AnnTarget.method),
|
||||
EnumSet.allOf(AnnotationGroup.AffectionKind.class),
|
||||
EnumSet.of(AnnotationGroup.AffectionScope.usages, AnnotationGroup.AffectionScope.subclasses),
|
||||
Set.of(
|
||||
new TypeRepr.ClassType("foo/Ann"),
|
||||
new TypeRepr.ClassType("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<JvmClass, JvmClass.Diff> change, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationDiff, Utils future, Utils present) {
|
||||
Set<AnnotationAffectionScope> 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<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmField, JvmField.Diff> fieldChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationDiff, Utils future, Utils present) {
|
||||
Set<AnnotationAffectionScope> 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<JvmClass, JvmClass.Diff> clsChange, Difference.Change<JvmMethod, JvmMethod.Diff> methodChange, Difference.Specifier<ElementAnnotation, ElementAnnotation.Diff> annotationsDiff, Difference.Specifier<ParamAnnotation, ParamAnnotation.Diff> paramAnnotationsDiff, Utils future, Utils present) {
|
||||
EnumSet<AnnotationAffectionKind> affectionKinds = EnumSet.of(AnnotationAffectionKind.added, AnnotationAffectionKind.removed, AnnotationAffectionKind.changed);
|
||||
Set<AnnotationAffectionScope> 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<AnnotationAffectionScope> getAffectionScope(Iterable<TypeRepr.ClassType> trackedAnnotations) {
|
||||
Set<AnnotationAffectionScope> 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;
|
||||
protected Iterable<AnnotationGroup> getTrackedAnnotations() {
|
||||
return ourTrackedAnnotations;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user