From bcec7451e941decddf86ddcdbe87a1f9b59eec30 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Tue, 5 Feb 2019 22:31:28 +0100 Subject: Bug 540846 - [regression] Cannot infer type argument(s) for map(Function Change-Id: I340a5e402d319615f21623cd6492ba4037078bd4 Signed-off-by: Stephan Herrmann --- .../regression/GenericsRegressionTest_1_8.java | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index 1979b4bbdd..4bf0b94b6e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -9485,4 +9485,31 @@ public void testBug508834_comment0() { }; runner.runConformTest(); } + public void testBug540846() { + Runner runner = new Runner(); + runner.testFiles = new String[] { + "Test.java", + "import java.util.*;\n" + + "import java.util.stream.*;\n" + + "import java.math.*;\n" + + "\n" + + "public class Test {\n" + + " private List getRowValues(Map record, Stream factors) {\n" + + " return Stream.concat(\n" + + " factors.map(f -> {\n" + + " if (f.equals(\"x\")) {\n" + + " return record.get(f);\n" + + " } else {\n" + + " return \"NM\";\n" + + " }\n" + + " }),\n" + + " Stream.of(BigDecimal.ONE)\n" + + " )\n" + + " .map(v -> (v instanceof BigDecimal) ? ((BigDecimal) v).setScale(10, BigDecimal.ROUND_HALF_UP) : v)\n" + + " .collect(Collectors.toList());\n" + + " }\n" + + "}\n" + }; + runner.runConformTest(); + } } -- cgit v1.2.3 From 56c7200f17bcd06f03618a81316a7dbfe1d7dcf8 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Thu, 24 Jan 2019 15:44:07 -0500 Subject: Bug 543727 - False positive "Unnecessary cast" - change EqualExpression.resolveType() to add additional check before reporting an unnecessary cast if one side is parameterized and the other is a cast of a base type that may be compatible with parameterized type when boxed - add test to CastTest Change-Id: I9e3e1be9a0d42965dba9c8dbf629171248d0b26b Signed-off-by: Jeff Johnston --- .../core/tests/compiler/regression/CastTest.java | 50 +++++++++++++++++++++- .../jdt/internal/compiler/ast/EqualExpression.java | 27 +++++++++--- 2 files changed, 71 insertions(+), 6 deletions(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java index e723cdbad6..e0e23ca878 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2017 IBM Corporation and others. + * Copyright (c) 2003, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -3297,6 +3297,54 @@ public void testAnonymous_bug520727() { runConformTest(source,""); } } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=543727 False positive "Unnecessary cast" +public void test543727() { + if (this.complianceLevel < ClassFileConstants.JDK1_7) + return; + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "Bug.java", + "import java.util.ArrayList;\n" + + "import java.util.List;\n" + + "public class Bug {\n" + + " public static int main(String[] args) {\n" + + " List> vector = new ArrayList<>();\n" + + " vector.add(0);\n" + + " if (vector.get(0) == (Integer)0) {\n" + + " System.out.print(\"SUCCESS\");\n" + + " }\n" + + " return 0;\n" + + " }" + + "}\n", + }, + "SUCCESS"); +} +public void test543727_notequals() { + if (this.complianceLevel < ClassFileConstants.JDK1_7) + return; + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "Bug.java", + "import java.util.ArrayList;\n" + + "import java.util.List;\n" + + "public class Bug {\n" + + " public static int main(String[] args) {\n" + + " List> vector = new ArrayList<>();\n" + + " vector.add(0);\n" + + " if (vector.get(0) != (Integer)1) {\n" + + " System.out.print(\"SUCCESS\");\n" + + " }\n" + + " return 0;\n" + + " }" + + "}\n", + }, + "SUCCESS"); +} + public static Class testClass() { return CastTest.class; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java index c3bbd55075..bdf1ed81fe 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -936,10 +936,13 @@ public class EqualExpression extends BinaryExpression { if (unnecessaryLeftCast || unnecessaryRightCast) { TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)this.left).expression.resolvedType : leftType; TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)this.right).expression.resolvedType : rightType; - if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null) - || checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) { - if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)this.left); - if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)this.right); + // Bug 543727 - check if either cast is really needed + if (!isCastNeeded(alternateLeftType, alternateRightType)) { + if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null) + || checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) { + if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)this.left); + if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)this.right); + } } } // check whether comparing identical expressions @@ -955,6 +958,20 @@ public class EqualExpression extends BinaryExpression { scope.problemReporter().notCompatibleTypesError(this, leftType, rightType); return null; } + + private boolean isCastNeeded(TypeBinding leftType, TypeBinding rightType) { + // Bug 543727 - if either type is parameterized and the other is a base type, + // a cast is necessary, even if boxing the base type will result in a compatible + // type. + if (leftType.isParameterizedType()) { + return rightType.isBaseType(); + } + if (rightType.isParameterizedType()) { + return leftType.isBaseType(); + } + return false; + } + @Override public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { -- cgit v1.2.3 From a9d77143a860475b4d660573eefc303be09d98f4 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Thu, 7 Feb 2019 21:54:48 +0100 Subject: Bug 538192 - [1.8][compiler] Eclipse IDE compiler error (lambda), using io.cucumber.datatable.DataTableType Change-Id: I3af5f99587f34fdcbff08c5d1635115b382a159c Signed-off-by: Stephan Herrmann --- .../regression/GenericsRegressionTest_1_8.java | 20 ++++++++++++++++++++ .../jdt/internal/compiler/ast/LambdaExpression.java | 2 ++ 2 files changed, 22 insertions(+) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index 4bf0b94b6e..c57ea95c8e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -9512,4 +9512,24 @@ public void testBug508834_comment0() { }; runner.runConformTest(); } + public void testBug538192() { + Runner runner = new Runner(); + runner.testFiles = new String[] { + "Test.java", + "import java.util.*;\n" + + "import java.util.function.Function;\n" + + "interface ListFunc extends Function, T> {}\n" + + "interface MapFunc extends Function, T> {}\n" + + "class DTT {\n" + + " public DTT(Class c, ListFunc f) {}\n" + + " public DTT(Class c, MapFunc f) {} \n" + + "}\n" + + "public class Test {\n" + + " void test() {\n" + + " new DTT(Integer.class, (Map row) -> Integer.valueOf(0));\n" + + " }\n" + + "}\n" + }; + runner.runConformTest(); + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java index 08067d8306..b252d45f42 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java @@ -481,6 +481,8 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre if (expected.isParameterizedType() && argument.isParameterizedType()) { TypeBinding[] expectedArgs = ((ParameterizedTypeBinding)expected).typeArguments(); TypeBinding[] args = ((ParameterizedTypeBinding)argument).typeArguments(); + if (args.length != expectedArgs.length) + return false; for (int j = 0; j < args.length; j++) { if (TypeBinding.notEquals(expectedArgs[j], args[j])) { if (expectedArgs[j].isWildcard() && args[j].isUnboundWildcard()) { -- cgit v1.2.3 From 18baae4ac007703438f2e33f74d619dae2cf177f Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Sat, 9 Feb 2019 13:25:56 +0100 Subject: Bug 404648 - [1.8][compiler] investigate differences between ECJ & Javac Signed-off-by: Stephan Herrmann --- .../regression/AbstractRegressionTest.java | 7 +-- .../core/tests/compiler/regression/CastTest.java | 66 +++++++++++----------- 2 files changed, 37 insertions(+), 36 deletions(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java index 9473d14de8..bdbc45a2aa 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java @@ -919,7 +919,9 @@ protected static class JavacTestOptions { JavacBug8044196 = RUN_JAVAC ? // likely https://bugs.openjdk.java.net/browse/JDK-8044196, intermittently masked by https://bugs.openjdk.java.net/browse/JDK-8029161 new JavacHasABug(MismatchType.EclipseErrorsJavacNone, ClassFileConstants.JDK9, 0000, true) : null, JavacBug6337964 = RUN_JAVAC ? // https://bugs.eclipse.org/bugs/show_bug.cgi?id=112433 - new JavacHasABug(MismatchType.JavacErrorsEclipseNone, ClassFileConstants.JDK1_6, 1045/*guessed*/, true) : null; + new JavacHasABug(MismatchType.JavacErrorsEclipseNone, ClassFileConstants.JDK1_6, 1045/*guessed*/, true) : null, + JavacBug8144832 = RUN_JAVAC ? // https://bugs.openjdk.java.net/browse/JDK-8144832 + new JavacHasABug(MismatchType.JavacErrorsEclipseNone, ClassFileConstants.JDK9, 0000) : null; // bugs that have been fixed but that we've not identified public static JavacHasABug @@ -941,9 +943,6 @@ protected static class JavacTestOptions { ClassFileConstants.JDK9, 0100 /* 9.0.1 or better */) : null; // bugs that have neither been fixed nor formally identified but which outcomes are obvious enough to clear any doubts public static JavacHasABug - JavacGeneratesByteCodeUponWhichJavaThrowsAnException = RUN_JAVAC ? - new JavacHasABug( - MismatchType.StandardOutputMismatch) : null, JavacThrowsAnException = RUN_JAVAC ? // some of these are transient - that is, depend on the system on which the test is run, aka stack overflow new JavacHasABug( MismatchType.JavacErrorsEclipseNone) : null, diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java index e0e23ca878..5deac455aa 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java @@ -21,6 +21,7 @@ import java.util.Map; import junit.framework.Test; import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.tests.compiler.regression.AbstractRegressionTest.JavacTestOptions.Excuse; import org.eclipse.jdt.core.tests.util.Util; import org.eclipse.jdt.core.util.ClassFileBytesDisassembler; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; @@ -1497,7 +1498,7 @@ public void test036() { "no base" /* expected output string */, "" /* expected error string */, // javac options - JavacTestOptions.JavacHasABug.JavacGeneratesByteCodeUponWhichJavaThrowsAnException /* javac test options */); + JavacTestOptions.JavacHasABug.JavacBugFixed_7 /* javac test options */); } public void test037() { this.runNegativeTest( @@ -1828,7 +1829,8 @@ public void test048() { public void test049() { CompilerOptions options = new CompilerOptions(getCompilerOptions()); if (options.sourceLevel < ClassFileConstants.JDK1_5) return; - this.runNegativeTest( + Runner runner = new Runner(); + runner.testFiles = new String[] { "A.java", "public class A {\n" + @@ -1844,14 +1846,18 @@ public void test049() { " class Member2 extends Other.Member {\n" + " }\n" + "}\n" - }, + }; + runner.expectedCompilerLog = "----------\n" + "1. WARNING in A.java (at line 3)\n" + " Other.Member m = (Other.Member) om2;\n" + " ^^^^^^^^^^^^^^^^^^^^^\n" + "Unnecessary cast from Other2.Member2 to Other.Member\n" + - "----------\n" - ); + "----------\n"; + runner.javacTestOptions = + Excuse.EclipseHasSomeMoreWarnings; // javac is inconsistent: accepting both assignments, not issuing a warning though in simpler cases it does + // note that javac 1.6 doesn't even accept the syntax of this cast + runner.runWarningTest(); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302919 public void test050() { @@ -2521,7 +2527,9 @@ public void testBug428274() { public void testBug428274b() { if (this.complianceLevel < ClassFileConstants.JDK1_5) return; // uses generics - String source = + Runner runner = new Runner(); + runner.testFiles = new String[] { + "Junk4.java", "public class Junk4 {\n" + " void setValue(T n) {\n" + " int rounded = (int) Math.round((double) n);\n" + @@ -2532,26 +2540,22 @@ public void testBug428274b() { " j.setValue(Double.valueOf(3.3));\n" + " j.setValue(Double.valueOf(3.7));\n" + " }\n" + - "}\n"; + "}\n" + }; if (this.complianceLevel < ClassFileConstants.JDK1_7) { - runNegativeTest( - new String[] { - "Junk4.java", - source - }, + runner.expectedCompilerLog = "----------\n" + "1. ERROR in Junk4.java (at line 3)\n" + " int rounded = (int) Math.round((double) n);\n" + " ^^^^^^^^^^\n" + "Cannot cast from T to double\n" + - "----------\n"); + "----------\n"; + runner.runNegativeTest(); } else { - runConformTest( - new String[] { - "Junk4.java", - source - }, - "3\n4"); + runner.expectedOutputString = + "3\n4"; + runner.javacTestOptions = JavacTestOptions.JavacHasABug.JavacBug8144832; + runner.runConformTest(); } } // note: spec allows all reference types, but neither javac nor common sense accept arrays :) @@ -3232,9 +3236,10 @@ public void test461706() { public void test461706a() { if (this.complianceLevel < ClassFileConstants.JDK1_8) return; - Map customOptions = getCompilerOptions(); - customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.ERROR); - this.runNegativeTest( + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.WARNING); + runner.testFiles = new String[] { "Bug.java", "import java.util.ArrayList;\n" + @@ -3261,16 +3266,15 @@ public void test461706a() { " .orElse(ICondition.TRUE);\n" + " }\n" + "}" - }, + }; + runner.expectedCompilerLog = "----------\n" + - "1. ERROR in Bug.java (at line 20)\n" + + "1. WARNING in Bug.java (at line 20)\n" + " .map(x -> (ICondition)x)\n" + " ^^^^^^^^^^^^^\n" + "Unnecessary cast from Bug.ICondition to Bug.ICondition\n" + - "----------\n", - null, - true, - customOptions); + "----------\n"; + runner.runWarningTest(); } public void testAnonymous_bug520727() { String[] source = { @@ -3309,13 +3313,12 @@ public void test543727() { "import java.util.ArrayList;\n" + "import java.util.List;\n" + "public class Bug {\n" + - " public static int main(String[] args) {\n" + + " public static void main(String[] args) {\n" + " List> vector = new ArrayList<>();\n" + " vector.add(0);\n" + " if (vector.get(0) == (Integer)0) {\n" + " System.out.print(\"SUCCESS\");\n" + " }\n" + - " return 0;\n" + " }" + "}\n", }, @@ -3332,13 +3335,12 @@ public void test543727_notequals() { "import java.util.ArrayList;\n" + "import java.util.List;\n" + "public class Bug {\n" + - " public static int main(String[] args) {\n" + + " public static void main(String[] args) {\n" + " List> vector = new ArrayList<>();\n" + " vector.add(0);\n" + " if (vector.get(0) != (Integer)1) {\n" + " System.out.print(\"SUCCESS\");\n" + " }\n" + - " return 0;\n" + " }" + "}\n", }, -- cgit v1.2.3 From c0a450d6d478972de7ffb4ec43ebd4a908dfbbbc Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Sun, 10 Feb 2019 11:35:48 +0100 Subject: Bug 395051 - Access restriction on method invocation: error range too big Change-Id: I533f832054f79ee59b31e902bcfe466be62bf517 Signed-off-by: Stephan Herrmann --- .../compiler/regression/BatchCompilerTest.java | 16 ++++----- .../core/tests/model/AccessRestrictionsTests.java | 42 +++++++++++----------- .../eclipse/jdt/internal/compiler/ast/ASTNode.java | 6 ++-- .../compiler/ast/AllocationExpression.java | 10 +++++- .../compiler/ast/ExplicitConstructorCall.java | 4 +-- .../compiler/ast/JavadocAllocationExpression.java | 4 +-- .../internal/compiler/ast/JavadocMessageSend.java | 4 +-- .../jdt/internal/compiler/ast/MessageSend.java | 12 +++++-- .../ast/QualifiedAllocationExpression.java | 4 +-- .../internal/compiler/ast/ReferenceExpression.java | 4 +-- .../internal/compiler/lookup/InvocationSite.java | 4 ++- .../internal/compiler/problem/ProblemReporter.java | 10 +++--- .../eval/CodeSnippetAllocationExpression.java | 4 +-- .../jdt/internal/eval/CodeSnippetMessageSend.java | 4 +-- 14 files changed, 73 insertions(+), 55 deletions(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java index ca1357961d..030401eee6 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -2527,13 +2527,13 @@ public void test039(){ "----------\n" + "4. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/src2/Y.java (at line 4)\n" + " X x2 = new X();\n" + - " ^^^^^^^^^^^^^^^\n" + - "Discouraged access: The constructor \'X()\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---/bin1\')\n" + + " ^\n" + + "Discouraged access: The type \'X\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---/bin1\')\n" + "----------\n" + "5. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/src2/Y.java (at line 4)\n" + " X x2 = new X();\n" + " ^\n" + - "Discouraged access: The type \'X\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---/bin1\')\n" + + "Discouraged access: The constructor \'X()\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---/bin1\')\n" + "----------\n" + "5 problems (5 warnings)\n", false); @@ -5331,17 +5331,17 @@ public void test148_access_restrictions(){ "----------\n" + "2. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 5)\n" + " ko = new KO();\n" + - " ^^^^^^^^\n" + - "Access restriction: The constructor \'KO()\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---\')\n" + + " ^^\n" + + "Access restriction: The type \'KO\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---\')\n" + "----------\n" + "3. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 5)\n" + " ko = new KO();\n" + " ^^\n" + - "Access restriction: The type \'KO\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---\')\n" + + "Access restriction: The constructor \'KO()\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---\')\n" + "----------\n" + "4. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 6)\n" + " ko.bar();\n" + - " ^^^^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'KO.bar()\' is not API (restriction on classpath entry \'---OUTPUT_DIR_PLACEHOLDER---\')\n" + "----------\n" + "5. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 7)\n" + diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AccessRestrictionsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AccessRestrictionsTests.java index 59b37f6f23..994a526d58 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AccessRestrictionsTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AccessRestrictionsTests.java @@ -167,7 +167,7 @@ public void test001() throws CoreException { "----------\n" + "1. ERROR in /P2/src/p/Y.java (at line 4)\n" + " foo(); // accesses X1.foo, should trigger an error\n" + - " ^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X1.foo()\' is not API (restriction on required project \'P1\')\n" + "----------\n" ); @@ -352,7 +352,7 @@ public void test003() throws CoreException { "----------\n" + "3. ERROR in /P2/src/p/Y.java (at line 6)\n" + " foo(); // error\n" + - " ^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X1.C1.foo()\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "4. ERROR in /P2/src/p/Y.java (at line 11)\n" + @@ -362,13 +362,13 @@ public void test003() throws CoreException { "----------\n" + "5. ERROR in /P2/src/p/Y.java (at line 12)\n" + " new C1(0); // error\n" + - " ^^^^^^^^^\n" + - "Access restriction: The constructor \'X1.C1(int)\' is not API (restriction on required project \'P1\')\n" + + " ^^\n" + + "Access restriction: The type \'X1.C1\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "6. ERROR in /P2/src/p/Y.java (at line 12)\n" + " new C1(0); // error\n" + " ^^\n" + - "Access restriction: The type \'X1.C1\' is not API (restriction on required project \'P1\')\n" + + "Access restriction: The constructor \'X1.C1(int)\' is not API (restriction on required project \'P1\')\n" + "----------\n" ); } finally { @@ -531,7 +531,7 @@ public void test005() throws CoreException { "----------\n" + "1. ERROR in /P2/src/r/Y.java (at line 4)\n" + " (new q.X2()).foo(); // accesses p.X1#foo, should trigger an error\n" + - " ^^^^^^^^^^^^^^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X1.foo()\' is not API (restriction on required project \'P1\')\n" + "----------\n" ); @@ -617,13 +617,13 @@ public void test006() throws CoreException { "----------\n" + "3. ERROR in /P2/src/p/Y.java (at line 4)\n" + " X x2 = new X();\n" + - " ^^^^^^^^^^^^^^^\n" + - "Access restriction: The constructor \'X()\' is not API (restriction on required project \'P1\')\n" + + " ^\n" + + "Access restriction: The type \'X\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "4. ERROR in /P2/src/p/Y.java (at line 4)\n" + " X x2 = new X();\n" + " ^\n" + - "Access restriction: The type \'X\' is not API (restriction on required project \'P1\')\n" + + "Access restriction: The constructor \'X()\' is not API (restriction on required project \'P1\')\n" + "----------\n"); } finally { if (x != null) { @@ -709,13 +709,13 @@ public void test007() throws CoreException { "----------\n" + "3. ERROR in /P2/src/p/Y.java (at line 4)\n" + " X x2 = new X(\"\");\n" + - " ^^^^^^^^^^^^^^^^^\n" + - "Access restriction: The constructor \'X(String)\' is not API (restriction on required project \'P1\')\n" + + " ^\n" + + "Access restriction: The type \'X\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "4. ERROR in /P2/src/p/Y.java (at line 4)\n" + " X x2 = new X(\"\");\n" + " ^\n" + - "Access restriction: The type \'X\' is not API (restriction on required project \'P1\')\n" + + "Access restriction: The constructor \'X(String)\' is not API (restriction on required project \'P1\')\n" + "----------\n"); } finally { if (x != null) { @@ -800,7 +800,7 @@ public void test008() throws CoreException { "----------\n" + "1. ERROR in /P2/src/p/Y.java (at line 4)\n" + " foo(); // accesses X1.foo, should trigger an error\n" + - " ^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X1.foo()\' is not API (restriction on required project \'P1\')\n" + "----------\n" ); @@ -996,7 +996,7 @@ public void test010() throws CoreException { "----------\n" + "3. ERROR in /P2/src/p/Y.java (at line 6)\n" + " foo(); // error\n" + - " ^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X1.C1.foo()\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "4. ERROR in /P2/src/p/Y.java (at line 11)\n" + @@ -1006,13 +1006,13 @@ public void test010() throws CoreException { "----------\n" + "5. ERROR in /P2/src/p/Y.java (at line 12)\n" + " new C1(0); // error\n" + - " ^^^^^^^^^\n" + - "Access restriction: The constructor \'X1.C1(int)\' is not API (restriction on required project \'P1\')\n" + + " ^^\n" + + "Access restriction: The type \'X1.C1\' is not API (restriction on required project \'P1\')\n" + "----------\n" + "6. ERROR in /P2/src/p/Y.java (at line 12)\n" + " new C1(0); // error\n" + " ^^\n" + - "Access restriction: The type \'X1.C1\' is not API (restriction on required project \'P1\')\n" + + "Access restriction: The constructor \'X1.C1(int)\' is not API (restriction on required project \'P1\')\n" + "----------\n" ); } finally { @@ -1070,17 +1070,17 @@ public void test011() throws CoreException { "----------\n" + "2. ERROR in /P1/src/q/Y.java (at line 4)\n" + " p.X x = new p.X();\n" + - " ^^^^^^^^^\n" + - "Access restriction: The constructor \'X()\' is not API (restriction on required library \'AccessRestrictions/lib.jar\')\n" + + " ^^^\n" + + "Access restriction: The type \'X\' is not API (restriction on required library \'AccessRestrictions/lib.jar\')\n" + "----------\n" + "3. ERROR in /P1/src/q/Y.java (at line 4)\n" + " p.X x = new p.X();\n" + " ^^^\n" + - "Access restriction: The type \'X\' is not API (restriction on required library \'AccessRestrictions/lib.jar\')\n" + + "Access restriction: The constructor \'X()\' is not API (restriction on required library \'AccessRestrictions/lib.jar\')\n" + "----------\n" + "4. ERROR in /P1/src/q/Y.java (at line 5)\n" + " x.foo();\n" + - " ^^^^^^^\n" + + " ^^^\n" + "Access restriction: The method \'X.foo()\' is not API (restriction on required library \'AccessRestrictions/lib.jar\')\n" + "----------\n" + "5. ERROR in /P1/src/q/Y.java (at line 6)\n" + diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java index 50391b4520..78b31ccf23 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -513,7 +513,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { * An access in the same compilation unit is allowed. */ public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope, - boolean isExplicitUse) { + boolean isExplicitUse, InvocationSite invocation) { // ignore references insing Javadoc comments if ((this.bits & ASTNode.InsideJavadoc) == 0 && method.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(method)) { // ignore cases where method is used from inside itself (e.g. direct recursions) @@ -530,7 +530,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { AccessRestriction restriction = env.getAccessRestriction(method.declaringClass.erasure()); if (restriction != null) { - scope.problemReporter().forbiddenReference(method, this, + scope.problemReporter().forbiddenReference(method, invocation, restriction.classpathEntryType, restriction.classpathEntryName, restriction.getProblemId()); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 7710fcfdee..d53c24f175 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -503,7 +503,7 @@ public TypeBinding resolveType(BlockScope scope) { if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInConstructor(this, this.binding); } - if (isMethodUseDeprecated(this.binding, scope, true)) { + if (isMethodUseDeprecated(this.binding, scope, true, this)) { scope.problemReporter().deprecatedMethod(this.binding, this); } if (checkInvocationArguments(scope, null, this.resolvedType, this.binding, this.arguments, this.argumentTypes, this.argsContainCast, this)) { @@ -809,4 +809,12 @@ public ExpressionContext getExpressionContext() { public InferenceContext18 freshInferenceContext(Scope scope) { return new InferenceContext18(scope, this.arguments, this, this.outerInferenceContext); } +@Override +public int nameSourceStart() { + return this.type.sourceStart; +} +@Override +public int nameSourceEnd() { + return this.type.sourceEnd; +} } \ No newline at end of file diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java index 0553640750..de4fc80b4d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -446,7 +446,7 @@ public class ExplicitConstructorCall extends Statement implements Invocation { scope.problemReporter().missingTypeInConstructor(this, this.binding); } } - if (isMethodUseDeprecated(this.binding, scope, this.accessMode != ExplicitConstructorCall.ImplicitSuper)) { + if (isMethodUseDeprecated(this.binding, scope, this.accessMode != ExplicitConstructorCall.ImplicitSuper, this)) { scope.problemReporter().deprecatedMethod(this.binding, this); } if (checkInvocationArguments(scope, null, receiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java index 7b69cf564b..d0c1c6d56a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -144,7 +144,7 @@ public class JavadocAllocationExpression extends AllocationExpression { } } } - if (isMethodUseDeprecated(this.binding, scope, true)) { + if (isMethodUseDeprecated(this.binding, scope, true, this)) { scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers()); } return allocationType; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java index a1988de9bf..4fdc64dc71 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -172,7 +172,7 @@ public class JavadocMessageSend extends MessageSend { } } } - if (isMethodUseDeprecated(this.binding, scope, true)) { + if (isMethodUseDeprecated(this.binding, scope, true, this)) { scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers()); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 2421cfb906..2e52f5a05e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -898,7 +898,7 @@ public TypeBinding resolveType(BlockScope scope) { } // abstract private methods cannot occur nor abstract static............ } - if (isMethodUseDeprecated(this.binding, scope, true)) + if (isMethodUseDeprecated(this.binding, scope, true, this)) scope.problemReporter().deprecatedMethod(this.binding, this); TypeBinding returnType; @@ -1171,4 +1171,12 @@ public InferenceContext18 freshInferenceContext(Scope scope) { public boolean isQualifiedSuper() { return this.receiver.isQualifiedSuper(); } +@Override +public int nameSourceStart() { + return (int) (this.nameSourcePosition >>> 32); +} +@Override +public int nameSourceEnd() { + return (int) this.nameSourcePosition; +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index bed5d38c3f..bd4ba12a44 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -561,7 +561,7 @@ public class QualifiedAllocationExpression extends AllocationExpression { ReferenceBinding receiver = (ReferenceBinding) receiverType; ReferenceBinding superType = receiver.isInterface() ? scope.getJavaLangObject() : receiver; if (constructorBinding.isValidBinding()) { - if (isMethodUseDeprecated(constructorBinding, scope, true)) { + if (isMethodUseDeprecated(constructorBinding, scope, true, this)) { scope.problemReporter().deprecatedMethod(constructorBinding, this); } if (checkInvocationArguments(scope, null, superType, constructorBinding, this.arguments, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java index c7e4eb8909..d6d044c7a5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -799,7 +799,7 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx srcMethod.bits &= ~ASTNode.CanBeStatic; } - if (isMethodUseDeprecated(this.binding, scope, true)) + if (isMethodUseDeprecated(this.binding, scope, true, this)) scope.problemReporter().deprecatedMethod(this.binding, this); if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java index 8513fed83b..aa57e1214e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -34,6 +34,8 @@ public interface InvocationSite { void setFieldIndex(int depth); int sourceEnd(); int sourceStart(); + default int nameSourceStart() { return sourceStart(); } + default int nameSourceEnd() { return sourceEnd(); } TypeBinding invocationTargetType(); boolean receiverIsImplicitThis(); boolean checkingPotentialCompatibility(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index a4db767ee5..1a47e1d8c2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -2453,7 +2453,7 @@ public void forbiddenReference(FieldBinding field, ASTNode location, } /** @param classpathEntryType one of {@link AccessRestriction#COMMAND_LINE}, * {@link AccessRestriction#LIBRARY}, {@link AccessRestriction#PROJECT} */ -public void forbiddenReference(MethodBinding method, ASTNode location, +public void forbiddenReference(MethodBinding method, InvocationSite location, byte classpathEntryType, String classpathEntryName, int problemId) { int severity = computeSeverity(problemId); if (severity == ProblemSeverities.Ignore) return; @@ -2466,8 +2466,8 @@ public void forbiddenReference(MethodBinding method, ASTNode location, classpathEntryName, new String(method.shortReadableName())}, severity, - location.sourceStart, - location.sourceEnd); + location.nameSourceStart(), + location.nameSourceEnd()); else this.handle( problemId, @@ -2478,8 +2478,8 @@ public void forbiddenReference(MethodBinding method, ASTNode location, new String(method.shortReadableName()), new String(method.declaringClass.shortReadableName())}, severity, - location.sourceStart, - location.sourceEnd); + location.nameSourceStart(), + location.nameSourceEnd()); } /** @param classpathEntryType one of {@link AccessRestriction#COMMAND_LINE}, * {@link AccessRestriction#LIBRARY}, {@link AccessRestriction#PROJECT} */ diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java index 2de2f1abcf..1536b4faf0 100644 --- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java +++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -279,7 +279,7 @@ public TypeBinding resolveType(BlockScope scope) { return this.resolvedType; } } - if (isMethodUseDeprecated(this.binding, scope, true)) { + if (isMethodUseDeprecated(this.binding, scope, true, this)) { scope.problemReporter().deprecatedMethod(this.binding, this); } if (this.arguments != null) { diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java index 98d1f8631c..9a00586b24 100644 --- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java +++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -337,7 +337,7 @@ public TypeBinding resolveType(BlockScope scope) { } // abstract private methods cannot occur nor abstract static............ } - if (isMethodUseDeprecated(this.binding, scope, true)) + if (isMethodUseDeprecated(this.binding, scope, true, this)) scope.problemReporter().deprecatedMethod(this.binding, this); // from 1.5 compliance on, array#clone() returns the array type (but binding still shows Object) -- cgit v1.2.3 From d72112c8968b4b1fb650450aadf69127448ef933 Mon Sep 17 00:00:00 2001 From: Vikas Chandra Date: Mon, 11 Feb 2019 09:46:22 +0530 Subject: Bug 543996 - [11][javadoc] Support all javadoc tags in module documentation Change-Id: Ie0358004fcefd9fab47ef08ad973f456bf26c65b Signed-off-by: Vikas Chandra --- .../parser/JavadocCompletionParserTest.java | 21 ++++++++--- .../jdt/internal/codeassist/CompletionEngine.java | 41 +++++++++++++++++++++- .../complete/CompletionOnJavadocTag.java | 6 +++- .../internal/compiler/parser/JavadocParser.java | 14 ++++++-- .../compiler/parser/JavadocTagConstants.java | 26 ++++++++++++-- 5 files changed, 97 insertions(+), 11 deletions(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/JavadocCompletionParserTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/JavadocCompletionParserTest.java index 677874c917..a12ef9f626 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/JavadocCompletionParserTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/JavadocCompletionParserTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -159,6 +159,7 @@ protected void verifyCompletionOnJavadocTag(char[] tag, char[][] expectedTags, b } protected void verifyAllTagsCompletion() { + char[][] allTagsFinal =null; char[][] allTags = { // Block tags TAG_AUTHOR, TAG_DEPRECATED, TAG_EXCEPTION, TAG_PARAM, TAG_RETURN, TAG_SEE, TAG_VERSION, TAG_CATEGORY, @@ -168,6 +169,15 @@ protected void verifyAllTagsCompletion() { TAG_LINK, TAG_DOC_ROOT, }; + char[][] allTagsJava9Plus = { + // Block tags + TAG_AUTHOR, TAG_DEPRECATED, TAG_EXCEPTION, TAG_PARAM, TAG_RETURN, TAG_SEE, TAG_VERSION, TAG_CATEGORY, + TAG_SINCE, + TAG_SERIAL, TAG_SERIAL_DATA, TAG_SERIAL_FIELD , TAG_THROWS, TAG_USES, TAG_PROVIDES, + // Inline tags + TAG_LINK, + TAG_DOC_ROOT + }; char[][] additionalTags = null; if(this.complianceLevel == ClassFileConstants.JDK1_4) { additionalTags = new char[][] { @@ -179,13 +189,14 @@ protected void verifyAllTagsCompletion() { TAG_CODE, TAG_LITERAL }; } + allTagsFinal = this.complianceLevel > ClassFileConstants.JDK1_8 ? allTagsJava9Plus : allTags; if (additionalTags != null) { - int length = allTags.length; + int length = allTagsFinal.length; int add = additionalTags.length; - System.arraycopy(allTags, 0, allTags = new char[length+add][], 0, length); - System.arraycopy(additionalTags, 0, allTags, length, add); + System.arraycopy(allTagsFinal, 0, allTagsFinal = new char[length+add][], 0, length); + System.arraycopy(additionalTags, 0, allTagsFinal, length, add); } - verifyCompletionOnJavadocTag(null, allTags, false); + verifyCompletionOnJavadocTag(null, allTagsFinal, false); } /** diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java index a25328f3e7..ba6cc119a2 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java @@ -60,6 +60,7 @@ import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.internal.codeassist.complete.AssistNodeParentAnnotationArrayInitializer; +import org.eclipse.jdt.internal.codeassist.complete.CompletionJavadoc; import org.eclipse.jdt.internal.codeassist.complete.CompletionNodeDetector; import org.eclipse.jdt.internal.codeassist.complete.CompletionNodeFound; import org.eclipse.jdt.internal.codeassist.complete.CompletionOnAnnotationOfType; @@ -2236,7 +2237,8 @@ public final class CompletionEngine } } } - + // javadoc tag completion in module-info file + contextAccepted = completeJavadocTagInModuleInfo(parsedUnit); if (parsedUnit.types != null) { try { this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); @@ -2339,6 +2341,43 @@ public final class CompletionEngine } } + private boolean completeJavadocTagInModuleInfo(CompilationUnitDeclaration parsedUnit) { + boolean contextAccepted = false; + if (this.parser.assistNodeParent instanceof CompletionJavadoc && parsedUnit.isModuleInfo() ) { + try { + this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); + if(this.parser.assistNode instanceof CompletionOnJavadocTag) { + ((CompletionOnJavadocTag)this.parser.assistNode).filterPossibleTags(parsedUnit.scope); + } + throw new CompletionNodeFound(this.parser.assistNode, null, parsedUnit.scope); + } + catch (CompletionNodeFound e) { + if (e.astNode != null) { + // if null then we found a problem in the completion node + if(DEBUG) { + System.out.print("COMPLETION - Completion node : "); //$NON-NLS-1$ + System.out.println(e.astNode.toString()); + if(this.parser.assistNodeParent != null) { + System.out.print("COMPLETION - Parent Node : "); //$NON-NLS-1$ + System.out.println(this.parser.assistNodeParent); + } + } + this.lookupEnvironment.unitBeingCompleted = parsedUnit; // better resilient to further error reporting + contextAccepted = + complete( + e.astNode, + this.parser.assistNodeParent, + this.parser.enclosingNode, + parsedUnit, + e.qualifiedBinding, + e.scope, + e.insideTypeAnnotation); + } + } + } + return contextAccepted; + } + private boolean checkForCNF(TypeReference ref, CompilationUnitDeclaration parsedUnit, boolean showAll) { this.lookupEnvironment.buildTypeBindings(parsedUnit, null); this.lookupEnvironment.completeTypeBindings(parsedUnit, true); diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java index 15215c711d..b620240aec 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java @@ -86,8 +86,12 @@ public class CompletionOnJavadocTag extends JavadocSingleNameReference implement switch (kind) { case Scope.COMPILATION_UNIT_SCOPE: // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=255752 - // Check for FAKE_TYPE_NAME to allow proposals (@see CompletionParser#consumeCompilationUnit) + // Check for FAKE_TYPE_NAME to allow proposals (@see CompletionParser#consumeCompilationUnit) CompilationUnitDeclaration compilationUnit = scope.referenceCompilationUnit(); + if(compilationUnit != null && compilationUnit.isModuleInfo() ) { + specifiedTags = MODULE_TAGS; + break; + } if (compilationUnit != null && (compilationUnit.types.length > 0 && compilationUnit.types[0].name == CompletionParser.FAKE_TYPE_NAME)) { specifiedTags = CLASS_TAGS; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java index efad084512..3817b6db1a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -609,6 +609,10 @@ public class JavadocParser extends AbstractCommentParser { valid = parseParam(); } } + if (length == TAG_PROVIDES_LENGTH && CharOperation.equals(TAG_PROVIDES, tagName, 0, length)) { + this.tagValue = TAG_PROVIDES_VALUE; + this.tagWaitingForDescription = this.tagValue; + } break; case 'r': if (length == TAG_RETURN_LENGTH && CharOperation.equals(TAG_RETURN, tagName, 0, length)) { @@ -636,7 +640,7 @@ public class JavadocParser extends AbstractCommentParser { } else if (length == TAG_SINCE_LENGTH && CharOperation.equals(TAG_SINCE, tagName, 0, length)) { this.tagValue = TAG_SINCE_VALUE; this.tagWaitingForDescription = this.tagValue; - } + } break; case 't': if (length == TAG_THROWS_LENGTH && CharOperation.equals(TAG_THROWS, tagName, 0, length)) { @@ -646,6 +650,12 @@ public class JavadocParser extends AbstractCommentParser { } } break; + case 'u': + if (length == TAG_USES_LENGTH && CharOperation.equals(TAG_USES, tagName, 0, length)) { + this.tagValue = TAG_USES_VALUE; + this.tagWaitingForDescription = this.tagValue; + } + break; case 'v': if (length == TAG_VALUE_LENGTH && CharOperation.equals(TAG_VALUE, tagName, 0, length)) { this.tagValue = TAG_VALUE_VALUE; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java index 64077fde76..10f540e36f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java @@ -44,6 +44,8 @@ public interface JavadocTagConstants { public static final char[] TAG_SINCE = "since".toCharArray(); //$NON-NLS-1$ public static final char[] TAG_VERSION = "version".toCharArray(); //$NON-NLS-1$ public static final char[] TAG_CATEGORY = "category".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_USES = "uses".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_PROVIDES = "provides".toCharArray(); //$NON-NLS-1$ // tags lengthes public static final int TAG_DEPRECATED_LENGTH = TAG_DEPRECATED.length; @@ -66,6 +68,8 @@ public interface JavadocTagConstants { public static final int TAG_CODE_LENGTH = TAG_CODE.length; public static final int TAG_LITERAL_LENGTH = TAG_LITERAL.length; public static final int TAG_DOC_ROOT_LENGTH = TAG_DOC_ROOT.length; + public static final int TAG_USES_LENGTH = TAG_USES.length; + public static final int TAG_PROVIDES_LENGTH = TAG_PROVIDES.length; // tags value public static final int NO_TAG_VALUE = 0; @@ -89,8 +93,9 @@ public interface JavadocTagConstants { public static final int TAG_CODE_VALUE = 18; public static final int TAG_LITERAL_VALUE = 19; public static final int TAG_DOC_ROOT_VALUE = 20; + public static final int TAG_USES_VALUE=21; + public static final int TAG_PROVIDES_VALUE=22; public static final int TAG_OTHERS_VALUE = 100; - // Tag names array public static final char[][] TAG_NAMES = { CharOperation.NO_CHAR, @@ -153,7 +158,7 @@ public interface JavadocTagConstants { // since 1.8 {}, // since 9 - {}, + {TAG_USES, TAG_PROVIDES}, // since 10 {}, // since 11 @@ -280,4 +285,21 @@ public interface JavadocTagConstants { TAG_CODE, TAG_LITERAL }; + public static final char[][] MODULE_TAGS = { + TAG_SEE, + TAG_SINCE, + TAG_DEPRECATED, + TAG_SERIAL, + TAG_AUTHOR, + TAG_VERSION, + TAG_CATEGORY, + TAG_LINK, + TAG_LINKPLAIN, + TAG_DOC_ROOT, + TAG_VALUE, + TAG_CODE, + TAG_LITERAL, + TAG_USES, + TAG_PROVIDES + }; } -- cgit v1.2.3 From b4f0aca0d0d0d586e169d20459c77ee8e03fbccb Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Fri, 22 Feb 2019 16:24:03 +0530 Subject: Bug 544602: Compile log page not found for jdt.core bundle Change-Id: If87853bf0a4f017e2c40b4614deaf182ef7a7777 Signed-off-by: Jay Arthanareeswaran --- .../eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java | 2 +- .../batch/org/eclipse/jdt/internal/compiler/batch/Main.java | 2 +- org.eclipse.jdt.core/schema/compiler.dtd | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java index 030401eee6..398e5acd37 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java @@ -984,7 +984,7 @@ public void test012b(){ String logContents = Util.fileContent(logFileName); String expectedLogContents = "\n" + - "\n" + + "\n" + "\n" + " \n" + " \n" + diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index ec77b2ada8..18957eae3e 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -191,7 +191,7 @@ public class Main implements ProblemSeverities, SuffixConstants { private static final String INFO = "INFO"; //$NON-NLS-1$ public static final int XML = 1; - private static final String XML_DTD_DECLARATION = ""; //$NON-NLS-1$ + private static final String XML_DTD_DECLARATION = ""; //$NON-NLS-1$ static { try { Class c = IProblem.class; diff --git a/org.eclipse.jdt.core/schema/compiler.dtd b/org.eclipse.jdt.core/schema/compiler.dtd index e83ee0a263..bb57d15ab7 100644 --- a/org.eclipse.jdt.core/schema/compiler.dtd +++ b/org.eclipse.jdt.core/schema/compiler.dtd @@ -69,7 +69,8 @@ optionKey CDATA #IMPLIED > - + Also-by: Stephan Herrmann --- .../regression/ModuleCompilationTests.java | 7 +- .../jdt/core/tests/util/AbstractCompilerTest.java | 2 + .../core/tests/model/AbstractJavaModelTests.java | 13 + .../jdt/core/tests/model/ModuleBuilderTests.java | 453 ++++++++++++++++++++- .../internal/compiler/batch/ClasspathJep247.java | 20 +- .../compiler/batch/ClasspathJep247Jdk12.java | 303 ++++++++++++++ .../jdt/internal/compiler/batch/FileSystem.java | 13 +- .../compiler/env/NameEnvironmentAnswer.java | 4 +- .../jdt/internal/compiler/util/JRTUtil.java | 262 +++++++++--- .../jdt/internal/core/builder/ClasspathJrt.java | 182 +++------ .../builder/ClasspathJrtWithReleaseOption.java | 387 ++++++++++++++++++ .../internal/core/builder/ClasspathLocation.java | 8 +- .../jdt/internal/core/builder/JavaBuilder.java | 2 +- .../eclipse/jdt/internal/core/builder/State.java | 28 +- .../search/matching/JavaSearchNameEnvironment.java | 3 +- 15 files changed, 1454 insertions(+), 233 deletions(-) create mode 100644 org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java create mode 100644 org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java index 65587be739..349e89cf8d 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java @@ -40,7 +40,7 @@ import junit.framework.Test; public class ModuleCompilationTests extends AbstractBatchCompilerTest { static { -// TESTS_NAMES = new String[] { "testBug540067e" }; +// TESTS_NAMES = new String[] { "test001" }; // TESTS_NUMBERS = new int[] { 1 }; // TESTS_RANGE = new int[] { 298, -1 }; } @@ -3975,11 +3975,11 @@ public void testBug521362_emptyFile() { "}", }, "\"" + OUTPUT_DIR + File.separator + "X.java\"" - + " --release 6 -d \"" + OUTPUT_DIR + "\"", + + " --release 7 -d \"" + OUTPUT_DIR + "\"", "", "", true); - String expectedOutput = "// Compiled from X.java (version 1.6 : 50.0, super bit)"; + String expectedOutput = "// Compiled from X.java (version 1.7 : 51.0, super bit)"; checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); } public void testReleaseOption4() throws Exception { @@ -4094,6 +4094,7 @@ public void testBug521362_emptyFile() { true); } public void testReleaseOption10() throws Exception { + if (isJRE12Plus) return; this.runNegativeTest( new String[] { "X.java", diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java index 33aa81cb9a..fee9aacbe9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java @@ -53,6 +53,7 @@ public class AbstractCompilerTest extends TestCase { protected boolean enableAPT = false; protected static boolean isJRE9Plus = false; // Stop gap, so tests need not be run at 9, but some tests can be adjusted for JRE 9 protected static boolean isJRE11Plus = false; + protected static boolean isJRE12Plus = false; protected static boolean reflectNestedClassUseDollar; /** @@ -147,6 +148,7 @@ public class AbstractCompilerTest extends TestCase { int lessthan9 = F_1_3 | F_1_4 | F_1_5 | F_1_6 | F_1_7 | F_1_8; isJRE9Plus = !isJRELevel(lessthan9); isJRE11Plus = isJRELevel(F_11); + isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); } /** diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java index df6e565b35..72600309b7 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java @@ -74,6 +74,9 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { protected String endChar = ","; protected static boolean isJRE9 = false; + protected static boolean isJRE10 = false; + protected static boolean isJRE11 = false; + protected static boolean isJRE12 = false; protected static String DEFAULT_MODULES = null; static { String javaVersion = System.getProperty("java.version"); @@ -87,6 +90,16 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { } } long jdkLevel = CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion); + if (jdkLevel >= ClassFileConstants.JDK11) { + if (CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion, false) == 0) { + // version was capped to 11 during versionToJdkLevel(version, true) + isJRE12 = true; + } + isJRE11 = true; + } + if (jdkLevel >= ClassFileConstants.JDK10) { + isJRE10 = true; + } if (jdkLevel >= ClassFileConstants.JDK9) { isJRE9 = true; if (vmName.contains("HotSpot")) { diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java index b80de70c73..ddc65ad408 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java @@ -696,8 +696,14 @@ public class ModuleBuilderTests extends ModifyingResourceTests { public void testConvertToModule() throws CoreException, IOException { Hashtable javaCoreOptions = JavaCore.getOptions(); try { - IJavaProject project = setUpJavaProject("ConvertToModule", "9"); - assertEquals(project.getOption("org.eclipse.jdt.core.compiler.compliance", true), "9"); + IJavaProject project = setUpJavaProject("ConvertToModule"); + Map options = new HashMap<>(); + // Make sure the new options map doesn't reset. + options.put(CompilerOptions.OPTION_Compliance, "9"); + options.put(CompilerOptions.OPTION_Source, "9"); + options.put(CompilerOptions.OPTION_TargetPlatform, "9"); + options.put(CompilerOptions.OPTION_Release, "enabled"); + project.setOptions(options); project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); IPackageFragmentRoot[] roots = project.getPackageFragmentRoots(); IPackageFragmentRoot theRoot = null; @@ -709,7 +715,14 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } assertNotNull("should not be null", theRoot); String[] modules = JavaCore.getReferencedModules(project); - assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); + if (isJRE12) + assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); + else if (isJRE11) + assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.net.http", "java.rmi", "java.sql"}, modules); + else if (isJRE10) + assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.rmi", "java.sql"}, modules); + else // 9 + assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); } finally { this.deleteProject("ConvertToModule"); JavaCore.setOptions(javaCoreOptions); @@ -8040,6 +8053,440 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } } + public void testReleaseOption1() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption2() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "The project was not built due to \"release 6 is not found in the system\". " + + "Fix the problem, then try refreshing this project and building it since it may be inconsistent", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption3() throws Exception { + if (isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "java.util.stream.Stream cannot be resolved to a type", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption4() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption5() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "java.util.stream.Stream cannot be resolved to a type", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption6() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "interface I {\n" + + " int add(int x, int y);\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " I i = (x, y) -> {\n" + + " return x + y;\n" + + " };\n" + + " }\n" + + "}\n"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "Lambda expressions are allowed only at source level 1.8 or above", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption7() throws Exception { + if (isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "import java.io.*;\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " try {\n" + + " System.out.println();\n" + + " Reader r = new FileReader(args[0]);\n" + + " r.read();\n" + + " } catch(IOException | FileNotFoundException e) {\n" + + " e.printStackTrace();\n" + + " }\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + sortMarkers(markers); + assertMarkers("Unexpected markers", + "Multi-catch parameters are not allowed for source level below 1.7\n" + + "The exception FileNotFoundException is already caught by the alternative IOException", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption8() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption9() throws Exception { + if (!isJRE10) return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption10() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + sortMarkers(markers); + String expected = + "Syntax error on token \"module\", package expected\n" + + "Syntax error on token(s), misplaced construct(s)\n" + + "Syntax error on token \".\", , expected\n" + + "Syntax error on token \"}\", delete this token"; + assertMarkers("Unexpected markers", + expected, markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption11() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + createFolder("p/src/foo"); + createFile( + "p/src/foo/Module.java", + "package foo;\n" + + "public class Module {}\n"); + createFile( + "p/src/foo/X.java", + "package foo;\n" + + "public class X { \n" + + " public Module getModule(String name) {\n" + + " return null;\n" + + " }\n" + + "}"); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption12() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "import java.io.*;\n" + + "\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " String str = Integer.toUnsignedString(1, 1);\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "The method toUnsignedString(int, int) is undefined for the type Integer", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption13() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " Integer.toUnsignedString(1, 1);\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } protected void assertNoErrors() throws CoreException { for (IProject p : getWorkspace().getRoot().getProjects()) { int maxSeverity = p.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java index 7a39271115..8aad54669b 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 IBM Corporation. + * Copyright (c) 2018, 2019 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,15 +42,15 @@ import org.eclipse.jdt.internal.compiler.util.Util; public class ClasspathJep247 extends ClasspathJrt { - private java.nio.file.FileSystem fs = null; - private String compliance = null; - private long jdklevel; - private String releaseInHex = null; - private String[] subReleases = null; - private Path releasePath = null; - private Set packageCache; - File jdkHome; - String modulePath = null; + protected java.nio.file.FileSystem fs = null; + protected String compliance = null; + protected long jdklevel; + protected String releaseInHex = null; + protected String[] subReleases = null; + protected Path releasePath = null; + protected Set packageCache; + protected File jdkHome; + protected String modulePath = null; public ClasspathJep247(File jdkHome, String release, AccessRuleSet accessRuleSet) { super(jdkHome, false, accessRuleSet, null); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java new file mode 100644 index 0000000000..52a83987cf --- /dev/null +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java @@ -0,0 +1,303 @@ +/******************************************************************************* + * Copyright (c) 2019 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ClasspathJep247Jdk12 extends ClasspathJep247 { + + Map modules; + + public ClasspathJep247Jdk12(File jdkHome, String release, AccessRuleSet accessRuleSet) { + super(jdkHome, release, accessRuleSet); + } + @Override + public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { + return null; + } + @Override + public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { + return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); + } + @Override + public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { + if (!isPackage(qualifiedPackageName, moduleName)) + return null; // most common case + + try { + ClassFileReader reader = null; + byte[] content = null; + qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ + if (this.subReleases != null && this.subReleases.length > 0) { + done: for (String rel : this.subReleases) { + if (moduleName == null) { + Path p = this.fs.getPath(rel); + try (DirectoryStream stream = Files.newDirectoryStream(p)) { + for (final java.nio.file.Path subdir: stream) { + Path f = this.fs.getPath(rel, subdir.getFileName().toString(), qualifiedBinaryFileName); + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content != null) + break done; + } + } + } + } else { + Path p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); + if (Files.exists(p)) { + content = JRTUtil.safeReadBytes(p); + if (content != null) + break; + } + } + } + } else { + content = JRTUtil.safeReadBytes(this.fs.getPath(this.releaseInHex, qualifiedBinaryFileName)); + } + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), null); + } + } catch(ClassFormatException e) { + // Continue + } catch (IOException e) { + // continue + } + return null; + } + + @Override + public void initialize() throws IOException { + if (this.compliance == null) { + return; + } + if (this.fs != null) { + super.initialize(); + return; + } + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.compliance)).toUpperCase(); + Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ + URI t = filePath.toUri(); + if (!Files.exists(filePath)) { + return; + } + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + this.fs = FileSystems.newFileSystem(uri, env); + } + this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + if (!Files.exists(this.fs.getPath(this.releaseInHex))) { + throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ + } + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (rel.contains(this.releaseInHex)) + sub.add(rel); + } + this.subReleases = sub.toArray(new String[sub.size()]); + } catch (IOException e) { + //e.printStackTrace(); + } + super.initialize(); + } + @Override + public void loadModules() { + // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt + if (this.jdklevel <= ClassFileConstants.JDK1_8) { + super.loadModules(); + return; + } + final Path modPath = this.fs.getPath(this.releaseInHex); + this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ + this.modules = ModulesCache.get(this.modulePath); + if (this.modules == null) { + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (!rel.contains(this.releaseInHex)) { + continue; + } + Files.walkFileTree(subdir, Collections.EMPTY_SET, 2, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { + if (attrs.isDirectory() || f.getNameCount() < 3) + return FileVisitResult.CONTINUE; + byte[] content = null; + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content == null) + return FileVisitResult.CONTINUE; + Path m = f.subpath(1, f.getNameCount() - 1); + ClasspathJep247Jdk12.this.acceptModule(m.getFileName().toString(), content); + ClasspathJep247Jdk12.this.moduleNamesCache.add(m.getFileName().toString()); + } + return FileVisitResult.SKIP_SIBLINGS; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } catch (IOException e) { + e.printStackTrace(); + } + } else { + this.moduleNamesCache.addAll(this.modules.keySet()); + } + } + @Override + public Collection getModuleNames(Collection limitModule, Function getModule) { + return selectModules(this.moduleNamesCache, limitModule, getModule); + } + @Override + public IModule getModule(char[] moduleName) { + if (this.modules != null) { + return this.modules.get(String.valueOf(moduleName)); + } + return null; + } + void acceptModule(String name, byte[] content) { + if (content == null) + return; + + if (this.modules != null) { + if (this.modules.containsKey(name)) + return; + } + + ClassFileReader reader = null; + try { + reader = new ClassFileReader(content, IModule.MODULE_INFO_CLASS.toCharArray()); + } catch (ClassFormatException e) { + e.printStackTrace(); + } + if (reader != null) { + acceptModule(reader); + } + } + @Override + void acceptModule(ClassFileReader reader) { + // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt + if (this.jdklevel <= ClassFileConstants.JDK1_8) { + super.acceptModule(reader); + return; + } + if (reader != null) { + IModule moduleDecl = reader.getModuleDeclaration(); + if (moduleDecl != null) { + if (this.modules == null) { + ModulesCache.put(this.modulePath, this.modules = new HashMap()); + } + this.modules.put(String.valueOf(moduleDecl.name()), moduleDecl); + } + } + } + @Override + public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { + // Ignore moduleName as this has nothing to do with modules (as of now) + if (this.packageCache != null) + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + + this.packageCache = new HashSet<>(41); + this.packageCache.add(Util.EMPTY_STRING); + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (!rel.contains(this.releaseInHex)) { + continue; + } + try (DirectoryStream stream2 = Files.newDirectoryStream(subdir)) { + for (final java.nio.file.Path subdir2: stream2) { + Files.walkFileTree(subdir2, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + if (dir.getNameCount() <= 2) + return FileVisitResult.CONTINUE; + Path relative = dir.subpath(2, dir.getNameCount()); + addToPackageCache(relative.toString(), false); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + // Rethrow + } + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + } +} diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java index 1a81699b44..060351e20a 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -164,11 +164,14 @@ public class FileSystem implements IModuleAwareNameEnvironment, SuffixConstants Set knownFileNames; protected boolean annotationsFromClasspath; // should annotation files be read from the classpath (vs. explicit separate path)? private static HashMap JRT_CLASSPATH_CACHE = null; - protected Map moduleLocations = new HashMap<>(); /** Tasks resulting from --add-reads or --add-exports command line options. */ Map moduleUpdates = new HashMap<>(); + static final boolean isJRE12Plus; + static { + isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); //$NON-NLS-1$ //$NON-NLS-2$ + } /* classPathNames is a collection is Strings representing the full path of each class path @@ -205,6 +208,8 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot final Classpath classpath = paths[i]; try { classpath.initialize(); + for (String moduleName : classpath.getModuleNames(limitedModules)) + this.moduleLocations.put(moduleName, classpath); this.classpaths[counter++] = classpath; } catch(IOException | InvalidPathException exception) { // JRE 9 could throw an IAE if the linked JAR paths have invalid chars, such as ":" @@ -256,7 +261,9 @@ public static Classpath getJrtClasspath(String jdkHome, String encoding, AccessR return new ClasspathJrt(new File(convertPathSeparators(jdkHome)), true, accessRuleSet, null); } public static Classpath getOlderSystemRelease(String jdkHome, String release, AccessRuleSet accessRuleSet) { - return new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); + return isJRE12Plus ? + new ClasspathJep247Jdk12(new File(convertPathSeparators(jdkHome)), release, accessRuleSet) : + new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); } public static Classpath getClasspath(String classpathName, String encoding, boolean isSourceOnly, AccessRuleSet accessRuleSet, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java index bb3bfb757c..b11078dfe5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java @@ -32,9 +32,7 @@ public class NameEnvironmentAnswer { String externalAnnotationPath; // should be an absolute file system path public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction) { - this.binaryType = binaryType; - this.accessRestriction = accessRestriction; - this.moduleName = binaryType.getModule(); + this(binaryType, accessRestriction, binaryType.getModule()); } public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction, char[] module) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java index 481bbef429..f6903f814f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java @@ -22,6 +22,7 @@ import java.net.URLClassLoader; import java.nio.channels.ClosedByInterruptException; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -59,7 +60,7 @@ public class JRTUtil { public static int NOTIFY_ALL = NOTIFY_FILES | NOTIFY_PACKAGES | NOTIFY_MODULES; // TODO: Java 9 Think about clearing the cache too. - private static Map images = null; + private static Map images = null; private static final Object lock = new Object(); @@ -100,7 +101,11 @@ public class JRTUtil { } public static JrtFileSystem getJrtSystem(File image) { - Map i = images; + return getJrtSystem(image, null); + } + + public static JrtFileSystem getJrtSystem(File image, String release) { + Map i = images; if (images == null) { synchronized (lock) { i = images; @@ -110,10 +115,12 @@ public class JRTUtil { } } JrtFileSystem system = null; + String key = image.toString(); + if (release != null) key = key + "|" + release; //$NON-NLS-1$ synchronized(i) { - if ((system = images.get(image)) == null) { + if ((system = images.get(key)) == null) { try { - images.put(image, system = new JrtFileSystem(image)); + images.put(key, system = JrtFileSystem.getNewJrtFileSystem(image, release)); } catch (IOException e) { e.printStackTrace(); // Needs better error handling downstream? But for now, make sure @@ -138,8 +145,8 @@ public class JRTUtil { * /modules/$MODULE/$PATH * /packages/$PACKAGE/$MODULE * The latter provides quick look up of the module that contains a particular package. However, - * this method only notifies its clients of the entries within the modules sub-directory. The - * clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, + * this method only notifies its clients of the entries within the modules (latter) sub-directory. + * Clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, * {@link JRTUtil#NOTIFY_FILES}, {@link JRTUtil#NOTIFY_PACKAGES} and {@link JRTUtil#NOTIFY_MODULES}. * * @param image a java.io.File handle to the JRT image. @@ -148,7 +155,10 @@ public class JRTUtil { * @throws IOException */ public static void walkModuleImage(File image, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { - getJrtSystem(image).walkModuleImage(visitor, false, notify); + getJrtSystem(image, null).walkModuleImage(visitor, notify); + } + public static void walkModuleImage(File image, String release, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { + getJrtSystem(image, release).walkModuleImage(visitor, notify); } public static InputStream getContentFromJrt(File jrt, String fileName, String module) throws IOException { @@ -187,13 +197,138 @@ public class JRTUtil { } } } +class JrtFileSystemWithOlderRelease extends JrtFileSystem { + final String release; + String releaseInHex = null; + //private Path releasePath = null; + private String[] subReleases = null; + protected Path modulePath = null; + + /** + * The jrt file system is based on the location of the JRE home whose libraries + * need to be loaded. + * + * @param jrt the path to the root of the JRE whose libraries we are interested in. + * @param release the older release where classes and modules should be searched for. + * @throws IOException + */ + JrtFileSystemWithOlderRelease(File jrt, String release) throws IOException { + super(jrt); + this.release = release; + initialize(jrt, release); + } + @Override + void initialize(File jdk) throws IOException { + // Just to make sure we don't do anything in super.initialize() + // before setting this.release + } + void initialize(File jdk, String rel) throws IOException { + super.initialize(jdk); + this.fs = null;// reset and proceed, TODO: this is crude and need to be removed. + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); + Path ct = Paths.get(this.jdkHome, "lib", "ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ + if (!Files.exists(ct)) { + return; + } + URI uri = URI.create("jar:file:" + ct.toUri().getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + return; + } + } + Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + if (!Files.exists(this.fs.getPath(this.releaseInHex)) + || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ + this.fs = null; + } + if (this.release != null) { + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String r = subdir.getFileName().toString(); + if (r.contains(this.releaseInHex)) { + sub.add(r); + } else { + continue; + } + } + } catch (IOException e) { + e.printStackTrace(); + // Rethrow? + } + this.subReleases = sub.toArray(new String[sub.size()]); + } + // Ensure walkJrtForModules() is not called + } + @Override + void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { + if (this.subReleases != null && this.subReleases.length > 0) { + for (String rel : this.subReleases) { + Path p = this.fs.getPath(rel); + Files.walkFileTree(p, new JRTUtil.AbstractFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + int count = dir.getNameCount(); + if (count == 1) { + return FileVisitResult.CONTINUE; + } + if (count == 2) { + // e.g. /9A/java.base + java.nio.file.Path mod = dir.getName(1); + if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 + && JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { + return FileVisitResult.SKIP_SUBTREE; + } + return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? FileVisitResult.CONTINUE + : visitor.visitModule(dir); + } + if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { + // client is not interested in packages + return FileVisitResult.CONTINUE; + } + return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) + throws IOException { + if ((notify & JRTUtil.NOTIFY_FILES) == 0) { + return FileVisitResult.CONTINUE; + } + // This happens when a file in a default package is present. E.g. /modules/some.module/file.name + if (file.getNameCount() == 3) { + cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); + } + return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); + } + }); + } + } + } + +} class JrtFileSystem { private final Map packageToModule = new HashMap(); private final Map> packageToModules = new HashMap>(); - FileSystem jrtSystem = null; - + FileSystem fs = null; + Path modRoot = null; + String jdkHome = null; + public static JrtFileSystem getNewJrtFileSystem(File jrt, String release) throws IOException { + return (release == null) ? new JrtFileSystem(jrt) : + new JrtFileSystemWithOlderRelease(jrt, release); + + } /** * The jrt file system is based on the location of the JRE home whose libraries * need to be loaded. @@ -201,18 +336,18 @@ class JrtFileSystem { * @param jrt the path to the root of the JRE whose libraries we are interested in. * @throws IOException */ - public JrtFileSystem(File jrt) throws IOException { + JrtFileSystem(File jrt) throws IOException { initialize(jrt); } void initialize(File jrt) throws IOException { URL jrtPath = null; - String jdkHome = null; + this.jdkHome = null; if (jrt.toString().endsWith(JRTUtil.JRT_FS_JAR)) { jrtPath = jrt.toPath().toUri().toURL(); - jdkHome = jrt.getParentFile().getParent(); + this.jdkHome = jrt.getParentFile().getParent(); } else { - jdkHome = jrt.toPath().toString(); - jrtPath = Paths.get(jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ + this.jdkHome = jrt.toPath().toString(); + jrtPath = Paths.get(this.jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ } JRTUtil.MODULE_TO_LOAD = System.getProperty("modules.to.load"); //$NON-NLS-1$ @@ -220,13 +355,15 @@ class JrtFileSystem { if (javaVersion != null && javaVersion.startsWith("1.8")) { //$NON-NLS-1$ URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath }); HashMap env = new HashMap<>(); - this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); + this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); } else { HashMap env = new HashMap<>(); - env.put("java.home", jdkHome); //$NON-NLS-1$ - this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); + env.put("java.home", this.jdkHome); //$NON-NLS-1$ + this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); } - walkModuleImage(null, true, 0 /* doesn't matter */); + this.modRoot = this.fs.getPath(JRTUtil.MODULES_SUBDIR); + // Set up the root directory wherere modules are located + walkJrtForModules(); } public List getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { @@ -279,7 +416,7 @@ class JrtFileSystem { String knownModule = this.packageToModule.get(qualifiedPackageName); if (knownModule == null || (knownModule != JRTUtil.MULTIPLE && !knownModule.equals(module))) return false; - Path packagePath = this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); + Path packagePath = this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); if (!Files.exists(packagePath)) return false; // iterate files: @@ -294,11 +431,11 @@ class JrtFileSystem { public InputStream getContentFromJrt(String fileName, String module) throws IOException { if (module != null) { - return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } String[] modules = getModules(fileName); for (String mod : modules) { - return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); } return null; } @@ -309,7 +446,7 @@ class JrtFileSystem { for (String mod : modules) { if (moduleNameFilter != null && !moduleNameFilter.test(mod)) continue; - content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { module = mod; break; @@ -330,7 +467,7 @@ class JrtFileSystem { } else { String[] modules = getModules(fileName); for (String mod : modules) { - content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { break; } @@ -339,7 +476,7 @@ class JrtFileSystem { return content; } private byte[] getClassfileBytes(String fileName, String module) throws IOException, ClassFormatException { - return JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } public ClassFileReader getClassfile(String fileName, String module, Predicate moduleNameFilter) throws IOException, ClassFormatException { ClassFileReader reader = null; @@ -367,47 +504,12 @@ class JrtFileSystem { return reader; } - void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, boolean visitPackageMapping, final int notify) throws IOException { - Iterable roots = this.jrtSystem.getRootDirectories(); + void walkJrtForModules() throws IOException { + Iterable roots = this.fs.getRootDirectories(); for (java.nio.file.Path path : roots) { try (DirectoryStream stream = Files.newDirectoryStream(path)) { for (final java.nio.file.Path subdir: stream) { - if (subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { - if (visitPackageMapping) continue; - Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - int count = dir.getNameCount(); - if (count == 2) { - // e.g. /modules/java.base - java.nio.file.Path mod = dir.getName(1); - if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && - JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { - return FileVisitResult.SKIP_SUBTREE; - } - return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? - FileVisitResult.CONTINUE : visitor.visitModule(mod); - } - if (dir == subdir || count < 3 || (notify & JRTUtil.NOTIFY_PACKAGES) == 0) { - // We are dealing with a module or not client is not interested in packages - return FileVisitResult.CONTINUE; - } - return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { - if ((notify & JRTUtil.NOTIFY_FILES) == 0) - return FileVisitResult.CONTINUE; - int count = file.getNameCount(); - // This happens when a file in a default package is present. E.g. /modules/some.module/file.name - if (count == 3) { - cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); - } - return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); - } - }); - } else if (visitPackageMapping) { + if (!subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { @Override public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { @@ -424,6 +526,42 @@ class JrtFileSystem { } } } + void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { + Files.walkFileTree(this.modRoot, new JRTUtil.AbstractFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + int count = dir.getNameCount(); + if (count == 1) return FileVisitResult.CONTINUE; + if (count == 2) { + // e.g. /modules/java.base + java.nio.file.Path mod = dir.getName(1); + if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && + JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { + return FileVisitResult.SKIP_SUBTREE; + } + return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? + FileVisitResult.CONTINUE : visitor.visitModule(mod); + } + if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { + // We are dealing with a module or not client is not interested in packages + return FileVisitResult.CONTINUE; + } + return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { + if ((notify & JRTUtil.NOTIFY_FILES) == 0) + return FileVisitResult.CONTINUE; + int count = file.getNameCount(); + // This happens when a file in a default package is present. E.g. /modules/some.module/file.name + if (count == 3) { + cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); + } + return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); + } + }); + } void cachePackage(String packageName, String module) { packageName = packageName.intern(); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java index 34ab941c95..50cfd275f1 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 IBM Corporation and others. + * Copyright (c) 2016, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -15,16 +15,9 @@ package org.eclipse.jdt.internal.core.builder; import java.io.File; import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -35,7 +28,6 @@ import java.util.function.Predicate; import java.util.zip.ZipFile; import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; @@ -50,36 +42,29 @@ import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.SimpleSet; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.JavaProject; -import org.eclipse.jdt.internal.core.util.Util; public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry { //private HashMap packagesInModule = null; -private static HashMap> PackageCache = new HashMap<>(); -private static HashMap> ModulesCache = new HashMap<>(); +protected static HashMap> PackageCache = new HashMap<>(); +protected static HashMap> ModulesCache = new HashMap<>(); String externalAnnotationPath; -private ZipFile annotationZipFile; +protected ZipFile annotationZipFile; String zipFilename; // keep for equals AccessRuleSet accessRuleSet; -String release = null; -String releaseInHex = null; -private Path releasePath = null; -private String[] subReleases = null; -private java.nio.file.FileSystem fs = null; static final Set NO_LIMIT_MODULES = new HashSet<>(); -public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, String release) { +/* + * Only for use from ClasspathJrtWithOlderRelease + */ +protected ClasspathJrt() { +} +public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) { this.zipFilename = zipFilename; this.accessRuleSet = accessRuleSet; if (externalAnnotationPath != null) this.externalAnnotationPath = externalAnnotationPath.toString(); - if (release != null && release.length() == 0) { - this.release = null; - } else { - this.release = release; - } - initialize(); loadModules(this); } /** @@ -89,7 +74,7 @@ public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath exter */ static HashMap findPackagesInModules(final ClasspathJrt jrt) { String zipFileName = jrt.zipFilename; - HashMap cache = PackageCache.get(zipFileName); + HashMap cache = PackageCache.get(jrt.getKey()); if (cache != null) { return cache; } @@ -97,7 +82,7 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) PackageCache.put(zipFileName, packagesInModule); try { final File imageFile = new File(zipFileName); - org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @Override @@ -132,12 +117,11 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) } public static void loadModules(final ClasspathJrt jrt) { - String zipFileName = jrt.zipFilename; - Set cache = ModulesCache.get(zipFileName); + Set cache = ModulesCache.get(jrt.getKey()); if (cache == null) { try { - final File imageFile = new File(zipFileName); + final File imageFile = new File(jrt.zipFilename); org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @@ -174,70 +158,11 @@ public static void loadModules(final ClasspathJrt jrt) { // } } } -public void initialize() { - if (this.release == null) { - return; - } - this.release = getReleaseOptionFromCompliance(this.release); - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); - Path lib = Paths.get(this.zipFilename).getParent(); - Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ - URI t = filePath.toUri(); - if (!Files.exists(filePath)) { - return; - } - URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ - try { - this.fs = FileSystems.getFileSystem(uri); - } catch(FileSystemNotFoundException fne) { - // Ignore and move on - } - if (this.fs == null) { - HashMap env = new HashMap<>(); - try { - this.fs = FileSystems.newFileSystem(uri, env); - } catch (IOException e) { - this.release = null; - return; - } - } - this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex)) - || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ - this.release = null; - } - if (this.release != null) { - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = subdir.getFileName().toString(); - if (rel.contains(this.releaseInHex)) { - sub.add(rel); - } else { - continue; - } - } - } catch (IOException e) { - e.printStackTrace(); - // Rethrow - } - this.subReleases = sub.toArray(new String[sub.size()]); - } -} -private String getReleaseOptionFromCompliance(String comp) { - if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { - // For a JDK 9 and above, the minimum release we support is "6" - return "6"; //$NON-NLS-1$ - } - int index = comp.indexOf("1."); //$NON-NLS-1$ - if (index != -1) { - return comp.substring(index + 2, comp.length()); - } else { - return comp; - } +protected String getKey() { + return this.zipFilename; } void acceptModule(byte[] content) { - if (content == null) + if (content == null) return; ClassFileReader reader = null; try { @@ -246,11 +171,12 @@ void acceptModule(byte[] content) { e.printStackTrace(); } if (reader != null) { + String key = getKey(); IModule moduleDecl = reader.getModuleDeclaration(); if (moduleDecl != null) { - Set cache = ModulesCache.get(this.zipFilename); + Set cache = ModulesCache.get(key); if (cache == null) { - ModulesCache.put(this.zipFilename, cache = new HashSet()); + ModulesCache.put(key, cache = new HashSet()); } cache.add(moduleDecl); } @@ -265,7 +191,6 @@ public void cleanup() { } this.annotationZipFile = null; } - this.fs = null; } @Override @@ -273,9 +198,6 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ClasspathJrt)) return false; ClasspathJrt jar = (ClasspathJrt) o; - if (!Util.equalOrNull(this.release, jar.release)) { - return false; - } if (this.accessRuleSet != jar.accessRuleSet) if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet)) return false; @@ -288,43 +210,31 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case try { - IBinaryType reader = null; - byte[] content = null; String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); - if (this.subReleases != null && this.subReleases.length > 0) { - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - for (String rel : this.subReleases) { - Path p = this.fs.getPath(rel, qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) { - reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); - break; - } - } - } - } else { - reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); - } - if (reader != null) { - if (this.externalAnnotationPath != null) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); - } catch (IOException e) { - // don't let error on annotations fail class reading + IBinaryType reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); + return createAnswer(fileNameWithoutExtension, reader); + } catch (ClassFormatException e) { // treat as if class file is missing + } catch (IOException e) { // treat as if class file is missing + } + return null; +} +protected NameEnvironmentAnswer createAnswer(String fileNameWithoutExtension, IBinaryType reader) { + if (reader != null) { + if (this.externalAnnotationPath != null) { + try { + if (this.annotationZipFile == null) { + this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); } + reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); + } catch (IOException e) { + // don't let error on annotations fail class reading } - if (this.accessRuleSet == null) - return new NameEnvironmentAnswer(reader, null, reader.getModule()); - return new NameEnvironmentAnswer(reader, - this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), - reader.getModule()); } - } catch (ClassFormatException e) { // treat as if class file is missing - } catch (IOException e) { // treat as if class file is missing + if (this.accessRuleSet == null) + return new NameEnvironmentAnswer(reader, null, reader.getModule()); + return new NameEnvironmentAnswer(reader, + this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), + reader.getModule()); } return null; } @@ -341,7 +251,7 @@ public int hashCode() { @Override public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { List moduleNames = JRTUtil.getModulesDeclaringPackage(new File(this.zipFilename), qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(moduleNames); + return CharOperation.toCharArrays(moduleNames); } @Override public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { @@ -374,7 +284,7 @@ public boolean hasModule() { } @Override public IModule getModule(char[] moduleName) { - Set modules = ModulesCache.get(this.zipFilename); + Set modules = ModulesCache.get(getKey()); if (modules != null) { for (IModule mod : modules) { if (CharOperation.equals(mod.name(), moduleName)) @@ -391,7 +301,7 @@ public Collection getModuleNames(Collection limitModules) { return Collections.emptyList(); } -private Collection selectModules(Set keySet, Collection limitModules) { +protected Collection selectModules(Set keySet, Collection limitModules) { Collection rootModules; if (limitModules == NO_LIMIT_MODULES) { rootModules = new HashSet<>(keySet); @@ -408,7 +318,7 @@ private Collection selectModules(Set keySet, Collection return allModules; } -private void addRequired(String mod, Set allModules) { +protected void addRequired(String mod, Set allModules) { IModule iMod = getModule(mod.toCharArray()); for (IModuleReference requiredRef : iMod.requires()) { IModule reqMod = getModule(requiredRef.name()); @@ -421,7 +331,7 @@ private void addRequired(String mod, Set allModules) { } @Override public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - // + // return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null); } /** TEST ONLY */ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java new file mode 100644 index 0000000000..a5d8446c37 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java @@ -0,0 +1,387 @@ +/******************************************************************************* + * Copyright (c) 2016, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.builder; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; +import org.eclipse.jdt.internal.compiler.util.SimpleSet; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.core.util.Util; + +public class ClasspathJrtWithReleaseOption extends ClasspathJrt { + + final String release; + String releaseInHex; + private String[] subReleases; + private java.nio.file.FileSystem fs; + protected Path modulePath; + private String modPathString; + private boolean isJRE12Plus; + + public ClasspathJrtWithReleaseOption(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, + String release) throws CoreException { + super(); + if (release == null || release.equals("")) { //$NON-NLS-1$ + throw new IllegalArgumentException("--release argument can not be null"); //$NON-NLS-1$ + } + this.zipFilename = zipFilename; + this.accessRuleSet = accessRuleSet; + if (externalAnnotationPath != null) + this.externalAnnotationPath = externalAnnotationPath.toString(); + this.release = getReleaseOptionFromCompliance(release); + initialize(); + loadModules(this); + } + /* + * JDK 11 doesn't contain release 5. Hence + * if the compliance is below 6, we simply return the lowest supported + * release, which is 6. + */ + private String getReleaseOptionFromCompliance(String comp) { + if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { + return "6"; //$NON-NLS-1$ + } + int index = comp.indexOf("1."); //$NON-NLS-1$ + if (index != -1) { + return comp.substring(index + 2, comp.length()); + } else { + return comp; + } + } + private boolean isJRE12Plus(Path path) { + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (final java.nio.file.Path subdir : stream) { + String rel = subdir.getFileName().toString(); + if (Files.exists(this.fs.getPath(rel, "system-modules"))) { //$NON-NLS-1$ + int parseInt = Integer.parseInt(rel, 16); + return (parseInt > 11); + } + } + } catch (IOException e) { + this.fs = null; + } + return false; + } + /* + * Set up the paths where modules and regular classes need to be read. We need to deal with two different kind of + * formats of cy.sym: Post JDK 12: ct.sym -> 9 -> java/ -> lang/* 9-modules -> java.base -> module-info.sig + * + * From JDK 12 onward: ct.sym -> 9 -> java.base -> module-info.sig java/ -> lang/* Notably, 1) in JDK 12 modules + * classes and ordinary classes are located in the same location 2) in JDK 12, ordinary classes are found inside + * their respective modules + * + */ + protected void initialize() throws CoreException { + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); + Path lib = Paths.get(this.zipFilename).getParent(); + Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ + URI t = filePath.toUri(); + if (!Files.exists(filePath)) { + return; + } + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch (FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + return; + } + } + Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + this.isJRE12Plus = isJRE12Plus(releasePath); + Path modPath = this.fs.getPath(this.releaseInHex + (this.isJRE12Plus ? "" : "-modules")); //$NON-NLS-1$ //$NON-NLS-2$ + if (Files.exists(modPath)) { + this.modulePath = modPath; + this.modPathString = this.zipFilename + "|"+ modPath.toString(); //$NON-NLS-1$ + } + + if (!Files.exists(releasePath.resolve(this.releaseInHex))) { + Exception e = new IllegalArgumentException("release " + this.release + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ + throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, e.getMessage(), e)); + } + if (Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ + this.fs = null; // Fallback to default version + return; + } + if (this.release != null) { + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { + for (final java.nio.file.Path subdir : stream) { + String rel = subdir.getFileName().toString(); + if (rel.contains(this.releaseInHex)) { + sub.add(rel); + } else { + continue; + } + } + } catch (IOException e) { + this.fs = null; // Fallback to default version + } + this.subReleases = sub.toArray(new String[sub.size()]); + } + } + + static HashMap findPackagesInModules(final ClasspathJrtWithReleaseOption jrt) { + // In JDK 11 and before, classes are not listed under their respective modules + // Hence, we simply go to the default module system for package-module mapping + if (jrt.fs == null || !jrt.isJRE12Plus) { + return ClasspathJrt.findPackagesInModules(jrt); + } + String zipFileName = jrt.zipFilename; + HashMap cache = PackageCache.get(jrt.modPathString); + if (cache != null) { + return cache; + } + final HashMap packagesInModule = new HashMap<>(); + PackageCache.put(jrt.modPathString, packagesInModule); + try { + final File imageFile = new File(zipFileName); + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, jrt.release, + new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { + SimpleSet packageSet = null; + + @Override + public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) + throws IOException { + ClasspathJar.addToPackageSet(this.packageSet, dir.toString(), true); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitModule(Path mod) throws IOException { + String name = mod.getName(1).toString(); + this.packageSet = new SimpleSet(41); + this.packageSet.add(""); //$NON-NLS-1$ + packagesInModule.put(name, this.packageSet); + return FileVisitResult.CONTINUE; + } + }, JRTUtil.NOTIFY_PACKAGES | JRTUtil.NOTIFY_MODULES); + } catch (IOException e) { + // return empty handed + } + return packagesInModule; + } + + public static void loadModules(final ClasspathJrtWithReleaseOption jrt) { + if (jrt.fs == null || !jrt.isJRE12Plus) { + ClasspathJrt.loadModules(jrt); + return; + } + if (jrt.modPathString == null) + return; + Set cache = ModulesCache.get(jrt.modPathString); + if (cache == null) { + try (DirectoryStream stream = Files.newDirectoryStream(jrt.modulePath)) { + for (final java.nio.file.Path subdir : stream) { + + Files.walkFileTree(subdir, Collections.EMPTY_SET, 1, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) + throws IOException { + byte[] content = null; + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content == null) + return FileVisitResult.CONTINUE; + jrt.acceptModule(content); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } catch (IOException e) { + // Nothing much to do + } + } + } + + + @Override + public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, + String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) { + + if (this.fs == null) { + return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, + asBinaryOnly, moduleNameFilter); + } + if (!isPackage(qualifiedPackageName, moduleName)) + return null; // most common case + + try { + IBinaryType reader = null; + byte[] content = null; + String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, + qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); + if (this.subReleases != null && this.subReleases.length > 0) { + qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ + outer: for (String rel : this.subReleases) { + Path p = null; + inner: if (this.isJRE12Plus) { + if (moduleName != null) { + p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); + } + else { + try (DirectoryStream stream = Files + .newDirectoryStream(this.fs.getPath(rel))) { + for (final java.nio.file.Path subdir : stream) { + p = subdir.resolve(qualifiedBinaryFileName); + if (Files.exists(p)) { + if (subdir.getNameCount() == 2 ) { + moduleName = subdir.getName(1).toString(); + } + break inner; + } + } + } + } + } else { + p = this.fs.getPath(rel, qualifiedBinaryFileName); + } + if (Files.exists(p)) { + content = JRTUtil.safeReadBytes(p); + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + if (moduleName != null) + ((ClassFileReader) reader).moduleName = moduleName.toCharArray(); + break outer; + } + } + } + } else { + reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, + moduleNameFilter); + } + return createAnswer(fileNameWithoutExtension, reader); + } catch (ClassFormatException e) { + // treat as if class file is missing + } catch (IOException e) { + // treat as if class file is missing + } + return null; + } + + @Override + public Collection getModuleNames(Collection limitModules) { + HashMap cache = findPackagesInModules(this); + if (cache != null) + return selectModules(cache.keySet(), limitModules); + return Collections.emptyList(); + } + + @Override + public void cleanup() { + try { + super.reset(); + } finally { + // The same file system is also used in JRTUtil, so don't close it here. + this.fs = null; + } + } + + @Override + public boolean hasModule() { + return this.modPathString != null; + } + + @Override + protected String getKey() { + return this.modPathString; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof ClasspathJrtWithReleaseOption)) + return false; + ClasspathJrtWithReleaseOption jar = (ClasspathJrtWithReleaseOption) o; + if (!Util.equalOrNull(this.release, jar.release)) { + return false; + } + return super.equals(o); + } + + @Override + public int hashCode() { + int hash = this.zipFilename == null ? super.hashCode() : this.zipFilename.hashCode(); + return Util.combineHashCodes(hash, this.release.hashCode()); + } + + @Override + public String toString() { + String start = "Classpath jrt file " + this.zipFilename + " with --release option " + this.release; //$NON-NLS-1$ //$NON-NLS-2$ + return start; + } + +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index d501e436cf..52cd7e0c31 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -23,6 +23,7 @@ import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; @@ -141,8 +142,9 @@ static ClasspathLocation forLibrary(String libraryPathname, new ClasspathMultiReleaseJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule, compliance)); } -static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) { - return new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath, release); +public static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) throws CoreException { + return (release == null || release.equals("")) ? new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath) : //$NON-NLS-1$ + new ClasspathJrtWithReleaseOption(jrtPath, accessRuleSet, annotationsPath, release); } public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet, IPath annotationsPath, diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java index 269e064480..abf0ebc7a7 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java @@ -152,7 +152,7 @@ public static void removeProblemsAndTasksFor(IResource resource) { } } -public static State readState(IProject project, DataInputStream in) throws IOException { +public static State readState(IProject project, DataInputStream in) throws IOException, CoreException { return State.read(project, in); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index dd240bcacb..a57cc107e6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -56,7 +56,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0021; +public static final byte VERSION = 0x0022; static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; @@ -233,7 +233,7 @@ void removeQualifiedTypeName(String qualifiedTypeNameToRemove) { this.typeLocators.removeKey(qualifiedTypeNameToRemove); } -static State read(IProject project, DataInputStream in) throws IOException { +static State read(IProject project, DataInputStream in) throws IOException, CoreException { if (JavaBuilder.DEBUG) System.out.println("About to read state " + project.getName()); //$NON-NLS-1$ if (VERSION != in.readByte()) { @@ -568,13 +568,20 @@ void write(DataOutputStream out) throws IOException { out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$ - } else { + } else if (c instanceof ClasspathJrt) { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ + out.writeUTF(""); //$NON-NLS-1$ + } else { + ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + out.writeByte(EXTERNAL_JAR); + out.writeUTF(jrt.zipFilename); + writeRestriction(jrt.accessRuleSet, out); + out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release); } char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray(); writeName(patchName, out); @@ -680,13 +687,20 @@ void write(DataOutputStream out) throws IOException { out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance != null ? jar.compliance : ""); //$NON-NLS-1$ - } else { + } else if (c instanceof ClasspathJrt) { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ + out.writeUTF(""); //$NON-NLS-1$ + } else { + ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + out.writeByte(EXTERNAL_JAR); + out.writeUTF(jrt.zipFilename); + writeRestriction(jrt.accessRuleSet, out); + out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release); } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java index a61e40abd2..db613ca5a3 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java @@ -49,7 +49,6 @@ import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.PackageFragmentRoot; -import org.eclipse.jdt.internal.core.builder.ClasspathJrt; import org.eclipse.jdt.internal.core.builder.ClasspathLocation; import org.eclipse.jdt.internal.core.util.Util; @@ -162,7 +161,7 @@ private ClasspathLocation mapToClassPathLocation(JavaModelManager manager, Packa IJavaProject project = (IJavaProject) root.getParent(); String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); cp = (root instanceof JrtPackageFragmentRoot) ? - new ClasspathJrt(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), + ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) : ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, -- cgit v1.2.3 From 51935ee9d486419f4f1f74060e0b14409482d023 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Mon, 25 Feb 2019 23:52:20 +0100 Subject: Bug 536860 - JDT compiler fails to infer correctly generic types in Eclipse Photon Change-Id: I9281f9defffb344edc5195a64988fc6378d22384 Signed-off-by: Stephan Herrmann --- .../regression/GenericsRegressionTest_1_8.java | 40 ++++++++++++++++++++++ .../jdt/internal/compiler/lookup/ArrayBinding.java | 12 ++++++- 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index c57ea95c8e..1504327072 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -9532,4 +9532,44 @@ public void testBug508834_comment0() { }; runner.runConformTest(); } + public void testBug536860() { + runConformTest( + new String[] { + "Snippet.java", + "import java.io.IOException;\n" + + "import java.io.InputStream;\n" + + "import java.nio.file.Path;\n" + + "import java.util.Map;\n" + + "import java.util.concurrent.Callable;\n" + + "import java.util.function.Function;\n" + + "\n" + + "interface EntityReader { }\n" + + "class ExtraIOUtils {\n" + + " public static Callable getInputStreamProvider() {\n" + + " return null;\n" + + " }\n" + + "}\n" + + "\n" + + "public class Snippet {\n" + + " public EntityReader createEntityReader(\n" + + " Function colNameMapper,\n" + + " Function instantiator,\n" + + " Map runtimeValues)\n" + + " throws IOException {\n" + + " EntityReader streamReader =\n" + + " createEntityStreamReader(\n" + + " ExtraIOUtils.getInputStreamProvider(),\n" + + " colNameMapper, instantiator, runtimeValues);\n" + + " return null;\n" + + " }\n" + + " public EntityReader> createEntityStreamReader(\n" + + " Callable streamProvider,\n" + + " Function colNameMapper, Function instantiator,\n" + + " Map runtimeValues)\n" + + " throws IOException {\n" + + " return null;\n" + + " }\n" + + "}\n" + }); + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java index 6510e346c9..8c298b9264 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -341,6 +341,16 @@ public boolean isSubtypeOf(TypeBinding otherType, boolean simulatingBugJDK802652 return false; } return true; + case Binding.TYPE_PARAMETER: + // check compatibility with capture of ? super X + if (otherType.isCapture()) { + CaptureBinding otherCapture = (CaptureBinding) otherType; + TypeBinding otherLowerBound; + if ((otherLowerBound = otherCapture.lowerBound) != null) { + if (!otherLowerBound.isArrayType()) return false; + return isSubtypeOf(otherLowerBound, simulatingBugJDK8026527); + } + } } switch (otherType.leafComponentType().id) { case TypeIds.T_JavaLangObject : -- cgit v1.2.3 From 6940b0b9166a7ea6c9647fc7c86ed1cd6c67da51 Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Wed, 27 Feb 2019 19:28:14 +0530 Subject: Revert "Bug 540922 - [12] ct.sym file has been restructured again for older releases" This reverts commit 9e75292b526e3af0dcce727eaeb336591779395c. --- .../regression/ModuleCompilationTests.java | 7 +- .../jdt/core/tests/util/AbstractCompilerTest.java | 2 - .../core/tests/model/AbstractJavaModelTests.java | 13 - .../jdt/core/tests/model/ModuleBuilderTests.java | 453 +-------------------- .../internal/compiler/batch/ClasspathJep247.java | 20 +- .../compiler/batch/ClasspathJep247Jdk12.java | 303 -------------- .../jdt/internal/compiler/batch/FileSystem.java | 13 +- .../compiler/env/NameEnvironmentAnswer.java | 4 +- .../jdt/internal/compiler/util/JRTUtil.java | 262 +++--------- .../jdt/internal/core/builder/ClasspathJrt.java | 182 ++++++--- .../builder/ClasspathJrtWithReleaseOption.java | 387 ------------------ .../internal/core/builder/ClasspathLocation.java | 8 +- .../jdt/internal/core/builder/JavaBuilder.java | 2 +- .../eclipse/jdt/internal/core/builder/State.java | 28 +- .../search/matching/JavaSearchNameEnvironment.java | 3 +- 15 files changed, 233 insertions(+), 1454 deletions(-) delete mode 100644 org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java delete mode 100644 org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java index 349e89cf8d..65587be739 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java @@ -40,7 +40,7 @@ import junit.framework.Test; public class ModuleCompilationTests extends AbstractBatchCompilerTest { static { -// TESTS_NAMES = new String[] { "test001" }; +// TESTS_NAMES = new String[] { "testBug540067e" }; // TESTS_NUMBERS = new int[] { 1 }; // TESTS_RANGE = new int[] { 298, -1 }; } @@ -3975,11 +3975,11 @@ public void testBug521362_emptyFile() { "}", }, "\"" + OUTPUT_DIR + File.separator + "X.java\"" - + " --release 7 -d \"" + OUTPUT_DIR + "\"", + + " --release 6 -d \"" + OUTPUT_DIR + "\"", "", "", true); - String expectedOutput = "// Compiled from X.java (version 1.7 : 51.0, super bit)"; + String expectedOutput = "// Compiled from X.java (version 1.6 : 50.0, super bit)"; checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); } public void testReleaseOption4() throws Exception { @@ -4094,7 +4094,6 @@ public void testBug521362_emptyFile() { true); } public void testReleaseOption10() throws Exception { - if (isJRE12Plus) return; this.runNegativeTest( new String[] { "X.java", diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java index fee9aacbe9..33aa81cb9a 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java @@ -53,7 +53,6 @@ public class AbstractCompilerTest extends TestCase { protected boolean enableAPT = false; protected static boolean isJRE9Plus = false; // Stop gap, so tests need not be run at 9, but some tests can be adjusted for JRE 9 protected static boolean isJRE11Plus = false; - protected static boolean isJRE12Plus = false; protected static boolean reflectNestedClassUseDollar; /** @@ -148,7 +147,6 @@ public class AbstractCompilerTest extends TestCase { int lessthan9 = F_1_3 | F_1_4 | F_1_5 | F_1_6 | F_1_7 | F_1_8; isJRE9Plus = !isJRELevel(lessthan9); isJRE11Plus = isJRELevel(F_11); - isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); } /** diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java index 72600309b7..df6e565b35 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java @@ -74,9 +74,6 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { protected String endChar = ","; protected static boolean isJRE9 = false; - protected static boolean isJRE10 = false; - protected static boolean isJRE11 = false; - protected static boolean isJRE12 = false; protected static String DEFAULT_MODULES = null; static { String javaVersion = System.getProperty("java.version"); @@ -90,16 +87,6 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { } } long jdkLevel = CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion); - if (jdkLevel >= ClassFileConstants.JDK11) { - if (CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion, false) == 0) { - // version was capped to 11 during versionToJdkLevel(version, true) - isJRE12 = true; - } - isJRE11 = true; - } - if (jdkLevel >= ClassFileConstants.JDK10) { - isJRE10 = true; - } if (jdkLevel >= ClassFileConstants.JDK9) { isJRE9 = true; if (vmName.contains("HotSpot")) { diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java index ddc65ad408..b80de70c73 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java @@ -696,14 +696,8 @@ public class ModuleBuilderTests extends ModifyingResourceTests { public void testConvertToModule() throws CoreException, IOException { Hashtable javaCoreOptions = JavaCore.getOptions(); try { - IJavaProject project = setUpJavaProject("ConvertToModule"); - Map options = new HashMap<>(); - // Make sure the new options map doesn't reset. - options.put(CompilerOptions.OPTION_Compliance, "9"); - options.put(CompilerOptions.OPTION_Source, "9"); - options.put(CompilerOptions.OPTION_TargetPlatform, "9"); - options.put(CompilerOptions.OPTION_Release, "enabled"); - project.setOptions(options); + IJavaProject project = setUpJavaProject("ConvertToModule", "9"); + assertEquals(project.getOption("org.eclipse.jdt.core.compiler.compliance", true), "9"); project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); IPackageFragmentRoot[] roots = project.getPackageFragmentRoots(); IPackageFragmentRoot theRoot = null; @@ -715,14 +709,7 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } assertNotNull("should not be null", theRoot); String[] modules = JavaCore.getReferencedModules(project); - if (isJRE12) - assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); - else if (isJRE11) - assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.net.http", "java.rmi", "java.sql"}, modules); - else if (isJRE10) - assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.rmi", "java.sql"}, modules); - else // 9 - assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); + assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); } finally { this.deleteProject("ConvertToModule"); JavaCore.setOptions(javaCoreOptions); @@ -8053,440 +8040,6 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } } - public void testReleaseOption1() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "public class X {\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption2() throws Exception { - if (!isJRE12) - return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "public class X {\n" + - " public java.util.stream.Stream emptyStream() {\n" + - " return null;\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "The project was not built due to \"release 6 is not found in the system\". " - + "Fix the problem, then try refreshing this project and building it since it may be inconsistent", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption3() throws Exception { - if (isJRE12) - return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "public class X {\n" + - " public java.util.stream.Stream emptyStream() {\n" + - " return null;\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "java.util.stream.Stream cannot be resolved to a type", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption4() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "public class X {\n" + - " public java.util.stream.Stream emptyStream() {\n" + - " return null;\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption5() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "public class X {\n" + - " public java.util.stream.Stream emptyStream() {\n" + - " return null;\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "java.util.stream.Stream cannot be resolved to a type", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption6() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "interface I {\n" + - " int add(int x, int y);\n" + - "}\n" + - "public class X {\n" + - " public static void main(String[] args) {\n" + - " I i = (x, y) -> {\n" + - " return x + y;\n" + - " };\n" + - " }\n" + - "}\n"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "Lambda expressions are allowed only at source level 1.8 or above", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption7() throws Exception { - if (isJRE12) - return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "import java.io.*;\n" + - "public class X {\n" + - " public static void main(String[] args) {\n" + - " try {\n" + - " System.out.println();\n" + - " Reader r = new FileReader(args[0]);\n" + - " r.read();\n" + - " } catch(IOException | FileNotFoundException e) {\n" + - " e.printStackTrace();\n" + - " }\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - sortMarkers(markers); - assertMarkers("Unexpected markers", - "Multi-catch parameters are not allowed for source level below 1.7\n" + - "The exception FileNotFoundException is already caught by the alternative IOException", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption8() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_9); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_9); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_9); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "module mod.one { \n" + - " requires java.base;\n" + - "}"; - String mPath = "p/src/module-info.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption9() throws Exception { - if (!isJRE10) return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_10); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_10); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_10); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "module mod.one { \n" + - " requires java.base;\n" + - "}"; - String mPath = "p/src/module-info.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption10() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "module mod.one { \n" + - " requires java.base;\n" + - "}"; - String mPath = "p/src/module-info.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - sortMarkers(markers); - String expected = - "Syntax error on token \"module\", package expected\n" + - "Syntax error on token(s), misplaced construct(s)\n" + - "Syntax error on token \".\", , expected\n" + - "Syntax error on token \"}\", delete this token"; - assertMarkers("Unexpected markers", - expected, markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption11() throws Exception { - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - createFolder("p/src/foo"); - createFile( - "p/src/foo/Module.java", - "package foo;\n" + - "public class Module {}\n"); - createFile( - "p/src/foo/X.java", - "package foo;\n" + - "public class X { \n" + - " public Module getModule(String name) {\n" + - " return null;\n" + - " }\n" + - "}"); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption12() throws Exception { - if (!isJRE12) - return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "import java.io.*;\n" + - "\n" + - "public class X {\n" + - " public static void main(String[] args) {\n" + - " String str = Integer.toUnsignedString(1, 1);\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "The method toUnsignedString(int, int) is undefined for the type Integer", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } - public void testReleaseOption13() throws Exception { - if (!isJRE12) - return; - Hashtable options = JavaCore.getOptions(); - IJavaProject p = createJava9Project("p"); - p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); - p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); - String outputDirectory = Util.getOutputDirectory(); - try { - String testSource = "\n" + - "public class X {\n" + - " public static void main(String[] args) {\n" + - " Integer.toUnsignedString(1, 1);\n" + - " }\n" + - "}"; - String mPath = "p/src/X.java"; - createFile(mPath, - testSource); - p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); - waitForAutoBuild(); - IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); - assertMarkers("Unexpected markers", - "", markers); - - } finally { - JavaCore.setOptions(options); - deleteProject(p); - File outputDir = new File(outputDirectory); - if (outputDir.exists()) - Util.flushDirectoryContent(outputDir); - } - } protected void assertNoErrors() throws CoreException { for (IProject p : getWorkspace().getRoot().getProjects()) { int maxSeverity = p.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java index 8aad54669b..7a39271115 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 IBM Corporation. + * Copyright (c) 2018 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,15 +42,15 @@ import org.eclipse.jdt.internal.compiler.util.Util; public class ClasspathJep247 extends ClasspathJrt { - protected java.nio.file.FileSystem fs = null; - protected String compliance = null; - protected long jdklevel; - protected String releaseInHex = null; - protected String[] subReleases = null; - protected Path releasePath = null; - protected Set packageCache; - protected File jdkHome; - protected String modulePath = null; + private java.nio.file.FileSystem fs = null; + private String compliance = null; + private long jdklevel; + private String releaseInHex = null; + private String[] subReleases = null; + private Path releasePath = null; + private Set packageCache; + File jdkHome; + String modulePath = null; public ClasspathJep247(File jdkHome, String release, AccessRuleSet accessRuleSet) { super(jdkHome, false, accessRuleSet, null); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java deleted file mode 100644 index 52a83987cf..0000000000 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java +++ /dev/null @@ -1,303 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathJep247Jdk12 extends ClasspathJep247 { - - Map modules; - - public ClasspathJep247Jdk12(File jdkHome, String release, AccessRuleSet accessRuleSet) { - super(jdkHome, release, accessRuleSet); - } - @Override - public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - return null; - } - @Override - public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); - } - @Override - public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - ClassFileReader reader = null; - byte[] content = null; - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - if (this.subReleases != null && this.subReleases.length > 0) { - done: for (String rel : this.subReleases) { - if (moduleName == null) { - Path p = this.fs.getPath(rel); - try (DirectoryStream stream = Files.newDirectoryStream(p)) { - for (final java.nio.file.Path subdir: stream) { - Path f = this.fs.getPath(rel, subdir.getFileName().toString(), qualifiedBinaryFileName); - if (Files.exists(f)) { - content = JRTUtil.safeReadBytes(f); - if (content != null) - break done; - } - } - } - } else { - Path p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) - break; - } - } - } - } else { - content = JRTUtil.safeReadBytes(this.fs.getPath(this.releaseInHex, qualifiedBinaryFileName)); - } - if (content != null) { - reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); - return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), null); - } - } catch(ClassFormatException e) { - // Continue - } catch (IOException e) { - // continue - } - return null; - } - - @Override - public void initialize() throws IOException { - if (this.compliance == null) { - return; - } - if (this.fs != null) { - super.initialize(); - return; - } - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.compliance)).toUpperCase(); - Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ - URI t = filePath.toUri(); - if (!Files.exists(filePath)) { - return; - } - URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ - try { - this.fs = FileSystems.getFileSystem(uri); - } catch(FileSystemNotFoundException fne) { - // Ignore and move on - } - if (this.fs == null) { - HashMap env = new HashMap<>(); - this.fs = FileSystems.newFileSystem(uri, env); - } - this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex))) { - throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ - } - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = subdir.getFileName().toString(); - if (rel.contains(this.releaseInHex)) - sub.add(rel); - } - this.subReleases = sub.toArray(new String[sub.size()]); - } catch (IOException e) { - //e.printStackTrace(); - } - super.initialize(); - } - @Override - public void loadModules() { - // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.loadModules(); - return; - } - final Path modPath = this.fs.getPath(this.releaseInHex); - this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ - this.modules = ModulesCache.get(this.modulePath); - if (this.modules == null) { - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = subdir.getFileName().toString(); - if (!rel.contains(this.releaseInHex)) { - continue; - } - Files.walkFileTree(subdir, Collections.EMPTY_SET, 2, new FileVisitor() { - - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - if (attrs.isDirectory() || f.getNameCount() < 3) - return FileVisitResult.CONTINUE; - byte[] content = null; - if (Files.exists(f)) { - content = JRTUtil.safeReadBytes(f); - if (content == null) - return FileVisitResult.CONTINUE; - Path m = f.subpath(1, f.getNameCount() - 1); - ClasspathJep247Jdk12.this.acceptModule(m.getFileName().toString(), content); - ClasspathJep247Jdk12.this.moduleNamesCache.add(m.getFileName().toString()); - } - return FileVisitResult.SKIP_SIBLINGS; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } catch (IOException e) { - e.printStackTrace(); - } - } else { - this.moduleNamesCache.addAll(this.modules.keySet()); - } - } - @Override - public Collection getModuleNames(Collection limitModule, Function getModule) { - return selectModules(this.moduleNamesCache, limitModule, getModule); - } - @Override - public IModule getModule(char[] moduleName) { - if (this.modules != null) { - return this.modules.get(String.valueOf(moduleName)); - } - return null; - } - void acceptModule(String name, byte[] content) { - if (content == null) - return; - - if (this.modules != null) { - if (this.modules.containsKey(name)) - return; - } - - ClassFileReader reader = null; - try { - reader = new ClassFileReader(content, IModule.MODULE_INFO_CLASS.toCharArray()); - } catch (ClassFormatException e) { - e.printStackTrace(); - } - if (reader != null) { - acceptModule(reader); - } - } - @Override - void acceptModule(ClassFileReader reader) { - // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.acceptModule(reader); - return; - } - if (reader != null) { - IModule moduleDecl = reader.getModuleDeclaration(); - if (moduleDecl != null) { - if (this.modules == null) { - ModulesCache.put(this.modulePath, this.modules = new HashMap()); - } - this.modules.put(String.valueOf(moduleDecl.name()), moduleDecl); - } - } - } - @Override - public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - // Ignore moduleName as this has nothing to do with modules (as of now) - if (this.packageCache != null) - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = subdir.getFileName().toString(); - if (!rel.contains(this.releaseInHex)) { - continue; - } - try (DirectoryStream stream2 = Files.newDirectoryStream(subdir)) { - for (final java.nio.file.Path subdir2: stream2) { - Files.walkFileTree(subdir2, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - if (dir.getNameCount() <= 2) - return FileVisitResult.CONTINUE; - Path relative = dir.subpath(2, dir.getNameCount()); - addToPackageCache(relative.toString(), false); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } - } - } catch (IOException e) { - e.printStackTrace(); - // Rethrow - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - } -} diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java index 060351e20a..1a81699b44 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -164,14 +164,11 @@ public class FileSystem implements IModuleAwareNameEnvironment, SuffixConstants Set knownFileNames; protected boolean annotationsFromClasspath; // should annotation files be read from the classpath (vs. explicit separate path)? private static HashMap JRT_CLASSPATH_CACHE = null; + protected Map moduleLocations = new HashMap<>(); /** Tasks resulting from --add-reads or --add-exports command line options. */ Map moduleUpdates = new HashMap<>(); - static final boolean isJRE12Plus; - static { - isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); //$NON-NLS-1$ //$NON-NLS-2$ - } /* classPathNames is a collection is Strings representing the full path of each class path @@ -208,8 +205,6 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot final Classpath classpath = paths[i]; try { classpath.initialize(); - for (String moduleName : classpath.getModuleNames(limitedModules)) - this.moduleLocations.put(moduleName, classpath); this.classpaths[counter++] = classpath; } catch(IOException | InvalidPathException exception) { // JRE 9 could throw an IAE if the linked JAR paths have invalid chars, such as ":" @@ -261,9 +256,7 @@ public static Classpath getJrtClasspath(String jdkHome, String encoding, AccessR return new ClasspathJrt(new File(convertPathSeparators(jdkHome)), true, accessRuleSet, null); } public static Classpath getOlderSystemRelease(String jdkHome, String release, AccessRuleSet accessRuleSet) { - return isJRE12Plus ? - new ClasspathJep247Jdk12(new File(convertPathSeparators(jdkHome)), release, accessRuleSet) : - new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); + return new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); } public static Classpath getClasspath(String classpathName, String encoding, boolean isSourceOnly, AccessRuleSet accessRuleSet, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java index b11078dfe5..bb3bfb757c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java @@ -32,7 +32,9 @@ public class NameEnvironmentAnswer { String externalAnnotationPath; // should be an absolute file system path public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction) { - this(binaryType, accessRestriction, binaryType.getModule()); + this.binaryType = binaryType; + this.accessRestriction = accessRestriction; + this.moduleName = binaryType.getModule(); } public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction, char[] module) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java index f6903f814f..481bbef429 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java @@ -22,7 +22,6 @@ import java.net.URLClassLoader; import java.nio.channels.ClosedByInterruptException; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; -import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -60,7 +59,7 @@ public class JRTUtil { public static int NOTIFY_ALL = NOTIFY_FILES | NOTIFY_PACKAGES | NOTIFY_MODULES; // TODO: Java 9 Think about clearing the cache too. - private static Map images = null; + private static Map images = null; private static final Object lock = new Object(); @@ -101,11 +100,7 @@ public class JRTUtil { } public static JrtFileSystem getJrtSystem(File image) { - return getJrtSystem(image, null); - } - - public static JrtFileSystem getJrtSystem(File image, String release) { - Map i = images; + Map i = images; if (images == null) { synchronized (lock) { i = images; @@ -115,12 +110,10 @@ public class JRTUtil { } } JrtFileSystem system = null; - String key = image.toString(); - if (release != null) key = key + "|" + release; //$NON-NLS-1$ synchronized(i) { - if ((system = images.get(key)) == null) { + if ((system = images.get(image)) == null) { try { - images.put(key, system = JrtFileSystem.getNewJrtFileSystem(image, release)); + images.put(image, system = new JrtFileSystem(image)); } catch (IOException e) { e.printStackTrace(); // Needs better error handling downstream? But for now, make sure @@ -145,8 +138,8 @@ public class JRTUtil { * /modules/$MODULE/$PATH * /packages/$PACKAGE/$MODULE * The latter provides quick look up of the module that contains a particular package. However, - * this method only notifies its clients of the entries within the modules (latter) sub-directory. - * Clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, + * this method only notifies its clients of the entries within the modules sub-directory. The + * clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, * {@link JRTUtil#NOTIFY_FILES}, {@link JRTUtil#NOTIFY_PACKAGES} and {@link JRTUtil#NOTIFY_MODULES}. * * @param image a java.io.File handle to the JRT image. @@ -155,10 +148,7 @@ public class JRTUtil { * @throws IOException */ public static void walkModuleImage(File image, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { - getJrtSystem(image, null).walkModuleImage(visitor, notify); - } - public static void walkModuleImage(File image, String release, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { - getJrtSystem(image, release).walkModuleImage(visitor, notify); + getJrtSystem(image).walkModuleImage(visitor, false, notify); } public static InputStream getContentFromJrt(File jrt, String fileName, String module) throws IOException { @@ -197,138 +187,13 @@ public class JRTUtil { } } } -class JrtFileSystemWithOlderRelease extends JrtFileSystem { - final String release; - String releaseInHex = null; - //private Path releasePath = null; - private String[] subReleases = null; - protected Path modulePath = null; - - /** - * The jrt file system is based on the location of the JRE home whose libraries - * need to be loaded. - * - * @param jrt the path to the root of the JRE whose libraries we are interested in. - * @param release the older release where classes and modules should be searched for. - * @throws IOException - */ - JrtFileSystemWithOlderRelease(File jrt, String release) throws IOException { - super(jrt); - this.release = release; - initialize(jrt, release); - } - @Override - void initialize(File jdk) throws IOException { - // Just to make sure we don't do anything in super.initialize() - // before setting this.release - } - void initialize(File jdk, String rel) throws IOException { - super.initialize(jdk); - this.fs = null;// reset and proceed, TODO: this is crude and need to be removed. - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); - Path ct = Paths.get(this.jdkHome, "lib", "ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ - if (!Files.exists(ct)) { - return; - } - URI uri = URI.create("jar:file:" + ct.toUri().getRawPath()); //$NON-NLS-1$ - try { - this.fs = FileSystems.getFileSystem(uri); - } catch(FileSystemNotFoundException fne) { - // Ignore and move on - } - if (this.fs == null) { - HashMap env = new HashMap<>(); - try { - this.fs = FileSystems.newFileSystem(uri, env); - } catch (IOException e) { - return; - } - } - Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex)) - || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ - this.fs = null; - } - if (this.release != null) { - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String r = subdir.getFileName().toString(); - if (r.contains(this.releaseInHex)) { - sub.add(r); - } else { - continue; - } - } - } catch (IOException e) { - e.printStackTrace(); - // Rethrow? - } - this.subReleases = sub.toArray(new String[sub.size()]); - } - // Ensure walkJrtForModules() is not called - } - @Override - void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { - if (this.subReleases != null && this.subReleases.length > 0) { - for (String rel : this.subReleases) { - Path p = this.fs.getPath(rel); - Files.walkFileTree(p, new JRTUtil.AbstractFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - int count = dir.getNameCount(); - if (count == 1) { - return FileVisitResult.CONTINUE; - } - if (count == 2) { - // e.g. /9A/java.base - java.nio.file.Path mod = dir.getName(1); - if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 - && JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { - return FileVisitResult.SKIP_SUBTREE; - } - return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? FileVisitResult.CONTINUE - : visitor.visitModule(dir); - } - if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { - // client is not interested in packages - return FileVisitResult.CONTINUE; - } - return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) - throws IOException { - if ((notify & JRTUtil.NOTIFY_FILES) == 0) { - return FileVisitResult.CONTINUE; - } - // This happens when a file in a default package is present. E.g. /modules/some.module/file.name - if (file.getNameCount() == 3) { - cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); - } - return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); - } - }); - } - } - } - -} class JrtFileSystem { private final Map packageToModule = new HashMap(); private final Map> packageToModules = new HashMap>(); - FileSystem fs = null; - Path modRoot = null; - String jdkHome = null; - public static JrtFileSystem getNewJrtFileSystem(File jrt, String release) throws IOException { - return (release == null) ? new JrtFileSystem(jrt) : - new JrtFileSystemWithOlderRelease(jrt, release); - - } + FileSystem jrtSystem = null; + /** * The jrt file system is based on the location of the JRE home whose libraries * need to be loaded. @@ -336,18 +201,18 @@ class JrtFileSystem { * @param jrt the path to the root of the JRE whose libraries we are interested in. * @throws IOException */ - JrtFileSystem(File jrt) throws IOException { + public JrtFileSystem(File jrt) throws IOException { initialize(jrt); } void initialize(File jrt) throws IOException { URL jrtPath = null; - this.jdkHome = null; + String jdkHome = null; if (jrt.toString().endsWith(JRTUtil.JRT_FS_JAR)) { jrtPath = jrt.toPath().toUri().toURL(); - this.jdkHome = jrt.getParentFile().getParent(); + jdkHome = jrt.getParentFile().getParent(); } else { - this.jdkHome = jrt.toPath().toString(); - jrtPath = Paths.get(this.jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ + jdkHome = jrt.toPath().toString(); + jrtPath = Paths.get(jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ } JRTUtil.MODULE_TO_LOAD = System.getProperty("modules.to.load"); //$NON-NLS-1$ @@ -355,15 +220,13 @@ class JrtFileSystem { if (javaVersion != null && javaVersion.startsWith("1.8")) { //$NON-NLS-1$ URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath }); HashMap env = new HashMap<>(); - this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); + this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); } else { HashMap env = new HashMap<>(); - env.put("java.home", this.jdkHome); //$NON-NLS-1$ - this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); + env.put("java.home", jdkHome); //$NON-NLS-1$ + this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); } - this.modRoot = this.fs.getPath(JRTUtil.MODULES_SUBDIR); - // Set up the root directory wherere modules are located - walkJrtForModules(); + walkModuleImage(null, true, 0 /* doesn't matter */); } public List getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { @@ -416,7 +279,7 @@ class JrtFileSystem { String knownModule = this.packageToModule.get(qualifiedPackageName); if (knownModule == null || (knownModule != JRTUtil.MULTIPLE && !knownModule.equals(module))) return false; - Path packagePath = this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); + Path packagePath = this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); if (!Files.exists(packagePath)) return false; // iterate files: @@ -431,11 +294,11 @@ class JrtFileSystem { public InputStream getContentFromJrt(String fileName, String module) throws IOException { if (module != null) { - return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } String[] modules = getModules(fileName); for (String mod : modules) { - return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); } return null; } @@ -446,7 +309,7 @@ class JrtFileSystem { for (String mod : modules) { if (moduleNameFilter != null && !moduleNameFilter.test(mod)) continue; - content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { module = mod; break; @@ -467,7 +330,7 @@ class JrtFileSystem { } else { String[] modules = getModules(fileName); for (String mod : modules) { - content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { break; } @@ -476,7 +339,7 @@ class JrtFileSystem { return content; } private byte[] getClassfileBytes(String fileName, String module) throws IOException, ClassFormatException { - return JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } public ClassFileReader getClassfile(String fileName, String module, Predicate moduleNameFilter) throws IOException, ClassFormatException { ClassFileReader reader = null; @@ -504,12 +367,47 @@ class JrtFileSystem { return reader; } - void walkJrtForModules() throws IOException { - Iterable roots = this.fs.getRootDirectories(); + void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, boolean visitPackageMapping, final int notify) throws IOException { + Iterable roots = this.jrtSystem.getRootDirectories(); for (java.nio.file.Path path : roots) { try (DirectoryStream stream = Files.newDirectoryStream(path)) { for (final java.nio.file.Path subdir: stream) { - if (!subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { + if (subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { + if (visitPackageMapping) continue; + Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + int count = dir.getNameCount(); + if (count == 2) { + // e.g. /modules/java.base + java.nio.file.Path mod = dir.getName(1); + if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && + JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { + return FileVisitResult.SKIP_SUBTREE; + } + return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? + FileVisitResult.CONTINUE : visitor.visitModule(mod); + } + if (dir == subdir || count < 3 || (notify & JRTUtil.NOTIFY_PACKAGES) == 0) { + // We are dealing with a module or not client is not interested in packages + return FileVisitResult.CONTINUE; + } + return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { + if ((notify & JRTUtil.NOTIFY_FILES) == 0) + return FileVisitResult.CONTINUE; + int count = file.getNameCount(); + // This happens when a file in a default package is present. E.g. /modules/some.module/file.name + if (count == 3) { + cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); + } + return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); + } + }); + } else if (visitPackageMapping) { Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { @Override public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { @@ -526,42 +424,6 @@ class JrtFileSystem { } } } - void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { - Files.walkFileTree(this.modRoot, new JRTUtil.AbstractFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - int count = dir.getNameCount(); - if (count == 1) return FileVisitResult.CONTINUE; - if (count == 2) { - // e.g. /modules/java.base - java.nio.file.Path mod = dir.getName(1); - if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && - JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { - return FileVisitResult.SKIP_SUBTREE; - } - return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? - FileVisitResult.CONTINUE : visitor.visitModule(mod); - } - if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { - // We are dealing with a module or not client is not interested in packages - return FileVisitResult.CONTINUE; - } - return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { - if ((notify & JRTUtil.NOTIFY_FILES) == 0) - return FileVisitResult.CONTINUE; - int count = file.getNameCount(); - // This happens when a file in a default package is present. E.g. /modules/some.module/file.name - if (count == 3) { - cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); - } - return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); - } - }); - } void cachePackage(String packageName, String module) { packageName = packageName.intern(); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java index 50cfd275f1..34ab941c95 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2019 IBM Corporation and others. + * Copyright (c) 2016, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -15,9 +15,16 @@ package org.eclipse.jdt.internal.core.builder; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -28,6 +35,7 @@ import java.util.function.Predicate; import java.util.zip.ZipFile; import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; @@ -42,29 +50,36 @@ import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.SimpleSet; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.JavaProject; +import org.eclipse.jdt.internal.core.util.Util; public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry { //private HashMap packagesInModule = null; -protected static HashMap> PackageCache = new HashMap<>(); -protected static HashMap> ModulesCache = new HashMap<>(); +private static HashMap> PackageCache = new HashMap<>(); +private static HashMap> ModulesCache = new HashMap<>(); String externalAnnotationPath; -protected ZipFile annotationZipFile; +private ZipFile annotationZipFile; String zipFilename; // keep for equals AccessRuleSet accessRuleSet; +String release = null; +String releaseInHex = null; +private Path releasePath = null; +private String[] subReleases = null; +private java.nio.file.FileSystem fs = null; static final Set NO_LIMIT_MODULES = new HashSet<>(); -/* - * Only for use from ClasspathJrtWithOlderRelease - */ -protected ClasspathJrt() { -} -public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) { +public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, String release) { this.zipFilename = zipFilename; this.accessRuleSet = accessRuleSet; if (externalAnnotationPath != null) this.externalAnnotationPath = externalAnnotationPath.toString(); + if (release != null && release.length() == 0) { + this.release = null; + } else { + this.release = release; + } + initialize(); loadModules(this); } /** @@ -74,7 +89,7 @@ public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath exter */ static HashMap findPackagesInModules(final ClasspathJrt jrt) { String zipFileName = jrt.zipFilename; - HashMap cache = PackageCache.get(jrt.getKey()); + HashMap cache = PackageCache.get(zipFileName); if (cache != null) { return cache; } @@ -82,7 +97,7 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) PackageCache.put(zipFileName, packagesInModule); try { final File imageFile = new File(zipFileName); - org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @Override @@ -117,11 +132,12 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) } public static void loadModules(final ClasspathJrt jrt) { - Set cache = ModulesCache.get(jrt.getKey()); + String zipFileName = jrt.zipFilename; + Set cache = ModulesCache.get(zipFileName); if (cache == null) { try { - final File imageFile = new File(jrt.zipFilename); + final File imageFile = new File(zipFileName); org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @@ -158,11 +174,70 @@ public static void loadModules(final ClasspathJrt jrt) { // } } } -protected String getKey() { - return this.zipFilename; +public void initialize() { + if (this.release == null) { + return; + } + this.release = getReleaseOptionFromCompliance(this.release); + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); + Path lib = Paths.get(this.zipFilename).getParent(); + Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ + URI t = filePath.toUri(); + if (!Files.exists(filePath)) { + return; + } + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + this.release = null; + return; + } + } + this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + if (!Files.exists(this.fs.getPath(this.releaseInHex)) + || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ + this.release = null; + } + if (this.release != null) { + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (rel.contains(this.releaseInHex)) { + sub.add(rel); + } else { + continue; + } + } + } catch (IOException e) { + e.printStackTrace(); + // Rethrow + } + this.subReleases = sub.toArray(new String[sub.size()]); + } +} +private String getReleaseOptionFromCompliance(String comp) { + if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { + // For a JDK 9 and above, the minimum release we support is "6" + return "6"; //$NON-NLS-1$ + } + int index = comp.indexOf("1."); //$NON-NLS-1$ + if (index != -1) { + return comp.substring(index + 2, comp.length()); + } else { + return comp; + } } void acceptModule(byte[] content) { - if (content == null) + if (content == null) return; ClassFileReader reader = null; try { @@ -171,12 +246,11 @@ void acceptModule(byte[] content) { e.printStackTrace(); } if (reader != null) { - String key = getKey(); IModule moduleDecl = reader.getModuleDeclaration(); if (moduleDecl != null) { - Set cache = ModulesCache.get(key); + Set cache = ModulesCache.get(this.zipFilename); if (cache == null) { - ModulesCache.put(key, cache = new HashSet()); + ModulesCache.put(this.zipFilename, cache = new HashSet()); } cache.add(moduleDecl); } @@ -191,6 +265,7 @@ public void cleanup() { } this.annotationZipFile = null; } + this.fs = null; } @Override @@ -198,6 +273,9 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ClasspathJrt)) return false; ClasspathJrt jar = (ClasspathJrt) o; + if (!Util.equalOrNull(this.release, jar.release)) { + return false; + } if (this.accessRuleSet != jar.accessRuleSet) if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet)) return false; @@ -210,31 +288,43 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case try { + IBinaryType reader = null; + byte[] content = null; String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); - IBinaryType reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); - return createAnswer(fileNameWithoutExtension, reader); - } catch (ClassFormatException e) { // treat as if class file is missing - } catch (IOException e) { // treat as if class file is missing - } - return null; -} -protected NameEnvironmentAnswer createAnswer(String fileNameWithoutExtension, IBinaryType reader) { - if (reader != null) { - if (this.externalAnnotationPath != null) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); + if (this.subReleases != null && this.subReleases.length > 0) { + qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ + for (String rel : this.subReleases) { + Path p = this.fs.getPath(rel, qualifiedBinaryFileName); + if (Files.exists(p)) { + content = JRTUtil.safeReadBytes(p); + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + break; + } + } + } + } else { + reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); + } + if (reader != null) { + if (this.externalAnnotationPath != null) { + try { + if (this.annotationZipFile == null) { + this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); + } + reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); + } catch (IOException e) { + // don't let error on annotations fail class reading } - reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); - } catch (IOException e) { - // don't let error on annotations fail class reading } + if (this.accessRuleSet == null) + return new NameEnvironmentAnswer(reader, null, reader.getModule()); + return new NameEnvironmentAnswer(reader, + this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), + reader.getModule()); } - if (this.accessRuleSet == null) - return new NameEnvironmentAnswer(reader, null, reader.getModule()); - return new NameEnvironmentAnswer(reader, - this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), - reader.getModule()); + } catch (ClassFormatException e) { // treat as if class file is missing + } catch (IOException e) { // treat as if class file is missing } return null; } @@ -251,7 +341,7 @@ public int hashCode() { @Override public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { List moduleNames = JRTUtil.getModulesDeclaringPackage(new File(this.zipFilename), qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(moduleNames); + return CharOperation.toCharArrays(moduleNames); } @Override public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { @@ -284,7 +374,7 @@ public boolean hasModule() { } @Override public IModule getModule(char[] moduleName) { - Set modules = ModulesCache.get(getKey()); + Set modules = ModulesCache.get(this.zipFilename); if (modules != null) { for (IModule mod : modules) { if (CharOperation.equals(mod.name(), moduleName)) @@ -301,7 +391,7 @@ public Collection getModuleNames(Collection limitModules) { return Collections.emptyList(); } -protected Collection selectModules(Set keySet, Collection limitModules) { +private Collection selectModules(Set keySet, Collection limitModules) { Collection rootModules; if (limitModules == NO_LIMIT_MODULES) { rootModules = new HashSet<>(keySet); @@ -318,7 +408,7 @@ protected Collection selectModules(Set keySet, Collection allModules) { +private void addRequired(String mod, Set allModules) { IModule iMod = getModule(mod.toCharArray()); for (IModuleReference requiredRef : iMod.requires()) { IModule reqMod = getModule(requiredRef.name()); @@ -331,7 +421,7 @@ protected void addRequired(String mod, Set allModules) { } @Override public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - // + // return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null); } /** TEST ONLY */ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java deleted file mode 100644 index a5d8446c37..0000000000 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java +++ /dev/null @@ -1,387 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.builder; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.SimpleSet; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.core.util.Util; - -public class ClasspathJrtWithReleaseOption extends ClasspathJrt { - - final String release; - String releaseInHex; - private String[] subReleases; - private java.nio.file.FileSystem fs; - protected Path modulePath; - private String modPathString; - private boolean isJRE12Plus; - - public ClasspathJrtWithReleaseOption(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, - String release) throws CoreException { - super(); - if (release == null || release.equals("")) { //$NON-NLS-1$ - throw new IllegalArgumentException("--release argument can not be null"); //$NON-NLS-1$ - } - this.zipFilename = zipFilename; - this.accessRuleSet = accessRuleSet; - if (externalAnnotationPath != null) - this.externalAnnotationPath = externalAnnotationPath.toString(); - this.release = getReleaseOptionFromCompliance(release); - initialize(); - loadModules(this); - } - /* - * JDK 11 doesn't contain release 5. Hence - * if the compliance is below 6, we simply return the lowest supported - * release, which is 6. - */ - private String getReleaseOptionFromCompliance(String comp) { - if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { - return "6"; //$NON-NLS-1$ - } - int index = comp.indexOf("1."); //$NON-NLS-1$ - if (index != -1) { - return comp.substring(index + 2, comp.length()); - } else { - return comp; - } - } - private boolean isJRE12Plus(Path path) { - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (final java.nio.file.Path subdir : stream) { - String rel = subdir.getFileName().toString(); - if (Files.exists(this.fs.getPath(rel, "system-modules"))) { //$NON-NLS-1$ - int parseInt = Integer.parseInt(rel, 16); - return (parseInt > 11); - } - } - } catch (IOException e) { - this.fs = null; - } - return false; - } - /* - * Set up the paths where modules and regular classes need to be read. We need to deal with two different kind of - * formats of cy.sym: Post JDK 12: ct.sym -> 9 -> java/ -> lang/* 9-modules -> java.base -> module-info.sig - * - * From JDK 12 onward: ct.sym -> 9 -> java.base -> module-info.sig java/ -> lang/* Notably, 1) in JDK 12 modules - * classes and ordinary classes are located in the same location 2) in JDK 12, ordinary classes are found inside - * their respective modules - * - */ - protected void initialize() throws CoreException { - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); - Path lib = Paths.get(this.zipFilename).getParent(); - Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ - URI t = filePath.toUri(); - if (!Files.exists(filePath)) { - return; - } - URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ - try { - this.fs = FileSystems.getFileSystem(uri); - } catch (FileSystemNotFoundException fne) { - // Ignore and move on - } - if (this.fs == null) { - HashMap env = new HashMap<>(); - try { - this.fs = FileSystems.newFileSystem(uri, env); - } catch (IOException e) { - return; - } - } - Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - this.isJRE12Plus = isJRE12Plus(releasePath); - Path modPath = this.fs.getPath(this.releaseInHex + (this.isJRE12Plus ? "" : "-modules")); //$NON-NLS-1$ //$NON-NLS-2$ - if (Files.exists(modPath)) { - this.modulePath = modPath; - this.modPathString = this.zipFilename + "|"+ modPath.toString(); //$NON-NLS-1$ - } - - if (!Files.exists(releasePath.resolve(this.releaseInHex))) { - Exception e = new IllegalArgumentException("release " + this.release + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ - throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, e.getMessage(), e)); - } - if (Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ - this.fs = null; // Fallback to default version - return; - } - if (this.release != null) { - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { - for (final java.nio.file.Path subdir : stream) { - String rel = subdir.getFileName().toString(); - if (rel.contains(this.releaseInHex)) { - sub.add(rel); - } else { - continue; - } - } - } catch (IOException e) { - this.fs = null; // Fallback to default version - } - this.subReleases = sub.toArray(new String[sub.size()]); - } - } - - static HashMap findPackagesInModules(final ClasspathJrtWithReleaseOption jrt) { - // In JDK 11 and before, classes are not listed under their respective modules - // Hence, we simply go to the default module system for package-module mapping - if (jrt.fs == null || !jrt.isJRE12Plus) { - return ClasspathJrt.findPackagesInModules(jrt); - } - String zipFileName = jrt.zipFilename; - HashMap cache = PackageCache.get(jrt.modPathString); - if (cache != null) { - return cache; - } - final HashMap packagesInModule = new HashMap<>(); - PackageCache.put(jrt.modPathString, packagesInModule); - try { - final File imageFile = new File(zipFileName); - org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, jrt.release, - new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { - SimpleSet packageSet = null; - - @Override - public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) - throws IOException { - ClasspathJar.addToPackageSet(this.packageSet, dir.toString(), true); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, Path mod, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitModule(Path mod) throws IOException { - String name = mod.getName(1).toString(); - this.packageSet = new SimpleSet(41); - this.packageSet.add(""); //$NON-NLS-1$ - packagesInModule.put(name, this.packageSet); - return FileVisitResult.CONTINUE; - } - }, JRTUtil.NOTIFY_PACKAGES | JRTUtil.NOTIFY_MODULES); - } catch (IOException e) { - // return empty handed - } - return packagesInModule; - } - - public static void loadModules(final ClasspathJrtWithReleaseOption jrt) { - if (jrt.fs == null || !jrt.isJRE12Plus) { - ClasspathJrt.loadModules(jrt); - return; - } - if (jrt.modPathString == null) - return; - Set cache = ModulesCache.get(jrt.modPathString); - if (cache == null) { - try (DirectoryStream stream = Files.newDirectoryStream(jrt.modulePath)) { - for (final java.nio.file.Path subdir : stream) { - - Files.walkFileTree(subdir, Collections.EMPTY_SET, 1, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) - throws IOException { - byte[] content = null; - if (Files.exists(f)) { - content = JRTUtil.safeReadBytes(f); - if (content == null) - return FileVisitResult.CONTINUE; - jrt.acceptModule(content); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) - throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } catch (IOException e) { - // Nothing much to do - } - } - } - - - @Override - public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, - String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) { - - if (this.fs == null) { - return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, - asBinaryOnly, moduleNameFilter); - } - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - IBinaryType reader = null; - byte[] content = null; - String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, - qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); - if (this.subReleases != null && this.subReleases.length > 0) { - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - outer: for (String rel : this.subReleases) { - Path p = null; - inner: if (this.isJRE12Plus) { - if (moduleName != null) { - p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); - } - else { - try (DirectoryStream stream = Files - .newDirectoryStream(this.fs.getPath(rel))) { - for (final java.nio.file.Path subdir : stream) { - p = subdir.resolve(qualifiedBinaryFileName); - if (Files.exists(p)) { - if (subdir.getNameCount() == 2 ) { - moduleName = subdir.getName(1).toString(); - } - break inner; - } - } - } - } - } else { - p = this.fs.getPath(rel, qualifiedBinaryFileName); - } - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) { - reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); - if (moduleName != null) - ((ClassFileReader) reader).moduleName = moduleName.toCharArray(); - break outer; - } - } - } - } else { - reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, - moduleNameFilter); - } - return createAnswer(fileNameWithoutExtension, reader); - } catch (ClassFormatException e) { - // treat as if class file is missing - } catch (IOException e) { - // treat as if class file is missing - } - return null; - } - - @Override - public Collection getModuleNames(Collection limitModules) { - HashMap cache = findPackagesInModules(this); - if (cache != null) - return selectModules(cache.keySet(), limitModules); - return Collections.emptyList(); - } - - @Override - public void cleanup() { - try { - super.reset(); - } finally { - // The same file system is also used in JRTUtil, so don't close it here. - this.fs = null; - } - } - - @Override - public boolean hasModule() { - return this.modPathString != null; - } - - @Override - protected String getKey() { - return this.modPathString; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof ClasspathJrtWithReleaseOption)) - return false; - ClasspathJrtWithReleaseOption jar = (ClasspathJrtWithReleaseOption) o; - if (!Util.equalOrNull(this.release, jar.release)) { - return false; - } - return super.equals(o); - } - - @Override - public int hashCode() { - int hash = this.zipFilename == null ? super.hashCode() : this.zipFilename.hashCode(); - return Util.combineHashCodes(hash, this.release.hashCode()); - } - - @Override - public String toString() { - String start = "Classpath jrt file " + this.zipFilename + " with --release option " + this.release; //$NON-NLS-1$ //$NON-NLS-2$ - return start; - } - -} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index 52cd7e0c31..d501e436cf 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -23,7 +23,6 @@ import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; @@ -142,9 +141,8 @@ static ClasspathLocation forLibrary(String libraryPathname, new ClasspathMultiReleaseJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule, compliance)); } -public static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) throws CoreException { - return (release == null || release.equals("")) ? new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath) : //$NON-NLS-1$ - new ClasspathJrtWithReleaseOption(jrtPath, accessRuleSet, annotationsPath, release); +static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) { + return new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath, release); } public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet, IPath annotationsPath, diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java index abf0ebc7a7..269e064480 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java @@ -152,7 +152,7 @@ public static void removeProblemsAndTasksFor(IResource resource) { } } -public static State readState(IProject project, DataInputStream in) throws IOException, CoreException { +public static State readState(IProject project, DataInputStream in) throws IOException { return State.read(project, in); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index a57cc107e6..dd240bcacb 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -56,7 +56,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0022; +public static final byte VERSION = 0x0021; static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; @@ -233,7 +233,7 @@ void removeQualifiedTypeName(String qualifiedTypeNameToRemove) { this.typeLocators.removeKey(qualifiedTypeNameToRemove); } -static State read(IProject project, DataInputStream in) throws IOException, CoreException { +static State read(IProject project, DataInputStream in) throws IOException { if (JavaBuilder.DEBUG) System.out.println("About to read state " + project.getName()); //$NON-NLS-1$ if (VERSION != in.readByte()) { @@ -568,20 +568,13 @@ void write(DataOutputStream out) throws IOException { out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$ - } else if (c instanceof ClasspathJrt) { - ClasspathJrt jrt = (ClasspathJrt) c; - out.writeByte(EXTERNAL_JAR); - out.writeUTF(jrt.zipFilename); - writeRestriction(jrt.accessRuleSet, out); - out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(""); //$NON-NLS-1$ } else { - ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release); + out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ } char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray(); writeName(patchName, out); @@ -687,20 +680,13 @@ void write(DataOutputStream out) throws IOException { out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance != null ? jar.compliance : ""); //$NON-NLS-1$ - } else if (c instanceof ClasspathJrt) { - ClasspathJrt jrt = (ClasspathJrt) c; - out.writeByte(EXTERNAL_JAR); - out.writeUTF(jrt.zipFilename); - writeRestriction(jrt.accessRuleSet, out); - out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(""); //$NON-NLS-1$ } else { - ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release); + out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java index db613ca5a3..a61e40abd2 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java @@ -49,6 +49,7 @@ import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.PackageFragmentRoot; +import org.eclipse.jdt.internal.core.builder.ClasspathJrt; import org.eclipse.jdt.internal.core.builder.ClasspathLocation; import org.eclipse.jdt.internal.core.util.Util; @@ -161,7 +162,7 @@ private ClasspathLocation mapToClassPathLocation(JavaModelManager manager, Packa IJavaProject project = (IJavaProject) root.getParent(); String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); cp = (root instanceof JrtPackageFragmentRoot) ? - ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), + new ClasspathJrt(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) : ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, -- cgit v1.2.3 From 2d1a2262035ea1459de3b9e679b11a5b72bfeb91 Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Wed, 27 Feb 2019 22:26:24 +0530 Subject: Revert "Revert "Bug 540922 - [12] ct.sym file has been restructured again for older releases"" This reverts commit 6940b0b9166a7ea6c9647fc7c86ed1cd6c67da51. --- .../regression/ModuleCompilationTests.java | 7 +- .../jdt/core/tests/util/AbstractCompilerTest.java | 2 + .../core/tests/model/AbstractJavaModelTests.java | 13 + .../jdt/core/tests/model/ModuleBuilderTests.java | 453 ++++++++++++++++++++- .../internal/compiler/batch/ClasspathJep247.java | 20 +- .../compiler/batch/ClasspathJep247Jdk12.java | 303 ++++++++++++++ .../jdt/internal/compiler/batch/FileSystem.java | 13 +- .../compiler/env/NameEnvironmentAnswer.java | 4 +- .../jdt/internal/compiler/util/JRTUtil.java | 262 +++++++++--- .../jdt/internal/core/builder/ClasspathJrt.java | 182 +++------ .../builder/ClasspathJrtWithReleaseOption.java | 387 ++++++++++++++++++ .../internal/core/builder/ClasspathLocation.java | 8 +- .../jdt/internal/core/builder/JavaBuilder.java | 2 +- .../eclipse/jdt/internal/core/builder/State.java | 28 +- .../search/matching/JavaSearchNameEnvironment.java | 3 +- 15 files changed, 1454 insertions(+), 233 deletions(-) create mode 100644 org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java create mode 100644 org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java (limited to 'org.eclipse.jdt.core.tests.compiler/src') diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java index 65587be739..349e89cf8d 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java @@ -40,7 +40,7 @@ import junit.framework.Test; public class ModuleCompilationTests extends AbstractBatchCompilerTest { static { -// TESTS_NAMES = new String[] { "testBug540067e" }; +// TESTS_NAMES = new String[] { "test001" }; // TESTS_NUMBERS = new int[] { 1 }; // TESTS_RANGE = new int[] { 298, -1 }; } @@ -3975,11 +3975,11 @@ public void testBug521362_emptyFile() { "}", }, "\"" + OUTPUT_DIR + File.separator + "X.java\"" - + " --release 6 -d \"" + OUTPUT_DIR + "\"", + + " --release 7 -d \"" + OUTPUT_DIR + "\"", "", "", true); - String expectedOutput = "// Compiled from X.java (version 1.6 : 50.0, super bit)"; + String expectedOutput = "// Compiled from X.java (version 1.7 : 51.0, super bit)"; checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); } public void testReleaseOption4() throws Exception { @@ -4094,6 +4094,7 @@ public void testBug521362_emptyFile() { true); } public void testReleaseOption10() throws Exception { + if (isJRE12Plus) return; this.runNegativeTest( new String[] { "X.java", diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java index 33aa81cb9a..fee9aacbe9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java @@ -53,6 +53,7 @@ public class AbstractCompilerTest extends TestCase { protected boolean enableAPT = false; protected static boolean isJRE9Plus = false; // Stop gap, so tests need not be run at 9, but some tests can be adjusted for JRE 9 protected static boolean isJRE11Plus = false; + protected static boolean isJRE12Plus = false; protected static boolean reflectNestedClassUseDollar; /** @@ -147,6 +148,7 @@ public class AbstractCompilerTest extends TestCase { int lessthan9 = F_1_3 | F_1_4 | F_1_5 | F_1_6 | F_1_7 | F_1_8; isJRE9Plus = !isJRELevel(lessthan9); isJRE11Plus = isJRELevel(F_11); + isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); } /** diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java index df6e565b35..72600309b7 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java @@ -74,6 +74,9 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { protected String endChar = ","; protected static boolean isJRE9 = false; + protected static boolean isJRE10 = false; + protected static boolean isJRE11 = false; + protected static boolean isJRE12 = false; protected static String DEFAULT_MODULES = null; static { String javaVersion = System.getProperty("java.version"); @@ -87,6 +90,16 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { } } long jdkLevel = CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion); + if (jdkLevel >= ClassFileConstants.JDK11) { + if (CompilerOptions.versionToJdkLevel(javaVersion.length() > 3 ? javaVersion.substring(0, 3) : javaVersion, false) == 0) { + // version was capped to 11 during versionToJdkLevel(version, true) + isJRE12 = true; + } + isJRE11 = true; + } + if (jdkLevel >= ClassFileConstants.JDK10) { + isJRE10 = true; + } if (jdkLevel >= ClassFileConstants.JDK9) { isJRE9 = true; if (vmName.contains("HotSpot")) { diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java index b80de70c73..ddc65ad408 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java @@ -696,8 +696,14 @@ public class ModuleBuilderTests extends ModifyingResourceTests { public void testConvertToModule() throws CoreException, IOException { Hashtable javaCoreOptions = JavaCore.getOptions(); try { - IJavaProject project = setUpJavaProject("ConvertToModule", "9"); - assertEquals(project.getOption("org.eclipse.jdt.core.compiler.compliance", true), "9"); + IJavaProject project = setUpJavaProject("ConvertToModule"); + Map options = new HashMap<>(); + // Make sure the new options map doesn't reset. + options.put(CompilerOptions.OPTION_Compliance, "9"); + options.put(CompilerOptions.OPTION_Source, "9"); + options.put(CompilerOptions.OPTION_TargetPlatform, "9"); + options.put(CompilerOptions.OPTION_Release, "enabled"); + project.setOptions(options); project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); IPackageFragmentRoot[] roots = project.getPackageFragmentRoots(); IPackageFragmentRoot theRoot = null; @@ -709,7 +715,14 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } assertNotNull("should not be null", theRoot); String[] modules = JavaCore.getReferencedModules(project); - assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); + if (isJRE12) + assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); + else if (isJRE11) + assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.net.http", "java.rmi", "java.sql"}, modules); + else if (isJRE10) + assertStringsEqual("incorrect result", new String[]{"java.datatransfer", "java.desktop", "java.rmi", "java.sql"}, modules); + else // 9 + assertStringsEqual("incorrect result", new String[]{"java.desktop", "java.rmi", "java.sql"}, modules); } finally { this.deleteProject("ConvertToModule"); JavaCore.setOptions(javaCoreOptions); @@ -8040,6 +8053,440 @@ public class ModuleBuilderTests extends ModifyingResourceTests { } } + public void testReleaseOption1() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption2() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "The project was not built due to \"release 6 is not found in the system\". " + + "Fix the problem, then try refreshing this project and building it since it may be inconsistent", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption3() throws Exception { + if (isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "java.util.stream.Stream cannot be resolved to a type", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption4() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption5() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "public class X {\n" + + " public java.util.stream.Stream emptyStream() {\n" + + " return null;\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "java.util.stream.Stream cannot be resolved to a type", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption6() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "interface I {\n" + + " int add(int x, int y);\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " I i = (x, y) -> {\n" + + " return x + y;\n" + + " };\n" + + " }\n" + + "}\n"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "Lambda expressions are allowed only at source level 1.8 or above", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption7() throws Exception { + if (isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "import java.io.*;\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " try {\n" + + " System.out.println();\n" + + " Reader r = new FileReader(args[0]);\n" + + " r.read();\n" + + " } catch(IOException | FileNotFoundException e) {\n" + + " e.printStackTrace();\n" + + " }\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + sortMarkers(markers); + assertMarkers("Unexpected markers", + "Multi-catch parameters are not allowed for source level below 1.7\n" + + "The exception FileNotFoundException is already caught by the alternative IOException", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption8() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_9); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption9() throws Exception { + if (!isJRE10) return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_10); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption10() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "module mod.one { \n" + + " requires java.base;\n" + + "}"; + String mPath = "p/src/module-info.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + sortMarkers(markers); + String expected = + "Syntax error on token \"module\", package expected\n" + + "Syntax error on token(s), misplaced construct(s)\n" + + "Syntax error on token \".\", , expected\n" + + "Syntax error on token \"}\", delete this token"; + assertMarkers("Unexpected markers", + expected, markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption11() throws Exception { + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + createFolder("p/src/foo"); + createFile( + "p/src/foo/Module.java", + "package foo;\n" + + "public class Module {}\n"); + createFile( + "p/src/foo/X.java", + "package foo;\n" + + "public class X { \n" + + " public Module getModule(String name) {\n" + + " return null;\n" + + " }\n" + + "}"); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption12() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "import java.io.*;\n" + + "\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " String str = Integer.toUnsignedString(1, 1);\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "The method toUnsignedString(int, int) is undefined for the type Integer", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } + public void testReleaseOption13() throws Exception { + if (!isJRE12) + return; + Hashtable options = JavaCore.getOptions(); + IJavaProject p = createJava9Project("p"); + p.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); + p.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + String outputDirectory = Util.getOutputDirectory(); + try { + String testSource = "\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " Integer.toUnsignedString(1, 1);\n" + + " }\n" + + "}"; + String mPath = "p/src/X.java"; + createFile(mPath, + testSource); + p.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); + waitForAutoBuild(); + IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "", markers); + + } finally { + JavaCore.setOptions(options); + deleteProject(p); + File outputDir = new File(outputDirectory); + if (outputDir.exists()) + Util.flushDirectoryContent(outputDir); + } + } protected void assertNoErrors() throws CoreException { for (IProject p : getWorkspace().getRoot().getProjects()) { int maxSeverity = p.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java index 7a39271115..8aad54669b 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 IBM Corporation. + * Copyright (c) 2018, 2019 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,15 +42,15 @@ import org.eclipse.jdt.internal.compiler.util.Util; public class ClasspathJep247 extends ClasspathJrt { - private java.nio.file.FileSystem fs = null; - private String compliance = null; - private long jdklevel; - private String releaseInHex = null; - private String[] subReleases = null; - private Path releasePath = null; - private Set packageCache; - File jdkHome; - String modulePath = null; + protected java.nio.file.FileSystem fs = null; + protected String compliance = null; + protected long jdklevel; + protected String releaseInHex = null; + protected String[] subReleases = null; + protected Path releasePath = null; + protected Set packageCache; + protected File jdkHome; + protected String modulePath = null; public ClasspathJep247(File jdkHome, String release, AccessRuleSet accessRuleSet) { super(jdkHome, false, accessRuleSet, null); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java new file mode 100644 index 0000000000..52a83987cf --- /dev/null +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java @@ -0,0 +1,303 @@ +/******************************************************************************* + * Copyright (c) 2019 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ClasspathJep247Jdk12 extends ClasspathJep247 { + + Map modules; + + public ClasspathJep247Jdk12(File jdkHome, String release, AccessRuleSet accessRuleSet) { + super(jdkHome, release, accessRuleSet); + } + @Override + public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { + return null; + } + @Override + public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { + return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); + } + @Override + public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { + if (!isPackage(qualifiedPackageName, moduleName)) + return null; // most common case + + try { + ClassFileReader reader = null; + byte[] content = null; + qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ + if (this.subReleases != null && this.subReleases.length > 0) { + done: for (String rel : this.subReleases) { + if (moduleName == null) { + Path p = this.fs.getPath(rel); + try (DirectoryStream stream = Files.newDirectoryStream(p)) { + for (final java.nio.file.Path subdir: stream) { + Path f = this.fs.getPath(rel, subdir.getFileName().toString(), qualifiedBinaryFileName); + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content != null) + break done; + } + } + } + } else { + Path p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); + if (Files.exists(p)) { + content = JRTUtil.safeReadBytes(p); + if (content != null) + break; + } + } + } + } else { + content = JRTUtil.safeReadBytes(this.fs.getPath(this.releaseInHex, qualifiedBinaryFileName)); + } + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), null); + } + } catch(ClassFormatException e) { + // Continue + } catch (IOException e) { + // continue + } + return null; + } + + @Override + public void initialize() throws IOException { + if (this.compliance == null) { + return; + } + if (this.fs != null) { + super.initialize(); + return; + } + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.compliance)).toUpperCase(); + Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ + URI t = filePath.toUri(); + if (!Files.exists(filePath)) { + return; + } + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + this.fs = FileSystems.newFileSystem(uri, env); + } + this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + if (!Files.exists(this.fs.getPath(this.releaseInHex))) { + throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ + } + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (rel.contains(this.releaseInHex)) + sub.add(rel); + } + this.subReleases = sub.toArray(new String[sub.size()]); + } catch (IOException e) { + //e.printStackTrace(); + } + super.initialize(); + } + @Override + public void loadModules() { + // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt + if (this.jdklevel <= ClassFileConstants.JDK1_8) { + super.loadModules(); + return; + } + final Path modPath = this.fs.getPath(this.releaseInHex); + this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ + this.modules = ModulesCache.get(this.modulePath); + if (this.modules == null) { + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (!rel.contains(this.releaseInHex)) { + continue; + } + Files.walkFileTree(subdir, Collections.EMPTY_SET, 2, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { + if (attrs.isDirectory() || f.getNameCount() < 3) + return FileVisitResult.CONTINUE; + byte[] content = null; + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content == null) + return FileVisitResult.CONTINUE; + Path m = f.subpath(1, f.getNameCount() - 1); + ClasspathJep247Jdk12.this.acceptModule(m.getFileName().toString(), content); + ClasspathJep247Jdk12.this.moduleNamesCache.add(m.getFileName().toString()); + } + return FileVisitResult.SKIP_SIBLINGS; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } catch (IOException e) { + e.printStackTrace(); + } + } else { + this.moduleNamesCache.addAll(this.modules.keySet()); + } + } + @Override + public Collection getModuleNames(Collection limitModule, Function getModule) { + return selectModules(this.moduleNamesCache, limitModule, getModule); + } + @Override + public IModule getModule(char[] moduleName) { + if (this.modules != null) { + return this.modules.get(String.valueOf(moduleName)); + } + return null; + } + void acceptModule(String name, byte[] content) { + if (content == null) + return; + + if (this.modules != null) { + if (this.modules.containsKey(name)) + return; + } + + ClassFileReader reader = null; + try { + reader = new ClassFileReader(content, IModule.MODULE_INFO_CLASS.toCharArray()); + } catch (ClassFormatException e) { + e.printStackTrace(); + } + if (reader != null) { + acceptModule(reader); + } + } + @Override + void acceptModule(ClassFileReader reader) { + // Modules below level 8 are not dealt with here. Leave it to ClasspathJrt + if (this.jdklevel <= ClassFileConstants.JDK1_8) { + super.acceptModule(reader); + return; + } + if (reader != null) { + IModule moduleDecl = reader.getModuleDeclaration(); + if (moduleDecl != null) { + if (this.modules == null) { + ModulesCache.put(this.modulePath, this.modules = new HashMap()); + } + this.modules.put(String.valueOf(moduleDecl.name()), moduleDecl); + } + } + } + @Override + public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { + // Ignore moduleName as this has nothing to do with modules (as of now) + if (this.packageCache != null) + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + + this.packageCache = new HashSet<>(41); + this.packageCache.add(Util.EMPTY_STRING); + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String rel = subdir.getFileName().toString(); + if (!rel.contains(this.releaseInHex)) { + continue; + } + try (DirectoryStream stream2 = Files.newDirectoryStream(subdir)) { + for (final java.nio.file.Path subdir2: stream2) { + Files.walkFileTree(subdir2, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + if (dir.getNameCount() <= 2) + return FileVisitResult.CONTINUE; + Path relative = dir.subpath(2, dir.getNameCount()); + addToPackageCache(relative.toString(), false); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + // Rethrow + } + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + } +} diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java index 1a81699b44..060351e20a 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -164,11 +164,14 @@ public class FileSystem implements IModuleAwareNameEnvironment, SuffixConstants Set knownFileNames; protected boolean annotationsFromClasspath; // should annotation files be read from the classpath (vs. explicit separate path)? private static HashMap JRT_CLASSPATH_CACHE = null; - protected Map moduleLocations = new HashMap<>(); /** Tasks resulting from --add-reads or --add-exports command line options. */ Map moduleUpdates = new HashMap<>(); + static final boolean isJRE12Plus; + static { + isJRE12Plus = "12".equals(System.getProperty("java.specification.version")); //$NON-NLS-1$ //$NON-NLS-2$ + } /* classPathNames is a collection is Strings representing the full path of each class path @@ -205,6 +208,8 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot final Classpath classpath = paths[i]; try { classpath.initialize(); + for (String moduleName : classpath.getModuleNames(limitedModules)) + this.moduleLocations.put(moduleName, classpath); this.classpaths[counter++] = classpath; } catch(IOException | InvalidPathException exception) { // JRE 9 could throw an IAE if the linked JAR paths have invalid chars, such as ":" @@ -256,7 +261,9 @@ public static Classpath getJrtClasspath(String jdkHome, String encoding, AccessR return new ClasspathJrt(new File(convertPathSeparators(jdkHome)), true, accessRuleSet, null); } public static Classpath getOlderSystemRelease(String jdkHome, String release, AccessRuleSet accessRuleSet) { - return new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); + return isJRE12Plus ? + new ClasspathJep247Jdk12(new File(convertPathSeparators(jdkHome)), release, accessRuleSet) : + new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); } public static Classpath getClasspath(String classpathName, String encoding, boolean isSourceOnly, AccessRuleSet accessRuleSet, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java index bb3bfb757c..b11078dfe5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java @@ -32,9 +32,7 @@ public class NameEnvironmentAnswer { String externalAnnotationPath; // should be an absolute file system path public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction) { - this.binaryType = binaryType; - this.accessRestriction = accessRestriction; - this.moduleName = binaryType.getModule(); + this(binaryType, accessRestriction, binaryType.getModule()); } public NameEnvironmentAnswer(IBinaryType binaryType, AccessRestriction accessRestriction, char[] module) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java index 481bbef429..f6903f814f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java @@ -22,6 +22,7 @@ import java.net.URLClassLoader; import java.nio.channels.ClosedByInterruptException; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -59,7 +60,7 @@ public class JRTUtil { public static int NOTIFY_ALL = NOTIFY_FILES | NOTIFY_PACKAGES | NOTIFY_MODULES; // TODO: Java 9 Think about clearing the cache too. - private static Map images = null; + private static Map images = null; private static final Object lock = new Object(); @@ -100,7 +101,11 @@ public class JRTUtil { } public static JrtFileSystem getJrtSystem(File image) { - Map i = images; + return getJrtSystem(image, null); + } + + public static JrtFileSystem getJrtSystem(File image, String release) { + Map i = images; if (images == null) { synchronized (lock) { i = images; @@ -110,10 +115,12 @@ public class JRTUtil { } } JrtFileSystem system = null; + String key = image.toString(); + if (release != null) key = key + "|" + release; //$NON-NLS-1$ synchronized(i) { - if ((system = images.get(image)) == null) { + if ((system = images.get(key)) == null) { try { - images.put(image, system = new JrtFileSystem(image)); + images.put(key, system = JrtFileSystem.getNewJrtFileSystem(image, release)); } catch (IOException e) { e.printStackTrace(); // Needs better error handling downstream? But for now, make sure @@ -138,8 +145,8 @@ public class JRTUtil { * /modules/$MODULE/$PATH * /packages/$PACKAGE/$MODULE * The latter provides quick look up of the module that contains a particular package. However, - * this method only notifies its clients of the entries within the modules sub-directory. The - * clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, + * this method only notifies its clients of the entries within the modules (latter) sub-directory. + * Clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL}, * {@link JRTUtil#NOTIFY_FILES}, {@link JRTUtil#NOTIFY_PACKAGES} and {@link JRTUtil#NOTIFY_MODULES}. * * @param image a java.io.File handle to the JRT image. @@ -148,7 +155,10 @@ public class JRTUtil { * @throws IOException */ public static void walkModuleImage(File image, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { - getJrtSystem(image).walkModuleImage(visitor, false, notify); + getJrtSystem(image, null).walkModuleImage(visitor, notify); + } + public static void walkModuleImage(File image, String release, final JRTUtil.JrtFileVisitor visitor, int notify) throws IOException { + getJrtSystem(image, release).walkModuleImage(visitor, notify); } public static InputStream getContentFromJrt(File jrt, String fileName, String module) throws IOException { @@ -187,13 +197,138 @@ public class JRTUtil { } } } +class JrtFileSystemWithOlderRelease extends JrtFileSystem { + final String release; + String releaseInHex = null; + //private Path releasePath = null; + private String[] subReleases = null; + protected Path modulePath = null; + + /** + * The jrt file system is based on the location of the JRE home whose libraries + * need to be loaded. + * + * @param jrt the path to the root of the JRE whose libraries we are interested in. + * @param release the older release where classes and modules should be searched for. + * @throws IOException + */ + JrtFileSystemWithOlderRelease(File jrt, String release) throws IOException { + super(jrt); + this.release = release; + initialize(jrt, release); + } + @Override + void initialize(File jdk) throws IOException { + // Just to make sure we don't do anything in super.initialize() + // before setting this.release + } + void initialize(File jdk, String rel) throws IOException { + super.initialize(jdk); + this.fs = null;// reset and proceed, TODO: this is crude and need to be removed. + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); + Path ct = Paths.get(this.jdkHome, "lib", "ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ + if (!Files.exists(ct)) { + return; + } + URI uri = URI.create("jar:file:" + ct.toUri().getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + return; + } + } + Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + if (!Files.exists(this.fs.getPath(this.releaseInHex)) + || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ + this.fs = null; + } + if (this.release != null) { + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { + for (final java.nio.file.Path subdir: stream) { + String r = subdir.getFileName().toString(); + if (r.contains(this.releaseInHex)) { + sub.add(r); + } else { + continue; + } + } + } catch (IOException e) { + e.printStackTrace(); + // Rethrow? + } + this.subReleases = sub.toArray(new String[sub.size()]); + } + // Ensure walkJrtForModules() is not called + } + @Override + void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { + if (this.subReleases != null && this.subReleases.length > 0) { + for (String rel : this.subReleases) { + Path p = this.fs.getPath(rel); + Files.walkFileTree(p, new JRTUtil.AbstractFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + int count = dir.getNameCount(); + if (count == 1) { + return FileVisitResult.CONTINUE; + } + if (count == 2) { + // e.g. /9A/java.base + java.nio.file.Path mod = dir.getName(1); + if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 + && JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { + return FileVisitResult.SKIP_SUBTREE; + } + return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? FileVisitResult.CONTINUE + : visitor.visitModule(dir); + } + if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { + // client is not interested in packages + return FileVisitResult.CONTINUE; + } + return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) + throws IOException { + if ((notify & JRTUtil.NOTIFY_FILES) == 0) { + return FileVisitResult.CONTINUE; + } + // This happens when a file in a default package is present. E.g. /modules/some.module/file.name + if (file.getNameCount() == 3) { + cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); + } + return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); + } + }); + } + } + } + +} class JrtFileSystem { private final Map packageToModule = new HashMap(); private final Map> packageToModules = new HashMap>(); - FileSystem jrtSystem = null; - + FileSystem fs = null; + Path modRoot = null; + String jdkHome = null; + public static JrtFileSystem getNewJrtFileSystem(File jrt, String release) throws IOException { + return (release == null) ? new JrtFileSystem(jrt) : + new JrtFileSystemWithOlderRelease(jrt, release); + + } /** * The jrt file system is based on the location of the JRE home whose libraries * need to be loaded. @@ -201,18 +336,18 @@ class JrtFileSystem { * @param jrt the path to the root of the JRE whose libraries we are interested in. * @throws IOException */ - public JrtFileSystem(File jrt) throws IOException { + JrtFileSystem(File jrt) throws IOException { initialize(jrt); } void initialize(File jrt) throws IOException { URL jrtPath = null; - String jdkHome = null; + this.jdkHome = null; if (jrt.toString().endsWith(JRTUtil.JRT_FS_JAR)) { jrtPath = jrt.toPath().toUri().toURL(); - jdkHome = jrt.getParentFile().getParent(); + this.jdkHome = jrt.getParentFile().getParent(); } else { - jdkHome = jrt.toPath().toString(); - jrtPath = Paths.get(jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ + this.jdkHome = jrt.toPath().toString(); + jrtPath = Paths.get(this.jdkHome, "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ } JRTUtil.MODULE_TO_LOAD = System.getProperty("modules.to.load"); //$NON-NLS-1$ @@ -220,13 +355,15 @@ class JrtFileSystem { if (javaVersion != null && javaVersion.startsWith("1.8")) { //$NON-NLS-1$ URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath }); HashMap env = new HashMap<>(); - this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); + this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env, loader); } else { HashMap env = new HashMap<>(); - env.put("java.home", jdkHome); //$NON-NLS-1$ - this.jrtSystem = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); + env.put("java.home", this.jdkHome); //$NON-NLS-1$ + this.fs = FileSystems.newFileSystem(JRTUtil.JRT_URI, env); } - walkModuleImage(null, true, 0 /* doesn't matter */); + this.modRoot = this.fs.getPath(JRTUtil.MODULES_SUBDIR); + // Set up the root directory wherere modules are located + walkJrtForModules(); } public List getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { @@ -279,7 +416,7 @@ class JrtFileSystem { String knownModule = this.packageToModule.get(qualifiedPackageName); if (knownModule == null || (knownModule != JRTUtil.MULTIPLE && !knownModule.equals(module))) return false; - Path packagePath = this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); + Path packagePath = this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, qualifiedPackageName); if (!Files.exists(packagePath)) return false; // iterate files: @@ -294,11 +431,11 @@ class JrtFileSystem { public InputStream getContentFromJrt(String fileName, String module) throws IOException { if (module != null) { - return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } String[] modules = getModules(fileName); for (String mod : modules) { - return Files.newInputStream(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + return Files.newInputStream(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); } return null; } @@ -309,7 +446,7 @@ class JrtFileSystem { for (String mod : modules) { if (moduleNameFilter != null && !moduleNameFilter.test(mod)) continue; - content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { module = mod; break; @@ -330,7 +467,7 @@ class JrtFileSystem { } else { String[] modules = getModules(fileName); for (String mod : modules) { - content = JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); + content = JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, mod, fileName)); if (content != null) { break; } @@ -339,7 +476,7 @@ class JrtFileSystem { return content; } private byte[] getClassfileBytes(String fileName, String module) throws IOException, ClassFormatException { - return JRTUtil.safeReadBytes(this.jrtSystem.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); + return JRTUtil.safeReadBytes(this.fs.getPath(JRTUtil.MODULES_SUBDIR, module, fileName)); } public ClassFileReader getClassfile(String fileName, String module, Predicate moduleNameFilter) throws IOException, ClassFormatException { ClassFileReader reader = null; @@ -367,47 +504,12 @@ class JrtFileSystem { return reader; } - void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, boolean visitPackageMapping, final int notify) throws IOException { - Iterable roots = this.jrtSystem.getRootDirectories(); + void walkJrtForModules() throws IOException { + Iterable roots = this.fs.getRootDirectories(); for (java.nio.file.Path path : roots) { try (DirectoryStream stream = Files.newDirectoryStream(path)) { for (final java.nio.file.Path subdir: stream) { - if (subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { - if (visitPackageMapping) continue; - Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - int count = dir.getNameCount(); - if (count == 2) { - // e.g. /modules/java.base - java.nio.file.Path mod = dir.getName(1); - if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && - JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { - return FileVisitResult.SKIP_SUBTREE; - } - return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? - FileVisitResult.CONTINUE : visitor.visitModule(mod); - } - if (dir == subdir || count < 3 || (notify & JRTUtil.NOTIFY_PACKAGES) == 0) { - // We are dealing with a module or not client is not interested in packages - return FileVisitResult.CONTINUE; - } - return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { - if ((notify & JRTUtil.NOTIFY_FILES) == 0) - return FileVisitResult.CONTINUE; - int count = file.getNameCount(); - // This happens when a file in a default package is present. E.g. /modules/some.module/file.name - if (count == 3) { - cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); - } - return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); - } - }); - } else if (visitPackageMapping) { + if (!subdir.toString().equals(JRTUtil.MODULES_SUBDIR)) { Files.walkFileTree(subdir, new JRTUtil.AbstractFileVisitor() { @Override public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { @@ -424,6 +526,42 @@ class JrtFileSystem { } } } + void walkModuleImage(final JRTUtil.JrtFileVisitor visitor, final int notify) throws IOException { + Files.walkFileTree(this.modRoot, new JRTUtil.AbstractFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + int count = dir.getNameCount(); + if (count == 1) return FileVisitResult.CONTINUE; + if (count == 2) { + // e.g. /modules/java.base + java.nio.file.Path mod = dir.getName(1); + if ((JRTUtil.MODULE_TO_LOAD != null && JRTUtil.MODULE_TO_LOAD.length() > 0 && + JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) { + return FileVisitResult.SKIP_SUBTREE; + } + return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? + FileVisitResult.CONTINUE : visitor.visitModule(mod); + } + if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) { + // We are dealing with a module or not client is not interested in packages + return FileVisitResult.CONTINUE; + } + return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs); + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException { + if ((notify & JRTUtil.NOTIFY_FILES) == 0) + return FileVisitResult.CONTINUE; + int count = file.getNameCount(); + // This happens when a file in a default package is present. E.g. /modules/some.module/file.name + if (count == 3) { + cachePackage(JRTUtil.DEFAULT_PACKAGE, file.getName(1).toString()); + } + return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs); + } + }); + } void cachePackage(String packageName, String module) { packageName = packageName.intern(); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java index 34ab941c95..50cfd275f1 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 IBM Corporation and others. + * Copyright (c) 2016, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -15,16 +15,9 @@ package org.eclipse.jdt.internal.core.builder; import java.io.File; import java.io.IOException; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -35,7 +28,6 @@ import java.util.function.Predicate; import java.util.zip.ZipFile; import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; @@ -50,36 +42,29 @@ import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.SimpleSet; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.JavaProject; -import org.eclipse.jdt.internal.core.util.Util; public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry { //private HashMap packagesInModule = null; -private static HashMap> PackageCache = new HashMap<>(); -private static HashMap> ModulesCache = new HashMap<>(); +protected static HashMap> PackageCache = new HashMap<>(); +protected static HashMap> ModulesCache = new HashMap<>(); String externalAnnotationPath; -private ZipFile annotationZipFile; +protected ZipFile annotationZipFile; String zipFilename; // keep for equals AccessRuleSet accessRuleSet; -String release = null; -String releaseInHex = null; -private Path releasePath = null; -private String[] subReleases = null; -private java.nio.file.FileSystem fs = null; static final Set NO_LIMIT_MODULES = new HashSet<>(); -public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, String release) { +/* + * Only for use from ClasspathJrtWithOlderRelease + */ +protected ClasspathJrt() { +} +public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) { this.zipFilename = zipFilename; this.accessRuleSet = accessRuleSet; if (externalAnnotationPath != null) this.externalAnnotationPath = externalAnnotationPath.toString(); - if (release != null && release.length() == 0) { - this.release = null; - } else { - this.release = release; - } - initialize(); loadModules(this); } /** @@ -89,7 +74,7 @@ public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath exter */ static HashMap findPackagesInModules(final ClasspathJrt jrt) { String zipFileName = jrt.zipFilename; - HashMap cache = PackageCache.get(zipFileName); + HashMap cache = PackageCache.get(jrt.getKey()); if (cache != null) { return cache; } @@ -97,7 +82,7 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) PackageCache.put(zipFileName, packagesInModule); try { final File imageFile = new File(zipFileName); - org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @Override @@ -132,12 +117,11 @@ static HashMap findPackagesInModules(final ClasspathJrt jrt) } public static void loadModules(final ClasspathJrt jrt) { - String zipFileName = jrt.zipFilename; - Set cache = ModulesCache.get(zipFileName); + Set cache = ModulesCache.get(jrt.getKey()); if (cache == null) { try { - final File imageFile = new File(zipFileName); + final File imageFile = new File(jrt.zipFilename); org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { SimpleSet packageSet = null; @@ -174,70 +158,11 @@ public static void loadModules(final ClasspathJrt jrt) { // } } } -public void initialize() { - if (this.release == null) { - return; - } - this.release = getReleaseOptionFromCompliance(this.release); - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); - Path lib = Paths.get(this.zipFilename).getParent(); - Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ - URI t = filePath.toUri(); - if (!Files.exists(filePath)) { - return; - } - URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ - try { - this.fs = FileSystems.getFileSystem(uri); - } catch(FileSystemNotFoundException fne) { - // Ignore and move on - } - if (this.fs == null) { - HashMap env = new HashMap<>(); - try { - this.fs = FileSystems.newFileSystem(uri, env); - } catch (IOException e) { - this.release = null; - return; - } - } - this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex)) - || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ - this.release = null; - } - if (this.release != null) { - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = subdir.getFileName().toString(); - if (rel.contains(this.releaseInHex)) { - sub.add(rel); - } else { - continue; - } - } - } catch (IOException e) { - e.printStackTrace(); - // Rethrow - } - this.subReleases = sub.toArray(new String[sub.size()]); - } -} -private String getReleaseOptionFromCompliance(String comp) { - if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { - // For a JDK 9 and above, the minimum release we support is "6" - return "6"; //$NON-NLS-1$ - } - int index = comp.indexOf("1."); //$NON-NLS-1$ - if (index != -1) { - return comp.substring(index + 2, comp.length()); - } else { - return comp; - } +protected String getKey() { + return this.zipFilename; } void acceptModule(byte[] content) { - if (content == null) + if (content == null) return; ClassFileReader reader = null; try { @@ -246,11 +171,12 @@ void acceptModule(byte[] content) { e.printStackTrace(); } if (reader != null) { + String key = getKey(); IModule moduleDecl = reader.getModuleDeclaration(); if (moduleDecl != null) { - Set cache = ModulesCache.get(this.zipFilename); + Set cache = ModulesCache.get(key); if (cache == null) { - ModulesCache.put(this.zipFilename, cache = new HashSet()); + ModulesCache.put(key, cache = new HashSet()); } cache.add(moduleDecl); } @@ -265,7 +191,6 @@ public void cleanup() { } this.annotationZipFile = null; } - this.fs = null; } @Override @@ -273,9 +198,6 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ClasspathJrt)) return false; ClasspathJrt jar = (ClasspathJrt) o; - if (!Util.equalOrNull(this.release, jar.release)) { - return false; - } if (this.accessRuleSet != jar.accessRuleSet) if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet)) return false; @@ -288,43 +210,31 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case try { - IBinaryType reader = null; - byte[] content = null; String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); - if (this.subReleases != null && this.subReleases.length > 0) { - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - for (String rel : this.subReleases) { - Path p = this.fs.getPath(rel, qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) { - reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); - break; - } - } - } - } else { - reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); - } - if (reader != null) { - if (this.externalAnnotationPath != null) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); - } catch (IOException e) { - // don't let error on annotations fail class reading + IBinaryType reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, moduleNameFilter); + return createAnswer(fileNameWithoutExtension, reader); + } catch (ClassFormatException e) { // treat as if class file is missing + } catch (IOException e) { // treat as if class file is missing + } + return null; +} +protected NameEnvironmentAnswer createAnswer(String fileNameWithoutExtension, IBinaryType reader) { + if (reader != null) { + if (this.externalAnnotationPath != null) { + try { + if (this.annotationZipFile == null) { + this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(this.externalAnnotationPath, null); } + reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile); + } catch (IOException e) { + // don't let error on annotations fail class reading } - if (this.accessRuleSet == null) - return new NameEnvironmentAnswer(reader, null, reader.getModule()); - return new NameEnvironmentAnswer(reader, - this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), - reader.getModule()); } - } catch (ClassFormatException e) { // treat as if class file is missing - } catch (IOException e) { // treat as if class file is missing + if (this.accessRuleSet == null) + return new NameEnvironmentAnswer(reader, null, reader.getModule()); + return new NameEnvironmentAnswer(reader, + this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), + reader.getModule()); } return null; } @@ -341,7 +251,7 @@ public int hashCode() { @Override public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { List moduleNames = JRTUtil.getModulesDeclaringPackage(new File(this.zipFilename), qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(moduleNames); + return CharOperation.toCharArrays(moduleNames); } @Override public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { @@ -374,7 +284,7 @@ public boolean hasModule() { } @Override public IModule getModule(char[] moduleName) { - Set modules = ModulesCache.get(this.zipFilename); + Set modules = ModulesCache.get(getKey()); if (modules != null) { for (IModule mod : modules) { if (CharOperation.equals(mod.name(), moduleName)) @@ -391,7 +301,7 @@ public Collection getModuleNames(Collection limitModules) { return Collections.emptyList(); } -private Collection selectModules(Set keySet, Collection limitModules) { +protected Collection selectModules(Set keySet, Collection limitModules) { Collection rootModules; if (limitModules == NO_LIMIT_MODULES) { rootModules = new HashSet<>(keySet); @@ -408,7 +318,7 @@ private Collection selectModules(Set keySet, Collection return allModules; } -private void addRequired(String mod, Set allModules) { +protected void addRequired(String mod, Set allModules) { IModule iMod = getModule(mod.toCharArray()); for (IModuleReference requiredRef : iMod.requires()) { IModule reqMod = getModule(requiredRef.name()); @@ -421,7 +331,7 @@ private void addRequired(String mod, Set allModules) { } @Override public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - // + // return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null); } /** TEST ONLY */ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java new file mode 100644 index 0000000000..a5d8446c37 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java @@ -0,0 +1,387 @@ +/******************************************************************************* + * Copyright (c) 2016, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.builder; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; +import org.eclipse.jdt.internal.compiler.util.SimpleSet; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.core.util.Util; + +public class ClasspathJrtWithReleaseOption extends ClasspathJrt { + + final String release; + String releaseInHex; + private String[] subReleases; + private java.nio.file.FileSystem fs; + protected Path modulePath; + private String modPathString; + private boolean isJRE12Plus; + + public ClasspathJrtWithReleaseOption(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, + String release) throws CoreException { + super(); + if (release == null || release.equals("")) { //$NON-NLS-1$ + throw new IllegalArgumentException("--release argument can not be null"); //$NON-NLS-1$ + } + this.zipFilename = zipFilename; + this.accessRuleSet = accessRuleSet; + if (externalAnnotationPath != null) + this.externalAnnotationPath = externalAnnotationPath.toString(); + this.release = getReleaseOptionFromCompliance(release); + initialize(); + loadModules(this); + } + /* + * JDK 11 doesn't contain release 5. Hence + * if the compliance is below 6, we simply return the lowest supported + * release, which is 6. + */ + private String getReleaseOptionFromCompliance(String comp) { + if (JavaCore.compareJavaVersions(comp, JavaCore.VERSION_1_5) <= 0) { + return "6"; //$NON-NLS-1$ + } + int index = comp.indexOf("1."); //$NON-NLS-1$ + if (index != -1) { + return comp.substring(index + 2, comp.length()); + } else { + return comp; + } + } + private boolean isJRE12Plus(Path path) { + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (final java.nio.file.Path subdir : stream) { + String rel = subdir.getFileName().toString(); + if (Files.exists(this.fs.getPath(rel, "system-modules"))) { //$NON-NLS-1$ + int parseInt = Integer.parseInt(rel, 16); + return (parseInt > 11); + } + } + } catch (IOException e) { + this.fs = null; + } + return false; + } + /* + * Set up the paths where modules and regular classes need to be read. We need to deal with two different kind of + * formats of cy.sym: Post JDK 12: ct.sym -> 9 -> java/ -> lang/* 9-modules -> java.base -> module-info.sig + * + * From JDK 12 onward: ct.sym -> 9 -> java.base -> module-info.sig java/ -> lang/* Notably, 1) in JDK 12 modules + * classes and ordinary classes are located in the same location 2) in JDK 12, ordinary classes are found inside + * their respective modules + * + */ + protected void initialize() throws CoreException { + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase(); + Path lib = Paths.get(this.zipFilename).getParent(); + Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ + URI t = filePath.toUri(); + if (!Files.exists(filePath)) { + return; + } + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch (FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + return; + } + } + Path releasePath = this.fs.getPath("/"); //$NON-NLS-1$ + this.isJRE12Plus = isJRE12Plus(releasePath); + Path modPath = this.fs.getPath(this.releaseInHex + (this.isJRE12Plus ? "" : "-modules")); //$NON-NLS-1$ //$NON-NLS-2$ + if (Files.exists(modPath)) { + this.modulePath = modPath; + this.modPathString = this.zipFilename + "|"+ modPath.toString(); //$NON-NLS-1$ + } + + if (!Files.exists(releasePath.resolve(this.releaseInHex))) { + Exception e = new IllegalArgumentException("release " + this.release + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ + throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, e.getMessage(), e)); + } + if (Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ + this.fs = null; // Fallback to default version + return; + } + if (this.release != null) { + List sub = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(releasePath)) { + for (final java.nio.file.Path subdir : stream) { + String rel = subdir.getFileName().toString(); + if (rel.contains(this.releaseInHex)) { + sub.add(rel); + } else { + continue; + } + } + } catch (IOException e) { + this.fs = null; // Fallback to default version + } + this.subReleases = sub.toArray(new String[sub.size()]); + } + } + + static HashMap findPackagesInModules(final ClasspathJrtWithReleaseOption jrt) { + // In JDK 11 and before, classes are not listed under their respective modules + // Hence, we simply go to the default module system for package-module mapping + if (jrt.fs == null || !jrt.isJRE12Plus) { + return ClasspathJrt.findPackagesInModules(jrt); + } + String zipFileName = jrt.zipFilename; + HashMap cache = PackageCache.get(jrt.modPathString); + if (cache != null) { + return cache; + } + final HashMap packagesInModule = new HashMap<>(); + PackageCache.put(jrt.modPathString, packagesInModule); + try { + final File imageFile = new File(zipFileName); + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, jrt.release, + new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { + SimpleSet packageSet = null; + + @Override + public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) + throws IOException { + ClasspathJar.addToPackageSet(this.packageSet, dir.toString(), true); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitModule(Path mod) throws IOException { + String name = mod.getName(1).toString(); + this.packageSet = new SimpleSet(41); + this.packageSet.add(""); //$NON-NLS-1$ + packagesInModule.put(name, this.packageSet); + return FileVisitResult.CONTINUE; + } + }, JRTUtil.NOTIFY_PACKAGES | JRTUtil.NOTIFY_MODULES); + } catch (IOException e) { + // return empty handed + } + return packagesInModule; + } + + public static void loadModules(final ClasspathJrtWithReleaseOption jrt) { + if (jrt.fs == null || !jrt.isJRE12Plus) { + ClasspathJrt.loadModules(jrt); + return; + } + if (jrt.modPathString == null) + return; + Set cache = ModulesCache.get(jrt.modPathString); + if (cache == null) { + try (DirectoryStream stream = Files.newDirectoryStream(jrt.modulePath)) { + for (final java.nio.file.Path subdir : stream) { + + Files.walkFileTree(subdir, Collections.EMPTY_SET, 1, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) + throws IOException { + byte[] content = null; + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content == null) + return FileVisitResult.CONTINUE; + jrt.acceptModule(content); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } catch (IOException e) { + // Nothing much to do + } + } + } + + + @Override + public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, + String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) { + + if (this.fs == null) { + return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, + asBinaryOnly, moduleNameFilter); + } + if (!isPackage(qualifiedPackageName, moduleName)) + return null; // most common case + + try { + IBinaryType reader = null; + byte[] content = null; + String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, + qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); + if (this.subReleases != null && this.subReleases.length > 0) { + qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ + outer: for (String rel : this.subReleases) { + Path p = null; + inner: if (this.isJRE12Plus) { + if (moduleName != null) { + p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); + } + else { + try (DirectoryStream stream = Files + .newDirectoryStream(this.fs.getPath(rel))) { + for (final java.nio.file.Path subdir : stream) { + p = subdir.resolve(qualifiedBinaryFileName); + if (Files.exists(p)) { + if (subdir.getNameCount() == 2 ) { + moduleName = subdir.getName(1).toString(); + } + break inner; + } + } + } + } + } else { + p = this.fs.getPath(rel, qualifiedBinaryFileName); + } + if (Files.exists(p)) { + content = JRTUtil.safeReadBytes(p); + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + if (moduleName != null) + ((ClassFileReader) reader).moduleName = moduleName.toCharArray(); + break outer; + } + } + } + } else { + reader = ClassFileReader.readFromModule(new File(this.zipFilename), moduleName, qualifiedBinaryFileName, + moduleNameFilter); + } + return createAnswer(fileNameWithoutExtension, reader); + } catch (ClassFormatException e) { + // treat as if class file is missing + } catch (IOException e) { + // treat as if class file is missing + } + return null; + } + + @Override + public Collection getModuleNames(Collection limitModules) { + HashMap cache = findPackagesInModules(this); + if (cache != null) + return selectModules(cache.keySet(), limitModules); + return Collections.emptyList(); + } + + @Override + public void cleanup() { + try { + super.reset(); + } finally { + // The same file system is also used in JRTUtil, so don't close it here. + this.fs = null; + } + } + + @Override + public boolean hasModule() { + return this.modPathString != null; + } + + @Override + protected String getKey() { + return this.modPathString; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof ClasspathJrtWithReleaseOption)) + return false; + ClasspathJrtWithReleaseOption jar = (ClasspathJrtWithReleaseOption) o; + if (!Util.equalOrNull(this.release, jar.release)) { + return false; + } + return super.equals(o); + } + + @Override + public int hashCode() { + int hash = this.zipFilename == null ? super.hashCode() : this.zipFilename.hashCode(); + return Util.combineHashCodes(hash, this.release.hashCode()); + } + + @Override + public String toString() { + String start = "Classpath jrt file " + this.zipFilename + " with --release option " + this.release; //$NON-NLS-1$ //$NON-NLS-2$ + return start; + } + +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index d501e436cf..52cd7e0c31 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -23,6 +23,7 @@ import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; @@ -141,8 +142,9 @@ static ClasspathLocation forLibrary(String libraryPathname, new ClasspathMultiReleaseJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule, compliance)); } -static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) { - return new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath, release); +public static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) throws CoreException { + return (release == null || release.equals("")) ? new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath) : //$NON-NLS-1$ + new ClasspathJrtWithReleaseOption(jrtPath, accessRuleSet, annotationsPath, release); } public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet, IPath annotationsPath, diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java index 269e064480..abf0ebc7a7 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java @@ -152,7 +152,7 @@ public static void removeProblemsAndTasksFor(IResource resource) { } } -public static State readState(IProject project, DataInputStream in) throws IOException { +public static State readState(IProject project, DataInputStream in) throws IOException, CoreException { return State.read(project, in); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index dd240bcacb..a57cc107e6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -56,7 +56,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0021; +public static final byte VERSION = 0x0022; static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; @@ -233,7 +233,7 @@ void removeQualifiedTypeName(String qualifiedTypeNameToRemove) { this.typeLocators.removeKey(qualifiedTypeNameToRemove); } -static State read(IProject project, DataInputStream in) throws IOException { +static State read(IProject project, DataInputStream in) throws IOException, CoreException { if (JavaBuilder.DEBUG) System.out.println("About to read state " + project.getName()); //$NON-NLS-1$ if (VERSION != in.readByte()) { @@ -568,13 +568,20 @@ void write(DataOutputStream out) throws IOException { out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$ - } else { + } else if (c instanceof ClasspathJrt) { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ + out.writeUTF(""); //$NON-NLS-1$ + } else { + ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + out.writeByte(EXTERNAL_JAR); + out.writeUTF(jrt.zipFilename); + writeRestriction(jrt.accessRuleSet, out); + out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release); } char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray(); writeName(patchName, out); @@ -680,13 +687,20 @@ void write(DataOutputStream out) throws IOException { out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance != null ? jar.compliance : ""); //$NON-NLS-1$ - } else { + } else if (c instanceof ClasspathJrt) { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ + out.writeUTF(""); //$NON-NLS-1$ + } else { + ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c; + out.writeByte(EXTERNAL_JAR); + out.writeUTF(jrt.zipFilename); + writeRestriction(jrt.accessRuleSet, out); + out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release); } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java index a61e40abd2..db613ca5a3 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java @@ -49,7 +49,6 @@ import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.PackageFragmentRoot; -import org.eclipse.jdt.internal.core.builder.ClasspathJrt; import org.eclipse.jdt.internal.core.builder.ClasspathLocation; import org.eclipse.jdt.internal.core.util.Util; @@ -162,7 +161,7 @@ private ClasspathLocation mapToClassPathLocation(JavaModelManager manager, Packa IJavaProject project = (IJavaProject) root.getParent(); String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); cp = (root instanceof JrtPackageFragmentRoot) ? - new ClasspathJrt(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), + ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) : ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, -- cgit v1.2.3