From b889cf00f2d36c22c848ae67ad0deb08734d7780 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Sun, 27 Nov 2016 00:25:43 +0100 Subject: update jdt.core to I20161124-2000 --- .../regression/AbstractRegressionTest.java | 52 +++++- .../tests/compiler/regression/AnnotationTest.java | 142 ++++++++++++-- .../compiler/regression/BatchCompilerTest.java | 21 +++ .../regression/CompilerInvocationTests.java | 6 + .../regression/ExpressionContextTests.java | 11 +- .../regression/GenericsRegressionTest_1_8.java | 56 ++++++ .../regression/GrammarCoverageTests308.java | 42 +++-- .../regression/JSR308SpecSnippetTests.java | 4 +- .../compiler/regression/LambdaExpressionsTest.java | 32 ++++ .../regression/NegativeTypeAnnotationTest.java | 42 +++-- .../compiler/regression/NullAnnotationTest.java | 66 ++++++- .../regression/NullTypeAnnotationTest.java | 205 ++++++++++++++++++++- .../regression/SerializableLambdaTest.java | 27 +++ .../core/tests/model/AbstractJavaModelTests.java | 15 +- .../model/JavadocMethodCompletionModelTest.java | 8 +- .../jdt/core/tests/model/ResolveTests2.java | 4 +- .../eclipse/jdt/core/compiler/CharOperation.java | 17 +- .../org/eclipse/jdt/core/compiler/IProblem.java | 8 + .../eclipse/jdt/internal/compiler/ast/ASTNode.java | 5 +- .../jdt/internal/compiler/ast/Annotation.java | 71 ++++--- .../jdt/internal/compiler/ast/CastExpression.java | 3 + .../compiler/ast/CompilationUnitDeclaration.java | 68 ++++--- .../jdt/internal/compiler/ast/MessageSend.java | 7 +- .../compiler/ast/QualifiedTypeReference.java | 11 +- .../internal/compiler/ast/ReferenceExpression.java | 2 +- .../jdt/internal/compiler/codegen/CodeStream.java | 2 +- .../internal/compiler/impl/CompilerOptions.java | 16 ++ .../jdt/internal/compiler/impl/IrritantSet.java | 4 +- .../compiler/lookup/BinaryTypeBinding.java | 4 +- .../compiler/lookup/CompilationUnitScope.java | 4 + .../lookup/ImplicitNullAnnotationVerifier.java | 10 +- .../compiler/lookup/InferenceContext18.java | 54 +----- .../compiler/lookup/InferenceSubstitution.java | 2 +- .../compiler/lookup/InferenceVariable.java | 86 +++++++-- .../lookup/ParameterizedGenericMethodBinding.java | 8 +- .../jdt/internal/compiler/lookup/TypeIds.java | 1 + .../jdt/internal/compiler/lookup/TypeSystem.java | 14 +- .../compiler/lookup/TypeVariableBinding.java | 9 +- .../internal/compiler/problem/ProblemReporter.java | 35 +++- .../internal/compiler/problem/messages.properties | 5 +- .../model/org/eclipse/jdt/core/JavaCore.java | 137 +++++++++----- .../internal/core/builder/BatchImageBuilder.java | 12 +- .../org/eclipse/jdt/internal/core/nd/Nd.java | 4 + .../jdt/internal/core/nd/indexer/Indexer.java | 27 +++ .../jdt/internal/core/nd/java/JavaIndex.java | 4 - .../core/nd/java/model/BinaryTypeFactory.java | 5 +- .../jdt/internal/core/nd/java/model/Package.java | 48 +++++ .../core/search/indexing/IndexManager.java | 31 +++- .../core/search/processing/JobManager.java | 29 +-- 49 files changed, 1158 insertions(+), 318 deletions(-) create mode 100644 org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java 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 0a6984c69..141b2d2d3 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 @@ -36,12 +36,15 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Processor; @@ -89,8 +92,6 @@ import org.eclipse.jdt.internal.core.search.indexing.BinaryIndexer; import org.eclipse.jdt.internal.core.util.Messages; import org.osgi.framework.Bundle; -import java.util.regex.Pattern; - @SuppressWarnings({ "unchecked", "rawtypes" }) public abstract class AbstractRegressionTest extends AbstractCompilerTest implements StopableTestCase { @@ -953,10 +954,11 @@ protected static class JavacTestOptions { String computedProblemLog = Util.convertToIndependantLineDelimiter(requestor.problemLog.toString()); if (this.shouldSwallowCaptureId) computedProblemLog = Pattern.compile("capture#(\\d+)").matcher(computedProblemLog).replaceAll("capture"); - + + ProblemLog problemLog = new ProblemLog(computedProblemLog); int i; for (i = 0; i < alternatePlatformIndependantExpectedLogs.length; i++) { - if (alternatePlatformIndependantExpectedLogs[i].equals(computedProblemLog)) + if (problemLog.sameAs(alternatePlatformIndependantExpectedLogs[i])) return; // OK } logTestTitle(); @@ -967,6 +969,48 @@ protected static class JavacTestOptions { } } + /** + * Used for performing order-independent log comparisons. + */ + private static final class ProblemLog { + final Set logEntry = new HashSet<>(); + + public ProblemLog(String log) { + String[] entries = log.split("----------\n"); + Pattern pattern = Pattern.compile("\\A(\\d*\\. )"); + + for (String entry : entries) { + Matcher matcher = pattern.matcher(entry); + if (matcher.find()) { + entry = entry.substring(matcher.end()); + } + this.logEntry.add(entry); + } + } + + public boolean sameAs(String toTest) { + ProblemLog log = new ProblemLog(toTest); + return equals(log); + } + + @Override + public int hashCode() { + return this.logEntry.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ProblemLog other = (ProblemLog) obj; + return this.logEntry.equals(other.logEntry); + } + } + protected void dualPrintln(String message) { System.out.println(message); javacFullLog.println(message); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java index cecfb2f02..a7fa3ea2a 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -59,7 +59,7 @@ public class AnnotationTest extends AbstractComparableTest { // Static initializer to specify tests subset using TESTS_* static variables // All specified tests which do not belong to the class are skipped... static { -// TESTS_NAMES = new String[] { "testBug384663" }; +// TESTS_NAMES = new String[] { "testBug506888c" }; // TESTS_NUMBERS = new int[] { 297 }; // TESTS_RANGE = new int[] { 294, -1 }; } @@ -4902,7 +4902,7 @@ public void test143() { public void test153() { Map options = getCompilerOptions(); options.put(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, CompilerOptions.WARNING); - this.runNegativeTest( + this.runConformTest( new String[] { "X.java", "enum E { A, B, C }\n" + @@ -4919,9 +4919,6 @@ public void test143() { " }\n" + "}", }, - "", - null, - true, options ); } @@ -8135,11 +8132,16 @@ public void test245() { "} \n", }, null, options, - "----------\n" + - "1. ERROR in X.java (at line 3)\n" + - " @SuppressWarnings({\"unchecked\",\"unused\"})\n" + - " ^^^^^^^^\n" + - "Unnecessary @SuppressWarnings(\"unused\")\n" + + "----------\n" + + "1. INFO in X.java (at line 3)\n" + + " @SuppressWarnings({\"unchecked\",\"unused\"})\n" + + " ^^^^^^^^^^^\n" + + "At least one of the problems in category \'unchecked\' is not analysed due to a compiler option being ignored\n" + + "----------\n" + + "2. ERROR in X.java (at line 3)\n" + + " @SuppressWarnings({\"unchecked\",\"unused\"})\n" + + " ^^^^^^^^\n" + + "Unnecessary @SuppressWarnings(\"unused\")\n" + "----------\n", JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); } @@ -11683,4 +11685,122 @@ public void testBug470665() throws Exception { this.enableAPT = apt; } } +public void testBug506888a() throws Exception { + if (this.complianceLevel <= ClassFileConstants.JDK1_5) { + return; + } + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, CompilerOptions.IGNORE); + options.put(CompilerOptions.OPTION_ReportMissingDefaultCase, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " \n" + + " @SuppressWarnings({\"incomplete-switch\"})\n" + + " void foo() {\n" + + " }\n" + + "} \n", + }, + "----------\n" + + "1. INFO in X.java (at line 3)\n" + + " @SuppressWarnings({\"incomplete-switch\"})\n" + + " ^^^^^^^^^^^^^^^^^^^\n" + + "At least one of the problems in category \'incomplete-switch\' is not analysed due to a compiler option being ignored\n" + + "----------\n", + null, true, options); +} +public void testBug506888b() throws Exception { + if (this.complianceLevel <= ClassFileConstants.JDK1_5) { + return; + } + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportMissingDefaultCase, CompilerOptions.IGNORE); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " \n" + + " @SuppressWarnings({\"incomplete-switch\"})\n" + + " void foo(Color c) {\n" + + " switch(c) {\n" + + " }\n" + + " }\n" + + " enum Color { BLUE, RED; } \n" + + "} \n", + }, + options); +} +public void testBug506888c() throws Exception { + if (this.complianceLevel <= ClassFileConstants.JDK1_5) { + return; + } + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportMissingDefaultCase, CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportUncheckedTypeOperation, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " \n" + + " @SuppressWarnings({\"incomplete-switch\", \"unchecked\"})\n" + + " void foo(Color c) {\n" + + " switch(c) {\n" + + " }\n" + + " }\n" + + " enum Color { BLUE, RED; } \n" + + "} \n", + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " @SuppressWarnings({\"incomplete-switch\", \"unchecked\"})\n" + + " ^^^^^^^^^^^\n" + + "Unnecessary @SuppressWarnings(\"unchecked\")\n" + + "----------\n", + null, true, options); +} +public void testBug506888d() throws Exception { + if (this.complianceLevel <= ClassFileConstants.JDK1_5) { + return; + } + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.IGNORE); + options.put(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " \n" + + " @SuppressWarnings({\"incomplete-switch\"})\n" + + " void foo() {\n" + + " }\n" + + "} \n", + }, + "", + null, true, options); +} +public void testBug506888e() throws Exception { + if (this.complianceLevel <= ClassFileConstants.JDK1_5) { + return; + } + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.IGNORE); + options.put(CompilerOptions.OPTION_ReportUnusedLabel, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " \n" + + " @SuppressWarnings({\"unused\"})\n" + + " void foo() {}\n" + + "} \n", + }, + "", + null, true, options); +} } 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 e48c9235c..2e44cd42e 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 @@ -14393,6 +14393,27 @@ public void testBug419351() { new File(lib1Path).delete(); } } + +public void test501457() throws IOException { + this.runConformTest(new String[] { + "FailingClass.java", + "import java.lang.invoke.MethodHandle;\n" + + "import java.util.ArrayList;\n" + + "public class FailingClass {\n" + + " protected void test(MethodHandle handle) throws Throwable {\n" + + " handle.invoke(null, new ArrayList<>());\n" + + " }\n" + + "}\n" + }, + " -1.8 " + + " -sourcepath \"" + OUTPUT_DIR + "\" " + + "\"" + OUTPUT_DIR + File.separator + "FailingClass.java", + "", + "", + true + ); +} + // Bug 440477 - [null] Infrastructure for feeding external annotations into compilation // - single external annotation directory public void test440477() throws IOException { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java index 5171ae970..4ba47f95e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java @@ -860,6 +860,7 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("NotVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("NotVisibleType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("NullableFieldReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); + expectedProblemAttributes.put("NullAnnotationAtQualifyingType", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("NullAnnotationUnsupportedLocation", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("NullAnnotationUnsupportedLocationAtType", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("NullExpressionReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); @@ -1004,6 +1005,7 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("TooManyMethods", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("TooManyParametersForSyntheticMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("TooManySyntheticArgumentSlots", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); + expectedProblemAttributes.put("TypeAnnotationAtQualifiedName", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("TypeArgumentMismatch", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("TypeArgumentsForRawGenericConstructor", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("TypeArgumentsForRawGenericMethod", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); @@ -1102,6 +1104,7 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("lambdaSignatureMismatched", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("IllegalArrayOfUnionType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("IllegalArrayTypeInIntersectionCast", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); + expectedProblemAttributes.put("ProblemNotAnalysed", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); //{ObjectTeams: new problems (incomplete list): //expectedProblemAttributes.put("", new ProblemAttributes(CategorizedProblem.CAT_UNSPECIFIED)); expectedProblemAttributes.put("OTJ_RELATED", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); @@ -1781,6 +1784,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("NotVisibleMethod", SKIP); expectedProblemAttributes.put("NotVisibleType", SKIP); expectedProblemAttributes.put("NullableFieldReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE)); + expectedProblemAttributes.put("NullAnnotationAtQualifyingType", SKIP); expectedProblemAttributes.put("NullAnnotationUnsupportedLocation", SKIP); expectedProblemAttributes.put("NullAnnotationUnsupportedLocationAtType", SKIP); expectedProblemAttributes.put("NullityMismatchAgainstFreeTypeVariable", new ProblemAttributes(JavaCore.COMPILER_PB_PESSIMISTIC_NULL_ANALYSIS_FOR_FREE_TYPE_VARIABLES)); @@ -1925,6 +1929,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("TooManyMethods", SKIP); expectedProblemAttributes.put("TooManyParametersForSyntheticMethod", SKIP); expectedProblemAttributes.put("TooManySyntheticArgumentSlots", SKIP); + expectedProblemAttributes.put("TypeAnnotationAtQualifiedName", SKIP); expectedProblemAttributes.put("TypeArgumentMismatch", SKIP); expectedProblemAttributes.put("TypeArgumentsForRawGenericConstructor", SKIP); expectedProblemAttributes.put("TypeArgumentsForRawGenericMethod", SKIP); @@ -2024,6 +2029,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("DisallowedExplicitThisParameter", SKIP); expectedProblemAttributes.put("IllegalArrayOfUnionType", SKIP); expectedProblemAttributes.put("IllegalArrayTypeInIntersectionCast", SKIP); + expectedProblemAttributes.put("ProblemNotAnalysed", SKIP); //{ObjectTeams: new constants: expectedProblemAttributes.put("OTJ_RELATED", SKIP); expectedProblemAttributes.put("OTCHAP", SKIP); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ExpressionContextTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ExpressionContextTests.java index 6392ec83c..71484d010 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ExpressionContextTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ExpressionContextTests.java @@ -241,16 +241,21 @@ public void test008() { "1. ERROR in X.java (at line 10)\n" + " Object p = (@Marker java.lang. @Readonly String & I & J) () -> {};\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in X.java (at line 10)\n" + " Object p = (@Marker java.lang. @Readonly String & I & J) () -> {};\n" + + " ^^^^^^\n" + + "Marker cannot be resolved to a type\n" + + "----------\n" + + "3. ERROR in X.java (at line 10)\n" + + " Object p = (@Marker java.lang. @Readonly String & I & J) () -> {};\n" + " ^^^^^^^^\n" + "Readonly cannot be resolved to a type\n" + "----------\n" + - "3. ERROR in X.java (at line 10)\n" + + "4. ERROR in X.java (at line 10)\n" + " Object p = (@Marker java.lang. @Readonly String & I & J) () -> {};\n" + - " ^^^^^\n" + + " ^^^^^\n" + "The target type of this expression must be a functional interface\n" + "----------\n"); } 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 5b965903c..8e25ab964 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 @@ -7309,4 +7309,60 @@ public void testBug499725() { "}\n" }); } +public void testBug499725a() { + runConformTest( + new String[] { + "Try22.java", + "import java.rmi.RemoteException;\n" + + "import java.util.Arrays;\n" + + "import java.util.Collection;\n" + + "import java.util.Collections;\n" + + "import java.util.List;\n" + + "import java.util.function.Function;\n" + + "import java.util.stream.Collectors;\n" + + "\n" + + "\n" + + "public class Try22 {\n" + + " public static class RemoteExceptionWrapper {\n" + + " @FunctionalInterface\n" + + " public static interface FunctionRemote {\n" + + " R apply(T t) throws RemoteException;\n" + + " }\n" + + " \n" + + " public static Function wrapFunction(FunctionRemote f) {\n" + + " return x -> {\n" + + " try {\n" + + " return f.apply(x);\n" + + " }\n" + + " catch(RemoteException e) {\n" + + " throw new RuntimeException(e);\n" + + " }\n" + + " };\n" + + " }\n" + + " }\n" + + "\n" + + "\n" + + " private static class ThrowingThingy {\n" + + " public Collection listStuff(String in) throws RemoteException {\n" + + " return Collections.emptyList();\n" + + " }\n" + + " }\n" + + "\n" + + " \n" + + " public static void main(String[] args) {\n" + + " List stagedNodes = Arrays.asList(\"a\", \"b\", \"c\");\n" + + " ThrowingThingy remoteThing = new ThrowingThingy(); // simulation of a rmi remote, hence the exceptio\n" + + " \n" + + " List resultingStuff = stagedNodes.stream()\n" + + " .flatMap(RemoteExceptionWrapper.wrapFunction(\n" + + " (String node) -> remoteThing.listStuff(node) // HERE\n" + + " .stream()\n" + + " .map(sub -> node + \"/\" + sub)))\n" + + " .collect(Collectors.toList());\n" + + " \n" + + " System.out.println(resultingStuff);\n" + + " }\n" + + "}\n" + }); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java index aaeded828..38199bdae 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java @@ -1565,64 +1565,74 @@ public class GrammarCoverageTests308 extends AbstractRegressionTest { "4. ERROR in X.java (at line 4)\n" + " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "5. ERROR in X.java (at line 4)\n" + " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" + + " ^^^^^^\n" + + "Marker cannot be resolved to a type\n" + + "----------\n" + + "6. ERROR in X.java (at line 4)\n" + + " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" + " ^^^^^^^\n" + "Syntax error, type annotations are illegal here\n" + "----------\n" + - "6. ERROR in X.java (at line 4)\n" + + "7. ERROR in X.java (at line 4)\n" + " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "7. ERROR in X.java (at line 4)\n" + + "8. ERROR in X.java (at line 4)\n" + " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "8. ERROR in X.java (at line 5)\n" + + "9. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + - "9. ERROR in X.java (at line 5)\n" + + "10. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "The member type Map.Entry cannot be qualified with a parameterized type, since it is static. Remove arguments from qualifying type Map\n" + "----------\n" + - "10. ERROR in X.java (at line 5)\n" + + "11. ERROR in X.java (at line 5)\n" + + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + + " ^^^^^^\n" + + "Marker cannot be resolved to a type\n" + + "----------\n" + + "12. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^^\n" + "Syntax error, type annotations are illegal here\n" + "----------\n" + - "11. ERROR in X.java (at line 5)\n" + - " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + - " ^^^^^^^\n" + - "Type annotations are not allowed on type names used to access static members\n" + + "13. ERROR in X.java (at line 5)\n" + + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + + " ^^^^^^^\n" + + "Type annotations are not allowed on type names used to access static members\n" + "----------\n" + - "12. ERROR in X.java (at line 5)\n" + + "14. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "13. ERROR in X.java (at line 5)\n" + + "15. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "14. ERROR in X.java (at line 5)\n" + + "16. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "15. ERROR in X.java (at line 5)\n" + + "17. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + "----------\n" + - "16. ERROR in X.java (at line 5)\n" + + "18. ERROR in X.java (at line 5)\n" + " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" + " ^^^^^^\n" + "Marker cannot be resolved to a type\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java index 01503f4ff..84297888f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR308SpecSnippetTests.java @@ -1402,7 +1402,7 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { "1. ERROR in X.java (at line 13)\n" + " @TAnno java.lang.Object field8; // illegal\n" + " ^^^^^^\n" + - "The annotation @TAnno is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in X.java (at line 15)\n" + " java.lang. @FAnno Object field10; // illegal\n" + @@ -1417,7 +1417,7 @@ public class JSR308SpecSnippetTests extends AbstractRegressionTest { "4. ERROR in X.java (at line 25)\n" + " @TAnno java.lang.Object myMethod8() { } // illegal\n" + " ^^^^^^\n" + - "The annotation @TAnno is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "5. ERROR in X.java (at line 27)\n" + " java.lang. @MAnno Object myMethod10() { } // illegal\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java index 69bda64da..f156721fa 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java @@ -6339,6 +6339,38 @@ public void testBug502871() { "----------\n" ); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=490469 Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.analyseCode(LambdaExpression.java:512) +public void testBUg490469() { + this.runConformTest( + new String[] { + "AbstractClientProxy.java", + "import java.util.function.Supplier;\n" + + "public abstract class AbstractClientProxy {\n" + + " protected T getRemoteObject(String url, Class responseType, Object... urlVariables) {\n" + + " return handleException(this.bindGet(REST::getForObject, url, responseType, urlVariables));\n" + + " }\n" + + " private T handleException(Supplier s){\n" + + " T t = null;\n" + + " try{\n" + + " t= s.get();\n" + + " }catch(Exception e){\n" + + " }\n" + + " return t;\n" + + " }\n" + + " private Supplier bindGet(GetFunc fn, String url, Class responseType, Object... uriVariables) {\n" + + " return () -> fn.invoke(url, responseType, uriVariables);\n" + + " }\n" + + "}\n" + + "class REST {\n" + + " static T getForObject(String url, Class respType, Object... vars) {\n" + + " return null;\n" + + " }\n" + + "}\n" + + "interface GetFunc {\n" + + " T invoke(String url, Class responseType, Object... uriVariables);\n" + + "}\n" + }); +} public static Class testClass() { return LambdaExpressionsTest.class; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java index c212f51ad..4910611a9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java @@ -2408,7 +2408,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "1. ERROR in X.java (at line 4)\n" + " Object o1 = (@Marker java.lang.Integer) null; // 1. Right.\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " Object o2 = (java. @Marker lang.Integer) null; // 2. Wrong.\n" + @@ -2423,7 +2423,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "4. ERROR in X.java (at line 9)\n" + " public void foobar(@Marker java.lang.Integer arg) {}\n" + " ^^^^^^^\n" + - "The annotation @Marker is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n"); } public void test0390882a() { @@ -2505,18 +2505,28 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "----------\n" + "1. ERROR in X.java (at line 4)\n" + " Object o1 = (@Marker @Annot java.util.List) null; // 1. Wrong.\n" + - " ^^^^^^^^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + " ^^^^^^^\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + - "2. ERROR in X.java (at line 5)\n" + + "2. ERROR in X.java (at line 4)\n" + + " Object o1 = (@Marker @Annot java.util.List) null; // 1. Wrong.\n" + + " ^^^^^^\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + + "----------\n" + + "3. ERROR in X.java (at line 5)\n" + " Object o2 = (java. @Marker @Annot lang.Integer[]) null; // 2. Wrong.\n" + " ^^^^^^^^^^^^^^\n" + "Syntax error, type annotations are illegal here\n" + "----------\n" + - "3. ERROR in X.java (at line 6)\n" + + "4. ERROR in X.java (at line 6)\n" + " Object o3 = (@Marker @Annot java.util.List[]) null; // 3. Wrong.\n" + - " ^^^^^^^^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + " ^^^^^^^\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + + "----------\n" + + "5. ERROR in X.java (at line 6)\n" + + " Object o3 = (@Marker @Annot java.util.List[]) null; // 3. Wrong.\n" + + " ^^^^^^\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385137 @@ -2574,7 +2584,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "4. ERROR in A.java (at line 7)\n" + " Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "5. WARNING in A.java (at line 7)\n" + " Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" + @@ -2633,7 +2643,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "1. ERROR in A.java (at line 6)\n" + " Object o1 = (@Marker p.@Marker A.@Marker B.@Marker C[]) null;\n" + " ^^^^^^^\n" + - "Syntax error, type annotations are illegal here\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in A.java (at line 6)\n" + " Object o1 = (@Marker p.@Marker A.@Marker B.@Marker C[]) null;\n" + @@ -3389,12 +3399,12 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "1. ERROR in p\\X.java (at line 6)\n" + " @A @B p.X.Y field4;\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in p\\X.java (at line 7)\n" + " @B(1) @A(1) java.lang.@A(1) @B(1) String field2;\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "3. ERROR in p\\X.java (at line 7)\n" + " @B(1) @A(1) java.lang.@A(1) @B(1) String field2;\n" + @@ -3404,7 +3414,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "4. ERROR in p\\X.java (at line 8)\n" + " public @B(1) @A(1) java.lang. @A(1) @B(1) String foo(@A(1) @B(1) java.lang. @A(1) @B(1) String str1) {\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "5. ERROR in p\\X.java (at line 8)\n" + " public @B(1) @A(1) java.lang. @A(1) @B(1) String foo(@A(1) @B(1) java.lang. @A(1) @B(1) String str1) {\n" + @@ -3414,7 +3424,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "6. ERROR in p\\X.java (at line 8)\n" + " public @B(1) @A(1) java.lang. @A(1) @B(1) String foo(@A(1) @B(1) java.lang. @A(1) @B(1) String str1) {\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "7. ERROR in p\\X.java (at line 8)\n" + " public @B(1) @A(1) java.lang. @A(1) @B(1) String foo(@A(1) @B(1) java.lang. @A(1) @B(1) String str1) {\n" + @@ -3424,7 +3434,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "8. ERROR in p\\X.java (at line 10)\n" + " @A(1) @B(1) java.lang. @B(1) @A(1) String local2;\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "9. ERROR in p\\X.java (at line 10)\n" + " @A(1) @B(1) java.lang. @B(1) @A(1) String local2;\n" + @@ -3434,7 +3444,7 @@ public class NegativeTypeAnnotationTest extends AbstractRegressionTest { "10. ERROR in p\\X.java (at line 12)\n" + " @B @A p.X.Y local4;\n" + " ^^\n" + - "The annotation @B is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "11. ERROR in p\\X.java (at line 13)\n" + " @B @A p.q.X local5;\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java index 2ef578a0b..1a835b6cc 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java @@ -6940,17 +6940,17 @@ public void testTypeAnnotationProblemNotIn17() { "1. ERROR in X.java (at line 3)\n" + " public @NonNull java.lang.String test(@NonNull java.lang.String arg) {\n" + " ^^^^^^^^\n" + - "The annotation @NonNull is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "2. ERROR in X.java (at line 3)\n" + " public @NonNull java.lang.String test(@NonNull java.lang.String arg) {\n" + " ^^^^^^^^\n" + - "The annotation @NonNull is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n" + "3. ERROR in X.java (at line 4)\n" + " @NonNull java.lang.String local = arg;\n" + " ^^^^^^^^\n" + - "The annotation @NonNull is disallowed for this location\n" + + "Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)\n" + "----------\n"); } public void testBug420313() { @@ -8974,4 +8974,64 @@ public void testBug502113b() { "----------\n" ); } +public void testBug502214() { + runNegativeTestWithLibs( + new String[] { + "test/X.java", + "package test;\n" + + "\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "import org.eclipse.jdt.annotation.Nullable;\n" + + "\n" + + "class A {\n" + + " public boolean m1(Object obj) {\n" + + " return this == obj;\n" + + " }\n" + + " public @Nullable String m2() {\n" + + " return null;\n" + + " }\n" + + "}\n" + + "\n" + + "interface I {\n" + + " public boolean m1(@Nullable Object obj);\n" + + " public @NonNull String m2(); \n" + + "}\n" + + "\n" + + "public class X {\n" + + " I f() {\n" + + " class Y extends A implements I {\n" + + " }\n" + + " return new Y();\n" + + " }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + (this.complianceLevel < ClassFileConstants.JDK1_8 ? + "----------\n" + + "1. ERROR in test\\X.java (at line 22)\n" + + " class Y extends A implements I {\n" + + " ^\n" + + "The method m2() from A cannot implement the corresponding method from I due to incompatible nullness constraints\n" + + "----------\n" + + "2. ERROR in test\\X.java (at line 22)\n" + + " class Y extends A implements I {\n" + + " ^\n" + + "The method m1(Object) from A cannot implement the corresponding method from I due to incompatible nullness constraints\n" + + "----------\n" + : + "----------\n" + + "1. ERROR in test\\X.java (at line 22)\n" + + " class Y extends A implements I {\n" + + " ^\n" + + "The method @Nullable String m2() from A cannot implement the corresponding method from I due to incompatible nullness constraints\n" + + "----------\n" + + "2. ERROR in test\\X.java (at line 22)\n" + + " class Y extends A implements I {\n" + + " ^\n" + + "The method m1(Object) from A cannot implement the corresponding method from I due to incompatible nullness constraints\n" + + "----------\n" + ) + ); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java index aac500093..d43b03721 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java @@ -2189,22 +2189,22 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "1. ERROR in X.java (at line 4)\n" + " @NonNull X.Inner f;\n" + " ^^^^^^^^\n" + - "The nullness annotation \'NonNull\' is not applicable at this location\n" + + "The nullness annotation \'NonNull\' is not applicable at this location, it must be placed directly before the nested type name.\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " @NonNull X.Inner foo(@NonNull X.Inner arg) {\n" + " ^^^^^^^^\n" + - "The nullness annotation \'NonNull\' is not applicable at this location\n" + + "The nullness annotation \'NonNull\' is not applicable at this location, it must be placed directly before the nested type name.\n" + "----------\n" + "3. ERROR in X.java (at line 5)\n" + " @NonNull X.Inner foo(@NonNull X.Inner arg) {\n" + " ^^^^^^^^\n" + - "The nullness annotation \'NonNull\' is not applicable at this location\n" + + "The nullness annotation \'NonNull\' is not applicable at this location, it must be placed directly before the nested type name.\n" + "----------\n" + "4. ERROR in X.java (at line 6)\n" + " @NonNull X.Inner local = arg;\n" + " ^^^^^^^^\n" + - "The nullness annotation \'NonNull\' is not applicable at this location\n" + + "The nullness annotation \'NonNull\' is not applicable at this location, it must be placed directly before the nested type name.\n" + "----------\n"); } @@ -13161,4 +13161,201 @@ public void testBug502112b() { "----------\n" ); } +public void testBug500885() { + runConformTest( + new String[] { + "annot/NonNull.java", + "package annot;\n" + + "@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" + + "public @interface NonNull {}\n", + "annot/NonNullByDefault.java", + "package annot;\n" + + "@annot.NonNull\n" + + "@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" + + "public @interface NonNullByDefault {}\n", + "annot/package-info.java", + "@annot.NonNullByDefault package annot;\n", + "test/package-info.java", + "@annot.NonNullByDefault package test;\n", + "test/X.java", + "package test;\n" + + "public interface X {\n" + + " public String get();\n" + + "}\n" + }, + getCompilerOptions(), + ""); + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES, "annot.NonNullByDefault"); + options.put(JavaCore.COMPILER_NONNULL_ANNOTATION_SECONDARY_NAMES, "annot.NonNull"); + runConformTestWithLibs( + new String[] { + "test2/package-info.java", + "@org.eclipse.jdt.annotation.NonNullByDefault package test2;\n", + "test2/Y.java", + "package test2;\n" + + "import test.X;\n" + + "public class Y implements X {\n" + + " public String get() {\n" + + " return \"\";\n" + + " }\n" + + "}\n" + }, + options, + ""); +} +public void testBug505671() { + runConformTestWithLibs( + new String[] { + "snippet/Pair.java", + "package snippet;\n" + + "\n" + + "import org.eclipse.jdt.annotation.NonNullByDefault;\n" + + "\n" + + "@NonNullByDefault\n" + + "public class Pair {\n" + + " public static S make(S left, T right, Object x) {\n" + + " throw new RuntimeException();\n" + + " }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + "" + ); + runNegativeTestWithLibs( + new String[] { + "snippet/Snippet.java", + "package snippet;\n" + + "\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "\n" + + "public class Snippet {\n" + + " public static final @NonNull Object FALSE = new Object();\n" + + "\n" + + " public static @NonNull Object abbreviateExplained0() {\n" + + " return Pair.make(null, FALSE, null);\n" + + " }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + "----------\n" + + "1. WARNING in snippet\\Snippet.java (at line 9)\n" + + " return Pair.make(null, FALSE, null);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'@NonNull Object\'\n" + + "----------\n" + + "2. ERROR in snippet\\Snippet.java (at line 9)\n" + + " return Pair.make(null, FALSE, null);\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + ); +} +public void testBug501564() { + runNegativeTestWithLibs( + new String[] { + "xxx/Foo.java", + "package xxx;\n" + + "import org.eclipse.jdt.annotation.NonNullByDefault;\n" + + "import org.eclipse.jdt.annotation.DefaultLocation;\n" + + "\n" + + "class Generic> { \n" + + "}\n" + + "class Foo { \n" + + " static > Bar foo() {\n" + + " return new Bar<>();\n" + + " }\n" + + "\n" + + " @NonNullByDefault(DefaultLocation.TYPE_PARAMETER)\n" + + " static class Bar> { }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + "----------\n" + + "1. ERROR in xxx\\Foo.java (at line 8)\n" + + " static > Bar foo() {\n" + + " ^^\n" + + "Null constraint mismatch: The type \'E2 extends Generic\' is not a valid substitute for the type parameter \'@NonNull E3 extends Generic>\'\n" + + "----------\n" + ); +} +public void testBug501564interface() { + runNegativeTestWithLibs( + new String[] { + "xxx/Foo.java", + "package xxx;\n" + + "import org.eclipse.jdt.annotation.NonNullByDefault;\n" + + "import org.eclipse.jdt.annotation.DefaultLocation;\n" + + "\n" + + "interface Generic> { \n" + + "}\n" + + "class Foo { \n" + + " static > Bar foo() {\n" + + " return new Bar<>();\n" + + " }\n" + + "\n" + + " @NonNullByDefault(DefaultLocation.TYPE_PARAMETER)\n" + + " static class Bar> { }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + "----------\n" + + "1. ERROR in xxx\\Foo.java (at line 8)\n" + + " static > Bar foo() {\n" + + " ^^\n" + + "Null constraint mismatch: The type \'E2 extends Generic\' is not a valid substitute for the type parameter \'@NonNull E3 extends Generic>\'\n" + + "----------\n" + ); +} +public void testBug501464() { + runNegativeTestWithLibs( + new String[] { + "Foo.java", + "import org.eclipse.jdt.annotation.*;\n" + + "\n" + + "interface MyList { @NonNull T getAny(); }\n" + + "\n" + + "@NonNullByDefault({})\n" + + "class Foo {\n" + + " @Nullable Object b;\n" + + " \n" + + " void foo() {\n" + + " @Nullable Object f = b;\n" + + " ((@NonNull Object)f).hashCode(); // Error (unexpected): Potential null pointer access: this expression has a '@Nullable' type\n" + + " }\n" + + " \n" + + " void workaround() {\n" + + " @Nullable Object f = b;\n" + + " @NonNull Object g = (@NonNull Object)f; // Warning (expected): Null type safety: Unchecked cast from @Nullable Object to @NonNull Object\n" + + " g.hashCode();\n" + + " }\n" + + " String three(@NonNull MyList<@Nullable String> list) {\n" + + " return ((@NonNull MyList<@NonNull String>) list).getAny().toUpperCase();\n" + + " }\n" + + "}\n" + + "", + }, + getCompilerOptions(), + "----------\n" + + "1. WARNING in Foo.java (at line 11)\n" + + " ((@NonNull Object)f).hashCode(); // Error (unexpected): Potential null pointer access: this expression has a \'@Nullable\' type\n" + + " ^^^^^^^^^^^^^^^^^^^^\n" + + "Null type safety: Unchecked cast from @Nullable Object to @NonNull Object\n" + + "----------\n" + + "2. WARNING in Foo.java (at line 16)\n" + + " @NonNull Object g = (@NonNull Object)f; // Warning (expected): Null type safety: Unchecked cast from @Nullable Object to @NonNull Object\n" + + " ^^^^^^^^^^^^^^^^^^\n" + + "Null type safety: Unchecked cast from @Nullable Object to @NonNull Object\n" + + "----------\n" + + "3. WARNING in Foo.java (at line 20)\n" + + " return ((@NonNull MyList<@NonNull String>) list).getAny().toUpperCase();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Null type safety: Unchecked cast from @NonNull MyList<@Nullable String> to @NonNull MyList<@NonNull String>\n" + + "----------\n" + ); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java index 30541d602..269fc338f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java @@ -2199,6 +2199,33 @@ public class SerializableLambdaTest extends AbstractRegressionTest { null,true, new String[]{"-Ddummy"}); } + public void testbug507011() { + this.runConformTest( + new String[]{ + "VerifyErrorDerived.java", + "import java.io.Serializable;\n" + + "import java.util.function.Function;\n" + + "public class VerifyErrorDerived extends VerifyErrorBase {\n" + + " public static void main(String [] args) {\n" + + " System.out.println(\"hello world\");\n" + + " }\n" + + " public int derivedMethod(String param) {\n" + + " SerializableFunction f = super::baseMethod;\n" + + " return f.apply(param);\n" + + " }\n" + + "}\n" + + "interface SerializableFunction extends Function, Serializable {}", + "VerifyErrorBase.java", + "public class VerifyErrorBase {\n" + + " public int baseMethod(String param) {\n" + + " return 7;\n" + + " }\n" + + "}\n" + }, + "hello world", + null,true, + new String[]{"-Ddummy"}); + } // --- private void checkExpected(String expected, String actual) { 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 2659d9960..74db7db79 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 @@ -13,6 +13,7 @@ package org.eclipse.jdt.core.tests.model; import java.io.*; import java.net.URL; import java.util.*; +import java.util.stream.*; import junit.framework.Test; import junit.framework.TestSuite; @@ -369,8 +370,12 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { protected void assertSearchResults(String message, String expected, Object collector) { assertSearchResults(message, expected, collector, true /* assertion */); } - protected void assertSearchResults(String message, String expected, Object collector, boolean assertion) { - String actual = collector.toString(); + private static String sortLines(String toSplit) { + return Arrays.stream(toSplit.split("\n")).sorted().collect(Collectors.joining("\n")); + } + protected void assertSearchResults(String message, String expectedString, Object collector, boolean assertion) { + String expected = sortLines(expectedString); + String actual = sortLines(collector.toString()); if (!expected.equals(actual)) { if (this.displayName) System.out.println(getName()+" actual result is:"); System.out.print(displayString(actual, this.tabs)); @@ -660,6 +665,9 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { assertElementsEqual(message, expected, elements, false/*don't show key*/); } protected void assertElementsEqual(String message, String expected, IJavaElement[] elements, boolean showResolvedInfo) { + assertElementsEqual(message, expected, elements, showResolvedInfo, false); + } + protected void assertElementsEqual(String message, String expected, IJavaElement[] elements, boolean showResolvedInfo, boolean sorted) { StringBuffer buffer = new StringBuffer(); if (elements != null) { for (int i = 0, length = elements.length; i < length; i++){ @@ -675,6 +683,9 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases { buffer.append(""); } String actual = buffer.toString(); + if (sorted) { + actual = sortLines(actual); + } if (!expected.equals(actual)) { if (this.displayName) System.out.println(getName()+" actual result is:"); System.out.println(displayString(actual, this.tabs) + this.endChar); diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavadocMethodCompletionModelTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavadocMethodCompletionModelTest.java index eeae0e816..198ec49a6 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavadocMethodCompletionModelTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavadocMethodCompletionModelTest.java @@ -338,7 +338,7 @@ public void test015() throws JavaModelException { " }\n" + "}\n"; completeInJavadoc("/Completion/src/javadoc/methods/tags/BasicTestMethods.java", source, true, "I"); - assertResults( + assertSortedResults( "IllegalMonitorStateException[TYPE_REF]{IllegalMonitorStateException, java.lang, Ljava.lang.IllegalMonitorStateException;, null, null, "+this.positions+R_DRICUNRE+"}\n" + "InterruptedException[TYPE_REF]{InterruptedException, java.lang, Ljava.lang.InterruptedException;, null, null, "+this.positions+R_DRICUNRE+"}" ); @@ -357,9 +357,9 @@ public void test016() throws JavaModelException { " }\n" + "}\n"; completeInJavadoc("/Completion/src/javadoc/methods/tags/BasicTestMethods.java", source, true, "java.lang.I"); - assertResults( - "IllegalMonitorStateException[TYPE_REF]{IllegalMonitorStateException, java.lang, Ljava.lang.IllegalMonitorStateException;, null, null, "+this.positions+R_DRICNRE+"}\n" + - "InterruptedException[TYPE_REF]{InterruptedException, java.lang, Ljava.lang.InterruptedException;, null, null, "+this.positions+R_DRICNREEET+"}" + assertSortedResults( + "InterruptedException[TYPE_REF]{InterruptedException, java.lang, Ljava.lang.InterruptedException;, null, null, "+this.positions+R_DRICNREEET+"}\n" + + "IllegalMonitorStateException[TYPE_REF]{IllegalMonitorStateException, java.lang, Ljava.lang.IllegalMonitorStateException;, null, null, "+this.positions+R_DRICNRE+"}" ); } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests2.java index fc42448c2..0c82ecdee 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests2.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests2.java @@ -926,7 +926,9 @@ public void testBug232880i() throws Exception { "Unexpected elements", "IResource [in IResource.class [in test1 [in "+outputDirectory+File.separator+"bug232880a.jar]]]\n" + "IResource [in IResource.class [in test2 [in "+outputDirectory+File.separator+"bug232880a.jar]]]", - elements + elements, + false, + true ); } finally { this.deleteExternalFile(externalJar1); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java index e62e8e210..40c728273 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,9 +9,12 @@ * IBM Corporation - initial API and implementation * Luiz-Otavio Zorzella - Improve CamelCase algorithm * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions + * Stefan Xenos (Google) - Bug 501283 - Lots of hash collisions during indexing *******************************************************************************/ package org.eclipse.jdt.core.compiler; +import java.util.Arrays; + import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; /** @@ -2281,19 +2284,9 @@ public static final boolean fragmentEquals( * * @param array the array for which a hashcode is required * @return the hashcode - * @throws NullPointerException if array is null */ public static final int hashCode(char[] array) { - int length = array.length; - int hash = length == 0 ? 31 : array[0]; - if (length < 8) { - for (int i = length; --i > 0;) - hash = (hash * 31) + array[i]; - } else { - // 8 characters is enough to compute a decent hash code, don't waste time examining every character - for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2) - hash = (hash * 31) + array[i]; - } + int hash = Arrays.hashCode(array); return hash & 0x7FFFFFFF; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 96ac0a2e3..fa8ee852a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -1873,6 +1873,12 @@ void setSourceStart(int sourceStart); int IllegalDefaultModifierSpecification = MethodRelated + 1058; /** @since 3.13 */ int CannotInferInvocationType = TypeRelated + 1059; + + /** @since 3.13 */ + int TypeAnnotationAtQualifiedName = Internal + Syntax + 1060; + + /** @since 3.13 */ + int NullAnnotationAtQualifyingType = Internal + Syntax + 1061; /** @since 3.10 */ int GenericInferenceError = 1100; // FIXME: This is just a stop-gap measure, be more specific via https://bugs.eclipse.org/404675 @@ -1880,6 +1886,8 @@ void setSourceStart(int sourceStart); /** @deprecated - problem is no longer generated (implementation issue has been resolved) * @since 3.10 */ int LambdaShapeComputationError = 1101; + /** @since 3.13 */ + int ProblemNotAnalysed = 1102; //{ObjectTeams: int OTJ_RELATED = 1000000; 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 80e2e1b9c..9fc88ae55 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 @@ -750,8 +750,11 @@ public abstract class ASTNode implements TypeConstants, TypeIds { } else { updatedArgumentType = argument.resolveType(scope); } - if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE) + if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE) { argumentTypes[i] = updatedArgumentType; + if (candidateMethod.isPolymorphic()) + candidateMethod.parameters[i] = updatedArgumentType; + } } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java index 828fa15f1..dfb613a58 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java @@ -654,7 +654,7 @@ public abstract class Annotation extends Expression { // no need to check annotation usage if missing return; } - if (! isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind())) { + if (isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind()) != AnnotationTargetAllowed.YES) { scope.problemReporter().disallowedTargetForContainerAnnotation(repeatingAnnotation, containerAnnotationType); } } @@ -987,75 +987,83 @@ public abstract class Annotation extends Expression { return this.resolvedType; } - private static boolean isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) { + public enum AnnotationTargetAllowed { + YES, TYPE_ANNOTATION_ON_QUALIFIED_NAME, NO; + } + + private static AnnotationTargetAllowed isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) { switch (kind) { case Binding.PACKAGE : if ((metaTagBits & TagBits.AnnotationForPackage) != 0) - return true; + return AnnotationTargetAllowed.YES; else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) { SourceTypeBinding sourceType = (SourceTypeBinding) recipient; if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME)) - return true; + return AnnotationTargetAllowed.YES; } break; case Binding.TYPE_USE : if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { // jsr 308 - return true; + return AnnotationTargetAllowed.YES; } if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { // already reported as syntax error; don't report secondary problems - return true; + return AnnotationTargetAllowed.YES; } break; case Binding.TYPE : case Binding.GENERIC_TYPE : if (((ReferenceBinding)recipient).isAnnotationType()) { if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) { - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) { if (CharOperation.equals(((ReferenceBinding) recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) - return true; + return AnnotationTargetAllowed.YES; } //{ObjectTeams: allow @Override for roles: if ( (((ReferenceBinding)recipient).isRole()) && (annotationType.id == TypeIds.T_JavaLangOverride)) - return true; + return AnnotationTargetAllowed.YES; //SH} break; //{ObjectTeams: method mappings // TODO(SH): should annotations for method mappings be controlled separately? case Binding.BINDING : if ((metaTagBits & TagBits.AnnotationForMethod) != 0) - return true; + return AnnotationTargetAllowed.YES; break; //SH} case Binding.METHOD : MethodBinding methodBinding = (MethodBinding) recipient; if (methodBinding.isConstructor()) { if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0) - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) { - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass; MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding); if (isTypeUseCompatible(methodDecl.returnType, scope)) { - return true; + return AnnotationTargetAllowed.YES; + } else { + return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; } } break; case Binding.FIELD : if ((metaTagBits & TagBits.AnnotationForField) != 0) { - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { FieldBinding sourceField = (FieldBinding) recipient; SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass; FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); if (isTypeUseCompatible(fieldDeclaration.type, scope)) { - return true; + return AnnotationTargetAllowed.YES; + } else { + return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; } } break; @@ -1063,27 +1071,31 @@ public abstract class Annotation extends Expression { LocalVariableBinding localVariableBinding = (LocalVariableBinding) recipient; if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) { if ((metaTagBits & TagBits.AnnotationForParameter) != 0) { - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - return true; + return AnnotationTargetAllowed.YES; + } else { + return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; } } } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) { - return true; + return AnnotationTargetAllowed.YES; } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - return true; + return AnnotationTargetAllowed.YES; + } else { + return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; } } break; case Binding.TYPE_PARAMETER : // jsr308 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196 if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) { - return true; + return AnnotationTargetAllowed.YES; } } - return false; + return AnnotationTargetAllowed.NO; } public static boolean isAnnotationTargetAllowed(BlockScope scope, TypeBinding annotationType, Binding recipient) { @@ -1091,10 +1103,10 @@ public abstract class Annotation extends Expression { if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { return true; } - return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits); + return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits)==AnnotationTargetAllowed.YES; } - static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { + static AnnotationTargetAllowed isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { @@ -1102,7 +1114,7 @@ public abstract class Annotation extends Expression { if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) { scope.problemReporter().explitAnnotationTargetRequired(annotation); } - return true; + return AnnotationTargetAllowed.YES; } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 @@ -1129,8 +1141,13 @@ public abstract class Annotation extends Expression { // no need to check annotation usage if missing return; } - if (! isAnnotationTargetAllowed(annotation, scope, annotationType, kind)) { + AnnotationTargetAllowed annotationTargetAllowed = isAnnotationTargetAllowed(annotation, scope, annotationType, kind); + if (annotationTargetAllowed != AnnotationTargetAllowed.YES) { + if(annotationTargetAllowed == AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME) { + scope.problemReporter().typeAnnotationAtQualifiedName(annotation); + } else { scope.problemReporter().disallowedTargetForAnnotation(annotation); + } if (recipient instanceof TypeBinding) ((TypeBinding)recipient).tagBits &= ~tagBitsToRevert; } @@ -1199,7 +1216,7 @@ public abstract class Annotation extends Expression { continue nextAnnotation; } else { if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) { - scope.problemReporter().nullAnnotationUnsupportedLocation(annotation); + scope.problemReporter().nullAnnotationAtQualifyingType(annotation); continue nextAnnotation; } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java index 13f06d9e1..bf50c2a28 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -360,6 +360,9 @@ public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int } public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { + if((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) { + return true; + } checkNPEbyUnboxing(scope, flowContext, flowInfo); return this.expression.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java index 98e3208cb..04287d411 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java @@ -376,22 +376,28 @@ public void finalizeProblems() { Constant cst = inits[iToken].constant; if (cst != Constant.NotAConstant && cst.typeID() == TypeIds.T_JavaLangString) { IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (tokenIrritants != null - && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") - && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled - && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem - if (unusedWarningTokenIsWarning) { - int start = value.sourceStart, end = value.sourceEnd; - nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { - long position = this.suppressWarningScopePositions[jSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? + if (tokenIrritants != null) { + if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") + && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem + if (unusedWarningTokenIsWarning) { + int start = value.sourceStart, end = value.sourceEnd; + nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { + long position = this.suppressWarningScopePositions[jSuppress]; + int startSuppress = (int) (position >>> 32); + int endSuppress = (int) position; + if (start < startSuppress) continue nextSuppress; + if (end > endSuppress) continue nextSuppress; + if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? + } + } + int id = options.getIgnoredIrritant(tokenIrritants); + if (id > 0) { + String key = CompilerOptions.optionKeyFromIrritant(id); + this.scope.problemReporter().problemNotAnalysed(inits[iToken], key); + } else { + this.scope.problemReporter().unusedWarningToken(inits[iToken]); } } - this.scope.problemReporter().unusedWarningToken(inits[iToken]); } } } @@ -400,22 +406,28 @@ public void finalizeProblems() { Constant cst = value.constant; if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) { IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (tokenIrritants != null - && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") - && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled - && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem - if (unusedWarningTokenIsWarning) { - int start = value.sourceStart, end = value.sourceEnd; - nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { - long position = this.suppressWarningScopePositions[jSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? + if (tokenIrritants != null) { + if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") + && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem + if (unusedWarningTokenIsWarning) { + int start = value.sourceStart, end = value.sourceEnd; + nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { + long position = this.suppressWarningScopePositions[jSuppress]; + int startSuppress = (int) (position >>> 32); + int endSuppress = (int) position; + if (start < startSuppress) continue nextSuppress; + if (end > endSuppress) continue nextSuppress; + if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? + } + } + int id = options.getIgnoredIrritant(tokenIrritants); + if (id > 0) { + String key = CompilerOptions.optionKeyFromIrritant(id); + this.scope.problemReporter().problemNotAnalysed(value, key); + } else { + this.scope.problemReporter().unusedWarningToken(value); } } - this.scope.problemReporter().unusedWarningToken(value); } } } 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 d6a97919f..0b3762cd8 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 @@ -867,8 +867,11 @@ public TypeBinding resolveType(BlockScope scope) { // MW,JH,SH} if (receiverCast && this.actualReceiverType != null) { // due to change of declaring class with receiver type, only identity cast should be notified - if (TypeBinding.equalsEquals(((CastExpression)this.receiver).expression.resolvedType, this.actualReceiverType)) { - scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); + TypeBinding resolvedType2 = ((CastExpression)this.receiver).expression.resolvedType; + if (TypeBinding.equalsEquals(resolvedType2, this.actualReceiverType)) { + if (!scope.environment().usesNullTypeAnnotations() || !NullAnnotationMatching.analyse(this.actualReceiverType, resolvedType2, -1).isAnyMismatch()) { + scope.problemReporter().unnecessaryCast((CastExpression) this.receiver); + } } } // resolve type arguments (for generic constructor call) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java index b7095550b..ae21034c6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java @@ -128,8 +128,15 @@ public class QualifiedTypeReference extends TypeReference { for (int j = 0; j < i; j++) { Annotation[] qualifierAnnot = this.annotations[j]; if (qualifierAnnot != null && qualifierAnnot.length > 0) { - scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0], qualifierAnnot[qualifierAnnot.length - 1]); - this.annotations[j] = null; + if (j == 0) { + for (int k = 0; k < qualifierAnnot.length; k++) { + scope.problemReporter().typeAnnotationAtQualifiedName(qualifierAnnot[k]); + } + } else { + scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0], + qualifierAnnot[qualifierAnnot.length - 1]); + this.annotations[j] = null; + } } } } 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 004ddafbd..3a2af2c64 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 @@ -239,7 +239,7 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx } // Process the lambda, taking care not to double report diagnostics. Don't expect any from resolve, Any from code generation should surface, but not those from flow analysis. - implicitLambda.resolve(currentScope); + implicitLambda.resolveType(currentScope, true); IErrorHandlingPolicy oldPolicy = currentScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy); try { implicitLambda.analyseCode(currentScope, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java index f7709c443..5cdf5b42e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java @@ -2797,7 +2797,7 @@ public void generateSyntheticBodyForDeserializeLambda(SyntheticMethodBinding met invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature); - checkcast(isLambda ? mb.declaringClass : ((ReferenceExpression)funcEx).receiverType); + checkcast(mb.declaringClass); sig.append(mb.declaringClass.signature()); } for (int p = 0, max = outerLocalVariables == null ? 0 : outerLocalVariables.length; p < max; p++) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index c4add1b80..c65ac55d3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -1622,6 +1622,22 @@ public class CompilerOptions { return this.warningThreshold.isAnySet(irritants) || this.errorThreshold.isAnySet(irritants) || this.infoThreshold.isAnySet(irritants); } + /* + * Just return the first irritant id that is set to 'ignored'. + */ + public int getIgnoredIrritant(IrritantSet irritants) { + int[] bits = irritants.getBits(); + for (int i = 0; i < IrritantSet.GROUP_MAX; i++) { + int bit = bits[i]; + if (bit > 0) { + bit |= (i << IrritantSet.GROUP_SHIFT); + if (!(this.warningThreshold.isSet(bit) || this.errorThreshold.isSet(bit) || this.infoThreshold.isSet(bit))) { + return bit; + } + } + } + return 0; + } protected void resetDefaults() { // problem default severities defined on IrritantSet diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java index 80db44d0e..6635519df 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java @@ -335,7 +335,9 @@ public class IrritantSet { int group = (singleGroupIrritants & GROUP_MASK) >> GROUP_SHIFT; return (this.bits[group] & singleGroupIrritants) != 0; } - + public int[] getBits() { + return this.bits; + } public IrritantSet set(int singleGroupIrritants) { int group = (singleGroupIrritants & GROUP_MASK) >> GROUP_SHIFT; this.bits[group] |= (singleGroupIrritants & ~GROUP_MASK); // erase the group bits diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index 616c23709..68f82cfdf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -2237,7 +2237,9 @@ private void scanTypeForNullDefaultAnnotation(IBinaryType binaryType, PackageBin } // no annotation found on the type or its enclosing types // check the package-info for default annotation if not already done before - if (packageBinding.defaultNullness == Binding.NO_NULL_DEFAULT && !isPackageInfo) { + if (packageBinding.defaultNullness == Binding.NO_NULL_DEFAULT && !isPackageInfo + && ((this.typeBits & (TypeIds.BitAnyNullAnnotation)) == 0)) + { // this will scan the annotations in package-info ReferenceBinding packageInfo = packageBinding.getType(TypeConstants.PACKAGE_INFO_NAME); if (packageInfo == null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java index c6e2a0233..5d9ecc06e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java @@ -18,6 +18,8 @@ package org.eclipse.jdt.internal.compiler.lookup; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; @@ -94,6 +96,8 @@ public class CompilationUnitScope extends Scope { boolean connectingHierarchy; private ArrayList inferredInvocations; + /** Cache of interned inference variables. Access only via {@link InferenceVariable#get(TypeBinding, int, InvocationSite, Scope, ReferenceBinding)}. */ + Map uniqueInferenceVariables = new HashMap<>(); //{ObjectTeams: when used as a baseimport scope, remember the original scope during this current lookup public Scope originalScope; // store parser for on-demand Dependencies.setup() lateron: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java index 8fd61f808..8dd65d1a4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java @@ -304,7 +304,7 @@ public class ImplicitNullAnnotationVerifier { this.environment.getNonNullAnnotationName()); break returnType; } else { - scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, useTypeAnnotations); + scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, useTypeAnnotations); return; } } @@ -320,7 +320,7 @@ public class ImplicitNullAnnotationVerifier { scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod, this.environment.getNonNullAnnotationName()); else - scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, useTypeAnnotations); + scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, useTypeAnnotations); return; } } @@ -412,7 +412,7 @@ public class ImplicitNullAnnotationVerifier { inheritedMethod.declaringClass, (inheritedNonNullNess == null) ? null : this.environment.getNullableAnnotationName()); } else { - scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false); + scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false); } continue; } else if (currentNonNullNess == null) @@ -425,7 +425,7 @@ public class ImplicitNullAnnotationVerifier { inheritedMethod.declaringClass, annotationName); } else { - scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false); + scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false); } continue; } else if (inheritedNonNullNess == Boolean.TRUE) { @@ -450,7 +450,7 @@ public class ImplicitNullAnnotationVerifier { if (currentArgument != null) scope.problemReporter().illegalParameterRedefinition(currentArgument, inheritedMethod.declaringClass, inheritedParameter); else - scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false); + scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java index 2bae65c59..ab2691c3c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java @@ -131,7 +131,6 @@ public class InferenceContext18 { /** The inference variables for which as solution is sought. */ InferenceVariable[] inferenceVariables; - int nextVarId; /** Constraints that have not yet been reduced and incorporated. */ ConstraintFormula[] initialConstraints; @@ -165,43 +164,12 @@ public class InferenceContext18 { /** Not per JLS: signal when current is ready to directly merge all bounds from inner. */ private boolean directlyAcceptingInnerBounds = false; - // InferenceVariable interning: - private InferenceVariable[] internedVariables; - - private InferenceVariable getInferenceVariable(TypeBinding typeParameter, int rank, InvocationSite site) { - InferenceContext18 outermostContext = this.environment.currentInferenceContext; - if (outermostContext == null) - outermostContext = this; - int i = 0; - InferenceVariable[] interned = outermostContext.internedVariables; - if (interned == null) { - outermostContext.internedVariables = new InferenceVariable[10]; - } else { - int len = interned.length; - for (i = 0; i < len; i++) { - InferenceVariable var = interned[i]; - if (var == null) - break; - if (var.typeParameter == typeParameter && var.rank == rank && isSameSite(var.site, site)) //$IDENTITY-COMPARISON$ - return var; - } - if (i >= len) - System.arraycopy(interned, 0, outermostContext.internedVariables = new InferenceVariable[len+10], 0, len); - } - boolean differentContext = outermostContext != this; - int id = differentContext ? Math.max(this.nextVarId, outermostContext.nextVarId) : this.nextVarId; - this.nextVarId = id + 1; - if (differentContext) - outermostContext.nextVarId = this.nextVarId; - return outermostContext.internedVariables[i] = new InferenceVariable(typeParameter, rank, id, site, this.environment, this.object); - } - - boolean isSameSite(InvocationSite site1, InvocationSite site2) { + public static boolean isSameSite(InvocationSite site1, InvocationSite site2) { if (site1 == site2) return true; if (site1 == null || site2 == null) return false; - if (site1.sourceStart() == site2.sourceStart() && site1.sourceEnd() == site2.sourceEnd() && site1.toString().equals(site2.toString())) + if (site1.sourceStart() == site2.sourceStart() && site1.sourceEnd() == site2.sourceEnd()) return true; return false; } @@ -337,7 +305,7 @@ public class InferenceContext18 { } InferenceVariable[] newVariables = new InferenceVariable[len]; for (int i = 0; i < len; i++) - newVariables[i] = getInferenceVariable(typeVariables[i], i, this.currentInvocation); + newVariables[i] = InferenceVariable.get(typeVariables[i], i, this.currentInvocation, this.scope, this.object); addInferenceVariables(newVariables); return newVariables; } @@ -365,7 +333,7 @@ public class InferenceContext18 { newVariables[i] = (InferenceVariable) typeVariables[i]; // prevent double substitution of an already-substituted inferenceVariable else toAdd[numToAdd++] = - newVariables[i] = getInferenceVariable(typeVariables[i], i, this.currentInvocation); + newVariables[i] = InferenceVariable.get(typeVariables[i], i, this.currentInvocation, this.scope, this.object); } if (numToAdd > 0) { int start = 0; @@ -1571,18 +1539,6 @@ public class InferenceContext18 { if (!isSameSite(innerCtx.currentInvocation, this.currentInvocation)) innerCtx.outerContext = this; this.usesUncheckedConversion = innerCtx.usesUncheckedConversion; - for (InferenceVariable variable : this.inferenceVariables) - if (!isInterned(variable)) - variable.updateSourceName(this.nextVarId++); - } - - boolean isInterned(InferenceVariable iv) { - if (this.internedVariables != null) - for (int i = 0; i < this.internedVariables.length; i++) { - if (this.internedVariables[i] == iv) //$IDENTITY-COMPARISON$ - return true; - } - return false; } public void resumeSuspendedInference(SuspendedInferenceRecord record) { @@ -1595,8 +1551,6 @@ public class InferenceContext18 { // move to back, add previous to front: System.arraycopy(this.inferenceVariables, 0, this.inferenceVariables=new InferenceVariable[l1+l2], l2, l1); System.arraycopy(record.inferenceVariables, 0, this.inferenceVariables, 0, l2); - for (int i=l1;i>> 32)); + result = prime * result + this.rank; + result = prime * result + this.typeParameter.id; + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof InferenceVarKey)) + return false; + InferenceVarKey other = (InferenceVarKey) obj; + if (this.position != other.position) + return false; + if (this.rank != other.rank) + return false; + if (TypeBinding.notEquals(this.typeParameter, other.typeParameter)) + return false; + return true; + } + } + + /** + * Create or retrieve the inference variable representing the given typeParameter. + * Inference variables are interned to avoid duplication due to lambda copying. + */ + public static InferenceVariable get(TypeBinding typeParameter, int rank, InvocationSite site, Scope scope, ReferenceBinding object) { + Map uniqueInferenceVariables = scope.compilationUnitScope().uniqueInferenceVariables; + InferenceVariable var = null; + InferenceVarKey key = null; + if (site != null && typeParameter != null) { + key = new InferenceVarKey(typeParameter, site, rank); + var = uniqueInferenceVariables.get(key); + } + if (var == null) { + int newVarId = uniqueInferenceVariables.size(); + var = new InferenceVariable(typeParameter, rank, newVarId, site, scope.environment(), object); + if (key != null) + uniqueInferenceVariables.put(key, var); + } + return var; + } + InvocationSite site; TypeBinding typeParameter; long nullHints; // one of TagBits.{AnnotationNonNull,AnnotationNullable} may steer inference into inferring nullness as well; set both bits to request avoidance. private InferenceVariable prototype; - int varId; // this is used for constructing a source name like T#0. NB: varId and sourceName are mutable, to be updated when two InferenceContext18 are integrated. + int varId; // this is used for constructing a source name like T#0. - public InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) { + private InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) { this(typeParameter, parameterRank, site, CharOperation.concat(typeParameter.shortReadableName(), Integer.toString(iVarId).toCharArray(), '#'), environment, object); @@ -49,15 +110,7 @@ public class InferenceVariable extends TypeVariableBinding { this.superclass = object; this.prototype = this; } - void updateSourceName(int newId) { - int hashPos = CharOperation.indexOf('#', this.sourceName); - this.varId = newId; - this.sourceName = CharOperation.concat( - CharOperation.subarray(this.sourceName, 0, hashPos), - Integer.toString(this.varId).toCharArray(), - '#'); - } - + @Override public TypeBinding clone(TypeBinding enclosingType) { InferenceVariable clone = new InferenceVariable(this.typeParameter, this.rank, this.site, this.sourceName, this.environment, this.superclass); @@ -137,17 +190,18 @@ public class InferenceVariable extends TypeVariableBinding { public int hashCode() { int code = this.typeParameter.hashCode() + 17 * this.rank; - if (this.site != null) - return 31 * code + this.site.hashCode(); - else - return code; + if (this.site != null) { + code = 31 * code + this.site.sourceStart(); + code = 31 * code + this.site.sourceEnd(); + } + return code; } public boolean equals(Object obj) { if (!(obj instanceof InferenceVariable)) return false; InferenceVariable other = (InferenceVariable) obj; return this.rank == other.rank - && this.site == other.site + && InferenceContext18.isSameSite(this.site, other.site) && TypeBinding.equalsEquals(this.typeParameter, other.typeParameter); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java index 6979eaaa6..6cfe6aaca 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java @@ -70,6 +70,12 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin */ public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod, TypeBinding[] arguments, Scope scope, InvocationSite invocationSite) { + LookupEnvironment environment = scope.environment(); + if ((originalMethod.tagBits & TagBits.IsNullnessKnown) == 0) { + // ensure nullness of originalMethod is known (but we are not interested in reporting problems against originalMethod) + new ImplicitNullAnnotationVerifier(environment, environment.globalOptions.inheritNullAnnotations) + .checkImplicitNullAnnotations(originalMethod, null/*srcMethod*/, false, scope); + } ParameterizedGenericMethodBinding methodSubstitute; TypeVariableBinding[] typeVariables = originalMethod.typeVariables; TypeBinding[] substitutes = invocationSite.genericTypeArguments(); @@ -90,7 +96,7 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin // incompatible due to wrong arity return new ProblemMethodBinding(originalMethod, originalMethod.selector, substitutes, ProblemReasons.TypeParameterArityMismatch); } - methodSubstitute = scope.environment().createParameterizedGenericMethod(originalMethod, substitutes); + methodSubstitute = environment.createParameterizedGenericMethod(originalMethod, substitutes); break computeSubstitutes; } // perform type argument inference (15.12.2.7) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java index af32c7801..7749b66f3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java @@ -251,6 +251,7 @@ public interface TypeIds { final int BitNullableAnnotation = 64; /** Bit for a type configured as a @NonNullByDefault annotation. */ final int BitNonNullByDefaultAnnotation = 128; + final int BitAnyNullAnnotation = BitNonNullAnnotation | BitNullableAnnotation | BitNonNullByDefaultAnnotation; /** * Set of type bits that should be inherited by any sub types. diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java index ca9ebeb7e..85421e94f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java @@ -224,19 +224,7 @@ public class TypeSystem { urb = (UnresolvedReferenceBinding) type; ReferenceBinding resolvedType = urb.resolvedType; if (resolvedType != null) { - if(CharOperation.indexOf('$', type.sourceName()) > 0) { - type = this.environment.convertToRawType(resolvedType, false); - } else { - type = resolvedType; - } - } else if (CharOperation.indexOf('$', type.sourceName()) > 0) { - boolean mayTolerateMissingType = this.environment.mayTolerateMissingType; - this.environment.mayTolerateMissingType = true; - try { - type = BinaryTypeBinding.resolveType(type, this.environment, true); // to ensure unique id assignment (when enclosing type is parameterized, inner type is also) - } finally { - this.environment.mayTolerateMissingType = mayTolerateMissingType; - } + type = resolvedType; } } try { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java index 62d041dfb..48664dcc3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java @@ -1119,8 +1119,7 @@ public class TypeVariableBinding extends ReferenceBinding { TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - if (annotatedType.firstBound == null) - annotatedType.firstBound = firstBound; + annotatedType.firstBound = firstBound; } } if (firstBound != null && firstBound.hasNullTypeAnnotations()) @@ -1136,8 +1135,7 @@ public class TypeVariableBinding extends ReferenceBinding { TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - if (annotatedType.superclass == null) - annotatedType.superclass = superclass; + annotatedType.superclass = superclass; } } return superclass; @@ -1151,8 +1149,7 @@ public class TypeVariableBinding extends ReferenceBinding { TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - if (annotatedType.superInterfaces == null) - annotatedType.superInterfaces = superInterfaces; + annotatedType.superInterfaces = superInterfaces; } } return superInterfaces; 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 b2efb250c..88b5e90ad 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 @@ -1807,6 +1807,8 @@ public int computeSeverity(int problemID){ return ProblemSeverities.Warning; case IProblem.IllegalUseOfUnderscoreAsAnIdentifier: return this.underScoreIsLambdaParameter ? ProblemSeverities.Error : ProblemSeverities.Warning; + case IProblem.ProblemNotAnalysed: + return ProblemSeverities.Info; // Not configurable } int irritant = getIrritant(problemID); if (irritant != 0) { @@ -6438,6 +6440,19 @@ public void nullAnnotationUnsupportedLocation(Annotation annotation) { severity, annotation.sourceStart, annotation.sourceEnd); } +public void nullAnnotationAtQualifyingType(Annotation annotation) { + String[] arguments = new String[] { + String.valueOf(annotation.resolvedType.readableName()) + }; + String[] shortArguments = new String[] { + String.valueOf(annotation.resolvedType.shortReadableName()) + }; + int severity = ProblemSeverities.Error | ProblemSeverities.Fatal; + handle(IProblem.NullAnnotationAtQualifyingType, + arguments, shortArguments, + severity, + annotation.sourceStart, annotation.sourceEnd); +} public void nullAnnotationUnsupportedLocation(TypeReference type) { int sourceEnd = type.sourceEnd; if (type instanceof ParameterizedSingleTypeReference) { @@ -9710,6 +9725,14 @@ public void unusedWarningToken(Expression token) { token.sourceStart, token.sourceEnd); } +public void problemNotAnalysed(Expression token, String optionKey) { + this.handle( + IProblem.ProblemNotAnalysed, + optionKey != null ? new String[]{optionKey} : new String[]{}, + new String[] { token.constant.stringValue() }, + token.sourceStart, + token.sourceEnd); +} public void useAssertAsAnIdentifier(int sourceStart, int sourceEnd) { this.handle( IProblem.UseAssertAsAnIdentifier, @@ -14047,11 +14070,11 @@ public void expressionPotentialNullReference(ASTNode location) { location.sourceEnd); } -public void cannotImplementIncompatibleNullness(MethodBinding currentMethod, MethodBinding inheritedMethod, boolean showReturn) { +public void cannotImplementIncompatibleNullness(ReferenceContext context, MethodBinding currentMethod, MethodBinding inheritedMethod, boolean showReturn) { int sourceStart = 0, sourceEnd = 0; - if (this.referenceContext instanceof TypeDeclaration) { - sourceStart = ((TypeDeclaration) this.referenceContext).sourceStart; - sourceEnd = ((TypeDeclaration) this.referenceContext).sourceEnd; + if (context instanceof TypeDeclaration) { + sourceStart = ((TypeDeclaration) context).sourceStart; + sourceEnd = ((TypeDeclaration) context).sourceEnd; } String[] problemArguments = { showReturn @@ -14800,6 +14823,10 @@ public void disallowedTargetForContainerAnnotation(Annotation annotation, TypeBi annotation.sourceStart, annotation.sourceEnd); } +public void typeAnnotationAtQualifiedName(Annotation annotation) { + this.handle(IProblem.TypeAnnotationAtQualifiedName, NoArgument, NoArgument, annotation.sourceStart, + annotation.sourceEnd); + } public void genericInferenceError(String message, InvocationSite invocationSite) { genericInferenceProblem(message, invocationSite, ProblemSeverities.Error); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index 3beee8e97..98c08302e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -861,9 +861,12 @@ 1057 = strictfp is not permitted for abstract interface method {0} 1058 = Default methods are allowed only in interfaces. 1059 = Cannot infer type argument(s) for <{0}> {1} +1060 = Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays) +1061 = The nullness annotation ''{0}'' is not applicable at this location, it must be placed directly before the nested type name. 1100 = Problem detected during type inference: {0} - +#1101 is already used up but deprecated +1102 = At least one of the problems in category ''{0}'' is not analysed due to a compiler option being ignored ### ELABORATIONS ## Access restrictions 78592 = The type ''{1}'' is not API (restriction on classpath entry ''{0}'') diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index 168465fc7..084f53ff9 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -116,6 +116,19 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Map; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; @@ -131,19 +144,6 @@ import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceChangeEvent; -import org.eclipse.core.resources.IResourceChangeListener; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.IWorkspaceRunnable; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.search.IJavaSearchConstants; @@ -154,10 +154,26 @@ import org.eclipse.jdt.core.search.TypeNameRequestor; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.core.*; +import org.eclipse.jdt.internal.core.BatchOperation; +import org.eclipse.jdt.internal.core.BufferManager; +import org.eclipse.jdt.internal.core.ClasspathAccessRule; +import org.eclipse.jdt.internal.core.ClasspathAttribute; +import org.eclipse.jdt.internal.core.ClasspathEntry; +import org.eclipse.jdt.internal.core.ClasspathValidation; +import org.eclipse.jdt.internal.core.CreateTypeHierarchyOperation; +import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner; +import org.eclipse.jdt.internal.core.ExternalFoldersManager; +import org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer; +import org.eclipse.jdt.internal.core.JavaModel; +import org.eclipse.jdt.internal.core.JavaModelManager; +import org.eclipse.jdt.internal.core.JavaProject; +import org.eclipse.jdt.internal.core.Region; +import org.eclipse.jdt.internal.core.SetContainerOperation; +import org.eclipse.jdt.internal.core.SetVariablesOperation; import org.eclipse.jdt.internal.core.builder.JavaBuilder; import org.eclipse.jdt.internal.core.builder.State; import org.eclipse.jdt.internal.core.nd.indexer.Indexer; +import org.eclipse.jdt.internal.core.search.indexing.IndexManager; import org.eclipse.jdt.internal.core.util.MementoTokenizer; import org.eclipse.jdt.internal.core.util.Messages; import org.eclipse.jdt.internal.core.util.Util; @@ -4162,7 +4178,7 @@ public final class JavaCore extends Plugin { // if factory is null, default factory must be used if (factory == null) factory = BufferManager.getDefaultBufferManager().getDefaultBufferFactory(); - return getWorkingCopies(BufferFactoryWrapper.create(factory)); + return getWorkingCopies(org.eclipse.jdt.internal.core.BufferFactoryWrapper.create(factory)); } /** @@ -4227,14 +4243,14 @@ public final class JavaCore extends Plugin { JavaModelManager manager = JavaModelManager.getJavaModelManager(); try { SubMonitor subMonitor = mainMonitor.split(50).setWorkRemaining(100); // 50% of the time is spent in initializing containers and variables - subMonitor.step(5); // give feedback to the user that something is happening + subMonitor.split(5); // give feedback to the user that something is happening manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(subMonitor); if (manager.forceBatchInitializations(true/*initAfterLoad*/)) { // if no other thread has started the batch container initializations manager.getClasspathContainer(Path.EMPTY, null); // force the batch initialization } else { // else wait for the batch initialization to finish while (manager.batchContainerInitializations == JavaModelManager.BATCH_INITIALIZATION_IN_PROGRESS) { subMonitor.subTask(manager.batchContainerInitializationsProgress.subTaskName); - subMonitor.step(manager.batchContainerInitializationsProgress.getWorked()); + subMonitor.split(manager.batchContainerInitializationsProgress.getWorked()); synchronized(manager) { try { manager.wait(100); @@ -4310,38 +4326,8 @@ public final class JavaCore extends Plugin { // dummy query for waiting until the indexes are ready mainMonitor.subTask(Messages.javamodel_configuring_searchengine); - SearchEngine engine = new SearchEngine(); - IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); - try { - engine.searchAllTypeNames( - null, - SearchPattern.R_EXACT_MATCH, - "!@$#!@".toCharArray(), //$NON-NLS-1$ - SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE, - IJavaSearchConstants.CLASS, - scope, - new TypeNameRequestor() { - public void acceptType( - int modifiers, - char[] packageName, - char[] simpleTypeName, - char[][] enclosingTypeNames, - String path) { - // no type to accept - } - }, - // will not activate index query caches if indexes are not ready, since it would take to long - // to wait until indexes are fully rebuild - IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH, - mainMonitor.split(47) // 47% of the time is spent in the dummy search - ); - } catch (JavaModelException e) { - // /search failed: ignore - } catch (OperationCanceledException e) { - if (mainMonitor.isCanceled()) - throw e; - // else indexes were not ready: catch the exception so that jars are still refreshed - } + // 47% of the time is spent in the dummy search + updateLegacyIndex(mainMonitor.split(47)); // check if the build state version number has changed since last session // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969) @@ -4388,6 +4374,41 @@ public final class JavaCore extends Plugin { } } + private static void updateLegacyIndex(IProgressMonitor monitor) { + SearchEngine engine = new SearchEngine(); + IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); + try { + engine.searchAllTypeNames( + null, + SearchPattern.R_EXACT_MATCH, + "!@$#!@".toCharArray(), //$NON-NLS-1$ + SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE, + IJavaSearchConstants.CLASS, + scope, + new TypeNameRequestor() { + public void acceptType( + int modifiers, + char[] packageName, + char[] simpleTypeName, + char[][] enclosingTypeNames, + String path) { + // no type to accept + } + }, + // will not activate index query caches if indexes are not ready, since it would take to long + // to wait until indexes are fully rebuild + IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH, + monitor + ); + } catch (JavaModelException e) { + // /search failed: ignore + } catch (OperationCanceledException e) { + if (monitor.isCanceled()) + throw e; + // else indexes were not ready: catch the exception so that jars are still refreshed + } + } + /** * Returns whether a given classpath variable is read-only or not. * @@ -5485,7 +5506,23 @@ public final class JavaCore extends Plugin { JavaModelManager.getDeltaState().removePreResourceChangedListener(listener); } - + /** + * Deletes and rebuilds the java index. + * + * @param monitor a progress monitor, or null if progress + * reporting and cancellation are not desired + * @throws CoreException + * @since 3.13 + */ + public static void rebuildIndex(IProgressMonitor monitor) throws CoreException { + SubMonitor subMonitor = SubMonitor.convert(monitor, 10); + IndexManager manager = JavaModelManager.getIndexManager(); + subMonitor.split(1); + manager.deleteIndexFiles(); + manager.reset(); + Indexer.getInstance().rebuildIndex(subMonitor.split(7)); + updateLegacyIndex(subMonitor.split(2)); + } /** * Runs the given action as an atomic Java model operation. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java index 3097a43c2..26fb1c4c4 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java @@ -112,7 +112,11 @@ protected void cleanOutputFolders(boolean copyBack) throws CoreException { } ); } - member.delete(IResource.FORCE, null); + try { + member.delete(IResource.FORCE, null); + } catch(CoreException e) { + Util.log(e, "Error occurred while deleting: " + member.getFullPath()); //$NON-NLS-1$ + } } } this.notifier.checkCancel(); @@ -139,7 +143,11 @@ protected void cleanOutputFolders(boolean copyBack) throws CoreException { return false; if (!resource.isDerived()) resource.setDerived(true, null); - resource.delete(IResource.FORCE, null); + try { + resource.delete(IResource.FORCE, null); + } catch(CoreException e) { + Util.log(e, "Error occurred while deleting: " + resource.getFullPath()); //$NON-NLS-1$ + } } return false; } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java index fb02f1319..71e492f3d 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java @@ -599,4 +599,8 @@ public class Nd { public NdNodeTypeRegistry getTypeRegistry() { return this.fNodeTypeRegistry; } + + public void clear(IProgressMonitor monitor) { + getDB().clear(getDefaultVersion()); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java index 318a736b3..7ca27245d 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java @@ -43,6 +43,7 @@ import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobGroup; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; @@ -115,10 +116,16 @@ public final class Indexer { */ private Set listeners = Collections.newSetFromMap(new WeakHashMap()); + private JobGroup group = new JobGroup(Messages.Indexer_updating_index_job_name, 1, 1); + private Job rescanJob = Job.create(Messages.Indexer_updating_index_job_name, monitor -> { rescan(monitor); }); + private Job rebuildIndexJob = Job.create(Messages.Indexer_updating_index_job_name, monitor -> { + rebuildIndex(monitor); + }); + public static interface Listener { void consume(IndexerEvent event); } @@ -983,6 +990,10 @@ public final class Indexer { public Indexer(Nd toPopulate, IWorkspaceRoot workspaceRoot) { this.nd = toPopulate; this.root = workspaceRoot; + this.rescanJob.setSystem(true); + this.rescanJob.setJobGroup(this.group); + this.rebuildIndexJob.setSystem(true); + this.rebuildIndexJob.setJobGroup(this.group); } public void rescanAll() { @@ -1070,4 +1081,20 @@ public final class Indexer { } } } + + public void rebuildIndex(IProgressMonitor monitor) throws CoreException { + SubMonitor subMonitor = SubMonitor.convert(monitor, 100); + + this.nd.acquireWriteLock(subMonitor.split(1)); + try { + this.nd.clear(subMonitor.split(2)); + } finally { + this.nd.releaseWriteLock(); + } + rescan(subMonitor.split(98)); + } + + public void requestRebuildIndex() { + this.rebuildIndexJob.schedule(); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java index 006aeff10..f0cbe1f53 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java @@ -293,8 +293,4 @@ public class JavaIndex { registry.register(0x0200, NdWorkspaceLocation.type.getFactory()); return registry; } - - public void rebuildIndex() { - // TODO: delete and recreate the index - } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java index d6d3981a7..e9ce570ad 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java @@ -37,6 +37,7 @@ import org.eclipse.jdt.internal.core.PackageFragment; import org.eclipse.jdt.internal.core.nd.IReader; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.IndexException; +import org.eclipse.jdt.internal.core.nd.indexer.Indexer; import org.eclipse.jdt.internal.core.nd.java.JavaIndex; import org.eclipse.jdt.internal.core.nd.java.JavaNames; import org.eclipse.jdt.internal.core.nd.java.NdResourceFile; @@ -217,8 +218,8 @@ public class BinaryTypeFactory { throw new JavaModelException(e); } } catch (IndexException e) { - // Index corrupted. Rebuild it. - index.rebuildIndex(); + Package.log("Index corruption detected. Rebuilding index.", e); //$NON-NLS-1$ + Indexer.getInstance().requestRebuildIndex(); } } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java new file mode 100644 index 000000000..1aad35428 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2015, 2016 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.nd.java.model; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.JavaCore; + +/* package */ class Package { + public static String PLUGIN_ID = JavaCore.PLUGIN_ID; + + public static void log(Throwable e) { + String msg = e.getMessage(); + if (msg == null) { + log("Error", e); //$NON-NLS-1$ + } else { + log("Error: " + msg, e); //$NON-NLS-1$ + } + } + + public static void log(String message, Throwable e) { + log(createStatus(message, e)); + } + + public static IStatus createStatus(String msg, Throwable e) { + return new Status(IStatus.ERROR, PLUGIN_ID, msg, e); + } + + public static IStatus createStatus(String msg) { + return new Status(IStatus.ERROR, PLUGIN_ID, msg); + } + + public static void logInfo(String message) { + log(new Status(IStatus.INFO, PLUGIN_ID, message)); + } + + public static void log(IStatus status) { + JavaCore.getPlugin().getLog().log(status); + } +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java index 7ce53faf5..dc7269743 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java @@ -28,6 +28,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; @@ -164,7 +165,7 @@ public void cleanUpIndexes() { if (count > 0) removeIndexesState(locations); } - deleteIndexFiles(knownPaths); + deleteIndexFiles(knownPaths, null); } /** * Compute the pre-built index location for a specified URL @@ -212,17 +213,25 @@ public synchronized IndexLocation computeIndexLocation(IPath containerPath) { } return indexLocation; } -public void deleteIndexFiles() { +/** + * Use {@link #deleteIndexFiles(IProgressMonitor)} + */ +public final void deleteIndexFiles() { + deleteIndexFiles(null); +} +public void deleteIndexFiles(IProgressMonitor monitor) { if (DEBUG) Util.verbose("Deleting index files"); //$NON-NLS-1$ this.savedIndexNamesFile.delete(); // forget saved indexes & delete each index file - deleteIndexFiles(null); + deleteIndexFiles(null, monitor); } -private void deleteIndexFiles(SimpleSet pathsToKeep) { +private void deleteIndexFiles(SimpleSet pathsToKeep, IProgressMonitor monitor) { File[] indexesFiles = getSavedIndexesDirectory().listFiles(); if (indexesFiles == null) return; + SubMonitor subMonitor = SubMonitor.convert(monitor, indexesFiles.length); for (int i = 0, l = indexesFiles.length; i < l; i++) { + subMonitor.split(1); String fileName = indexesFiles[i].getAbsolutePath(); if (pathsToKeep != null && pathsToKeep.includes(new FileIndexLocation(indexesFiles[i]))) continue; String suffix = ".index"; //$NON-NLS-1$ @@ -865,14 +874,16 @@ public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFol /** * Flush current state */ -public synchronized void reset() { +public void reset() { super.reset(); - if (this.indexes != null) { - this.indexes = new SimpleLookupTable(); - this.indexStates = null; + synchronized (this) { + if (this.indexes != null) { + this.indexes = new SimpleLookupTable(); + this.indexStates = null; + } + this.indexLocations = new SimpleLookupTable(); + this.javaPluginLocation = null; } - this.indexLocations = new SimpleLookupTable(); - this.javaPluginLocation = null; } /** * Resets the index for a given path. diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java index 71bc06163..7c07d0f47 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java @@ -297,22 +297,29 @@ public abstract class JobManager implements Runnable { /** * Flush current state */ - public synchronized void reset() { + public void reset() { if (VERBOSE) Util.verbose("Reset"); //$NON-NLS-1$ - if (this.processingThread != null) { + Thread thread; + synchronized (this) { + thread = this.processingThread; + } + + if (thread != null) { discardJobs(null); // discard all jobs } else { - /* initiate background processing */ - this.processingThread = new Thread(this, processName()); - this.processingThread.setDaemon(true); - // less prioritary by default, priority is raised if clients are actively waiting on it - this.processingThread.setPriority(Thread.NORM_PRIORITY-1); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=296343 - // set the context loader to avoid leaking the current context loader - this.processingThread.setContextClassLoader(this.getClass().getClassLoader()); - this.processingThread.start(); + synchronized (this) { + /* initiate background processing */ + this.processingThread = new Thread(this, processName()); + this.processingThread.setDaemon(true); + // less prioritary by default, priority is raised if clients are actively waiting on it + this.processingThread.setPriority(Thread.NORM_PRIORITY-1); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=296343 + // set the context loader to avoid leaking the current context loader + this.processingThread.setContextClassLoader(this.getClass().getClassLoader()); + this.processingThread.start(); + } } } /** -- cgit v1.2.3