diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild.log b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild.log new file mode 100644 index 000000000000..52242cad794f --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild.log @@ -0,0 +1,6 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java new file mode 100644 index 000000000000..c6bd1d274375 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to B, C, D; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..58ee8e16cfb2 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/module-info.java.new @@ -0,0 +1,3 @@ +module A { + exports ppp to B, C; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..6c727f8af86b --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + ppp.Util.perform(); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsNoRebuild/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps.log b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps.log new file mode 100644 index 000000000000..5f607df92e75 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files +Cleaning output files: +out/production/B/module-info.class +out/production/B/qqq/Client.class +End of files +Compiling files: +moduleB/src/module-info.java +moduleB/src/qqq/Client.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java new file mode 100644 index 000000000000..c6bd1d274375 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to B, C, D; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..248add6d02d6 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/module-info.java.new @@ -0,0 +1,3 @@ +module A { + exports ppp to C, D; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..1cd3b05e3818 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + // do perform + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildDirectDeps/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps.log b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps.log new file mode 100644 index 000000000000..39d767c72ad4 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java new file mode 100644 index 000000000000..c6bd1d274375 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to B, C, D; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..43fb736fdbf7 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/module-info.java.new @@ -0,0 +1,3 @@ +module A { + exports ppp to B, D; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..6c727f8af86b --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + ppp.Util.perform(); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleExportsRebuildIndirectDeps/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires.log b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires.log new file mode 100644 index 000000000000..ea3ca8790fa6 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/B/module-info.class +End of files +Compiling files: +moduleB/src/module-info.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/module-info.java new file mode 100644 index 000000000000..56d5b6c219d3 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java.new new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/module-info.java.new @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..e862cdf12e29 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + System.out.println("ClientB.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..9bb6a073e624 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeQualifiedTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,7 @@ +package qqq2; + +public class ClientC { + public void perform() { + // do perform + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires.log b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires.log new file mode 100644 index 000000000000..ea3ca8790fa6 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/B/module-info.class +End of files +Compiling files: +moduleB/src/module-info.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/module-info.java new file mode 100644 index 000000000000..dfd0909d61b8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java.new new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/module-info.java.new @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..e862cdf12e29 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + System.out.println("ClientB.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/changeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports.log new file mode 100644 index 000000000000..5f607df92e75 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files +Cleaning output files: +out/production/B/module-info.class +out/production/B/qqq/Client.class +End of files +Compiling files: +moduleB/src/module-info.java +moduleB/src/qqq/Client.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java new file mode 100644 index 000000000000..dfd0909d61b8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..46f7994fe0a2 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/module-info.java.new @@ -0,0 +1,2 @@ +module A { +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/module-info.java new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..1cd3b05e3818 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + // do perform + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ae285b22ca00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleExports/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,8 @@ +package qqq2; + + +public class ClientC { + public void perform() { + // do perform + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires.log new file mode 100644 index 000000000000..a60439ffdf81 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/B/module-info.class +End of files +Compiling files: +moduleB/src/module-info.java +End of files +Cleaning output files: +out/production/B/module-info.class +out/production/B/qqq/Client.class +End of files +Compiling files: +moduleB/src/module-info.java +moduleB/src/qqq/Client.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/module-info.java new file mode 100644 index 000000000000..dfd0909d61b8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java.new new file mode 100644 index 000000000000..2fab91b37842 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/module-info.java.new @@ -0,0 +1,2 @@ +module B { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..2b1bab75d804 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleB/src/qqq/Client.java @@ -0,0 +1,8 @@ +package qqq; +import ppp.Util; + +public class Client { + public void perform() { + Util.perform(); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/qqq2/ClientC.java new file mode 100644 index 000000000000..4d7a30b6aa07 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeModuleRequires/moduleC/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import qqq.Client; + +public class Client { + public void perform() { + new Client().perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports.log new file mode 100644 index 000000000000..52242cad794f --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports.log @@ -0,0 +1,6 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java new file mode 100644 index 000000000000..9b28b7533db0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to C; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..46f7994fe0a2 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/module-info.java.new @@ -0,0 +1,2 @@ +module A { +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/module-info.java new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..1cd3b05e3818 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + // do perform + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ae285b22ca00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedModuleExports/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,8 @@ +package qqq2; + + +public class ClientC { + public void perform() { + // do perform + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports.log new file mode 100644 index 000000000000..39d767c72ad4 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports.log @@ -0,0 +1,14 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java new file mode 100644 index 000000000000..9b28b7533db0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp to C; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..c24e080e6317 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/module-info.java.new @@ -0,0 +1,2 @@ +module A { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..1cd3b05e3818 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + // do perform + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeQualifiedTransitiveModuleExports/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports.log new file mode 100644 index 000000000000..fe111b0e7dc8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports.log @@ -0,0 +1,22 @@ +Cleaning output files: +out/production/A/module-info.class +End of files +Compiling files: +moduleA/src/module-info.java +End of files +Cleaning output files: +out/production/B/module-info.class +out/production/B/qqq/Client.class +End of files +Compiling files: +moduleB/src/module-info.java +moduleB/src/qqq/Client.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java new file mode 100644 index 000000000000..dfd0909d61b8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java.new new file mode 100644 index 000000000000..c24e080e6317 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/module-info.java.new @@ -0,0 +1,2 @@ +module A { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..e862cdf12e29 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + System.out.println("ClientB.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleExports/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires.log b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires.log new file mode 100644 index 000000000000..b7efba9abb52 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires.log @@ -0,0 +1,22 @@ +Cleaning output files: +out/production/B/module-info.class +End of files +Compiling files: +moduleB/src/module-info.java +End of files +Cleaning output files: +out/production/B/module-info.class +out/production/B/qqq/Client.class +End of files +Compiling files: +moduleB/src/module-info.java +moduleB/src/qqq/Client.java +End of files +Cleaning output files: +out/production/C/module-info.class +out/production/C/qqq2/ClientC.class +End of files +Compiling files: +moduleC/src/module-info.java +moduleC/src/qqq2/ClientC.java +End of files \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/module-info.java new file mode 100644 index 000000000000..dfd0909d61b8 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/module-info.java @@ -0,0 +1,3 @@ +module A { + exports ppp; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java new file mode 100644 index 000000000000..d51d16ef6c00 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires transitive A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java.new b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java.new new file mode 100644 index 000000000000..2fab91b37842 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/module-info.java.new @@ -0,0 +1,2 @@ +module B { +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/qqq/Client.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/qqq/Client.java new file mode 100644 index 000000000000..e862cdf12e29 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleB/src/qqq/Client.java @@ -0,0 +1,7 @@ +package qqq; + +public class Client { + public void perform() { + System.out.println("ClientB.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/module-info.java new file mode 100644 index 000000000000..e5d213f20466 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/module-info.java @@ -0,0 +1,3 @@ +module C { + requires B; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java new file mode 100644 index 000000000000..ea58f777e417 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/removeTransitiveModuleRequires/moduleC/src/qqq2/ClientC.java @@ -0,0 +1,9 @@ +package qqq2; + +import ppp.Util; + +public class ClientC { + public void perform() { + Util.perform(); + } +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java index 2fc09acb60b9..328bea2af7d1 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java @@ -37,6 +37,9 @@ import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; import org.jetbrains.jps.incremental.messages.ProgressMessage; import org.jetbrains.jps.model.JpsDummyElement; +import org.jetbrains.jps.model.JpsProject; +import org.jetbrains.jps.model.java.JavaModuleIndex; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.java.JpsJavaSdkType; import org.jetbrains.jps.model.library.JpsTypedLibrary; import org.jetbrains.jps.model.library.sdk.JpsSdk; @@ -63,6 +66,7 @@ public class JavaBuilderUtil { private static final Key> SUCCESSFULLY_COMPILED_FILES_KEY = Key.create("_successfully_compiled_files_"); private static final Key> SKIP_MARKING_DIRTY_FILTERS_KEY = Key.create("_skip_marking_dirty_filters_"); private static final Key> MAPPINGS_DELTA_KEY = Key.create("_mappings_delta_"); + private static final String MODULE_INFO_FILE = "module-info.java"; public static void registerFileToCompile(CompileContext context, File file) { registerFilesToCompile(context, Collections.singleton(file)); @@ -214,6 +218,7 @@ public class JavaBuilderUtil { LOG.debug("End Of Differentiate Results."); } + final boolean compilingIncrementally = isCompileJavaIncrementally(context); if (incremental) { final Set newlyAffectedFiles = new HashSet<>(allAffectedFiles); newlyAffectedFiles.removeAll(affectedBeforeDif); @@ -241,10 +246,47 @@ public class JavaBuilderUtil { } } + Set targetsToMark = null; + final JavaModuleIndex moduleIndex = getJavaModuleIndex(context); for (File file : newlyAffectedFiles) { - FSOperations.markDirtyIfNotDeleted(context, markDirtyRound, file); + if (MODULE_INFO_FILE.equals(file.getName())) { + final JavaSourceRootDescriptor rootDescr = context.getProjectDescriptor().getBuildRootIndex().findJavaRootDescriptor(context, file); + if (rootDescr != null) { + final ModuleBuildTarget target = rootDescr.getTarget(); + final File targetModuleInfo = moduleIndex.getModuleInfoFile(target.getModule(), target.isTests()); + if (FileUtil.filesEqual(targetModuleInfo, file)) { + if (targetsToMark == null) { + targetsToMark = new THashSet<>(); // lazy init + } + targetsToMark.add(target); + } + } + } + else { + FSOperations.markDirtyIfNotDeleted(context, markDirtyRound, file); + } } - additionalPassRequired = isCompileJavaIncrementally(context) && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles); + if (targetsToMark != null) { + boolean currentChunkAfected = false; + for (ModuleBuildTarget target : targetsToMark) { + if (chunk.getTargets().contains(target)) { + currentChunkAfected = true; + } + else { + FSOperations.markDirty(context, markDirtyRound, target, null); + } + } + if (currentChunkAfected) { + if (compilingIncrementally) { + // turn on non-incremental mode for targets from the current chunk, if at least one of them was affected. + for (ModuleBuildTarget target : chunk.getTargets()) { + context.markNonIncremental(target); + } + } + FSOperations.markDirty(context, markDirtyRound, chunk, null); + } + } + additionalPassRequired = compilingIncrementally && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles); } } else { @@ -254,7 +296,7 @@ public class JavaBuilderUtil { context.processMessage(new ProgressMessage(messageText)); final boolean alreadyMarkedDirty = FSOperations.isMarkedDirty(context, chunk); - additionalPassRequired = isCompileJavaIncrementally(context) && !alreadyMarkedDirty; + additionalPassRequired = compilingIncrementally && !alreadyMarkedDirty; if (alreadyMarkedDirty) { // need this to make sure changes data stored in Delta is complete @@ -303,6 +345,17 @@ public class JavaBuilderUtil { } } + @Nullable + public static File findModuleInfoFile(CompileContext context, ModuleBuildTarget target) { + return getJavaModuleIndex(context).getModuleInfoFile(target.getModule(), target.isTests()); + } + + private static JavaModuleIndex getJavaModuleIndex(CompileContext context) { + JpsProject project = context.getProjectDescriptor().getProject(); + File storageRoot = context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot(); + return JpsJavaExtensionService.getInstance().getJavaModuleIndex(project, storageRoot); + } + private static FileFilter createOrFilter(final List filters) { if (filters == null || filters.isEmpty()) return null; return pathname -> { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileRepr.java new file mode 100644 index 000000000000..4555d6c12fa7 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileRepr.java @@ -0,0 +1,97 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import com.intellij.util.io.DataInputOutputUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Set; + +/** + * @author Eugene Zhuravlev + * Date: 30-Sep-17 + */ +public abstract class ClassFileRepr extends Proto { + protected final DependencyContext myContext; + private final int myFileName; + private final Set myUsages; + + public ClassFileRepr( + int access, + int signature, + int name, + @NotNull Set annotations, + final int fileName, final DependencyContext context, final Set usages) { + super(access, signature, name, annotations); + myFileName = fileName; + this.myContext = context; + this.myUsages = usages; + } + + public ClassFileRepr(DependencyContext context, DataInput in) { + super(context, in); + myContext = context; + try { + myFileName = DataInputOutputUtil.readINT(in); + myUsages = RW.read(UsageRepr.externalizer(context), new THashSet<>(), in); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + public int getFileName() { + return myFileName; + } + + public Set getUsages() { + return myUsages; + } + + public boolean addUsage(final UsageRepr.Usage usage) { + return myUsages.add(usage); + } + + protected abstract void updateClassUsages(DependencyContext context, Set s); + + public void toStream(DependencyContext context, PrintStream stream) { + super.toStream(context, stream); + stream.print(" Filename : "); + stream.println(context.getValue(myFileName)); + } + + @Override + public void save(final DataOutput out) { + try { + super.save(out); + DataInputOutputUtil.writeINT(out, myFileName); + RW.save(myUsages, UsageRepr.externalizer(myContext), out); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public int hashCode() { + return 31 * myFileName + name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ClassFileRepr classRepr = (ClassFileRepr)o; + + if (myFileName != classRepr.myFileName) return false; + if (name != classRepr.name) return false; + + return true; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileReprExternalizer.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileReprExternalizer.java new file mode 100644 index 000000000000..ce5f7f183fbc --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassFileReprExternalizer.java @@ -0,0 +1,41 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Eugene Zhuravlev + * Date: 04-Oct-17 + */ +class ClassFileReprExternalizer implements DataExternalizer { + + private static final byte CLASS = 0x1; + private static final byte MODULE = 0x2; + private final DataExternalizer myClassReprExternalizer; + private final DataExternalizer myModuleReprExternalizer; + + public ClassFileReprExternalizer(DependencyContext context) { + myClassReprExternalizer = ClassRepr.externalizer(context); + myModuleReprExternalizer = ModuleRepr.externalizer(context); + } + + public void save(@NotNull DataOutput out, ClassFileRepr value) throws IOException { + if (value instanceof ClassRepr) { + out.writeByte(CLASS); + myClassReprExternalizer.save(out, (ClassRepr)value); + } + else { + out.writeByte(MODULE); + myModuleReprExternalizer.save(out, (ModuleRepr)value); + } + } + + public ClassFileRepr read(@NotNull DataInput in) throws IOException { + return in.readByte() == CLASS ? myClassReprExternalizer.read(in) : myModuleReprExternalizer.read(in); + } +} 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 0b63008a9da8..e5dd19d977c8 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 @@ -31,9 +31,7 @@ import java.util.*; * @author: db * Date: 01.02.11 */ -public class ClassRepr extends Proto { - private final DependencyContext myContext; - private final int myFileName; +public class ClassRepr extends ClassFileRepr { private final TypeRepr.ClassType mySuperClass; private final Set myInterfaces; private final Set myAnnotationTargets; @@ -41,7 +39,6 @@ public class ClassRepr extends Proto { private final Set myFields; private final Set myMethods; - private final Set myUsages; private final int myOuterClassName; private final boolean myIsLocal; @@ -75,19 +72,16 @@ public class ClassRepr extends Proto { return myRetentionPolicy; } - public Set getUsages() { - return myUsages; - } - - public boolean addUsage(final UsageRepr.Usage usage) { - return myUsages.add(usage); - } - public boolean isInterface() { return (access & Opcodes.ACC_INTERFACE) != 0; } - public abstract static class Diff extends Difference { + public abstract static class Diff extends DifferenceImpl { + + Diff(@NotNull Difference delegate) { + super(delegate); + } + public abstract Specifier interfaces(); public abstract Specifier fields(); @@ -119,12 +113,12 @@ public class ClassRepr extends Proto { base |= Difference.SUPERCLASS; } - if (!myUsages.equals(pastClass.myUsages)) { + if (!getUsages().equals(pastClass.getUsages())) { base |= Difference.USAGES; } final int d = base; - return new Diff() { + return new Diff(diff) { @Override public boolean extendsAdded() { if ((d & Difference.SUPERCLASS) <= 0) { @@ -134,21 +128,6 @@ public class ClassRepr extends Proto { return "java/lang/Object".equals(pastSuperName); } - @Override - public boolean packageLocalOn() { - return diff.packageLocalOn(); - } - - @Override - public int addedModifiers() { - return diff.addedModifiers(); - } - - @Override - public int removedModifiers() { - return diff.removedModifiers(); - } - @Override public Difference.Specifier interfaces() { return Difference.make(pastClass.myInterfaces, myInterfaces); @@ -169,10 +148,6 @@ public class ClassRepr extends Proto { return Difference.make(pastClass.myAnnotationTargets, myAnnotationTargets); } - public Specifier annotations() { - return diff.annotations(); - } - @Override public boolean retentionChanged() { return !((myRetentionPolicy == null && pastClass.myRetentionPolicy == RetentionPolicy.CLASS) || @@ -189,11 +164,6 @@ public class ClassRepr extends Proto { public boolean hadValue() { return false; } - - @Override - public boolean weakedAccess() { - return diff.weakedAccess(); - } }; } @@ -211,7 +181,7 @@ public class ClassRepr extends Proto { return result; } - public void updateClassUsages(final DependencyContext context, final Set s) { + protected void updateClassUsages(final DependencyContext context, final Set s) { mySuperClass.updateClassUsages(context, name, s); for (TypeRepr.AbstractType t : myInterfaces) { @@ -239,9 +209,7 @@ public class ClassRepr extends Proto { final boolean localClassFlag, final boolean anonymousClassFlag, final Set usages) { - super(access, sig, name, annotations); - this.myContext = context; - myFileName = fileName; + super(access, sig, name, annotations, fileName, context, usages); mySuperClass = TypeRepr.createClassType(context, superClass); myInterfaces = (Set)TypeRepr.createClassType(context, interfaces, new THashSet<>(1)); myFields = fields; @@ -251,19 +219,17 @@ public class ClassRepr extends Proto { this.myOuterClassName = outerClassName; this.myIsLocal = localClassFlag; this.myIsAnonymous = anonymousClassFlag; - this.myUsages = usages; + updateClassUsages(context, usages); } public ClassRepr(final DependencyContext context, final DataInput in) { super(context, in); try { - this.myContext = context; - myFileName = DataInputOutputUtil.readINT(in); mySuperClass = (TypeRepr.ClassType)TypeRepr.externalizer(context).read(in); - myInterfaces = (Set)RW.read(TypeRepr.externalizer(context), new THashSet<>(1), in); - myFields = (Set)RW.read(FieldRepr.externalizer(context), new THashSet<>(), in); - myMethods = (Set)RW.read(MethodRepr.externalizer(context), new THashSet<>(), in); - myAnnotationTargets = (Set)RW.read(UsageRepr.AnnotationUsage.elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in); + myInterfaces = RW.read(TypeRepr.externalizer(context), new THashSet<>(1), in); + myFields = RW.read(FieldRepr.externalizer(context), new THashSet<>(), in); + myMethods = RW.read(MethodRepr.externalizer(context), new THashSet<>(), in); + myAnnotationTargets = RW.read(UsageRepr.AnnotationUsage.elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in); final String s = RW.readUTF(in); @@ -273,7 +239,6 @@ public class ClassRepr extends Proto { int flags = DataInputOutputUtil.readINT(in); myIsLocal = (flags & LOCAL_MASK) != 0; myIsAnonymous = (flags & ANONYMOUS_MASK) != 0; - myUsages =(Set)RW.read(UsageRepr.externalizer(context), new THashSet<>(), in); } catch (IOException e) { throw new BuildDataCorruptedException(e); @@ -287,7 +252,6 @@ public class ClassRepr extends Proto { public void save(final DataOutput out) { try { super.save(out); - DataInputOutputUtil.writeINT(out, myFileName); mySuperClass.save(out); RW.save(myInterfaces, out); RW.save(myFields, out); @@ -296,32 +260,12 @@ public class ClassRepr extends Proto { RW.writeUTF(out, myRetentionPolicy == null ? "" : myRetentionPolicy.toString()); DataInputOutputUtil.writeINT(out, myOuterClassName); DataInputOutputUtil.writeINT(out, (myIsLocal ? LOCAL_MASK:0) | (myIsAnonymous ? ANONYMOUS_MASK : 0)); - - RW.save(myUsages, UsageRepr.externalizer(myContext), out); } catch (IOException e) { throw new BuildDataCorruptedException(e); } } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ClassRepr classRepr = (ClassRepr)o; - - if (myFileName != classRepr.myFileName) return false; - if (name != classRepr.name) return false; - - return true; - } - - @Override - public int hashCode() { - return 31 * myFileName + name; - } - public UsageRepr.Usage createUsage() { return UsageRepr.createClassUsage(myContext, name); } @@ -400,9 +344,6 @@ public class ClassRepr extends Proto { public void toStream(final DependencyContext context, final PrintStream stream) { super.toStream(context, stream); - stream.print(" Filename : "); - stream.println(context.getValue(myFileName)); - stream.print(" Superclass : "); stream.println(mySuperClass == null ? "" : mySuperClass.getDescr(context)); @@ -494,7 +435,7 @@ public class ClassRepr extends Proto { final List usages = new LinkedList<>(); - for (final UsageRepr.Usage u : myUsages) { + for (final UsageRepr.Usage u : getUsages()) { final ByteArrayOutputStream bas = new ByteArrayOutputStream(); u.toStream(myContext, new PrintStream(bas)); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassfileAnalyzer.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassfileAnalyzer.java index da8507ae933f..7229b89267e8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassfileAnalyzer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ClassfileAnalyzer.java @@ -16,7 +16,6 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.util.SmartList; import gnu.trove.THashMap; @@ -29,10 +28,7 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author: db @@ -242,6 +238,51 @@ class ClassfileAnalyzer { } } + private class ModuleCrawler extends ModuleVisitor { + public ModuleCrawler() { + super(ASM_API_VERSION); + } + + @Override + public void visitMainClass(String mainClass) { + myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(mainClass))); + } + + @Override + public void visitRequire(String module, int access, String version) { + if (isExplicit(access)) { + // collect non-synthetic dependencies only + myModuleRequires.add(new ModuleRequiresRepr(myContext, access, myContext.get(module), version)); + } + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + if (isExplicit(access)) { + // collect non-synthetic dependencies only + myModuleExports.add(new ModulePackageRepr(myContext, myContext.get(packaze), modules != null? Arrays.asList(modules) : Collections.emptyList())); + } + } + + public void visitUse(String service) { + myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(service))); + } + + @Override + public void visitProvide(String service, String... providers) { + myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(service))); + if (providers != null) { + for (String provider : providers) { + myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(provider))); + } + } + } + + private boolean isExplicit(int access) { + return (access & (Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED)) == 0; + } + } + private void processSignature(final String sig) { if (sig != null) { try { @@ -278,11 +319,12 @@ class ClassfileAnalyzer { } }; - private Boolean myTakeIntoAccount = false; - + private boolean myTakeIntoAccount = false; + private boolean myIsModule = false; private final int myFileName; private int myAccess; private int myName; + private int myVersion; // for class contains a class bytecode version, for module contains a module version private String mySuperClass; private String[] myInterfaces; private String mySignature; @@ -302,6 +344,9 @@ class ClassfileAnalyzer { private final Map> myAnnotationTargets = new THashMap<>(); private final Set myAnnotations = new THashSet<>(); + private final Set myModuleRequires = new THashSet<>(); + private final Set myModuleExports = new THashSet<>(); + public ClassCrawler(final int fn) { super(ASM_API_VERSION); myFileName = fn; @@ -311,17 +356,18 @@ class ClassfileAnalyzer { return (access & Opcodes.ACC_PRIVATE) == 0; } - public Pair> getResult() { - ClassRepr repr = myTakeIntoAccount ? new ClassRepr( + public ClassFileRepr getResult() { + if (!myTakeIntoAccount) { + return null; + } + if (myIsModule) { + return new ModuleRepr(myContext, myAccess, myVersion, myFileName, myName, myModuleRequires, myModuleExports, myUsages); + } + return new ClassRepr( myContext, myAccess, myFileName, myName, myContext.get(mySignature), myContext.get(mySuperClass), myInterfaces, myFields, myMethods, myAnnotations, myTargets, myRetentionPolicy, myContext.get(myOuterClassName.get()), myLocalClassFlag.get(), - myAnonymousClassFlag.get(), myUsages) : null; - - if (repr != null) { - repr.updateClassUsages(myContext, myUsages); - } - - return Pair.create(repr, myUsages); + myAnonymousClassFlag.get(), myUsages + ); } @Override @@ -330,6 +376,7 @@ class ClassfileAnalyzer { myAccess = access; myName = myContext.get(name); + myVersion = version; mySignature = sig; mySuperClass = superName; myInterfaces = interfaces; @@ -364,6 +411,15 @@ class ClassfileAnalyzer { } } + @Override + public ModuleVisitor visitModule(String name, int access, String version) { + myIsModule = true; + myAccess = access; + myName = myContext.get(name); + myVersion = myContext.get(version); + return new ModuleCrawler(); + } + @Override public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { if (desc.equals("Ljava/lang/annotation/Target;")) { @@ -779,7 +835,7 @@ class ClassfileAnalyzer { } } - public Pair> analyze(int fileName, ClassReader cr) { + public ClassFileRepr analyze(int fileName, ClassReader cr) { ClassCrawler visitor = new ClassCrawler(fileName); try { diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Difference.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Difference.java index f95fcfeb1063..ab595b0ce6e0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Difference.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Difference.java @@ -56,6 +56,26 @@ public abstract class Difference { } public static Specifier make(final Set past, final Set now) { + if ((past == null || past.isEmpty()) && (now == null || now.isEmpty())) { + return new Specifier() { + public Collection added() { + return Collections.emptySet(); + } + + public Collection removed() { + return Collections.emptySet(); + } + + public Collection> changed() { + return Collections.emptySet(); + } + + public boolean unchanged() { + return true; + } + }; + } + if (past == null) { final Collection _now = Collections.unmodifiableCollection(now); return new Specifier() { @@ -78,11 +98,9 @@ public abstract class Difference { } final Set added = new HashSet<>(now); - added.removeAll(past); final Set removed = new HashSet<>(past); - removed.removeAll(now); final Set> changed; @@ -133,7 +151,7 @@ public abstract class Difference { }; } - private static boolean canContainChangedElements(final Set past, final Set now) { + private static boolean canContainChangedElements(final Collection past, final Collection now) { if (past != null && now != null && !past.isEmpty() && !now.isEmpty()) { return past.iterator().next() instanceof Proto; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/DifferenceImpl.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/DifferenceImpl.java new file mode 100644 index 000000000000..6f2827fab41c --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/DifferenceImpl.java @@ -0,0 +1,49 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene Zhuravlev + * Date: 02-Oct-17 + */ +class DifferenceImpl extends Difference{ + + private final Difference myDelegate; + + public DifferenceImpl(@NotNull Difference delegate) { + myDelegate = delegate; + } + + public int base() { + return myDelegate.base(); + } + + public boolean no() { + return myDelegate.no(); + } + + public boolean weakedAccess() { + return myDelegate.weakedAccess(); + } + + public int addedModifiers() { + return myDelegate.addedModifiers(); + } + + public int removedModifiers() { + return myDelegate.removedModifiers(); + } + + public boolean packageLocalOn() { + return myDelegate.packageLocalOn(); + } + + public boolean hadValue() { + return myDelegate.hadValue(); + } + + public Specifier annotations() { + return myDelegate.annotations(); + } +} 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 29188578e8be..6d0a86c67f28 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 @@ -53,12 +53,6 @@ public class Mappings { private static final IntInlineKeyDescriptor INT_KEY_DESCRIPTOR = new IntInlineKeyDescriptor(); private static final int DEFAULT_SET_CAPACITY = 32; private static final float DEFAULT_SET_LOAD_FACTOR = 0.98f; - private static final CollectionFactory ourClassSetConstructor = new CollectionFactory() { - public Set create() { - // for IDEA codebase on average there is no more than 2.5 classes out of one source file, so we use smaller estimate - return new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR); - } - }; private final boolean myIsDelta; private final boolean myDeltaIsTransient; @@ -67,7 +61,7 @@ public class Mappings { private final TIntHashSet myChangedClasses; private final THashSet myChangedFiles; - private final Set> myDeletedClasses; + private final Set> myDeletedClasses; private final Set myAddedClasses; private final Object myLock; private final File myRootDir; @@ -85,7 +79,7 @@ public class Mappings { values: class names that use the class registered as the key */ private IntIntMultiMaplet myClassToClassDependency; - private ObjectObjectMultiMaplet mySourceFileToClasses; + private ObjectObjectMultiMaplet mySourceFileToClasses; private IntObjectMultiMaplet myClassToSourceFile; /** * [short className] -> list of FQ names @@ -148,7 +142,7 @@ public class Mappings { myClassToSubclasses = new IntIntTransientMultiMaplet(); myClassToClassDependency = new IntIntTransientMultiMaplet(); myShortClassNameIndex = null; - mySourceFileToClasses = new ObjectObjectTransientMultiMaplet<>(FileUtil.FILE_HASHING_STRATEGY, ourClassSetConstructor); + mySourceFileToClasses = new ObjectObjectTransientMultiMaplet<>(FileUtil.FILE_HASHING_STRATEGY, () -> new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR)); myClassToSourceFile = new IntObjectTransientMultiMaplet<>(fileCollectionFactory); } else { @@ -159,12 +153,12 @@ public class Mappings { myClassToClassDependency = new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_CLASS), INT_KEY_DESCRIPTOR); myShortClassNameIndex = myIsDelta? null : new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, SHORT_NAMES), INT_KEY_DESCRIPTOR); mySourceFileToClasses = new ObjectObjectPersistentMultiMaplet<>( - DependencyContext.getTableFile(myRootDir, SOURCE_TO_CLASS), new FileKeyDescriptor(), ClassRepr.externalizer(myContext), - ourClassSetConstructor + DependencyContext.getTableFile(myRootDir, SOURCE_TO_CLASS), new FileKeyDescriptor(), new ClassFileReprExternalizer(myContext), + () -> new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR) + ); + myClassToSourceFile = new IntObjectPersistentMultiMaplet<>( + DependencyContext.getTableFile(myRootDir, CLASS_TO_SOURCE), INT_KEY_DESCRIPTOR, new FileKeyDescriptor(), fileCollectionFactory ); - myClassToSourceFile = - new IntObjectPersistentMultiMaplet<>(DependencyContext.getTableFile(myRootDir, CLASS_TO_SOURCE), INT_KEY_DESCRIPTOR, - new FileKeyDescriptor(), fileCollectionFactory); } } @@ -196,14 +190,19 @@ public class Mappings { } @Nullable - private ClassRepr getReprByName(final @Nullable File source, final int qName) { + private ClassRepr getClassReprByName(final @Nullable File source, final int qName) { + final ClassFileRepr reprByName = getReprByName(source, qName); + return reprByName instanceof ClassRepr? (ClassRepr)reprByName : null; + } + + @Nullable + private ClassFileRepr getReprByName(@Nullable File source, int qName) { final Collection sources = source != null? Collections.singleton(source) : myClassToSourceFile.get(qName); if (sources != null) { for (File src : sources) { - final Collection reprs = mySourceFileToClasses.get(src); - + final Collection reprs = mySourceFileToClasses.get(src); if (reprs != null) { - for (ClassRepr repr : reprs) { + for (ClassFileRepr repr : reprs) { if (repr.name == qName) { return repr; } @@ -236,9 +235,9 @@ public class Mappings { private final LinkedBlockingQueue myPostPasses = new LinkedBlockingQueue<>(); private void runPostPasses() { - final Set> deleted = myDeletedClasses; + final Set> deleted = myDeletedClasses; if (deleted != null) { - for (Pair pair : deleted) { + for (Pair pair : deleted) { final int deletedClassName = pair.first.name; final Collection sources = myClassToSourceFile.get(deletedClassName); if (sources == null || sources.isEmpty()) { // if really deleted and not e.g. moved @@ -270,7 +269,7 @@ public class Mappings { myMappings = mappings; } - void appendDependents(final ClassRepr c, final TIntHashSet result) { + void appendDependents(final ClassFileRepr c, final TIntHashSet result) { final TIntHashSet depClasses = myClassToClassDependency.get(c.name); if (depClasses != null) { @@ -279,7 +278,7 @@ public class Mappings { } void propagateMemberAccessRec(final TIntHashSet acc, final boolean isField, final boolean root, final MemberComparator comparator, final int reflcass) { - final ClassRepr repr = reprByName(reflcass); + final ClassRepr repr = classReprByName(reflcass); if (repr != null) { if (!root) { final Set members = isField ? repr.getFields() : repr.getMethods(); @@ -370,7 +369,7 @@ public class Mappings { } final TIntHashSet _visitedClasses = visitedClasses; subClasses.forEach(subClassName -> { - final ClassRepr r = reprByName(subClassName); + final ClassRepr r = classReprByName(subClassName); if (r != null) { boolean cont = true; @@ -415,7 +414,7 @@ public class Mappings { if (!visitedClasses.add(superName) || superName == myObjectClassName) { continue; } - final ClassRepr superClass = reprByName(superName); + final ClassRepr superClass = classReprByName(superName); if (superClass != null) { for (MethodRepr mm : superClass.findMethods(predicate)) { if (isVisibleIn(superClass, mm, fromClass)) { @@ -439,7 +438,7 @@ public class Mappings { if (!visitedClasses.add(superName) || superName == myObjectClassName) { continue; } - final ClassRepr superClass = reprByName(superName); + final ClassRepr superClass = classReprByName(superName); if (superClass == null || extendsLibraryClass(superClass, visitedClasses)) { return true; } @@ -456,7 +455,7 @@ public class Mappings { if (!visitedClasses.add(superName)) { continue; // prevent SOE } - final ClassRepr superClass = reprByName(superName); + final ClassRepr superClass = classReprByName(superName); if (superClass != null) { boolean cont = true; final Collection methods = superClass.findMethods(predicate); @@ -485,7 +484,7 @@ public class Mappings { if (!visitedClasses.add(supername) || supername == myObjectClassName) { continue; } - final ClassRepr superClass = reprByName(supername); + final ClassRepr superClass = classReprByName(supername); if (superClass != null) { final FieldRepr ff = superClass.findField(f.name); if (ff != null && isVisibleIn(superClass, ff, fromClass)) { @@ -507,7 +506,7 @@ public class Mappings { if (!visitedClasses.add(supername) || supername == myObjectClassName) { continue; } - final ClassRepr superClass = reprByName(supername); + final ClassRepr superClass = classReprByName(supername); if (superClass != null) { final FieldRepr ff = superClass.findField(f.name); if (ff != null && isVisibleIn(superClass, ff, fromClass)) { @@ -523,9 +522,21 @@ public class Mappings { } @Nullable - ClassRepr reprByName(final int name) { + ClassRepr classReprByName(final int name) { + final ClassFileRepr r = reprByName(name); + return r instanceof ClassRepr? (ClassRepr)r : null; + } + + @Nullable + ModuleRepr moduleReprByName(final int name) { + final ClassFileRepr r = reprByName(name); + return r instanceof ModuleRepr? (ModuleRepr)r : null; + } + + @Nullable + ClassFileRepr reprByName(final int name) { if (myMappings != null) { - final ClassRepr r = myMappings.getReprByName(null, name); + final ClassFileRepr r = myMappings.getReprByName(null, name); if (r != null) { return r; @@ -541,7 +552,7 @@ public class Mappings { return Boolean.TRUE; } - final ClassRepr repr = reprByName(who); + final ClassRepr repr = classReprByName(who); if (repr != null) { if (visitedClasses == null) { @@ -598,7 +609,7 @@ public class Mappings { } boolean isFieldVisible(final int className, final FieldRepr field) { - final ClassRepr r = reprByName(className); + final ClassRepr r = classReprByName(className); if (r == null || r.getFields().contains(field)) { return true; } @@ -606,7 +617,7 @@ public class Mappings { } void collectSupersRecursively(final int className, @NotNull final TIntHashSet container) { - final ClassRepr classRepr = reprByName(className); + final ClassRepr classRepr = classReprByName(className); if (classRepr != null) { final int[] supers = classRepr.getSupers(); if (container.addAll(supers)) { @@ -637,7 +648,7 @@ public class Mappings { if (usages) { debug("Class usages affection requested"); - final ClassRepr classRepr = reprByName(className); + final ClassRepr classRepr = classReprByName(className); if (classRepr != null) { debug("Added class usage for ", classRepr.name); affectedUsages.add(classRepr.createUsage()); @@ -698,11 +709,50 @@ public class Mappings { } } - public abstract class UsageConstraint { - public abstract boolean checkResidence(final int residence); + void affectModule(ModuleRepr m, final Collection affectedFiles) { + final Collection depFiles = myClassToSourceFile.get(m.name); + if (depFiles != null) { + debug("Affecting module ", m.name); + affectedFiles.addAll(depFiles); + } } - public class FileFilterConstraint extends UsageConstraint { + void affectDependentModules(Differential.DiffState state, final int moduleName, @Nullable UsageConstraint constraint, boolean checkTransitive) { + new Object() { + final TIntHashSet visited = new TIntHashSet(); + + void perform(final int modName) { + final TIntHashSet depNames = myClassToClassDependency.get(modName); + if (depNames != null && !depNames.isEmpty()) { + final TIntHashSet next = new TIntHashSet(); + final UsageRepr.Usage moduleUsage = UsageRepr.createModuleUsage(myContext, modName); + state.myAffectedUsages.add(moduleUsage); + final UsageConstraint prevConstraint = state.myUsageConstraints.put(moduleUsage, constraint == null? UsageConstraint.ANY : constraint); + if (prevConstraint != null) { + state.myUsageConstraints.put(moduleUsage, prevConstraint.or(constraint)); + } + depNames.forEach(depName -> { + if (visited.add(depName)) { + final ClassFileRepr depRepr = reprByName(depName); + if (depRepr instanceof ModuleRepr) { + state.myDependants.add(depName); + if (checkTransitive && ((ModuleRepr)depRepr).requiresTransitevely(modName)) { + next.add(depName); + } + } + } + return true; + }); + next.forEach(m -> { + perform(m); + return true; + }); + } + } + }.perform(moduleName); + } + + public class FileFilterConstraint implements UsageConstraint { @NotNull private final DependentFilesFilter myFilter; @@ -724,7 +774,7 @@ public class Mappings { } } - public class PackageConstraint extends UsageConstraint { + public class PackageConstraint implements UsageConstraint { public final String packageName; public PackageConstraint(final String packageName) { @@ -751,34 +801,6 @@ public class Mappings { return inheritorOf == null || !inheritorOf || super.checkResidence(residence); } } - - public class NegationConstraint extends UsageConstraint { - final UsageConstraint x; - - public NegationConstraint(UsageConstraint x) { - this.x = x; - } - - @Override - public boolean checkResidence(final int residence) { - return !x.checkResidence(residence); - } - } - - public class IntersectionConstraint extends UsageConstraint { - final UsageConstraint x; - final UsageConstraint y; - - public IntersectionConstraint(final UsageConstraint x, final UsageConstraint y) { - this.x = x; - this.y = y; - } - - @Override - public boolean checkResidence(final int residence) { - return x.checkResidence(residence) && y.checkResidence(residence); - } - } } void affectAll(final int className, @NotNull final File sourceFile, final Collection affectedFiles, final Collection alreadyCompiledFiles, @Nullable final DependentFilesFilter filter) { @@ -1022,11 +1044,19 @@ public class Mappings { private class FileClasses { final File myFileName; - final Set myFileClasses; + final Set myFileClasses = new THashSet<>(); + final Set myFileModules = new THashSet<>(); - FileClasses(File fileName, Collection fileClasses) { - this.myFileName = fileName; - this.myFileClasses = new HashSet<>(fileClasses); + FileClasses(File fileName, Collection fileContent) { + myFileName = fileName; + for (ClassFileRepr repr : fileContent) { + if (repr instanceof ClassRepr) { + myFileClasses.add((ClassRepr)repr); + } + else { + myFileModules.add((ModuleRepr)repr); + } + } } } @@ -1035,12 +1065,14 @@ public class Mappings { final public Set myAffectedUsages = new HashSet<>(); final public Set myAnnotationQuery = new HashSet<>(); - final public Map myUsageConstraints = new HashMap<>(); + final public Map myUsageConstraints = new HashMap<>(); final Difference.Specifier myClassDiff; + final Difference.Specifier myModulesDiff; - private DiffState(Difference.Specifier classDiff) { - this.myClassDiff = classDiff; + DiffState(Difference.Specifier classDiff, Difference.Specifier modulesDiff) { + myClassDiff = classDiff; + myModulesDiff = modulesDiff; } } @@ -1120,10 +1152,10 @@ public class Mappings { if (removed != null) { for (final String file : removed) { final File sourceFile = new File(file); - final Collection classes = mySourceFileToClasses.get(sourceFile); + final Collection classes = mySourceFileToClasses.get(sourceFile); if (classes != null) { - for (ClassRepr c : classes) { + for (ClassFileRepr c : classes) { debug("Affecting usages of removed class ", c.name); affectAll(c.name, sourceFile, myAffectedFiles, myCompiledFiles, myFilter); } @@ -1160,7 +1192,7 @@ public class Mappings { if (!m.isPrivate() && m.name != myInitName) { if (oldItRef == null) { - oldItRef = new Ref<>(getReprByName(null, it.name)); // lazy init + oldItRef = new Ref<>(getClassReprByName(null, it.name)); // lazy init } final ClassRepr oldIt = oldItRef.get(); @@ -1240,7 +1272,7 @@ public class Mappings { final TIntHashSet subClasses = getAllSubclasses(it.name); subClasses.forEach(subClass -> { - final ClassRepr r = myFuture.reprByName(subClass); + final ClassRepr r = myFuture.classReprByName(subClass); if (r == null) { return true; } @@ -1248,7 +1280,7 @@ public class Mappings { if (sourceFileNames != null && !myCompiledFiles.containsAll(sourceFileNames)) { final int outerClass = r.getOuterClassName(); if (!isEmpty(outerClass)) { - final ClassRepr outerClassRepr = myFuture.reprByName(outerClass); + final ClassRepr outerClassRepr = myFuture.classReprByName(outerClass); if (outerClassRepr != null && (myFuture.isMethodVisible(outerClassRepr, m) || myFuture.extendsLibraryClass(outerClassRepr, null))) { myAffectedFiles.addAll(sourceFileNames); for (File sourceFileName : sourceFileNames) { @@ -1320,7 +1352,7 @@ public class Mappings { if (!m.isAbstract()) { propagated.forEach(p -> { if (p != it.name) { - final ClassRepr s = myFuture.reprByName(p); + final ClassRepr s = myFuture.classReprByName(p); if (s != null) { final Collection> overridenInS = myFuture.findOverriddenMethods(m, s); @@ -1538,7 +1570,7 @@ public class Mappings { if (!f.isPrivate()) { final TIntHashSet subClasses = getAllSubclasses(classRepr.name); subClasses.forEach(subClass -> { - final ClassRepr r = myFuture.reprByName(subClass); + final ClassRepr r = myFuture.classReprByName(subClass); if (r != null) { final Collection sourceFileNames = myClassToSourceFile.get(subClass); if (sourceFileNames != null && !myCompiledFiles.containsAll(sourceFileNames)) { @@ -1591,19 +1623,18 @@ public class Mappings { // nothing } else { - Util.UsageConstraint constraint; + UsageConstraint constraint; if ((ff.isProtected() && f.isPublic()) || (f.isProtected() && ff.isPublic()) || (ff.isPackageLocal() && f.isProtected())) { - constraint = myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name)); + constraint = myFuture.new InheritanceConstraint(cc.name).negate(); } else if (ff.isPublic() && ff.isPackageLocal()) { - constraint = myFuture.new NegationConstraint(myFuture.new PackageConstraint(cc.getPackageName())); + constraint = myFuture.new PackageConstraint(cc.getPackageName()).negate(); } else { - constraint = - myFuture.new IntersectionConstraint(myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name)), - myFuture.new NegationConstraint( - myFuture.new PackageConstraint(cc.getPackageName()))); + final Util.InheritanceConstraint inherit = myFuture.new InheritanceConstraint(cc.name); + final Util.PackageConstraint matchPackage = myFuture.new PackageConstraint(cc.getPackageName()); + constraint = inherit.negate().and(matchPackage.negate()); } for (final UsageRepr.Usage usage : localUsages) { @@ -1803,7 +1834,7 @@ public class Mappings { if (superClassChanged) { myDelta.registerRemovedSuperClass(changedClass.name, changedClass.getSuperClass().className); - final ClassRepr newClass = myDelta.getReprByName(null, changedClass.name); + final ClassRepr newClass = myDelta.getClassReprByName(null, changedClass.name); assert (newClass != null); @@ -2143,12 +2174,12 @@ public class Mappings { debug("Dependent class: ", depClass); - final ClassRepr classRepr = getReprByName(depFile, depClass); - if (classRepr == null) { + final ClassFileRepr repr = getReprByName(depFile, depClass); + if (repr == null) { return; } - final Set depUsages = classRepr.getUsages(); + final Set depUsages = repr.getUsages(); if (depUsages == null || depUsages.isEmpty()) { return; } @@ -2164,7 +2195,7 @@ public class Mappings { } } else if (state.myAffectedUsages.contains(usage)) { - final Util.UsageConstraint constraint = state.myUsageConstraints.get(usage); + final UsageConstraint constraint = state.myUsageConstraints.get(usage); if (constraint == null) { debug("Added file with no constraints"); myAffectedFiles.add(depFile); @@ -2196,13 +2227,13 @@ public class Mappings { processDisappearedClasses(); final List newClasses = new ArrayList<>(); - myDelta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { + myDelta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { @Override - public boolean execute(File fileName, Collection classes) { + public boolean execute(File fileName, Collection content) { if (myFilesToCompile == null || myFilesToCompile.contains(fileName)) { // Consider only files actually compiled in this round. // For other sources the list of classes taken from this map will be possibly incomplete. - newClasses.add(new FileClasses(fileName, classes)); + newClasses.add(new FileClasses(fileName, content)); } return true; } @@ -2210,10 +2241,28 @@ public class Mappings { for (final FileClasses compiledFile : newClasses) { final File fileName = compiledFile.myFileName; - final Set classes = compiledFile.myFileClasses; - final Set pastClasses = (Set)mySourceFileToClasses.get(fileName); - final DiffState state = new DiffState(Difference.make(pastClasses, classes)); - + final Set pastClasses = new THashSet<>(); + final Set pastModules = new THashSet<>(); + final Collection past = mySourceFileToClasses.get(fileName); + if (past != null) { + for (ClassFileRepr repr : past) { + if (repr instanceof ClassRepr) { + pastClasses.add((ClassRepr)repr); + } + else { + pastModules.add((ModuleRepr)repr); + } + } + } + + final DiffState state = new DiffState( + Difference.make(pastClasses, compiledFile.myFileClasses), + Difference.make(pastModules, compiledFile.myFileModules) + ); + + if (!myEasyMode) { + processModules(state, fileName); + } if (!processChangedClasses(state)) { if (!myEasyMode) { // turning non-incremental @@ -2280,6 +2329,112 @@ public class Mappings { } } } + + private void processModules(final DiffState state, File fileName) { + final Difference.Specifier modulesDiff = state.myModulesDiff; + if (modulesDiff.unchanged()) { + return; + } + for (ModuleRepr removedModule : modulesDiff.removed()) { + myDelta.addDeletedClass(removedModule, fileName); + myPresent.affectDependentModules(state, removedModule.name, null, true); + } + + for (Pair pair : modulesDiff.changed()) { + final ModuleRepr moduleRepr = pair.first; + final ModuleRepr.Diff d = pair.second; + boolean affectSelf = false; + boolean affectDeps = false; + UsageConstraint constraint = null; + + myDelta.addChangedClass(moduleRepr.name); + + if (d.versionChanged()) { + final int version = moduleRepr.getVersion(); + myPresent.affectDependentModules(state, moduleRepr.name, new UsageConstraint() { + public boolean checkResidence(int dep) { + final ModuleRepr depModule = myPresent.moduleReprByName(dep); + if (depModule != null) { + for (ModuleRequiresRepr requires : depModule.getRequires()) { + if (requires.name == moduleRepr.name && requires.getVersion() == version) { + return true; + } + } + } + return false; + } + }, false); + } + + final Difference.Specifier requiresDiff = d.requires(); + for (ModuleRequiresRepr removed : requiresDiff.removed()) { + affectSelf = true; + if (removed.isTransitive()) { + affectDeps = true; + constraint = UsageConstraint.ANY; + break; + } + } + for (Pair changed : requiresDiff.changed()) { + affectSelf |= changed.second.versionChanged(); + if (changed.second.becameNonTransitive()) { + affectDeps = true; + // we could have created more precise constraint here: analyze if required module (recursively) + // has only qualified exports that include given module's name. But this seems to be excessive since + // in most cases module's exports are unqualified, so that any other module can access the exported API. + constraint = UsageConstraint.ANY; + } + } + + final Difference.Specifier exportsDiff = d.exports(); + + if (!affectDeps) { + for (ModulePackageRepr removedPackage : exportsDiff.removed()) { + affectDeps = true; + if (!removedPackage.isQualified()) { + constraint = UsageConstraint.ANY; + break; + } + for (Integer name : removedPackage.getModuleNames()) { + final UsageConstraint matchName = UsageConstraint.exactMatch(name); + if (constraint == null) { + constraint = matchName; + } + else { + constraint = constraint.or(matchName); + } + } + } + } + + if (!affectDeps || constraint != UsageConstraint.ANY) { + for (Pair p : exportsDiff.changed()) { + final Collection removedModuleNames = p.second.targetModules().removed(); + affectDeps |= !removedModuleNames.isEmpty(); + if (!removedModuleNames.isEmpty()) { + affectDeps = true; + for (Integer name : removedModuleNames) { + final UsageConstraint matchName = UsageConstraint.exactMatch(name); + if (constraint == null) { + constraint = matchName; + } + else { + constraint = constraint.or(matchName); + } + } + } + } + } + + if (affectSelf) { + myPresent.affectModule(moduleRepr, myAffectedFiles); + } + if (affectDeps) { + myPresent.affectDependentModules(state, moduleRepr.name, constraint, true); + } + } + } + } public void differentiateOnRebuild(final Mappings delta) { @@ -2304,11 +2459,9 @@ public class Mappings { return new Differential(delta, removed, filesToCompile, compiledWithErrors, compiledFiles, affectedFiles, filter, constantSearch).differentiate(); } - private void cleanupBackDependency(final int className, - @Nullable Set usages, - final IntIntMultiMaplet buffer) { + private void cleanupBackDependency(final int className, @Nullable Set usages, final IntIntMultiMaplet buffer) { if (usages == null) { - final ClassRepr repr = getReprByName(null, className); + final ClassFileRepr repr = getReprByName(null, className); if (repr != null) { usages = repr.getUsages(); @@ -2322,7 +2475,7 @@ public class Mappings { } } - private void cleanupRemovedClass(final Mappings delta, @NotNull final ClassRepr cr, File sourceFile, final Set usages, final IntIntMultiMaplet dependenciesTrashBin) { + private void cleanupRemovedClass(final Mappings delta, @NotNull final ClassFileRepr cr, File sourceFile, final Set usages, final IntIntMultiMaplet dependenciesTrashBin) { final int className = cr.name; // it is safe to cleanup class information if it is mapped to non-existing files only @@ -2346,8 +2499,10 @@ public class Mappings { } } - for (final int superSomething : cr.getSupers()) { - delta.registerRemovedSuperClass(className, superSomething); + if (cr instanceof ClassRepr) { + for (final int superSomething : ((ClassRepr)cr).getSupers()) { + delta.registerRemovedSuperClass(className, superSomething); + } } cleanupBackDependency(className, usages, dependenciesTrashBin); @@ -2355,8 +2510,11 @@ public class Mappings { myClassToClassDependency.remove(className); myClassToSubclasses.remove(className); myClassToSourceFile.remove(className); - if (!cr.isLocal() && !cr.isAnonymous()) { - myShortClassNameIndex.removeFrom(myContext.get(cr.getShortName()), className); + if (cr instanceof ClassRepr) { + final ClassRepr _cr = (ClassRepr)cr; + if (!_cr.isLocal() && !_cr.isAnonymous()) { + myShortClassNameIndex.removeFrom(myContext.get(_cr.getShortName()), className); + } } } @@ -2374,10 +2532,10 @@ public class Mappings { if (removed != null) { for (final String file : removed) { final File deletedFile = new File(file); - final Set fileClasses = (Set)mySourceFileToClasses.get(deletedFile); + final Set fileClasses = (Set)mySourceFileToClasses.get(deletedFile); if (fileClasses != null) { - for (final ClassRepr aClass : fileClasses) { + for (final ClassFileRepr aClass : fileClasses) { cleanupRemovedClass(delta, aClass, deletedFile, aClass.getUsages(), dependenciesTrashBin); } mySourceFileToClasses.remove(deletedFile); @@ -2386,8 +2544,8 @@ public class Mappings { } if (!delta.isRebuild()) { - for (final Pair pair : delta.getDeletedClasses()) { - final ClassRepr deletedClass = pair.first; + for (final Pair pair : delta.getDeletedClasses()) { + final ClassFileRepr deletedClass = pair.first; cleanupRemovedClass(delta, deletedClass, pair.second, deletedClass.getUsages(), dependenciesTrashBin); } for (ClassRepr repr : delta.getAddedClasses()) { @@ -2450,7 +2608,7 @@ public class Mappings { }); delta.getChangedFiles().forEach(fileName -> { - final Collection classes = delta.mySourceFileToClasses.get(fileName); + final Collection classes = delta.mySourceFileToClasses.get(fileName); mySourceFileToClasses.replace(fileName, classes); return true; }); @@ -2459,9 +2617,9 @@ public class Mappings { // In case some of these sources was not compiled, but the class was changed, we need to update // sourceToClasses mapping for such sources to include the updated ClassRepr version of the changed class final THashSet unchangedSources = new THashSet<>(FileUtil.FILE_HASHING_STRATEGY); - delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { + delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { @Override - public boolean execute(File source, Collection b) { + public boolean execute(File source, Collection b) { unchangedSources.add(source); return true; } @@ -2469,11 +2627,11 @@ public class Mappings { unchangedSources.removeAll(delta.getChangedFiles()); if (!unchangedSources.isEmpty()) { unchangedSources.forEach(unchangedSource -> { - final Collection updatedClasses = delta.mySourceFileToClasses.get(unchangedSource); + final Collection updatedClasses = delta.mySourceFileToClasses.get(unchangedSource); if (updatedClasses != null && !updatedClasses.isEmpty()) { - final List classesToPut = new ArrayList<>(); + final List classesToPut = new ArrayList<>(); final TIntHashSet updatedClassNames = new TIntHashSet(); - for (ClassRepr aClass : updatedClasses) { + for (ClassFileRepr aClass : updatedClasses) { // from all generated classes on this round consider only 'differentiated' ones, for // which we can reliably say that the class has changed. Keep classes, for which no such checks were made, // to make it possible to create a diff and compare changes on next compilation rounds. @@ -2482,9 +2640,9 @@ public class Mappings { updatedClassNames.add(aClass.name); } } - Collection currentClasses = mySourceFileToClasses.get(unchangedSource); + final Collection currentClasses = mySourceFileToClasses.get(unchangedSource); if (currentClasses != null) { - for (ClassRepr aClass : currentClasses) { + for (ClassFileRepr aClass : currentClasses) { if (!updatedClassNames.contains(aClass.name)) { classesToPut.add(aClass); } @@ -2500,11 +2658,14 @@ public class Mappings { myClassToSubclasses.putAll(delta.myClassToSubclasses); myClassToSourceFile.replaceAll(delta.myClassToSourceFile); mySourceFileToClasses.replaceAll(delta.mySourceFileToClasses); - delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { - public boolean execute(File src, Collection classes) { - for (ClassRepr repr : classes) { - if (!repr.isAnonymous() && !repr.isLocal()) { - myShortClassNameIndex.put(myContext.get(repr.getShortName()), repr.name); + delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { + public boolean execute(File src, Collection classes) { + for (ClassFileRepr repr : classes) { + if (repr instanceof ClassRepr) { + final ClassRepr clsRepr = (ClassRepr)repr; + if (!clsRepr.isAnonymous() && !clsRepr.isLocal()) { + myShortClassNameIndex.put(myContext.get(clsRepr.getShortName()), repr.name); + } } } return true; @@ -2564,25 +2725,25 @@ public class Mappings { public void associate(String classFileName, Collection sources, ClassReader cr) { synchronized (myLock) { final int classFileNameS = myContext.get(classFileName); - final Pair> result = new ClassfileAnalyzer(myContext).analyze(classFileNameS, cr); - final ClassRepr repr = result.first; - if (repr != null) { - final Set localUsages = result.second; - final int className = repr.name; + final ClassFileRepr result = new ClassfileAnalyzer(myContext).analyze(classFileNameS, cr); + if (result != null) { + // since java9 'repr' can represent either a class or a compiled module-info.java + final int className = result.name; for (String sourceFileName : sources) { final File sourceFile = new File(sourceFileName); myClassToSourceFile.put(className, sourceFile); - mySourceFileToClasses.put(sourceFile, repr); + mySourceFileToClasses.put(sourceFile, result); } - for (final int s : repr.getSupers()) { - myClassToSubclasses.put(s, className); + if (result instanceof ClassRepr) { + for (final int s : ((ClassRepr)result).getSupers()) { + myClassToSubclasses.put(s, className); + } } - for (final UsageRepr.Usage u : localUsages) { + for (final UsageRepr.Usage u : result.getUsages()) { final int owner = u.getOwner(); - if (owner != className) { myClassToClassDependency.put(owner, className); } @@ -2618,7 +2779,7 @@ public class Mappings { myPostPasses.offer(() -> { final int rootClassName = myContext.get(className.replace(".", "/")); final Collection fileNames = myClassToSourceFile.get(rootClassName); - final ClassRepr repr = fileNames != null && !fileNames.isEmpty()? getReprByName(fileNames.iterator().next(), rootClassName) : null; + final ClassRepr repr = fileNames != null && !fileNames.isEmpty()? getClassReprByName(fileNames.iterator().next(), rootClassName) : null; for (final String i : allImports) { final int iname = myContext.get(i.replace('.', '/')); @@ -2637,8 +2798,19 @@ public class Mappings { @Nullable public Set getClasses(final String sourceFileName) { + final File f = new File(sourceFileName); synchronized (myLock) { - return (Set)mySourceFileToClasses.get(new File(sourceFileName)); + final Collection reprs = mySourceFileToClasses.get(f); + if (reprs == null || reprs.isEmpty()) { + return null; + } + final Set result = new THashSet<>(); + for (ClassFileRepr repr : reprs) { + if (repr instanceof ClassRepr) { + result.add((ClassRepr)repr); + } + } + return result; } } @@ -2736,7 +2908,7 @@ public class Mappings { return myIsRebuild; } - private void addDeletedClass(final ClassRepr cr, File fileName) { + private void addDeletedClass(final ClassFileRepr cr, File fileName) { assert (myDeletedClasses != null); myDeletedClasses.add(Pair.create(cr, fileName)); @@ -2764,7 +2936,7 @@ public class Mappings { } @NotNull - private Set> getDeletedClasses() { + private Set> getDeletedClasses() { return myDeletedClasses == null ? Collections.emptySet() : Collections.unmodifiableSet(myDeletedClasses); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java index 02a2c28df9cc..f448818e7ac5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/MethodRepr.java @@ -45,7 +45,11 @@ class MethodRepr extends ProtoMember { public final TypeRepr.AbstractType[] myArgumentTypes; public final Set myExceptions; - public static abstract class Diff extends Difference { + public static abstract class Diff extends DifferenceImpl { + + Diff(@NotNull Difference delegate) { + super(delegate); + } public abstract Specifier parameterAnnotations(); @@ -62,28 +66,14 @@ class MethodRepr extends ProtoMember { final Difference diff = super.difference(past); final Difference.Specifier excs = Difference.make(m.myExceptions, myExceptions); final Difference.Specifier paramAnnotations = Difference.make(m.myParameterAnnotations, myParameterAnnotations); + final int base = paramAnnotations.unchanged()? diff.base() : diff.base() | Difference.ANNOTATIONS; - return new Diff() { - @Override - public Specifier annotations() { - return diff.annotations(); - } - + return new Diff(diff) { @Override public Specifier parameterAnnotations() { return paramAnnotations; } - @Override - public int addedModifiers() { - return diff.addedModifiers(); - } - - @Override - public int removedModifiers() { - return diff.removedModifiers(); - } - @Override public boolean no() { return base() == NONE && !defaultAdded() && !defaultRemoved() && excs.unchanged() && paramAnnotations.unchanged(); @@ -106,24 +96,13 @@ class MethodRepr extends ProtoMember { @Override public int base() { - final int base = diff.base(); - return paramAnnotations.unchanged()? base : base | Difference.ANNOTATIONS; - } - - @Override - public boolean packageLocalOn() { - return diff.packageLocalOn(); + return base; } @Override public boolean hadValue() { return m.hasValue(); } - - @Override - public boolean weakedAccess() { - return diff.weakedAccess(); - } }; } @@ -164,10 +143,10 @@ class MethodRepr extends ProtoMember { final int size = DataInputOutputUtil.readINT(in); myArgumentTypes = RW.read(externalizer, in, new TypeRepr.AbstractType[size]); - myExceptions = (Set)RW.read(externalizer, new THashSet<>(0), in); + myExceptions = RW.read(externalizer, new THashSet<>(0), in); final DataExternalizer clsTypeExternalizer = TypeRepr.classTypeExternalizer(context); - myParameterAnnotations = (Set)RW.read(new DataExternalizer() { + myParameterAnnotations = RW.read(new DataExternalizer() { @Override public void save(@NotNull DataOutput out, ParamAnnotation value) throws IOException { value.save(out); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModulePackageRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModulePackageRepr.java new file mode 100644 index 000000000000..ba281c519c6e --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModulePackageRepr.java @@ -0,0 +1,121 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataInputOutputUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.PrintStream; +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: 02-Oct-17 + */ +public class ModulePackageRepr extends Proto { + private static final DataExternalizer INT_EXTERNALIZER = new DataExternalizer() { + public void save(@NotNull DataOutput out, Integer value) throws IOException { + DataInputOutputUtil.writeINT(out, value); + } + + public Integer read(@NotNull DataInput in) throws IOException { + return DataInputOutputUtil.readINT(in); + } + }; + private final Set myModuleNames = new THashSet<>(); + + protected ModulePackageRepr(DependencyContext context, int name, Collection modules) { + super(0, context.get(null), name, Collections.emptySet()); + for (String module : modules) { + myModuleNames.add(context.get(module)); + } + } + + protected ModulePackageRepr(DependencyContext context, DataInput in) { + super(context, in); + RW.read(INT_EXTERNALIZER, myModuleNames, in); + } + + public Set getModuleNames() { + return Collections.unmodifiableSet(myModuleNames); + } + + public boolean isQualified() { + return !myModuleNames.isEmpty(); + } + + public void save(DataOutput out) { + super.save(out); + RW.save(myModuleNames, INT_EXTERNALIZER, out); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return name == ((ModulePackageRepr)o).name; + } + + public int hashCode() { + return 31 * name; + } + + public abstract static class Diff extends DifferenceImpl { + + public abstract Specifier targetModules(); + + Diff(@NotNull Difference delegate) { + super(delegate); + } + } + + public Diff difference(Proto past) { + final Difference.Specifier targetModulesDiff = Difference.make(((ModulePackageRepr)past).myModuleNames, myModuleNames); + return new Diff(super.difference(past)) { + public Specifier targetModules() { + return targetModulesDiff; + } + + public boolean no() { + return super.no() && targetModules().unchanged(); + } + }; + } + + public void toStream(DependencyContext context, PrintStream stream) { + final StringBuilder sb = new StringBuilder(); + sb.append("Module package: ").append(context.getValue(name)); + final Set moduleNames = myModuleNames; + if (moduleNames != null && !moduleNames.isEmpty()) { + final List names = new ArrayList<>(); + for (Integer moduleName : moduleNames) { + names.add(context.getValue(moduleName)); + } + Collections.sort(names, String::compareToIgnoreCase); + sb.append(" to"); + for (String s : names) { + sb.append(" ").append(s); + } + } + stream.println(sb.toString()); + } + + public static DataExternalizer externalizer(final DependencyContext context) { + return new DataExternalizer() { + public void save(@NotNull DataOutput out, ModulePackageRepr value) { + value.save(out); + } + + public ModulePackageRepr read(@NotNull DataInput in) { + return new ModulePackageRepr(context, in); + } + }; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRepr.java new file mode 100644 index 000000000000..0efb3ddce092 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRepr.java @@ -0,0 +1,160 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataInputOutputUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.PrintStream; +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: 30-Sep-17 + */ +public class ModuleRepr extends ClassFileRepr{ + private final int myVersion; + private final Set myRequires; // module names + private final Set myExports; // package names + + public ModuleRepr(DependencyContext context, int access, int version, int fileName, int name, Set requires, Set exports, Set usages) { + super(access, context.get(null), name, Collections.emptySet(), fileName, context, usages); + myVersion = version; + myRequires = requires; + myExports = exports; + updateClassUsages(context, usages); + } + + public ModuleRepr(DependencyContext context, DataInput in) { + super(context, in); + try { + myVersion = DataInputOutputUtil.readINT(in); + myRequires = RW.read(ModuleRequiresRepr.externalizer(context), new THashSet<>(), in); + myExports = RW.read(ModulePackageRepr.externalizer(context), new THashSet<>(), in); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + public int getVersion() { + return myVersion; + } + + public Set getRequires() { + return myRequires; + } + + public Set getExports() { + return myExports; + } + + public void save(DataOutput out) { + super.save(out); + try { + DataInputOutputUtil.writeINT(out, myVersion); + RW.save(myRequires, out); + RW.save(myExports, out); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + protected void updateClassUsages(DependencyContext context, Set s) { + for (ModuleRequiresRepr require : myRequires) { + if (require.name != name) { + s.add(UsageRepr.createModuleUsage(context, require.name)); + } + } + } + + public void toStream(DependencyContext context, PrintStream stream) { + super.toStream(context, stream); + + stream.println(" Requires:"); + streamProtoCollection(context, stream, myRequires); + stream.println(" End Of Requires"); + + stream.println(" Exports:"); + streamProtoCollection(context, stream, myExports); + stream.println(" End Of Exports"); + } + + private static void streamProtoCollection(DependencyContext context, PrintStream stream, final Collection collection) { + final List list = new ArrayList<>(collection); + list.sort(Comparator.comparingInt(o -> o.name)); + for (T reqRepr : list) { + reqRepr.toStream(context, stream); + } + } + + public boolean requiresTransitevely(int requirementName) { + for (ModuleRequiresRepr require : myRequires) { + if (require.name == requirementName) { + return require.isTransitive(); + } + } + return false; + } + + public abstract static class Diff extends DifferenceImpl { + + Diff(@NotNull Difference delegate) { + super(delegate); + } + + public abstract Specifier requires(); + + public abstract Specifier exports(); + + public abstract boolean versionChanged(); + + public boolean no() { + return base() == NONE && requires().unchanged() && exports().unchanged() && !versionChanged(); + } + } + + public Diff difference(Proto past) { + final Difference delegate = super.difference(past); + final ModuleRepr pastModule = (ModuleRepr)past; + final int base = !getUsages().equals(pastModule.getUsages())? delegate.base() | Difference.USAGES : delegate.base(); + + return new Diff(delegate) { + public Specifier requires() { + return Difference.make(pastModule.myRequires, myRequires); + } + + public Specifier exports() { + return Difference.make(pastModule.myExports, myExports); + } + + public boolean versionChanged() { + return pastModule.getVersion() != myVersion; + } + + public int base() { + return base; + } + }; + } + + public static DataExternalizer externalizer(final DependencyContext context) { + return new DataExternalizer() { + @Override + public void save(@NotNull final DataOutput out, final ModuleRepr value) throws IOException { + value.save(out); + } + + @Override + public ModuleRepr read(@NotNull final DataInput in) throws IOException { + return new ModuleRepr(context, in); + } + }; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRequiresRepr.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRequiresRepr.java new file mode 100644 index 000000000000..cfd03696c289 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ModuleRequiresRepr.java @@ -0,0 +1,116 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataInputOutputUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; +import org.jetbrains.org.objectweb.asm.Opcodes; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Collections; + +/** + * @author Eugene Zhuravlev + * Date: 02-Oct-17 + */ +public class ModuleRequiresRepr extends Proto { + + private final int myVersion; + + public ModuleRequiresRepr(DependencyContext context, int access, int name, String version) { + super(access, context.get(null), name, Collections.emptySet()); + myVersion = context.get(version); + } + + public ModuleRequiresRepr(DependencyContext context, DataInput in) { + super(context, in); + try { + myVersion = DataInputOutputUtil.readINT(in); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + public boolean isTransitive() { + return (access & Opcodes.ACC_TRANSITIVE) != 0; + } + + public int getVersion() { + return myVersion; + } + + @Override + public void save(final DataOutput out) { + try { + super.save(out); + DataInputOutputUtil.writeINT(out, myVersion); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + public static DataExternalizer externalizer(DependencyContext context) { + return new DataExternalizer() { + public void save(@NotNull DataOutput out, ModuleRequiresRepr value) throws IOException { + value.save(out); + } + + public ModuleRequiresRepr read(@NotNull DataInput in) throws IOException { + return new ModuleRequiresRepr(context, in); + } + }; + } + + public abstract static class Diff extends DifferenceImpl { + + Diff(@NotNull Difference delegate) { + super(delegate); + } + + public abstract boolean versionChanged(); + + public abstract boolean becameNonTransitive(); + } + + public Diff difference(Proto past) { + final ModuleRequiresRepr pastRequirement = (ModuleRequiresRepr)past; + return new Diff(super.difference(past)) { + public boolean versionChanged() { + return pastRequirement.myVersion != myVersion; + } + + public boolean no() { + return super.no() && !versionChanged(); + } + + public boolean becameNonTransitive() { + return pastRequirement.isTransitive() && !ModuleRequiresRepr.this.isTransitive(); + } + }; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return name == ((ModuleRequiresRepr)o).name; + } + + public int hashCode() { + return 31 * name; + } + + @Override + public void toStream(final DependencyContext context, final PrintStream stream) { + stream.println("Requires module: " + context.getValue(name) + ":" + access + ":" + myVersion); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Proto.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Proto.java index df250cf558c7..a962131b96eb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Proto.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Proto.java @@ -50,7 +50,7 @@ class Proto implements RW.Savable, Streamable { access = DataInputOutputUtil.readINT(in); signature = DataInputOutputUtil.readINT(in); name = DataInputOutputUtil.readINT(in); - annotations = (Set)RW.read(TypeRepr.classTypeExternalizer(context), new THashSet<>(), in); + annotations = RW.read(TypeRepr.classTypeExternalizer(context), new THashSet<>(), in); } catch (IOException e) { throw new BuildDataCorruptedException(e); @@ -197,16 +197,18 @@ class Proto implements RW.Savable, Streamable { stream.print(" Class "); stream.println(context.getValue(name)); } - - if (this instanceof MethodRepr) { + else if (this instanceof MethodRepr) { stream.print(" Method "); stream.println(context.getValue(name)); } - - if (this instanceof FieldRepr) { + else if (this instanceof FieldRepr) { stream.print(" Field "); stream.println(context.getValue(name)); } + else if (this instanceof ModuleRepr) { + stream.print(" Module "); + stream.println(context.getValue(name)); + } stream.print(d); stream.print("Access : "); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ProtoMember.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ProtoMember.java index 23333c35fb7e..b06e86cc9b2c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ProtoMember.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ProtoMember.java @@ -302,12 +302,7 @@ abstract class ProtoMember extends Proto { final int newBase = base; - return new Difference() { - @Override - public Specifier annotations() { - return diff.annotations(); - } - + return new DifferenceImpl(diff) { @Override public int base() { return newBase; @@ -315,33 +310,13 @@ abstract class ProtoMember extends Proto { @Override public boolean no() { - return newBase == NONE && diff.no(); - } - - @Override - public int addedModifiers() { - return diff.addedModifiers(); - } - - @Override - public int removedModifiers() { - return diff.removedModifiers(); - } - - @Override - public boolean packageLocalOn() { - return diff.packageLocalOn(); + return newBase == NONE && super.no(); } @Override public boolean hadValue() { return ((ProtoMember)past).hasValue(); } - - @Override - public boolean weakedAccess() { - return diff.weakedAccess(); - } }; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/RW.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/RW.java index 079ffc6b49c1..b6ef1aac9e1c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/RW.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/RW.java @@ -19,7 +19,6 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import com.intellij.util.io.IOUtil; import gnu.trove.TIntHashSet; -import gnu.trove.TIntProcedure; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; import java.io.*; @@ -132,7 +131,7 @@ public class RW { } } - public static Collection read(final DataExternalizer e, final Collection acc, final DataInput in) { + public static > C read(final DataExternalizer e, final C acc, final DataInput in) { try { final int size = DataInputOutputUtil.readINT(in); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageConstraint.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageConstraint.java new file mode 100644 index 000000000000..ada62aaff87e --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/UsageConstraint.java @@ -0,0 +1,28 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.builders.java.dependencyView; + +/** + * @author Eugene Zhuravlev + * Date: 12-Oct-17 + */ +public interface UsageConstraint { + UsageConstraint ANY = residence -> true; + + boolean checkResidence(final int residence); + + static UsageConstraint exactMatch(int name) { + return residence -> name == residence; + } + + default UsageConstraint negate() { + return residence -> !checkResidence(residence); + } + + default UsageConstraint and(UsageConstraint c) { + return c == ANY? this : residence -> checkResidence(residence) && c.checkResidence(residence); + } + + default UsageConstraint or(UsageConstraint c) { + return c == ANY? ANY : residence -> checkResidence(residence) || c.checkResidence(residence); + } +} 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 fac650518128..7a361acf3a4a 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 @@ -18,7 +18,6 @@ package org.jetbrains.jps.builders.java.dependencyView; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TIntHashSet; -import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; import org.jetbrains.org.objectweb.asm.Type; @@ -43,6 +42,7 @@ class UsageRepr { private static final byte ANNOTATION_USAGE = 0x6; private static final byte METAMETHOD_USAGE = 0x7; private static final byte CLASS_AS_GENERIC_BOUND_USAGE = 0x8; + private static final byte MODULE_USAGE = 0x9; private static final int DEFAULT_SET_CAPACITY = 32; private static final float DEFAULT_SET_LOAD_FACTOR = 0.98f; @@ -246,10 +246,7 @@ class UsageRepr { if (myName != that.myName) return false; if (myOwner != that.myOwner) return false; - return Arrays.equals(myArgumentTypes, that.myArgumentTypes) && - myReturnType.equals(that.myReturnType) && - myName == that.myName && - myOwner == that.myOwner; + return true; } @Override @@ -356,6 +353,59 @@ class UsageRepr { } } + public static class ModuleUsage extends Usage { + final int myModuleName; + + @Override + public int getOwner() { + return myModuleName; + } + + private ModuleUsage(final int moduleName) { + this.myModuleName = moduleName; + } + + private ModuleUsage(final DataInput in) { + try { + myModuleName = DataInputOutputUtil.readINT(in); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public void save(final DataOutput out) { + try { + out.writeByte(MODULE_USAGE); + DataInputOutputUtil.writeINT(out, myModuleName); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ModuleUsage that = (ModuleUsage)o; + + return myModuleName == that.myModuleName; + } + + @Override + public int hashCode() { + return myModuleName; + } + + @Override + public void toStream(final DependencyContext context, final PrintStream stream) { + stream.println("ModuleUsage: " + context.getValue(myModuleName)); + } + } + public static class ClassAsGenericBoundUsage extends ClassUsage { public ClassAsGenericBoundUsage(int className) { super(className); @@ -542,7 +592,7 @@ class UsageRepr { try { myType = (TypeRepr.ClassType)externalizer.read(in); myUsedArguments = RW.read(new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR), in); - myUsedTargets = (EnumSet)RW.read(elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in); + myUsedTargets = RW.read(elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in); } catch (IOException e) { throw new BuildDataCorruptedException(e); @@ -664,6 +714,10 @@ class UsageRepr { return context.getUsage(new AnnotationUsage(type, usedArguments, targets)); } + public static Usage createModuleUsage(final DependencyContext context, final int name) { + return context.getUsage(new ModuleUsage(name)); + } + public static DataExternalizer externalizer(final DependencyContext context) { return new DataExternalizer() { @Override @@ -701,6 +755,9 @@ class UsageRepr { case METAMETHOD_USAGE: return context.getUsage(new MetaMethodUsage(in)); + + case MODULE_USAGE: + return context.getUsage(new ModuleUsage(in)); } assert (false); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSOperations.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSOperations.java index 0597bfcc3183..22583d719243 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSOperations.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSOperations.java @@ -116,12 +116,16 @@ public class FSOperations { } public static void markDirty(CompileContext context, final CompilationRound round, final ModuleChunk chunk, @Nullable FileFilter filter) throws IOException { - final ProjectDescriptor pd = context.getProjectDescriptor(); for (ModuleBuildTarget target : chunk.getTargets()) { - markDirtyFiles(context, target, round, pd.timestamps.getStorage(), true, null, filter); + markDirty(context, round, target, filter); } } + public static void markDirty(CompileContext context, final CompilationRound round, final ModuleBuildTarget target, @Nullable FileFilter filter) throws IOException { + final ProjectDescriptor pd = context.getProjectDescriptor(); + markDirtyFiles(context, target, round, pd.timestamps.getStorage(), true, null, filter); + } + /** * @deprecated use markDirtyRecursively(CompileContext context, final CompilationRound round, ModuleChunk chunk, FileFilter filter) */ diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 579aa84cf8ec..8e9d90d4c0fc 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -57,7 +57,6 @@ import org.jetbrains.jps.incremental.messages.ProgressMessage; import org.jetbrains.jps.javac.*; import org.jetbrains.jps.model.JpsDummyElement; import org.jetbrains.jps.model.JpsProject; -import org.jetbrains.jps.model.java.JavaModuleIndex; import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.java.JpsJavaSdkType; import org.jetbrains.jps.model.java.LanguageLevel; @@ -70,7 +69,8 @@ import org.jetbrains.jps.model.serialization.PathMacroUtil; import org.jetbrains.jps.service.JpsServiceManager; import org.jetbrains.jps.service.SharedThreadPool; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; import java.io.File; import java.io.FileFilter; import java.io.IOException; @@ -233,14 +233,9 @@ public class JavaBuilder extends ModuleLevelBuilder { int javaModulesCount = 0; - if ((!filesToCompile.isEmpty() || dirtyFilesHolder.hasRemovedFiles()) && - JpsJavaSdkType.parseVersion(getLanguageLevel(ContainerUtil.getFirstItem(chunk.getModules()))) >= 9) { - // at the moment, there is no incremental compilation for module-info files, so they should be rebuilt on every change - JavaModuleIndex index = getJavaModuleIndex(context); + if ((!filesToCompile.isEmpty() || dirtyFilesHolder.hasRemovedFiles()) && getTargetPlatformLanguageVersion(chunk.representativeTarget().getModule()) >= 9) { for (ModuleBuildTarget target : chunk.getTargets()) { - File moduleInfoFile = index.getModuleInfoFile(target.getModule(), target.isTests()); - if (moduleInfoFile != null) { - filesToCompile.add(moduleInfoFile); + if (JavaBuilderUtil.findModuleInfoFile(context, target) != null) { javaModulesCount++; } } @@ -404,7 +399,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final Map> outs = buildOutputDirectoriesMap(context, chunk); try { - final int targetLanguageLevel = JpsJavaSdkType.parseVersion(getLanguageLevel(chunk.getModules().iterator().next())); + final int targetLanguageLevel = getTargetPlatformLanguageVersion(chunk.representativeTarget().getModule()); final boolean shouldForkJavac = shouldForkCompilerProcess(context, chunk, targetLanguageLevel); // when forking external javac, compilers from SDK 1.6 and higher are supported @@ -1000,11 +995,32 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - private static String getLanguageLevel(JpsModule module) { + @Nullable + private static String getLanguageLevel(@NotNull JpsModule module) { final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module); return level != null ? level.getComplianceOption() : null; } + /** + * The assumed module's source code language version. + * Returns the version number, corresponding to the language level, associated with the given module. + * If no language level set (neither on module- nor on project-level), the version of JDK associated with the module is returned. + * If no JDK is associated, returns 0. + */ + private static int getTargetPlatformLanguageVersion(@NotNull JpsModule module) { + final String level = getLanguageLevel(module); + if (level != null) { + return JpsJavaSdkType.parseVersion(level); + } + // when compiling, if language level is not explicitly set, it is assumed to be equal to + // the highest possible language level, that target JDK supports + final JpsSdk sdk = module.getSdk(JpsJavaSdkType.INSTANCE); + if (sdk != null) { + return JpsJavaSdkType.getJavaVersion(sdk); + } + return 0; + } + private static boolean isEncodingSet(List options) { for (String option : options) { if ("-encoding".equals(option)) { @@ -1096,12 +1112,6 @@ public class JavaBuilder extends ModuleLevelBuilder { return map; } - private static JavaModuleIndex getJavaModuleIndex(CompileContext context) { - JpsProject project = context.getProjectDescriptor().getProject(); - File storageRoot = context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot(); - return JpsJavaExtensionService.getInstance().getJavaModuleIndex(project, storageRoot); - } - private static class DiagnosticSink implements DiagnosticOutputConsumer { private final CompileContext myContext; private volatile int myErrorCount; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java index 1cbeef00c17c..62b165f0a600 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java @@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentMap; * Date: 10/7/11 */ public class BuildDataManager implements StorageOwner { - private static final int VERSION = 31 + (PersistentHashMapValueStorage.COMPRESSION_ENABLED ? 1:0); + private static final int VERSION = 33 + (PersistentHashMapValueStorage.COMPRESSION_ENABLED ? 1:0); private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.storage.BuildDataManager"); private static final String SRC_TO_FORM_STORAGE = "src-form"; private static final String OUT_TARGET_STORAGE = "out-target"; diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java b/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java new file mode 100644 index 000000000000..1730f6e0f65d --- /dev/null +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java @@ -0,0 +1,117 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.ether; + +import com.intellij.openapi.util.SystemInfo; +import org.jetbrains.jps.builders.BuildResult; +import org.jetbrains.jps.model.JpsModuleRootModificationUtil; +import org.jetbrains.jps.model.module.JpsModule; + +import java.io.File; +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: 09-Oct-17 + */ +public class Java9Test extends IncrementalTestCase { + + private static final String MODULE_DIR_PREFIX = "module"; + private static boolean IS_AT_LEAST_JAVA9 = SystemInfo.isJavaVersionAtLeast("9"); + public Java9Test() { + super("java9-features"); + } + + protected boolean shouldRunTest() { + if (!IS_AT_LEAST_JAVA9) { + System.out.println("Test '" + getTestName(false) + "' skipped because it requires at least java 9 runtime"); + return false; + } + return super.shouldRunTest(); + } + + public void testRemoveModuleRequires() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testRemoveTransitiveModuleRequires() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testChangeTransitiveModuleRequires() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testChangeQualifiedTransitiveModuleRequires() { + final BuildResult buildResult = doTest(); + buildResult.assertSuccessful(); + } + + public void testRemoveModuleExports() { + final BuildResult buildResult = doTest(); + buildResult.assertSuccessful(); + } + + public void testRemoveTransitiveModuleExports() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testRemoveQualifiedModuleExports() { + final BuildResult buildResult = doTest(); + buildResult.assertSuccessful(); + } + + public void testRemoveQualifiedTransitiveModuleExports() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testChangeQualifiedTransitiveModuleExportsNoRebuild() { + final BuildResult buildResult = doTest(); + buildResult.assertSuccessful(); + } + + public void testChangeQualifiedTransitiveModuleExportsRebuildIndirectDeps() { + final BuildResult buildResult = doTest(); + buildResult.assertFailed(); + } + + public void testChangeQualifiedTransitiveModuleExportsRebuildDirectDeps() { + final BuildResult buildResult = doTest(); + buildResult.assertSuccessful(); + } + + protected BuildResult doTestBuild(int makesCount) { + setupModules(); + return super.doTestBuild(makesCount); + } + + private void setupModules() { + final File projectDir = getOrCreateProjectDir(); + final File[] moduleDirs = projectDir.listFiles((dir, name) -> name.startsWith(MODULE_DIR_PREFIX)); + + if (moduleDirs != null && moduleDirs.length > 0) { + final Map modules = new HashMap<>(); + final List moduleNames = new ArrayList<>(); + for (File moduleDir : moduleDirs) { + final String name = moduleDir.getName().substring(MODULE_DIR_PREFIX.length()); + final JpsModule m = addModule(name, moduleDir.getName() + "/src"); + modules.put(name, m); + moduleNames.add(name); + } + Collections.sort(moduleNames, Collections.reverseOrder()); + // set dependencies in alphabet reverse order + JpsModule from = null; + for (String name : moduleNames) { + final JpsModule mod = modules.get(name); + if (from != null) { + JpsModuleRootModificationUtil.addDependency(from, mod); + } + from = mod; + } + } + } +} diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java index 753b6eb038cc..62d4d622e449 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java @@ -276,7 +276,10 @@ public abstract class JpsBuildTestCase extends UsefulTestCase { sdkTable.setSdkReference(JpsJavaSdkType.INSTANCE, JpsJavaExtensionService. getInstance().createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper)sdkType, wrapperRef)); } + // ensure jdk entry is the first one in dependency list + module.getDependenciesList().clear(); module.getDependenciesList().addSdkDependency(sdkType); + module.getDependenciesList().addModuleSourceDependency(); if (srcPaths.length > 0 || outputPath != null) { for (String srcPath : srcPaths) { module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(srcPath)); diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java index aaa3f4f72e3b..50ad6592f893 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java @@ -17,14 +17,15 @@ package org.jetbrains.jps.model.java; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.module.JpsModule; import java.io.File; -public abstract class JavaModuleIndex { +public interface JavaModuleIndex extends JpsElement { /** * Returns a path to a module descriptor (module-info.java file) for the given module, * or {@code null} when there is no descriptor. */ - public abstract @Nullable File getModuleInfoFile(@NotNull JpsModule module, boolean forTests); + @Nullable File getModuleInfoFile(@NotNull JpsModule module, boolean forTests); } \ No newline at end of file diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java index 3a8e1704b8f0..a9c1f15f7932 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.ex.JpsElementBase; import org.jetbrains.jps.model.java.JavaModuleIndex; import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes; @@ -32,7 +33,7 @@ import java.util.Collections; import java.util.Map; import java.util.Properties; -public class JavaModuleIndexImpl extends JavaModuleIndex { +public class JavaModuleIndexImpl extends JpsElementBase implements JavaModuleIndex { public static final String SOURCE_SUFFIX = ":S"; public static final String TEST_SUFFIX = ":T"; @@ -53,6 +54,21 @@ public class JavaModuleIndexImpl extends JavaModuleIndex { myExcludes = null; } + @NotNull + public JavaModuleIndexImpl createCopy() { + final JpsCompilerExcludes excludes = myExcludes; + if (excludes == null) { + return new JavaModuleIndexImpl(myMapping); + } + final JavaModuleIndexImpl copy = new JavaModuleIndexImpl(excludes); + copy.myMapping.putAll(myMapping); + return copy; + } + + public void applyChanges(@NotNull JavaModuleIndexImpl modified) { + // not supported + } + @Nullable @Override public File getModuleInfoFile(@NotNull JpsModule module, boolean forTests) { diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexRole.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexRole.java new file mode 100644 index 000000000000..c967d791a4f5 --- /dev/null +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexRole.java @@ -0,0 +1,28 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.model.java.impl; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.JpsElementParameterizedCreator; +import org.jetbrains.jps.model.ex.JpsElementChildRoleBase; +import org.jetbrains.jps.model.java.JavaModuleIndex; +import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration; + +import java.io.File; + +/** + * @author Eugene Zhuravlev + * Date: 11-Oct-17 + */ +public class JavaModuleIndexRole extends JpsElementChildRoleBase implements JpsElementParameterizedCreator>{ + public static final JavaModuleIndexRole INSTANCE = new JavaModuleIndexRole(); + + public JavaModuleIndexRole() { + super("java module index"); + } + + @NotNull + public JavaModuleIndex create(@NotNull Pair param) { + return JavaModuleIndexImpl.load(param.second, param.first.getCompilerExcludes()); + } +} diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java index 8ae38360a277..065754d6ff12 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java @@ -15,26 +15,30 @@ */ package org.jetbrains.jps.model.java.impl; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes; -import org.jetbrains.jps.model.java.impl.runConfiguration.JpsApplicationRunConfigurationPropertiesImpl; -import org.jetbrains.jps.model.java.runConfiguration.JpsApplicationRunConfigurationProperties; -import org.jetbrains.jps.model.java.runConfiguration.JpsApplicationRunConfigurationState; -import org.jetbrains.jps.model.module.impl.JpsTestModulePropertiesImpl; -import org.jetbrains.jps.util.JpsPathUtil; import org.jetbrains.jps.model.JpsDummyElement; +import org.jetbrains.jps.model.JpsElementContainer; import org.jetbrains.jps.model.JpsGlobal; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.java.*; import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration; import org.jetbrains.jps.model.java.impl.compiler.JpsJavaCompilerConfigurationImpl; +import org.jetbrains.jps.model.java.impl.runConfiguration.JpsApplicationRunConfigurationPropertiesImpl; +import org.jetbrains.jps.model.java.runConfiguration.JpsApplicationRunConfigurationProperties; +import org.jetbrains.jps.model.java.runConfiguration.JpsApplicationRunConfigurationState; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.library.JpsTypedLibrary; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.library.sdk.JpsSdkReference; -import org.jetbrains.jps.model.module.*; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.module.JpsModuleReference; +import org.jetbrains.jps.model.module.JpsTestModuleProperties; +import org.jetbrains.jps.model.module.impl.JpsTestModulePropertiesImpl; +import org.jetbrains.jps.util.JpsPathUtil; import java.io.File; import java.util.ArrayList; @@ -46,8 +50,6 @@ import java.util.List; * @author nik */ public class JpsJavaExtensionServiceImpl extends JpsJavaExtensionService { - private JavaModuleIndex myModuleIndex = null; - @NotNull @Override public JpsJavaProjectExtension getOrCreateProjectExtension(@NotNull JpsProject project) { @@ -239,10 +241,11 @@ public class JpsJavaExtensionServiceImpl extends JpsJavaExtensionService { @NotNull @Override public JavaModuleIndex getJavaModuleIndex(@NotNull JpsProject project, @NotNull File storageRoot) { - if (myModuleIndex == null) { - JpsCompilerExcludes excludes = getOrCreateCompilerConfiguration(project).getCompilerExcludes(); - myModuleIndex = JavaModuleIndexImpl.load(storageRoot, excludes); + final JpsElementContainer container = project.getContainer(); + final JavaModuleIndex index = container.getChild(JavaModuleIndexRole.INSTANCE); + if (index != null) { + return index; } - return myModuleIndex; + return container.setChild(JavaModuleIndexRole.INSTANCE, Pair.create(getOrCreateCompilerConfiguration(project), storageRoot)); } } \ No newline at end of file