diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse.log b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse.log new file mode 100644 index 000000000000..cb86adeceaca --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/AddAnnotationTargetTypeUse/A.class +End of files +Compiling files: +src/A.java +End of files +Cleaning output files: +out/production/AddAnnotationTargetTypeUse/C.class +out/production/AddAnnotationTargetTypeUse/C2.class +End of files +Compiling files: +src/C.java +src/C2.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/A.java.new b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/A.java.new new file mode 100644 index 000000000000..5936e5e3ddc8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/A.java.new @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD, METHOD, TYPE_USE}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/A.java b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/A.java new file mode 100644 index 000000000000..97986d1f99d3 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/A.java @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD, TYPE_USE}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C.java b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C.java new file mode 100644 index 000000000000..b962aef4050f --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C.java @@ -0,0 +1,3 @@ +@A(10) +public class C { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C2.java b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C2.java new file mode 100644 index 000000000000..e776156b63a1 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addAnnotationTargetTypeUse/src/C2.java @@ -0,0 +1,5 @@ +public class C2 { + + @A(30) + int field; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget.log b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget.log new file mode 100644 index 000000000000..8a92a179e0d8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/AddTypeUseAnnotationTarget/A.class +End of files +Compiling files: +src/A.java +End of files +Cleaning output files: +out/production/AddTypeUseAnnotationTarget/C.class +out/production/AddTypeUseAnnotationTarget/C2.class +End of files +Compiling files: +src/C.java +src/C2.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/A.java.new b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/A.java.new new file mode 100644 index 000000000000..97986d1f99d3 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/A.java.new @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD, TYPE_USE}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/A.java b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/A.java new file mode 100644 index 000000000000..56a252dde0d8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/A.java @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C.java b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C.java new file mode 100644 index 000000000000..b962aef4050f --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C.java @@ -0,0 +1,3 @@ +@A(10) +public class C { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C2.java b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C2.java new file mode 100644 index 000000000000..e776156b63a1 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/addTypeUseAnnotationTarget/src/C2.java @@ -0,0 +1,5 @@ +public class C2 { + + @A(30) + int field; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget.log b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget.log new file mode 100644 index 000000000000..109497952f26 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/RemoveTypeUseAnnotationTarget/A.class +End of files +Compiling files: +src/A.java +End of files +Cleaning output files: +out/production/RemoveTypeUseAnnotationTarget/C.class +out/production/RemoveTypeUseAnnotationTarget/C2.class +End of files +Compiling files: +src/C.java +src/C2.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/A.java.new b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/A.java.new new file mode 100644 index 000000000000..56a252dde0d8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/A.java.new @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/A.java b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/A.java new file mode 100644 index 000000000000..97986d1f99d3 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/A.java @@ -0,0 +1,7 @@ +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD, TYPE_USE}) +public @interface A { + int value() default 3; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C.java b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C.java new file mode 100644 index 000000000000..b962aef4050f --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C.java @@ -0,0 +1,3 @@ +@A(10) +public class C { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C2.java b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C2.java new file mode 100644 index 000000000000..e776156b63a1 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/annotations/removeTypeUseAnnotationTarget/src/C2.java @@ -0,0 +1,5 @@ +public class C2 { + + @A(30) + int field; +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java index e5dd19d977c8..2ad7efd4679e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassRepr.java @@ -72,6 +72,11 @@ public class ClassRepr extends ClassFileRepr { return myRetentionPolicy; } + public Set getAnnotationTargets() { + final Set targets = myAnnotationTargets; + return targets != null ? Collections.unmodifiableSet(targets) : Collections.emptySet(); + } + public boolean isInterface() { return (access & Opcodes.ACC_INTERFACE) != 0; } @@ -94,6 +99,8 @@ public class ClassRepr extends ClassFileRepr { public abstract boolean extendsAdded(); + public abstract boolean targetAttributeCategoryMightChange(); + public boolean no() { return base() == NONE && interfaces().unchanged() && @@ -155,6 +162,17 @@ public class ClassRepr extends ClassFileRepr { (myRetentionPolicy == pastClass.myRetentionPolicy)); } + @Override + public boolean targetAttributeCategoryMightChange() { + final Specifier targetsDiff = targets(); + if (!targetsDiff.unchanged()) { + return targetsDiff.added().contains(ElemType.TYPE_USE) || + targetsDiff.removed().contains(ElemType.TYPE_USE) || + pastClass.getAnnotationTargets().contains(ElemType.TYPE_USE); + } + return false; + } + @Override public int base() { return d; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java index 6d0a86c67f28..a2a14a0579f1 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java @@ -1942,6 +1942,10 @@ public class Mappings { debug("Retention policy change detected, adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } + else if (diff.targetAttributeCategoryMightChange()) { + debug("Annotation's attribute category in bytecode might be affected because of TYPE_USE target, adding class usage to affected usages"); + state.myAffectedUsages.add(changedClass.createUsage()); + } else { final Collection removedtargets = diff.targets().removed(); @@ -1955,9 +1959,9 @@ public class Mappings { if (!removedtargets.isEmpty()) { debug("Removed some annotation targets, adding annotation query"); - final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)UsageRepr - .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, changedClass.name), null, EnumSet.copyOf(removedtargets)); - state.myAnnotationQuery.add(annotationUsage); + state.myAnnotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr.createAnnotationUsage( + myContext, TypeRepr.createClassType(myContext, changedClass.name), null, EnumSet.copyOf(removedtargets) + )); } for (final MethodRepr m : diff.methods().added()) { @@ -2186,8 +2190,9 @@ public class Mappings { for (UsageRepr.Usage usage : depUsages) { if (usage instanceof UsageRepr.AnnotationUsage) { + final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)usage; for (final UsageRepr.AnnotationUsage query : state.myAnnotationQuery) { - if (query.satisfies(usage)) { + if (query.satisfies(annotationUsage)) { debug("Added file due to annotation query"); myAffectedFiles.add(depFile); return; diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java index 7a361acf3a4a..57a96e51b100 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageRepr.java @@ -546,38 +546,32 @@ class UsageRepr { final TIntHashSet myUsedArguments; final Set myUsedTargets; - public boolean satisfies(final Usage usage) { - if (usage instanceof AnnotationUsage) { - final AnnotationUsage annotationUsage = (AnnotationUsage)usage; - - if (!myType.equals(annotationUsage.myType)) { - return false; - } - - boolean argumentsSatisfy = false; - - if (myUsedArguments != null) { - final TIntHashSet arguments = new TIntHashSet(myUsedArguments.toArray()); - - arguments.removeAll(annotationUsage.myUsedArguments.toArray()); - - argumentsSatisfy = !arguments.isEmpty(); - } - - boolean targetsSatisfy = false; - - if (myUsedTargets != null) { - final Collection targets = EnumSet.copyOf(myUsedTargets); - - targets.retainAll(annotationUsage.myUsedTargets); - - targetsSatisfy = !targets.isEmpty(); - } - - return argumentsSatisfy || targetsSatisfy; + public boolean satisfies(final AnnotationUsage annotationUsage) { + if (!myType.equals(annotationUsage.myType)) { + return false; } - return false; + boolean argumentsSatisfy = false; + + if (myUsedArguments != null) { + final TIntHashSet arguments = new TIntHashSet(myUsedArguments.toArray()); + + arguments.removeAll(annotationUsage.myUsedArguments.toArray()); + + argumentsSatisfy = !arguments.isEmpty(); + } + + boolean targetsSatisfy = false; + + if (myUsedTargets != null) { + final Collection targets = EnumSet.copyOf(myUsedTargets); + + targets.retainAll(annotationUsage.myUsedTargets); + + targetsSatisfy = !targets.isEmpty(); + } + + return argumentsSatisfy || targetsSatisfy; } private AnnotationUsage(final TypeRepr.ClassType type, final TIntHashSet usedArguments, final Set targets) { diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/AnnotationTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/AnnotationTest.java index 6b7da9985e93..d28c65894d00 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/AnnotationTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/AnnotationTest.java @@ -28,6 +28,14 @@ public class AnnotationTest extends IncrementalTestCase { doTest(); } + public void testAddAnnotationTargetTypeUse() { + doTest(); + } + + public void testAddTypeUseAnnotationTarget() { + doTest(); + } + public void testAddAnnotationTypeMemberWithDefaultValue() { doTest(); } @@ -97,6 +105,10 @@ public class AnnotationTest extends IncrementalTestCase { doTest(); } + public void testRemoveTypeUseAnnotationTarget() { + doTest(); + } + public void testRemoveAnnotationTypeMember() { doTest(); }