Update jdt.core to I20150428-0800 (M7 warm-up).
Manually merge from origin (bogus lineend changes):
- NullTypeAnnotationTest
- AstConverter18Test (no real change)
- FormatterBugsTests (no real change)
- SpacePreparator
- SourceTypeBinding
diff --git a/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF
index 7936ce0..a1fb1eb 100644
--- a/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.core.tests.compiler;singleton:=true
-Bundle-Version: 3.11.0.qualifier
+Bundle-Version: 3.12.0.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.jdt.core.tests.compiler,
diff --git a/org.eclipse.jdt.core.tests.compiler/pom.xml b/org.eclipse.jdt.core.tests.compiler/pom.xml
index 1b27e0e..b89dd4a 100644
--- a/org.eclipse.jdt.core.tests.compiler/pom.xml
+++ b/org.eclipse.jdt.core.tests.compiler/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core.tests.compiler</artifactId>
- <version>3.11.0-SNAPSHOT</version>
+ <version>3.12.0-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/GenericDietRecoveryTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/GenericDietRecoveryTest.java
index 17e6dd6..f351736 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/GenericDietRecoveryTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/GenericDietRecoveryTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -954,7 +954,7 @@
expectedFullUnitToString,
expectedCompletionDietUnitToString, testName);
}
-public void _test0019() {
+public void test0019() {
String s =
"package a; \n"
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractComparableTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractComparableTest.java
index 3931ddb..dc9770e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractComparableTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractComparableTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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,6 +9,8 @@
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contribution for
* bug 376590 - Private fields with @Inject are ignored by unused field validation
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -44,6 +46,23 @@
"@Retention(RUNTIME)\n" +
"public @interface Inject {}\n";
+ protected static final String SPRINGFRAMEWORK_AUTOWIRED_NAME = "org/springframework/beans/factory/annotation/Autowired.java";
+ protected static final String SPRINGFRAMEWORK_AUTOWIRED_CONTENT =
+ "package org.springframework.beans.factory.annotation;\n" +
+ "import java.lang.annotation.Documented;\n" +
+ "import java.lang.annotation.ElementType;\n" +
+ "import java.lang.annotation.Retention;\n" +
+ "import java.lang.annotation.RetentionPolicy;\n" +
+ "import java.lang.annotation.Target;\n" +
+ "@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})\n" +
+ "@Retention(RetentionPolicy.RUNTIME)\n" +
+ "@Documented\n" +
+ "public @interface Autowired {\n" +
+ "\n" +
+ " boolean required() default true;\n" +
+ "\n" +
+ "}";
+
public static Test buildComparableTestSuite(Class evaluationTestClass) {
Test suite = buildMinimalComplianceTestSuite(evaluationTestClass, F_1_5);
TESTS_COUNTERS.put(evaluationTestClass.getName(), new Integer(suite.countTestCases()));
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 2a0d236..67b74ff 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -902,16 +902,17 @@
.append(fileName)
.append("\" -d \"")
.append(EVAL_DIRECTORY);
+ String processAnnot = this.enableAPT ? "" : "-proc:none";
if (this.complianceLevel < ClassFileConstants.JDK1_5) {
buffer.append("\" -1.4 -source 1.3 -target 1.2");
} else if (this.complianceLevel == ClassFileConstants.JDK1_5) {
buffer.append("\" -1.5");
} else if (this.complianceLevel == ClassFileConstants.JDK1_6) {
- buffer.append("\" -1.6 -proc:none");
+ buffer.append("\" -1.6 " + processAnnot);
} else if (this.complianceLevel == ClassFileConstants.JDK1_7) {
- buffer.append("\" -1.7 -proc:none");
+ buffer.append("\" -1.7 " + processAnnot);
} else if (this.complianceLevel == ClassFileConstants.JDK1_8) {
- buffer.append("\" -1.8 -proc:none");
+ buffer.append("\" -1.8 " + processAnnot);
}
buffer
.append(" -preserveAllLocals -nowarn -g -classpath \"")
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
index 34aa40c..17dad44 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -4499,4 +4499,44 @@
"The method method(File) is ambiguous for the type AmbiguousTest.AbstractClass\n" +
"----------\n");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=458563 - invalid ambiguous method error on Java 8 that isn't seen on Java 7 (or with javac)
+public void testBug458563() {
+ runConformTest(
+ new String[] {
+ "X.java",
+ "interface IStoredNode<T> extends INodeHandle<DocumentImpl>, NodeHandle { }\n" +
+ "interface NodeHandle extends INodeHandle<DocumentImpl> { }\n" +
+ "class DocumentImpl implements INodeHandle<DocumentImpl> {\n" +
+ " public Object getNodeId() {return null;}\n" +
+ "}\n" +
+ "interface INodeHandle<D> {\n" +
+ " public Object getNodeId();\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public void foo(IStoredNode bar) {\n" +
+ " bar.getNodeId();\n" +
+ " }\n" +
+ "}"
+ });
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=458563 - invalid ambiguous method error on Java 8 that isn't seen on Java 7 (or with javac)
+public void testBug458563a() {
+ runConformTest(
+ new String[] {
+ "X.java",
+ "interface IStoredNode<T> extends INodeHandle<DocumentImpl>, NodeHandle { }\n" +
+ "interface NodeHandle extends INodeHandle<DocumentImpl> { }\n" +
+ "class DocumentImpl implements INodeHandle<DocumentImpl> {\n" +
+ " public Object getNodeId() {return null;}\n" +
+ "}\n" +
+ "interface INodeHandle<D> {\n" +
+ " public Object getNodeId();\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public void foo(IStoredNode<?> bar) {\n" +
+ " bar.getNodeId();\n" +
+ " }\n" +
+ "}"
+ });
+}
}
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 32a21f7..676b8ba 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
@@ -19,6 +19,8 @@
* Jesper S Moller - Contributions for
* bug 384567 - [1.5][compiler] Compiler accepts illegal modifiers on package declaration
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -11354,6 +11356,7 @@
} catch(org.eclipse.jdt.core.util.ClassFormatException cfe) {
fail("Error reading classfile");
}
+
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=449330 - [1.6]Eclipse compiler doesn't compile annotations in class files
public void test449330() throws Exception {
@@ -11419,4 +11422,76 @@
this.runConformTest(testFiles, "");
checkDisassembledClassFile(OUTPUT_DIR + File.separator + "p/package-info.class", "", "HELLO");
}
+//https://bugs.eclipse.org/386692
+public void testBug386692() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);
+ customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);
+ this.runNegativeTest(
+ true,
+ new String[] {
+ SPRINGFRAMEWORK_AUTOWIRED_NAME,
+ SPRINGFRAMEWORK_AUTOWIRED_CONTENT,
+ "Example.java",
+ "class Example {\n" +
+ " private @org.springframework.beans.factory.annotation.Autowired Object o;\n" +
+ " private Example() {}\n" +
+ " public Example(Object o) { this.o = o; }\n" +
+ " private @org.springframework.beans.factory.annotation.Autowired void setO(Object o) { this.o = o;}\n" +
+ "}\n"
+ },
+ null, customOptions,
+ "----------\n" +
+ "1. ERROR in Example.java (at line 2)\n" +
+ " private @org.springframework.beans.factory.annotation.Autowired Object o;\n" +
+ " ^\n" +
+ "The value of the field Example.o is not used\n" +
+ "----------\n" +
+ "2. ERROR in Example.java (at line 3)\n" +
+ " private Example() {}\n" +
+ " ^^^^^^^^^\n" +
+ "The constructor Example() is never used locally\n" +
+ "----------\n",
+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=464977
+public void testBug464977() throws Exception {
+ if (this.complianceLevel < ClassFileConstants.JDK1_6 || this.complianceLevel > ClassFileConstants.JDK1_8) {
+ return; // Enough to run in 3 levels rather!
+ }
+ boolean apt = this.enableAPT;
+ String source = "@Deprecated\n" +
+ "public class DeprecatedClass {\n" +
+ "}";
+ String version = "";
+ if (this.complianceLevel == ClassFileConstants.JDK1_8) {
+ version = "1.8 : 52.0";
+ } else if (this.complianceLevel == ClassFileConstants.JDK1_7) {
+ version = "1.7 : 51.0";
+ } else if (this.complianceLevel == ClassFileConstants.JDK1_6) {
+ version = "1.6 : 50.0";
+ }
+ String expectedOutput = "// Compiled from DeprecatedClass.java (version " + version + ", super bit, deprecated)\n" +
+ "@Deprecated\n" +
+ "public class DeprecatedClass {\n" +
+ " \n" +
+ " // Method descriptor #6 ()V\n" +
+ " // Stack: 1, Locals: 1\n" +
+ " public DeprecatedClass();\n" +
+ " 0 aload_0 [this]\n" +
+ " 1 invokespecial Object() [8]\n" +
+ " 4 return\n" +
+ " Line numbers:\n" +
+ " [pc: 0, line: 2]\n" +
+ " Local variable table:\n" +
+ " [pc: 0, pc: 5] local: this index: 0 type: DeprecatedClass\n" +
+ "\n" +
+ "}";
+ try {
+ this.enableAPT = true;
+ checkClassFile("DeprecatedClass", source, expectedOutput, ClassFileBytesDisassembler.DETAILED | ClassFileBytesDisassembler.COMPACT);
+ } finally {
+ this.enableAPT = apt;
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
index e8e16fc..4fe1df1 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2014 IBM Corporation and others.
+ * Copyright (c) 2003, 2015 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
@@ -3185,6 +3185,86 @@
assertEquals("Wrong contents", expectedOutput, actualOutput);
}
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=461706 [1.8][compiler] "Unnecessary cast" problems for necessary cast in lambda expression
+public void test461706() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_8)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.ERROR);
+ this.runConformTest(
+ new String[] {
+ "Bug.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "public class Bug {\n" +
+ " private static class AndCondition implements ICondition {\n" +
+ " public AndCondition(ICondition cond1, ICondition cond2) {\n" +
+ " // todo\n" +
+ " }\n" +
+ " }\n" +
+ " private static class SimpleCondition implements ICondition {\n" +
+ " }\n" +
+ " private static interface ICondition {\n" +
+ " ICondition TRUE = new SimpleCondition();\n" +
+ " default ICondition and(final ICondition cond) {\n" +
+ " return new AndCondition(this, cond);\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(final String[] args) {\n" +
+ " final List<SimpleCondition> conditions = new ArrayList<>();\n" +
+ " conditions.stream()\n" +
+ " .map(x -> (ICondition)x)\n" +
+ " .reduce((x, y) -> x.and(y))\n" +
+ " .orElse(ICondition.TRUE);\n" +
+ " }\n" +
+ "}"
+ },
+ customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=461706 [1.8][compiler] "Unnecessary cast" problems for necessary cast in lambda expression
+public void test461706a() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_8)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, CompilerOptions.ERROR);
+ this.runNegativeTest(
+ new String[] {
+ "Bug.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "public class Bug {\n" +
+ " private static class AndCondition implements ICondition {\n" +
+ " public AndCondition(ICondition cond1, ICondition cond2) {\n" +
+ " // todo\n" +
+ " }\n" +
+ " }\n" +
+ " static class SimpleCondition implements ICondition {\n" +
+ " }\n" +
+ " private static interface ICondition {\n" +
+ " ICondition TRUE = new SimpleCondition();\n" +
+ " default ICondition and(final ICondition cond) {\n" +
+ " return new AndCondition(this, cond);\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(final String[] args) {\n" +
+ " final List<ICondition> conditions = new ArrayList<>();\n" +
+ " conditions.stream()\n" +
+ " .map(x -> (ICondition)x)\n" +
+ " .reduce((x, y) -> x.and(y))\n" +
+ " .orElse(ICondition.TRUE);\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in Bug.java (at line 20)\n" +
+ " .map(x -> (ICondition)x)\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Unnecessary cast from Bug.ICondition to Bug.ICondition\n" +
+ "----------\n",
+ null,
+ true,
+ customOptions);
+}
public static Class testClass() {
return CastTest.class;
}
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 699683f..ac1c66a 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
@@ -5106,4 +5106,125 @@
"}\n"
});
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=445231, [compiler] IllegalAccessError running Eclipse-compiled class
+public void testBug445231() {
+ runConformTest(
+ true,
+ new String[] {
+ "com/n/Bug.java",
+ "package com.n;\n" +
+ "public class Bug {\n" +
+ " public static void main(String[] args) {\n" +
+ " try {\n" +
+ " new Bug().go();\n" +
+ " System.err.println(\"Ok\");\n" +
+ " } catch (IllegalAccessError e) {\n" +
+ " System.err.println(\"Error\");\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ " public void go() {\n" +
+ " Class<?> clazz = Buggered.Foo.class;\n" +
+ " System.err.println(\"Here we go\");\n" +
+ " if (clazz.isAnonymousClass()) {\n" +
+ " System.err.println(\"is anon\");\n" +
+ " } else {\n" +
+ " System.err.println(\"not anon\");\n" +
+ " }\n" +
+ " }\n" +
+ "}\n",
+ "com/g/Base.java",
+ "package com.g;\n" +
+ "class Base2{}\n" +
+ "class Base {\n" +
+ " class A {}\n" +
+ " static class Builder<B extends Builder<B>> {\n" +
+ " public B setJobName() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public Base2 setJobName2(B b) {\n" +
+ " return null;\n" +
+ " }\n" +
+
+ // Wildcard
+ " public void foo(H<? super H<Base3.A>> h) {\n" +
+ " return;\n" +
+ " }\n" +
+ " private class H<T> {}\n" +
+ " }\n" +
+ " static class Builder2 {\n" +
+ " public <B extends Builder<B>> B setJobName3() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+ " static class R {}\n" +
+ " public static class Builder3<B extends R> {\n" +
+ " public B setJobName() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+ " public static class Builder4<B extends R> {\n" +
+ " public <Q extends R> Builder3<Q> setJobName() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+
+ // Testing Parameters
+ " static class Builder5 {\n" +
+ " public <B extends Builder<B>> void foo(B b) {}\n" +
+ " }\n" +
+
+ "}\n" +
+
+ "class Base3 {\n" +
+ " static class A{}\n" +
+ "}\n"
+ ,
+
+ "com/g/Child.java",
+ "package com.g;\n" +
+ "import com.g.Base.R;\n" +
+ "public final class Child {\n" +
+ " public static class Builder<I> extends Base.Builder<Builder<I>> {\n" +
+ " public void setDummyName(){}\n" +
+ " }\n" +
+ " public static class Builder2 extends Base.Builder2 {}\n" +
+ " public static class Builder3<I> extends Base.Builder3<R> {}\n" +
+ " public static class Builder4<I> extends Base.Builder4<R> {}\n" +
+
+ " public static class Builder5 extends Base.Builder5 {} \n" +
+ "}\n",
+ "com/n/Buggered.java",
+ "package com.n;\n" +
+ "import com.g.Child;\n" +
+ "class Z{}\n" +
+ "public final class Buggered {\n" +
+ " public static final class Foo {}\n" +
+ " void unused() {\n" +
+ " Child.Builder<Void> c = new Child.Builder<Void>();\n" +
+ " c.setJobName();\n" +
+ " c.setJobName2(new Child.Builder<Void>());\n" +
+ " Child.Builder<Z> cb = new Child.Builder<Z>();\n" +
+ " cb.setJobName();\n" +
+ " cb.setJobName2(new Child.Builder<Z>());\n" +
+ " Child.Builder2 cb2 = new Child.Builder2();\n" +
+ " cb2.setJobName3();\n" +
+ " Child.Builder3<Void> cb3 = new Child.Builder3<Void>();\n" +
+ " cb3.setJobName();\n" +
+ " Child.Builder4<Void> cb4 = new Child.Builder4<Void>();\n" +
+ " cb4.setJobName();\n" +
+
+ " Child.Builder5 cb5 = new Child.Builder5();\n" +
+ " cb5.foo(null);\n" +
+
+ // Wildcard
+ " c.foo(null);\n" +
+ " }\n" +
+ "}\n"
+ },
+ null, null,
+ "Here we go\n" +
+ "not anon\n" +
+ "Ok", null);
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
index eddb943..1c28ca2 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
@@ -782,6 +782,113 @@
"The blank final field value may not have been initialized\n" +
"----------\n");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
+// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
+public void testBug463526() {
+ runNegativeTest(new String [] {
+ "Test.java",
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " Receiver r = new Receiver();\n" +
+ " r.accept((l) -> (doItOnTheClass(new Object())));\n" +
+ " }\n" +
+ " public static void doItOnTheClass(Object o) {\n" +
+ " System.out.println(\"done it\");\n" +
+ " }\n" +
+ " public static class Receiver {\n" +
+ " public void accept(Listener l) {\n" +
+ " l.doIt(new Object());\n" +
+ " }\n" +
+ " }\n" +
+ " public static interface Listener {\n" +
+ " public void doIt(Object o);\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 4)\n" +
+ " r.accept((l) -> (doItOnTheClass(new Object())));\n" +
+ " ^^^^^^\n" +
+ "The method accept(Test.Listener) in the type Test.Receiver is not applicable for the arguments ((<no type> l) -> {})\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
+// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
+public void testBug463526b() {
+ runNegativeTest(new String [] {
+ "Test.java",
+ "import java.util.function.Consumer;\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " Receiver r = new Receiver();\n" +
+ " r.process((o) -> (new Object()));\n" +
+ " }\n" +
+ " public static class Receiver {\n" +
+ " public void process(Consumer<Object> p) {\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 5)\n" +
+ " r.process((o) -> (new Object()));\n" +
+ " ^^^^^^^\n" +
+ "The method process(Consumer<Object>) in the type Test.Receiver is not applicable for the arguments ((<no type> o) -> {})\n" +
+ "----------\n" +
+ "2. ERROR in Test.java (at line 5)\n" +
+ " r.process((o) -> (new Object()));\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Void methods cannot return a value\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
+// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
+public void testBug463526c() {
+ runNegativeTest(new String [] {
+ "Test.java",
+ "import java.util.function.Consumer;\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " Receiver r = new Receiver();\n" +
+ " r.assign((o) -> (o = new Object()));\n" +
+ " }\n" +
+ " public static class Receiver {\n" +
+ " public void assign(Consumer<Object> a) {\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 5)\n" +
+ " r.assign((o) -> (o = new Object()));\n" +
+ " ^^^^^^\n" +
+ "The method assign(Consumer<Object>) in the type Test.Receiver is not applicable for the arguments ((<no type> o) -> {})\n" +
+ "----------\n" +
+ "2. ERROR in Test.java (at line 5)\n" +
+ " r.assign((o) -> (o = new Object()));\n" +
+ " ^^^^^^^^^^^^^^^^^^\n" +
+ "Void methods cannot return a value\n" +
+ "----------\n");
+}
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=464408
+public void testBug464408() {
+ runNegativeTest(new String[]{
+ "test/X.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "public class X {\n" +
+ " void x() {\n" +
+ " List<List<String>> list = new ArrayList<>();\n" +
+ " list.stream().toArray(List<String>[]::new);\n" +
+ " }" +
+ "}"
+ }, "----------\n" +
+ "1. ERROR in test\\X.java (at line 6)\n" +
+ " list.stream().toArray(List<String>[]::new);\n" +
+ " ^^^^^^^^^^^^^^^^^^^\n" +
+ "Cannot create a generic array of List<String>\n" +
+ "----------\n");
+}
public static Class testClass() {
return LambdaRegressionTest.class;
}
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 b31d027..b97f570 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
@@ -8053,4 +8053,474 @@
true,
customOptions);
}
+public void testBug462790() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // multi catch used
+ runConformTestWithLibs(
+ new String[] {
+ "EclipseBug.java",
+ "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "public class EclipseBug {\n" +
+ "\n" +
+ " public void method(Class<? extends String> commandType) {\n" +
+ " String command = (String)getCommand(commandType);\n" +
+ " }\n" +
+ " \n" +
+ " public static <T extends String> T getCommand(Class<T> commandType) {\n" +
+ " try {\n" +
+ " return commandType.newInstance();\n" +
+ " } catch (InstantiationException | IllegalAccessException e) {\n" +
+ " throw new RuntimeException();\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in EclipseBug.java (at line 5)\n" +
+ " String command = (String)getCommand(commandType);\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Unnecessary cast from capture#1-of ? extends String to String\n" +
+ "----------\n" +
+ "2. WARNING in EclipseBug.java (at line 8)\n" +
+ " public static <T extends String> T getCommand(Class<T> commandType) {\n" +
+ " ^^^^^^\n" +
+ "The type parameter T should not be bounded by the final type String. Final types cannot be further extended\n" +
+ "----------\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8
+ ?
+ "3. WARNING in EclipseBug.java (at line 10)\n" +
+ " return commandType.newInstance();\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type \'T\' needs unchecked conversion to conform to \'@NonNull T\'\n" +
+ "----------\n"
+ :
+ ""));
+}
+public void testBug459967_Enum_valueOf() {
+ runConformTestWithLibs(
+ new String[] {
+ "MyEnum.java",
+ "public enum MyEnum { V1, V2 }\n",
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class X {\n" +
+ " @NonNull MyEnum forString(String name) {\n" +
+ " return MyEnum.valueOf(name);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+public void testBug459967_Enum_values() {
+ String[] testFiles = new String[] {
+ "MyEnum.java",
+ "public enum MyEnum { V1, V2 }\n",
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class X {\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8
+ ?
+ " @NonNull MyEnum[] getValues() {\n"
+ :
+ " MyEnum @NonNull[] getValues() {\n"
+ )+
+ " return MyEnum.values();\n" +
+ " }\n" +
+ " void printAll() {\n" +
+ " for (@NonNull MyEnum value : MyEnum.values())\n" +
+ " System.out.println(value);\n" +
+ " }\n" +
+ "}\n"
+ };
+ if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+ runConformTestWithLibs(
+ testFiles,
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in X.java (at line 7)\n" +
+ " for (@NonNull MyEnum value : MyEnum.values())\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type \'MyEnum\' needs unchecked conversion to conform to \'@NonNull MyEnum\'\n" +
+ "----------\n");
+ } else {
+ runConformTestWithLibs(
+ testFiles,
+ getCompilerOptions(),
+ "");
+ }
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=407414
+// Incorrect warning on a primitive type being null.
+public void test407414a() {
+ String testCode = "package p1;\n" +
+ "public class Test {\n" +
+ " void fooI(int i) { \n" +
+ " barI(i);\n" +
+ " }\n" +
+ " void fooB(boolean i) {\n" +
+ " barB(i);\n" +
+ " }\n" +
+ " void fooBy(byte i) {\n" +
+ " barBy(i);\n" +
+ " }\n" +
+ " void fooF(float i) {\n" +
+ " barF(i);\n" +
+ " }\n" +
+ " void fooL(long i) {\n" +
+ " barL(i);\n" +
+ " }\n" +
+ " void fooC(char i) {\n" +
+ " barC(i);\n" +
+ " }\n" +
+ " void fooS(short i) {\n" +
+ " barS(i);\n" +
+ " }\n" +
+ " static void barI(Integer i) {}\n" +
+ " static void barB(Boolean i) {}\n" +
+ " static void barBy(Byte i) {}\n" +
+ " static void barF(Float i) {}\n" +
+ " static void barL(Long i) {}\n" +
+ " static void barC(Character i) {}\n" +
+ " static void barS(Short i) {}\n" +
+ "}";
+ String pcode = "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=407414
+// Incorrect warning on a primitive type being null.
+// The information that boxing is happening at i2 = i
+// and therefore there cannot be null values in i2 is
+// not flowing down to access of i2.
+// The test case also illustrates array access and Qualified access.
+public void test407414b() {
+ String testCode = "package p1;\n" +
+ " public class Test {\n" +
+ " class Y {\n" +
+ " class Z {\n" +
+ " int i;\n" +
+ " int a[];\n" +
+ " Z() {\n" +
+ " a = new int[0];\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " void foo(int i) {\n" +
+ " Integer i2 = i;\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " void fooA(int a[], int i) {\n" +
+ " Integer i2 = a[i];\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " void fooQ(Y.Z yz, int i) {\n" +
+ " Integer i2 = yz.i;\n" +
+ " bar(i2);\n" +
+ " i2 = yz.a[i];\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " static void bar(Integer i) { }\n" +
+ "}";
+ String pcode = "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+public void test407414b2() {
+ String testCode = "package p1;\n" +
+ " public class Test {\n" +
+ " int a[];\n" +
+ " Test() {\n" +
+ " a = new int[0];\n" +
+ " a[0] = 0;\n" +
+ " }\n" +
+ " void fooA(int i) {\n" +
+ " Integer i2 = a[i];\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " static void bar(Integer i) { }\n" +
+ "}";
+ String pcode = "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// FieldReference.
+public void test407414b3() {
+ String testCode = "package p1;\n" +
+ "public class Test {\n" +
+ " class Z {\n" +
+ " int a[];\n" +
+ " Z() {\n" +
+ " a = new int[0];\n" +
+ " a[0] = 0;\n" +
+ " }\n" +
+ " }\n" +
+ " class Y {\n" +
+ " Z[] z;\n" +
+ " Y () {\n" +
+ " z = new Z[0];\n" +
+ " }\n" +
+ " }\n" +
+ " void fooQ(Y y, int i) {\n" +
+ " Integer i2 = y.z[i].a[i];\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " static void bar(Integer i) { }\n" +
+ "}";
+ String pcode = "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// arrayRefrence
+public void test407414b4() {
+ String testCode = "package p1;\n" +
+ "public class Test {\n" +
+ " class Y {\n" +
+ " int a[];\n" +
+ " Y() {\n" +
+ " a = new int[0];\n" +
+ " a[0] = 0;\n" +
+ " }\n" +
+ " }\n" +
+ " void fooQ(Y[] y, int i) {\n" +
+ " Integer i2 = y[i].a[i];\n" +
+ " bar(i2);\n" +
+ " }\n" +
+ " static void bar(Integer i) { }\n" +
+ "}";
+ String pcode = "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// value of a (compound) assignment
+public void testBug407414c() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " int fI;\n" +
+ " @org.eclipse.jdt.annotation.NonNull Integer test1(int i) {\n" +
+ " return fI = i;\n" +
+ " }\n" +
+ " @org.eclipse.jdt.annotation.NonNull Integer test2(int i) {\n" +
+ " return fI += i;\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// primitive cast
+public void testBug407414d() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test(int i) {\n" +
+ " return (long)i;\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// conditional
+public void testBug407414e() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test(long l, boolean b) {\n" +
+ " return b ? l : 3;\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// operators
+public void testBug407414f() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test1(long l) {\n" +
+ " return l + 3;\n" +
+ " }\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test2(long l) {\n" +
+ " return l << 3;\n" +
+ " }\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test3(long l) {\n" +
+ " return l++;\n" +
+ " }\n" +
+ " @org.eclipse.jdt.annotation.NonNull Long test4(long l) {\n" +
+ " return -l;\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=428104
+// Null annotation heuristics does not understand autoboxed primitives to be non-null.
+public void test428104() {
+ String testCode = "package p1;\n" +
+ "import org.eclipse.jdt.annotation.NonNull;\n" +
+ "public class Test {\n" +
+ " @NonNull\n" +
+ " Boolean case1Parent() {\n" +
+ " return case1Child();\n" +
+ " }\n" +
+ " boolean case1Child() {\n" +
+ " return Math.random() > 0.5;\n" +
+ " }\n" +
+ "}\n";
+ String pcode = "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=424702
+// Warning at an assignment of a boolean-Variable to an Boolean-Variable
+public void test424702() {
+ String testCode = "package p1;\n" +
+ "import org.eclipse.jdt.annotation.NonNull;\n" +
+ "public class Test {\n" +
+ " private @NonNull Boolean t = true;\n" +
+ " Boolean foo() {\n" +
+ " boolean y = false;\n" +
+ " t = y;\n" +
+ " return t;\n" +
+ " }\n" +
+ "}\n";
+ String pcode = "package p1;";
+ runConformTestWithLibs(
+ new String[] {
+ "p1/package-info.java",
+ pcode,
+ "p1/Test.java",
+ testCode
+ },
+ getCompilerOptions(),
+ "");
+}
+
+public void testBug237236() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "public class X {\n" +
+ " public void x(Long l) {}\n" +
+ " public long z() { return 0L; }\n" +
+ " public void y() { x(z()); }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+public void testBug418236() {
+ runConformTestWithLibs(
+ new String[] {
+ "MyClass.java",
+ "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "public class MyClass {\n" +
+ " private static final int CONSTANT = 24;\n" +
+ "\n" +
+ " public Integer returnConstant() {\n" +
+ " return CONSTANT; // <-- incorrect error. Integer.valueOf is declared as non-null.\n" +
+ " }\n" +
+ "\n" +
+ " public Integer returnInteger() {\n" +
+ " return 24; // <-- no error reported here\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+public void testBug461878() {
+ Map compilerOptions = getCompilerOptions();
+ compilerOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "javax.annotation.Nonnull");
+ runNegativeTest(
+ new String[] {
+ "javax/annotation/Nonnull.java",
+ "package javax.annotation;\n" +
+ "import java.lang.annotation.Retention;\n" +
+ "import java.lang.annotation.RetentionPolicy;\n" +
+ "@Retention(RetentionPolicy.RUNTIME)\n" +
+ "public @interface Nonnull {\n" +
+ "}\n",
+ "edu/umd/cs/findbugs/annotations/PossiblyNull.java",
+ "package edu.umd.cs.findbugs.annotations;\n" +
+ "@javax.annotation.Nonnull // <-- error!!!\n" +
+ "public @interface PossiblyNull {\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in edu\\umd\\cs\\findbugs\\annotations\\PossiblyNull.java (at line 2)\n" +
+ " @javax.annotation.Nonnull // <-- error!!!\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "The nullness annotation \'Nonnull\' is not applicable at this location\n" +
+ "----------\n",
+ null,
+ true,
+ compilerOptions);
+}
}
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 1e3fba1..cf625da 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
@@ -1212,7 +1212,7 @@
"1. ERROR in Y1.java (at line 5)\n" +
" X1<@Nullable String> maybeStrings;\n" +
" ^^^^^^^^^^^^^^^^\n" +
- "Null constraint mismatch: The type \'@Nullable String\' is not a valid substitute for the type parameter \'@NonNull T extends @NonNull Object\'\n" +
+ "Null constraint mismatch: The type \'@Nullable String\' is not a valid substitute for the type parameter \'T extends @NonNull Object\'\n" +
"----------\n" +
"2. ERROR in Y1.java (at line 6)\n" +
" X2<@NonNull String> strings;\n" +
@@ -1222,7 +1222,7 @@
"3. ERROR in Y1.java (at line 8)\n" +
" x.<Y1, @NonNull Object>foo(this, new Object());\n" +
" ^^^^^^^^^^^^^^^\n" +
- "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'@Nullable V extends @Nullable Object'\n" +
+ "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'V extends @Nullable Object'\n" +
"----------\n"
);
}
@@ -1288,7 +1288,7 @@
"1. ERROR in Y1.java (at line 3)\n" +
" p.X1<java.lang.@Nullable String> maybeStrings;\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Null constraint mismatch: The type \'@Nullable String\' is not a valid substitute for the type parameter \'@NonNull T extends @NonNull Object\'\n" +
+ "Null constraint mismatch: The type \'@Nullable String\' is not a valid substitute for the type parameter \'T extends @NonNull Object\'\n" +
"----------\n" +
"2. ERROR in Y1.java (at line 4)\n" +
" p.X2<java.lang.@NonNull String> strings;\n" +
@@ -1298,7 +1298,7 @@
"3. ERROR in Y1.java (at line 6)\n" +
" x.<Y1, java.lang.@NonNull Object>foo(this, new Object());\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'@Nullable V extends @Nullable Object\'\n" +
+ "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'V extends @Nullable Object\'\n" +
"----------\n"
);
}
@@ -1342,7 +1342,7 @@
"1. ERROR in Y1.java (at line 5)\n" +
" x.<@NonNull Y1, @NonNull Object>foo(this, new Object())\n" +
" ^^^^^^^^^^^^^^^\n" +
- "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'@Nullable V extends @Nullable Object\'\n" +
+ "Null constraint mismatch: The type \'@NonNull Object\' is not a valid substitute for the type parameter \'V extends @Nullable Object\'\n" +
"----------\n" +
"2. ERROR in Y1.java (at line 6)\n" +
" .get(0).put(null, null);\n" +
@@ -4860,7 +4860,12 @@
" ^^^^\n" +
"Null type mismatch: required \'@NonNull T\' but the provided value is null\n" +
"----------\n" +
- "2. ERROR in X.java (at line 11)\n" +
+ "2. ERROR in X.java (at line 10)\n" +
+ " void test(Inner<Number> inum) {\n" +
+ " ^^^^^^\n" +
+ "Null constraint mismatch: The type \'Number\' is not a valid substitute for the type parameter \'@NonNull T\'\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 11)\n" +
" @NonNull Number nnn = inum.process(null); // ERR on argument\n" +
" ^^^^\n" +
"Null type mismatch: required \'@NonNull Number\' but the provided value is null\n" +
@@ -4918,7 +4923,7 @@
" }\n" +
" }\n" +
" void test(Inner inner) {\n" +
- " @NonNull Number nnn = inner.process(Integer.MAX_VALUE, new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
+ " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
" }\n" +
"}\n"
},
@@ -4930,12 +4935,12 @@
"Null type mismatch: required \'T extends @NonNull Number\' but the provided value is null\n" +
"----------\n" +
"2. WARNING in X.java (at line 13)\n" +
- " @NonNull Number nnn = inner.process(Integer.MAX_VALUE, new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
- " ^^^^^^^^^^^^^^^^^\n" +
- "Null type safety (type annotations): The expression of type \'int\' needs unchecked conversion to conform to \'@NonNull Integer\'\n" +
+ " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
+ " ^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety (type annotations): The expression of type \'Integer\' needs unchecked conversion to conform to \'@NonNull Integer\'\n" +
"----------\n" +
"3. ERROR in X.java (at line 13)\n" +
- " @NonNull Number nnn = inner.process(Integer.MAX_VALUE, new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
+ " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Null type mismatch (type annotations): required \'List<? extends @NonNull Number>\' but this expression has type \'ArrayList<@Nullable Integer>\', corresponding supertype is \'List<@Nullable Integer>\'\n" +
"----------\n");
@@ -5187,16 +5192,16 @@
"import java.util.*;\n" +
"public class Y {\n" +
" void test(X.Inner inner) {\n" +
- " @NonNull Number nnn = inner.process(Integer.MAX_VALUE, new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
+ " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
" }\n" +
"}\n"
},
getCompilerOptions(),
"----------\n" + // FIXME: this should not be a warning, a case of unrecognized boxing
"1. WARNING in Y.java (at line 5)\n" +
- " @NonNull Number nnn = inner.process(Integer.MAX_VALUE, new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
- " ^^^^^^^^^^^^^^^^^\n" +
- "Null type safety (type annotations): The expression of type \'int\' needs unchecked conversion to conform to \'@NonNull Integer\'\n" +
+ " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" +
+ " ^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety (type annotations): The expression of type \'Integer\' needs unchecked conversion to conform to \'@NonNull Integer\'\n" +
"----------\n");
}
public void testBug431269() {
@@ -6984,7 +6989,7 @@
"5. ERROR in DoubleInference.java (at line 17)\n" +
" f2.a(null);\n" +
" ^^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'@NonNull @Nullable String a(@NonNull @Nullable String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'@Nullable @NonNull String a(@Nullable @NonNull String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n");
}
public void testBug446442_comment2a() {
@@ -7312,17 +7317,17 @@
" return x;\n" +
" };\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Contradictory null annotations: function type was inferred as \'ArrayList<@NonNull @Nullable Integer> (ArrayList<@NonNull @Nullable Integer>)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: function type was inferred as \'ArrayList<@NonNull @Nullable Integer> (ArrayList<@Nullable @NonNull Integer>)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n" +
"4. ERROR in Test.java (at line 17)\n" +
" x.add(null);\n" +
" ^^^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'boolean add(@NonNull @Nullable Integer)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'boolean add(@Nullable @NonNull Integer)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n" +
"5. ERROR in Test.java (at line 18)\n" +
" x.get(0);\n" +
" ^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'@NonNull @Nullable Integer get(int)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'@Nullable @NonNull Integer get(int)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n");
}
public void testBug453475() {
@@ -7532,7 +7537,7 @@
"2. ERROR in Optional.java (at line 5)\n" +
" public static <@NonNull T> Optional<T> of(T value) { return new Optional<T>(value); }\n" +
" ^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'void <init>(@NonNull @Nullable T)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'void <init>(@Nullable @NonNull T)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n" +
"3. ERROR in Optional.java (at line 5)\n" +
" public static <@NonNull T> Optional<T> of(T value) { return new Optional<T>(value); }\n" +
@@ -7548,12 +7553,12 @@
"2. ERROR in OTest.java (at line 6)\n" +
" @NonNull String s = os1.get();\n" +
" ^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'@NonNull @Nullable String get()\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'@Nullable @NonNull String get()\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n" +
"3. ERROR in OTest.java (at line 7)\n" +
" @Nullable String ns = os1.orElse(null);\n" +
" ^^^^^^^^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'@NonNull @Nullable String orElse(@NonNull @Nullable String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'@Nullable @NonNull String orElse(@Nullable @NonNull String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n" +
"4. ERROR in OTest.java (at line 10)\n" +
" Optional<String> os = Optional.of(null);\n" +
@@ -7568,7 +7573,7 @@
"6. ERROR in OTest.java (at line 11)\n" +
" @NonNull String s = os.orElse(null);\n" +
" ^^^^^^^^^^^^^^^\n" +
- "Contradictory null annotations: method was inferred as \'@NonNull @Nullable String orElse(@NonNull @Nullable String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "Contradictory null annotations: method was inferred as \'@Nullable @NonNull String orElse(@Nullable @NonNull String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n");
}
public void testBug454182() {
@@ -7739,4 +7744,171 @@
"1->2\n" +
"1->2");
}
+public void testBug459967_Array_constructor() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface FI<T> {\n" +
+ " T @NonNull[] getArray(int size);" +
+ "}\n" +
+ "public class X {\n" +
+ " void consumer(FI<String> fis) {}\n" +
+ " void test() {\n" +
+ " consumer(String[]::new);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+public void testBug459967_Array_constructor_b() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface FI<T> {\n" +
+ " @NonNull T @NonNull[] getArray(int size);" +
+ "}\n" +
+ "public class X {\n" +
+ " void consumer(FI<String> fis) {}\n" +
+ " void test() {\n" +
+ " consumer(String[]::new);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in X.java (at line 7)\n" +
+ " consumer(String[]::new);\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Null type safety at method return type: Method descriptor FI<String>.getArray(int) promises \'@NonNull String @NonNull[]\' but referenced method provides \'String @NonNull[]\'\n" +
+ "----------\n");
+}
+public void testBug459967_Array_clone() {
+ runConformTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface FI<T> {\n" +
+ " T @NonNull[] getArray(T[] orig);" +
+ "}\n" +
+ "public class X {\n" +
+ " void consumer(FI<String> fis) {}\n" +
+ " void test() {\n" +
+ " consumer(String[]::clone);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+public void testBug459967_Array_clone_b() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface FI<T> {\n" +
+ " @NonNull T @NonNull[] getArray(T[] orig);" +
+ "}\n" +
+ "public class X {\n" +
+ " void consumer(FI<String> fis) {}\n" +
+ " void test() {\n" +
+ " consumer(String[]::clone);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in X.java (at line 7)\n" +
+ " consumer(String[]::clone);\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "Null type safety at method return type: Method descriptor FI<String>.getArray(String[]) promises \'@NonNull String @NonNull[]\' but referenced method provides \'String @NonNull[]\'\n" +
+ "----------\n");
+}
+public void testBug448709_allocationExpression1() {
+ // inference prioritizes constraint (<@Nullable T>) over expected type (@NonNull String), hence a null type mismatch results
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface F0<T> {}\n" +
+ "class FI<@Nullable T> implements F0<T> {\n" +
+ "}\n" +
+ "public abstract class X {\n" +
+ " abstract <Z> Z zork(F0<Z> f);\n" +
+ " @NonNull String test() {\n" +
+ " return zork(new FI<>());\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " return zork(new FI<>());\n" +
+ " ^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'F0<@NonNull String>\' but this expression has type \'FI<@Nullable String>\', corresponding supertype is \'F0<@Nullable String>\'\n" +
+ "----------\n");
+}
+public void testBug448709_allocationExpression2() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "class F {\n" +
+ " <@Nullable U> F(U arg1, U arg2) {}\n" +
+ "}\n" +
+ "public class X {\n" +
+ " F f = new <@NonNull Integer>F(1,2);\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " F f = new <@NonNull Integer>F(1,2);\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Null constraint mismatch: The type \'@NonNull Integer\' is not a valid substitute for the type parameter \'@Nullable U\'\n" +
+ "----------\n");
+}
+public void testBug448709_allocationExpression3() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class X {\n" +
+ " class F {\n" +
+ " <@Nullable U> F(U arg1, U arg2) {}\n" +
+ " }\n" +
+ " F f = this.new <@NonNull Integer>F(1,2);\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " F f = this.new <@NonNull Integer>F(1,2);\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Null constraint mismatch: The type \'@NonNull Integer\' is not a valid substitute for the type parameter \'@Nullable U\'\n" +
+ "----------\n");
+}
+public void testBug465513() {
+ runConformTestWithLibs(
+ new String[] {
+ "pack1/A.java",
+ "package pack1;\r\n" +
+ "import java.math.BigInteger;\r\n" +
+ "\r\n" +
+ "interface A { Object m(Class c); }\r\n" +
+ "interface B<S extends Number> { Object m(Class<S> c); }\r\n" +
+ "interface C<T extends BigInteger> { Object m(Class<T> c); }\r\n" +
+ "@FunctionalInterface\r\n" +
+ "interface D<S,T> extends A, B<BigInteger>, C<BigInteger> {}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in pack1\\A.java (at line 4)\n" +
+ " interface A { Object m(Class c); }\n" +
+ " ^^^^^\n" +
+ "Class is a raw type. References to generic type Class<T> should be parameterized\n" +
+ "----------\n");
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java
index b622ff9..aaa5457 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java
@@ -49,7 +49,7 @@
"}\n";
static {
-// TESTS_NAMES = new String[] { "testBug415790" };
+// TESTS_NAMES = new String[] { "testBug462371_shouldWarn" };
// TESTS_NUMBERS = new int[] { 50 };
// TESTS_RANGE = new int[] { 11, -1 };
}
@@ -4850,4 +4850,587 @@
},
options);
}
+public void testBug371614_comment0() {
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runNegativeTest(
+ new String[] {
+ "C.java",
+ "import java.io.FileInputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.InputStream;\n" +
+ "\n" +
+ "public class C {\n" +
+ " public static void main(String[] args) {\n" +
+ " FileInputStream fileInputStream= null;\n" +
+ " try {\n" +
+ " fileInputStream = new FileInputStream(args[0]);\n" +
+ " while (true) {\n" +
+ " if (fileInputStream.read() == -1) {\n" +
+ " System.out.println(\"done\");\n" +
+ "// Resource leak: 'fileInputStream' is not closed at this location\n" +
+ " return;\n" +
+ " }\n" +
+ " }\n" +
+ " } catch (IOException e) {\n" +
+ " e.printStackTrace();\n" +
+ " return;\n" +
+ " } finally {\n" +
+ " closeStream(fileInputStream);\n" +
+ " }\n" +
+ " }\n" +
+ " \n" +
+ " private static void closeStream(InputStream stream) {\n" +
+ " if (stream != null) {\n" +
+ " try {\n" +
+ " stream.close();\n" +
+ " } catch (IOException e) {\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}\n" +
+ "\n"
+ },
+ "----------\n" +
+ "1. ERROR in C.java (at line 14)\n" +
+ " return;\n" +
+ " ^^^^^^^\n" +
+ "Potential resource leak: \'fileInputStream\' may not be closed at this location\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
+public void testBug371614_comment2() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "ResourceLeak.java",
+ "import java.io.FileInputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.InputStreamReader;\n" +
+ "import java.io.Reader;\n" +
+ "\n" +
+ "public class ResourceLeak {\n" +
+ "\n" +
+ " boolean check(final Reader r) throws IOException {\n" +
+ " final int i = r.read();\n" +
+ " return (i != -1);\n" +
+ " }\n" +
+ "\n" +
+ " public void test1() throws IOException {\n" +
+ " try (Reader r = new InputStreamReader(System.in);) {\n" +
+ " while (check(r)) {\n" +
+ " if (check(r))\n" +
+ " throw new IOException(\"fail\");\n" +
+ " if (!check(r))\n" +
+ " throw new IOException(\"fail\");\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public void test2() throws IOException {\n" +
+ " try (Reader r = new InputStreamReader(new FileInputStream(\"test.txt\"));) {\n" +
+ " while (check(r)) {\n" +
+ " if (check(r))\n" +
+ " throw new IOException(\"fail\");\n" +
+ " if (!check(r))\n" +
+ " throw new IOException(\"fail\");\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug371614_comment8() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "X.java",
+ "import java.io.*;\n" +
+ "import java.net.*;\n" +
+ "public class X {\n" +
+ " Socket fSocket;\n" +
+ " void test() {\n" +
+ " try (InputStreamReader socketIn = new InputStreamReader(fSocket.getInputStream())) {\n" +
+ " while (true) {\n" +
+ " if (socketIn.read(new char[1024]) < 0)\n" +
+ " throw new IOException(\"Error\");\n" +
+ " } \n" +
+ " } catch (IOException e) {\n" +
+ " }" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug462371_orig() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "X.java",
+ "import java.io.*;\n" +
+ "interface IFile {\n" +
+ " InputStream getContents();\n" +
+ " boolean exists();\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public static String getAnnotatedSignature(String typeName, IFile file, String selector, String originalSignature) {\n" +
+ " if (file.exists()) {\n" +
+ " try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents()))) {\n" +
+ " reader.readLine();\n" +
+ " while (true) {\n" +
+ " String line = reader.readLine(); \n" +
+ " // selector:\n" +
+ " if (selector.equals(line)) {\n" +
+ " // original signature:\n" +
+ " line = reader.readLine();\n" +
+ " if (originalSignature.equals(\"\")) {\n" +
+ " // annotated signature:\n" +
+ " return reader.readLine();\n" +
+ " }\n" +
+ " }\n" +
+ " if (line == null)\n" +
+ " break;\n" +
+ " }\n" +
+ " } catch (IOException e) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void _testBug462371_shouldWarn() {
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.io.*;\n" +
+ "interface IFile {\n" +
+ " InputStream getContents();\n" +
+ " boolean exists();\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public static String getAnnotatedSignature(String typeName, IFile file, String selector, String originalSignature) {\n" +
+ " if (file.exists()) {\n" +
+ " try {\n" +
+ " BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents())); \n" +
+ " reader.readLine();\n" +
+ " while (true) {\n" +
+ " String line = reader.readLine(); \n" +
+ " // selector:\n" +
+ " if (selector.equals(line)) {\n" +
+ " // original signature:\n" +
+ " line = reader.readLine();\n" +
+ " if (originalSignature.equals(\"\")) {\n" +
+ " // annotated signature:\n" +
+ " return reader.readLine();\n" +
+ " }\n" +
+ " }\n" +
+ " if (line == null)\n" +
+ " break;\n" +
+ " }\n" +
+ " } catch (IOException e) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in C.java (at line 14)\n" +
+ " return;\n" +
+ " ^^^^^^^\n" +
+ "Potential resource leak: \'fileInputStream\' may not be closed at this location\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
+public void testBug421035() {
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "Test.java",
+ "import java.io.BufferedReader;\n" +
+ "import java.io.FileNotFoundException;\n" +
+ "import java.io.FileReader;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.Reader;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " void test() throws FileNotFoundException {\n" +
+ " Reader a = (Reader)new BufferedReader(new FileReader(\"a\"));\n" +
+ " try {\n" +
+ " a.close();\n" +
+ " } catch (IOException e) {\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug444964() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "Bug444964.java",
+ "import java.io.*;\n" +
+ "\n" +
+ "public class Bug444964 {\n" +
+ " void wrong() {\n" +
+ " try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {\n" +
+ " for (;;) {\n" +
+ " return;\n" +
+ " }\n" +
+ " } catch (Exception e) {\n" +
+ " }\n" +
+ " }\n" +
+ " void right() {\n" +
+ " try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {\n" +
+ " while (true) {\n" +
+ " return;\n" +
+ " }\n" +
+ " } catch (Exception e) {\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug397204() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "HostIdTest.java",
+ "import java.io.*;\n" +
+ "import java.net.InetAddress;\n" +
+ "import java.net.NetworkInterface;\n" +
+ "import java.util.Enumeration;\n" +
+ "import java.util.Formatter;\n" +
+ "import java.util.Locale;\n" +
+ "\n" +
+ "\n" +
+ "public class HostIdTest {\n" +
+ "\n" +
+ " public final void primaryNetworkInterface() throws IOException {\n" +
+ " System.out.println(InetAddress.getLocalHost());\n" +
+ " System.out.println(InetAddress.getLocalHost().getHostName());\n" +
+ " System.out.println(hostId());\n" +
+ " }\n" +
+ "\n" +
+ " String hostId() throws IOException {\n" +
+ " try (StringWriter s = new StringWriter(); PrintWriter p = new PrintWriter(s)) {\n" +
+ " p.print(InetAddress.getLocalHost().getHostName());\n" +
+ " p.print('/');\n" +
+ " Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();\n" +
+ " while (e.hasMoreElements()) {\n" +
+ " NetworkInterface i = e.nextElement();\n" +
+ " System.out.println(i);\n" +
+ " if (i.getHardwareAddress() == null || i.getHardwareAddress().length == 0)\n" +
+ " continue;\n" +
+ " for (byte b : i.getHardwareAddress())\n" +
+ " p.printf(\"%02x\", b);\n" +
+ " return s.toString();\n" +
+ " }\n" +
+ " throw new RuntimeException(\"Unable to determine Host ID\");\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public void otherHostId() throws Exception {\n" +
+ " InetAddress addr = InetAddress.getLocalHost();\n" +
+ " byte[] ipaddr = addr.getAddress();\n" +
+ " if (ipaddr.length == 4) {\n" +
+ " int hostid = ipaddr[1] << 24 | ipaddr[0] << 16 | ipaddr[3] << 8 | ipaddr[2];\n" +
+ " StringBuilder sb = new StringBuilder();\n" +
+ " try (Formatter formatter = new Formatter(sb, Locale.US)) {\n" +
+ " formatter.format(\"%08x\", hostid);\n" +
+ " System.out.println(sb.toString());\n" +
+ " }\n" +
+ " } else {\n" +
+ " throw new Exception(\"hostid for IPv6 addresses not implemented yet\");\n" +
+ " }\n" +
+ " }\n" +
+ " \n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug397204_comment4() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "HostIdTest.java",
+ "import java.io.*;\n" +
+ "\n" +
+ "public class HostIdTest {\n" +
+ "\n" +
+ " void simple() throws Exception {\n" +
+ " try (InputStream x = new ByteArrayInputStream(null)) {\n" +
+ " while (Math.abs(1) == 1)\n" +
+ " if (Math.abs(1) == 1)\n" +
+ " return;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug433510() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // t-w-r used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runConformTest(
+ new String[] {
+ "Bug433510.java",
+ "import java.io.*;\n" +
+ "\n" +
+ "public class Bug433510 {\n" +
+ "\n" +
+ " void test() throws Exception {\n" +
+ " try (Reader r = new StringReader(\"Hello World!\")) {\n" +
+ " int c;\n" +
+ " while ((c = r.read()) != -1) {\n" +
+ " if (c == ' ')\n" +
+ " throw new IOException(\"Unexpected space\");\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ options);
+}
+public void testBug440282() {
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ runNegativeTest(
+ new String[] {
+ "ResourceLeakFalseNegative.java",
+ "import java.io.FileInputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.InputStreamReader;\n" +
+ "\n" +
+ "public final class ResourceLeakFalseNegative {\n" +
+ "\n" +
+ " private static final class Foo implements AutoCloseable {\n" +
+ " final InputStreamReader reader;\n" +
+ "\n" +
+ " Foo(final InputStreamReader reader) {\n" +
+ " this.reader = reader;\n" +
+ " }\n" +
+ " \n" +
+ " public int read() throws IOException {\n" +
+ " return reader.read();\n" +
+ " }\n" +
+ "\n" +
+ " public void close() throws IOException {\n" +
+ " reader.close();\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private static final class Bar {\n" +
+ " final int read;\n" +
+ "\n" +
+ " Bar(final InputStreamReader reader) throws IOException {\n" +
+ " read = reader.read();\n" +
+ " }\n" +
+ " \n" +
+ " public int read() {\n" +
+ " return read;\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public final static int foo() throws IOException {\n" +
+ " final FileInputStream in = new FileInputStream(\"/dev/null\");\n" +
+ " final InputStreamReader reader = new InputStreamReader(in);\n" +
+ " try {\n" +
+ " return new Foo(reader).read();\n" +
+ " } finally {\n" +
+ " // even though Foo is not closed, no potential resource leak is reported.\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public final static int bar() throws IOException {\n" +
+ " final FileInputStream in = new FileInputStream(\"/dev/null\");\n" +
+ " final InputStreamReader reader = new InputStreamReader(in);\n" +
+ " try {\n" +
+ " final Bar bar = new Bar(reader);\n" +
+ " return bar.read();\n" +
+ " } finally {\n" +
+ " // Removing the close correctly reports potential resource leak as a warning,\n" +
+ " // because Bar does not implement AutoCloseable.\n" +
+ " reader.close();\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public static void main(String[] args) throws IOException {\n" +
+ " for (;;) {\n" +
+ " foo();\n" +
+ " bar();\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in ResourceLeakFalseNegative.java (at line 39)\n" +
+ " return new Foo(reader).read();\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "Resource leak: \'<unassigned Closeable value>\' is never closed\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
+public void testBug390064() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5) return; // generics used
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.IGNORE);
+ runNegativeTest(
+ new String[] {
+ "Redundant.java",
+ "public class Redundant\n" +
+ "{\n" +
+ " private static class A<T> implements AutoCloseable\n" +
+ " {\n" +
+ " public void close()\n" +
+ " {\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private static class B extends A<Object>\n" +
+ " {\n" +
+ " \n" +
+ " }\n" +
+ " \n" +
+ " private static class C implements AutoCloseable\n" +
+ " {\n" +
+ " public void close()\n" +
+ " {\n" +
+ " }\n" +
+ " }\n" +
+ " \n" +
+ " private static class D extends C\n" +
+ " {\n" +
+ " \n" +
+ " }\n" +
+ " \n" +
+ " public static void main(String[] args)\n" +
+ " {\n" +
+ " new B();\n" +
+ " \n" +
+ " new D();\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Redundant.java (at line 29)\n" +
+ " new B();\n" +
+ " ^^^^^^^\n" +
+ "Resource leak: \'<unassigned Closeable value>\' is never closed\n" +
+ "----------\n" +
+ "2. ERROR in Redundant.java (at line 31)\n" +
+ " new D();\n" +
+ " ^^^^^^^\n" +
+ "Resource leak: \'<unassigned Closeable value>\' is never closed\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
+public void testBug396575() {
+ Map options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
+ options.put(CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.IGNORE);
+ runNegativeTest(
+ new String[] {
+ "Bug396575.java",
+ "import java.io.*;\n" +
+ "\n" +
+ "public class Bug396575 {\n" +
+ " void test1(File myFile) {\n" +
+ " OutputStream out = null;\n" +
+ " BufferedWriter bw = null;\n" +
+ " try {\n" +
+ " // code...\n" +
+ " out = new FileOutputStream(myFile);\n" +
+ " OutputStreamWriter writer = new OutputStreamWriter(out);\n" +
+ " bw = new BufferedWriter(writer);\n" +
+ " // more code...\n" +
+ " } catch (Exception e) {\n" +
+ " try {\n" +
+ " bw.close(); // WARN: potential null pointer access\n" +
+ " } catch (Exception ignored) {}\n" +
+ " return; // WARN: resource leak - bw may not be closed\n" +
+ " }\n" +
+ " }\n" +
+ " \n" +
+ " void test2(File myFile) {\n" +
+ " BufferedWriter bw = null;\n" +
+ " try {\n" +
+ " // code...\n" +
+ " // declare \"out\" here inside try-catch as a temp variable\n" +
+ " OutputStream out = new FileOutputStream(myFile); // WARN: out is never closed.\n" +
+ " OutputStreamWriter writer = new OutputStreamWriter(out);\n" +
+ " bw = new BufferedWriter(writer);\n" +
+ " // more code...\n" +
+ " } catch (Exception e) {\n" +
+ " try {\n" +
+ " bw.close(); // WARN: potential null pointer access\n" +
+ " } catch (Exception ignored) {}\n" +
+ " return; // WARN: resource leak - bw may not be closed\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Bug396575.java (at line 11)\n" +
+ " bw = new BufferedWriter(writer);\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Resource leak: \'bw\' is never closed\n" +
+ "----------\n" +
+ "2. ERROR in Bug396575.java (at line 28)\n" +
+ " bw = new BufferedWriter(writer);\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Resource leak: \'bw\' is never closed\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java
index 9c65b46..259c8ab 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2014 IBM Corporation and others.
+ * Copyright (c) 2010, 2015 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
@@ -21,6 +21,7 @@
import java.util.Map;
import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
@@ -349,6 +350,185 @@
fileY.delete();
}
}
+
+ /**
+ * @deprecated
+ * @throws IOException
+ */
+ public void testBug415066_001() throws IOException {
+ File rootDir = new File(System.getProperty("java.io.tmpdir"));
+ ASTParser parser = ASTParser.newParser(AST.JLS4);
+ parser.setEnvironment(null, null, null, true);
+ parser.setResolveBindings(true);
+ parser.setStatementsRecovery(true);
+ parser.setBindingsRecovery(true);
+ parser.setCompilerOptions(getCompilerOptions());
+
+ final String key = "Lp/C;";
+ final IBinding[] bindings = new IBinding[2];
+
+ String contents =
+ "package p;\n" +
+ "public class A{}\n" +
+ "class B{}";
+
+ File packageDir = new File(rootDir, "p");
+ packageDir.mkdir();
+ File file = new File(packageDir, "A.java");
+ Writer writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(file));
+ writer.write(contents);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ String contents2 =
+ "package p;\n" +
+ "public class C extends B {}";
+ File fileY = new File(packageDir, "C.java");
+ Writer writer2 = null;
+ try {
+ writer2 = new BufferedWriter(new FileWriter(fileY));
+ writer2.write(contents2);
+ } finally {
+ if (writer2 != null) {
+ try {
+ writer2.close();
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ try {
+ final String canonicalPath = fileY.getCanonicalPath();
+ final CompilationUnit[] units = new CompilationUnit[1];
+
+ FileASTRequestor requestor = new FileASTRequestor() {
+ public void acceptBinding(String bindingKey, IBinding binding) {
+ if (key.equals(bindingKey)) {
+ bindings[0] = binding;
+ IBinding[] temp = createBindings(new String[] {"Lp/C;"});
+ for (int i = 0; i < temp.length; ++i) {
+ bindings[i + 1] = temp[i];
+ }
+ }
+ }
+ public void acceptAST(String sourceFilePath, CompilationUnit ast) {
+ if (canonicalPath.equals(sourceFilePath)) {
+ units[0] = ast;
+ }
+ }
+ };
+
+ parser.setEnvironment(null, new String[] { rootDir.getCanonicalPath() }, null, true);
+ org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.MAX_AT_ONCE = 0;
+ parser.createASTs(new String[] {canonicalPath}, null, new String[] {key}, requestor, null);
+ assertNotNull("No ast", units[0]);
+ assertEquals("No problem", 0, units[0].getProblems().length);
+ } finally {
+ file.delete();
+ fileY.delete();
+ }
+ }
+
+ /**
+ * Negative test case
+ * @deprecated
+ * @throws IOException
+ */
+ public void testBug415066_002() throws IOException {
+ File rootDir = new File(System.getProperty("java.io.tmpdir"));
+ ASTParser parser = ASTParser.newParser(AST.JLS4);
+ parser.setEnvironment(null, null, null, true);
+ parser.setResolveBindings(true);
+ parser.setStatementsRecovery(true);
+ parser.setBindingsRecovery(true);
+ parser.setCompilerOptions(getCompilerOptions());
+
+ final String key = "Lp/C;";
+ final IBinding[] bindings = new IBinding[2];
+
+ String contents =
+ "package p;\n" +
+ "public class A{}\n" +
+ "class B{}";
+
+ File packageDir = new File(rootDir, "p");
+ packageDir.mkdir();
+ File file = new File(packageDir, "A.java");
+ Writer writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(file));
+ writer.write(contents);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ String contents2 =
+ "package q;\n" +
+ "import p.*;\n" +
+ "public class C extends B {}";
+ File fileY = new File(packageDir, "C.java");
+ Writer writer2 = null;
+ try {
+ writer2 = new BufferedWriter(new FileWriter(fileY));
+ writer2.write(contents2);
+ } finally {
+ if (writer2 != null) {
+ try {
+ writer2.close();
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ try {
+ final String canonicalPath = fileY.getCanonicalPath();
+ final CompilationUnit[] units = new CompilationUnit[1];
+
+ FileASTRequestor requestor = new FileASTRequestor() {
+ public void acceptBinding(String bindingKey, IBinding binding) {
+ if (key.equals(bindingKey)) {
+ bindings[0] = binding;
+ IBinding[] temp = createBindings(new String[] {"Lq/C;"});
+ for (int i = 0; i < temp.length; ++i) {
+ bindings[i + 1] = temp[i];
+ }
+ }
+ }
+ public void acceptAST(String sourceFilePath, CompilationUnit ast) {
+ if (canonicalPath.equals(sourceFilePath)) {
+ units[0] = ast;
+ }
+ }
+ };
+
+ parser.setEnvironment(null, new String[] { rootDir.getCanonicalPath() }, null, true);
+ parser.createASTs(new String[] {canonicalPath}, null, new String[] {key}, requestor, null);
+ assertNotNull("No ast", units[0]);
+ IProblem[] problems = units[0].getProblems();
+ assertEquals("No problem", 1, problems.length);
+ assertEquals("Pb(3) The type B is not visible", problems[0].toString());
+ } finally {
+ file.delete();
+ fileY.delete();
+ }
+ }
public void test7() throws IOException {
File rootDir = new File(System.getProperty("java.io.tmpdir"));
diff --git a/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF
index 6d16f79..100e1d5 100644
--- a/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.core.tests.model;singleton:=true
-Bundle-Version: 3.9.4.qualifier
+Bundle-Version: 3.10.0.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.jdt.core.tests,
diff --git a/org.eclipse.jdt.core.tests.model/pom.xml b/org.eclipse.jdt.core.tests.model/pom.xml
index 7f16f09..7d592ab 100644
--- a/org.eclipse.jdt.core.tests.model/pom.xml
+++ b/org.eclipse.jdt.core.tests.model/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core.tests.model</artifactId>
- <version>3.9.4-SNAPSHOT</version>
+ <version>3.10.0-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
index 9d4bd69..07e1a7a 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
@@ -27,6 +27,7 @@
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.core.ResolvedBinaryMethod;
@SuppressWarnings({"rawtypes"})
@@ -1579,7 +1580,8 @@
assertEquals("vlambda -> {\n return 200;\n}\n", lambdaExpression.toString());
assertTrue(lambdaExpression.parameters().size() == 1);
IMethodBinding binding = lambdaExpression.resolveMethodBinding();
- assertEquals("private static int lambda$0(int) ", binding.toString());
+ assertEquals("public int foo(int) ", binding.toString());
+ assertEquals("real modifiers", ClassFileConstants.AccPublic, binding.getModifiers());
VariableDeclaration variableDeclaration = (VariableDeclaration) lambdaExpression.parameters().get(0);
assertTrue(variableDeclaration instanceof VariableDeclarationFragment);
fragment = (VariableDeclarationFragment)variableDeclaration;
@@ -1614,7 +1616,8 @@
LambdaExpression lambdaExpression = (LambdaExpression)expression;
assertEquals("vlambda -> 200", lambdaExpression.toString());
IMethodBinding binding = lambdaExpression.resolveMethodBinding();
- assertEquals("private static int lambda$0(int) ", binding.toString());
+ assertEquals("public int foo(int) ", binding.toString());
+ assertEquals("real modifiers", ClassFileConstants.AccPublic, binding.getModifiers());
assertTrue(lambdaExpression.parameters().size() == 1);
VariableDeclaration variableDeclaration = (VariableDeclaration) lambdaExpression.parameters().get(0);
assertTrue(variableDeclaration instanceof VariableDeclarationFragment);
@@ -1648,7 +1651,8 @@
LambdaExpression lambdaExpression = (LambdaExpression)expression;
assertEquals("(int[] ia) -> {\n return ia.clone();\n}\n", lambdaExpression.toString());
IMethodBinding binding = lambdaExpression.resolveMethodBinding();
- assertEquals("private static java.lang.Object lambda$0(int[]) ", binding.toString());
+ assertEquals("public java.lang.Object foo(int[]) ", binding.toString());
+ assertEquals("real modifiers", ClassFileConstants.AccPublic, binding.getModifiers());
assertTrue(lambdaExpression.parameters().size() == 1);
VariableDeclaration variableDeclaration = (VariableDeclaration) lambdaExpression.parameters().get(0);
assertTrue(variableDeclaration instanceof SingleVariableDeclaration);
@@ -1690,7 +1694,8 @@
LambdaExpression lambdaExpression = (LambdaExpression)expression;
assertEquals("() -> {\n System.out.println(this);\n I j=() -> {\n System.out.println(this);\n I k=() -> {\n System.out.println(this);\n }\n;\n }\n;\n}\n", lambdaExpression.toString());
IMethodBinding binding = lambdaExpression.resolveMethodBinding();
- assertEquals("private void lambda$0() ", binding.toString());
+ assertEquals("public void doit() ", binding.toString());
+ assertEquals("real modifiers", ClassFileConstants.AccPublic, binding.getModifiers());
assertTrue(lambdaExpression.parameters().size() == 0);
}
@@ -1943,7 +1948,8 @@
LambdaExpression lambdaExpression = (LambdaExpression)expression;
assertEquals("() -> () -> 10", lambdaExpression.toString());
IMethodBinding binding = lambdaExpression.resolveMethodBinding();
- assertEquals("private static test399793.J lambda$0() ", binding.toString());
+ assertEquals("public test399793.J foo() ", binding.toString());
+ assertEquals("real modifiers", ClassFileConstants.AccPublic, binding.getModifiers());
assertTrue(lambdaExpression.parameters().size() == 0);
}
@@ -4938,7 +4944,7 @@
*
* @throws JavaModelException
*/
-public void _testBug425601_001() throws JavaModelException {
+public void testBug425601_001() throws JavaModelException {
this.workingCopy = getWorkingCopy("/Converter18/src/testBug425601_001/Outer.java",
true/* resolve */);
String contents = "package testBug425601_001;\n" +
@@ -4983,7 +4989,7 @@
*
* @throws JavaModelException
*/
-public void _testBug425601_002() throws JavaModelException {
+public void testBug425601_002() throws JavaModelException {
this.workingCopy = getWorkingCopy("/Converter18/src/testBug425601_002/Outer.java",
true/* resolve */);
String contents = "package testBug425601_002;\n" +
@@ -5137,4 +5143,53 @@
assertTrue("Test Failed", false);
}
}
+/**
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=429813
+ *
+ * @throws JavaModelException
+ */
+public void test429813() throws JavaModelException {
+ this.workingCopy = getWorkingCopy("/Converter18/src/test429813/Snippet.java",
+ true/* resolve */);
+ String contents = "package test429813;"
+ + "public class Snippet {\n"
+ + " Function<Integer, int[]> m1L = n -> new int[n];\n"
+ + "}"
+ + "interface Function<T, R> {\n"
+ + " public R apply(T t);\n"
+ + "}\n";
+ CompilationUnit cu = (CompilationUnit) buildAST(contents, this.workingCopy);
+ TypeDeclaration typedeclaration = (TypeDeclaration) getASTNode(cu, 0);
+ FieldDeclaration fieldDeclaration = (FieldDeclaration) typedeclaration.bodyDeclarations().get(0);
+ VariableDeclarationFragment fragment = (VariableDeclarationFragment)fieldDeclaration.fragments().get(0);
+ Expression expression = fragment.getInitializer();
+ assertTrue(expression instanceof LambdaExpression);
+ LambdaExpression lambdaExpression = (LambdaExpression)expression;
+ IMethodBinding binding = lambdaExpression.resolveMethodBinding();
+ IJavaElement element = binding.getJavaElement();
+ assertEquals("Not a method", IJavaElement.METHOD, element.getElementType());
+ assertFalse("Should not be a synthetic", binding.isSynthetic());
+}
+
+public void test429813a() throws JavaModelException {
+ this.workingCopy = getWorkingCopy("/Converter18/src/test429813/Snippet.java",
+ true/* resolve */);
+ String contents = "package test429813;"
+ + "interface FTest {\n"
+ + " Object foo (int[]... ints);\n"
+ + "};"
+ + "class TestX {"
+ + " FTest fi= ints -> null;\n"
+ + "}\n";
+ CompilationUnit cu = (CompilationUnit) buildAST(contents, this.workingCopy);
+ TypeDeclaration typedeclaration = (TypeDeclaration) getASTNode(cu, 1);
+ FieldDeclaration fieldDeclaration = (FieldDeclaration) typedeclaration.bodyDeclarations().get(0);
+ VariableDeclarationFragment fragment = (VariableDeclarationFragment)fieldDeclaration.fragments().get(0);
+ Expression expression = fragment.getInitializer();
+ assertTrue(expression instanceof LambdaExpression);
+ LambdaExpression lambdaExpression = (LambdaExpression)expression;
+ IMethodBinding binding = lambdaExpression.resolveMethodBinding();
+ assertTrue("Should be a varargs", binding.isVarargs());
+}
+
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java
index 0fd7a86..512b9fa 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2013 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 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
@@ -7,6 +7,10 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contributions for
+ * Bug 463330 - [dom] DOMFinder doesn't find the VariableBinding corresponding to a method argument
+ * Bug 464463 - [dom] DOMFinder doesn't find an ITypeParameter
+ * Bug 464615 - [dom] ASTParser.createBindings() ignores parameterization of a method invocation
*******************************************************************************/
package org.eclipse.jdt.core.tests.dom;
@@ -1062,6 +1066,36 @@
/*
* Ensures that the correct IBindings are created for a given set of IJavaElement
+ * (type parameter with bound)
+ */
+ public void testCreateBindings14a() throws JavaModelException {
+ IBinding[] bindings = createBindings(
+ "public class X<T extends java.lang.Number> {\n" +
+ "}",
+ this.workingCopy.getType("X").getTypeParameter("T")
+ );
+ assertBindingsEqual(
+ "LX;:TT;",
+ bindings);
+ }
+
+ /*
+ * Ensures that the correct IBindings are created for a given set of IJavaElement
+ * (type parameter with parameterized bound)
+ */
+ public void testCreateBindings14b() throws JavaModelException {
+ IBinding[] bindings = createBindings(
+ "public class X<T extends java.util.List<String>> {\n" +
+ "}",
+ this.workingCopy.getType("X").getTypeParameter("T")
+ );
+ assertBindingsEqual(
+ "LX;:TT;",
+ bindings);
+ }
+
+ /*
+ * Ensures that the correct IBindings are created for a given set of IJavaElement
* (binary type)
*/
public void testCreateBindings15() throws CoreException {
@@ -1222,6 +1256,83 @@
}
/*
+ * Ensures that the correct IBindings are created for a given set of IJavaElement
+ * (method arguments)
+ */
+ public void testCreateBindings25() throws JavaModelException {
+ this.workingCopy.getBuffer().setContents(
+ "public class X {\n" +
+ " void foo(String str, int i) {}\n" +
+ "}");
+ this.workingCopy.makeConsistent(null);
+ IMethod method = this.workingCopy.getType("X").getMethod("foo", new String[]{"QString;", "I"});
+ ASTParser parser = ASTParser.newParser(AST.JLS8);
+ parser.setProject(getJavaProject("P"));
+ IBinding[] bindings = parser.createBindings(method.getParameters(), null);
+ assertBindingsEqual(
+ "LX;.foo(Ljava/lang/String;I)V#str\n" +
+ "LX;.foo(Ljava/lang/String;I)V#i",
+ bindings);
+ }
+
+ /*
+ * Ensures that the correct IBindings are created for a given set of IJavaElement
+ * (binary method arguments)
+ */
+ public void testCreateBindings26() throws CoreException {
+ createClassFile("/P/lib", "A.class",
+ "public class A {\n" +
+ " void foo(String str, int i) {}\n" +
+ "}");
+ IMethod method = getClassFile("/P/lib/A.class").getType().getMethod("foo", new String[] {"Ljava.lang.String;", "I"});
+ ASTParser parser = ASTParser.newParser(AST.JLS8);
+ parser.setProject(getJavaProject("P"));
+ IBinding[] bindings = parser.createBindings(method.getParameters(), null);
+ assertBindingsEqual(
+ "LA;.foo(Ljava/lang/String;I)V#str\n" +
+ "LA;.foo(Ljava/lang/String;I)V#i",
+ bindings);
+ }
+
+ /*
+ * Ensures that the correct IBindings are created for a given set of IJavaElement
+ * (invocation of a generic method - binary)
+ */
+ public void testCreateBinding27() throws Exception {
+ createClassFile("/P/lib", "p/A.class",
+ "package p;\n" +
+ "public class A {\n" +
+ " public static <T> T foo(T[] arg) { return arg[0]; }\n" +
+ "}");
+ this.workingCopies = new ICompilationUnit[1];
+ String xSource = "public class X {\n" +
+ " public String test(String[] args) {\n" +
+ " return p.A.foo(args);\n" +
+ " }\n" +
+ "}";
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/X.java",
+ xSource,
+ this.wcOwner
+ );
+
+ IJavaElement elem= this.workingCopies[0].codeSelect(xSource.indexOf("foo"), 0)[0];
+ ASTParser parser = ASTParser.newParser(AST.JLS8);
+ parser.setProject(getJavaProject("P"));
+ IBinding[] bindings = parser.createBindings(new IJavaElement[]{ elem }, null);
+ assertBindingsEqual(
+ "Lp/A;.foo<T:Ljava/lang/Object;>([TT;)TT;%<Ljava/lang/String;>",
+ bindings);
+ IMethodBinding method = (IMethodBinding) bindings[0];
+ assertBindingsEqual(
+ "[Ljava/lang/String;",
+ method.getParameterTypes());
+ assertBindingsEqual(
+ "Ljava/lang/String;",
+ new IBinding[] {method.getReturnType()});
+ }
+
+ /*
* Ensures that the IJavaElement of an IBinding representing a field is correct.
*/
public void testField1() throws JavaModelException {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugs18Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugs18Tests.java
index b9559ec..f9dcb0a 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugs18Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugs18Tests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 IBM Corporation and others.
+ * Copyright (c) 2014, 2015 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
@@ -145,5 +145,96 @@
"}\n"
);
}
+public void testBug433177() throws Exception {
+ String source =
+ "interface Function<T, R> {\n" +
+ " R apply(T t);\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ "\n" +
+ " public Function<String, String> testOK() {\n" +
+ " return foo((s) -> {\n" +
+ " // nothing\n" +
+ " System.out.println(\"\");\n" +
+ " return \"\";\n" +
+ " });\n" +
+ " }\n" +
+ "\n" +
+ " public Function<String, String> testBad() {\n" +
+ " return this.foo((s) -> {\n" +
+ " // nothing\n" +
+ " System.out.println(\"\");\n" +
+ " return \"\";\n" +
+ " });\n" +
+ " }\n" +
+ "\n" +
+ " public Function<String, String> foo(Function<String, String> f) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "\n" +
+ " }\n";
+ String expected = "interface Function<T, R> {\n" +
+ " R apply(T t);\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ "\n" +
+ " public Function<String, String> testOK() {\n" +
+ " return foo((s) -> {\n" +
+ " // nothing\n" +
+ " System.out.println(\"\");\n" +
+ " return \"\";\n" +
+ " } );\n" +
+ " }\n" +
+ "\n" +
+ " public Function<String, String> testBad() {\n" +
+ " return this.foo((s) -> {\n" +
+ " // nothing\n" +
+ " System.out.println(\"\");\n" +
+ " return \"\";\n" +
+ " } );\n" +
+ " }\n" +
+ "\n" +
+ " public Function<String, String> foo(Function<String, String> f) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "\n" +
+ "}\n";
+
+ formatSource(source,expected);
+}
+public void testBug434821() throws Exception {
+ String source ="public class FormatterTest {\n"+
+ " public void doNothing() {\n"+
+ " new Thread(() -> {\n"+
+ " synchronized (this) {\n"+
+ " try {\n"+
+ " Thread.sleep(0); // blah\n"+
+ " } catch (final InterruptedException e2) {\n"+
+ " e2.printStackTrace();\n"+
+ " }\n"+
+ " }\n"+
+ "\n"+
+ " } ).start();\n"+
+ " }\n"+
+ "}\n";
+ String expected = "public class FormatterTest {\n"+
+ " public void doNothing() {\n"+
+ " new Thread(() -> {\n"+
+ " synchronized (this) {\n"+
+ " try {\n"+
+ " Thread.sleep(0); // blah\n"+
+ " } catch (final InterruptedException e2) {\n"+
+ " e2.printStackTrace();\n"+
+ " }\n"+
+ " }\n"+
+ "\n"+
+ " } ).start();\n"+
+ " }\n"+
+ "}\n";
+
+ formatSource(source,expected);
+}
}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
index c32d48a..8d214ac 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
@@ -10,6 +10,7 @@
* Ray V. (voidstar@gmail.com) - Contribution for bug 282988
* Robin Stocker - Bug 49619 - [formatting] comment formatter leaves whitespace in comments
* Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] IndexOutOfBoundsException in TokenManager - https://bugs.eclipse.org/462945
*******************************************************************************/
package org.eclipse.jdt.core.tests.formatter;
@@ -10640,4 +10641,84 @@
// K_COMPILATION_UNIT is tested by FormatterRegressionTests#test512() and #test643()
}
+/**
+ * @bug 462945 - [formatter] IndexOutOfBoundsException in TokenManager
+ * @test no exception is thrown for malformed code
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=462945"
+ */
+public void testBug462945() throws Exception {
+ String source =
+ "package p1;\n" +
+ "enum ReviewResult {\n" +
+ " Good{, Bad\n" +
+ "}\n";
+ formatSource(source,
+ "package p1;\n" +
+ "\n" +
+ "enum ReviewResult {\n" +
+ " Good{, Bad\n" +
+ "}\n"
+ );
+}
+public void testBug407629() throws Exception {
+ String source =
+ "public class X {\n" +
+ " /**\n" +
+ " * Builds a {@link Level}.\n" +
+ " * <p>\n" +
+ " * Does <b>not</b> set :\n" +
+ " * <ul>\n" +
+ " * <li>{@link Level#setA(Boolean)</li>\n" +
+ " * <li>{@link Level#setB(Long)}</li>\n" +
+ " * <li>{@link Level#setC(Integer)}</li>\n" +
+ " * </ul>\n" +
+ " * </p>\n" +
+ " */\n" +
+ " public static Level buildLevel() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Level {\n" +
+ " void setA(Boolean b) {}\n" +
+ " void setB(Long l) {}\n" +
+ " void setC(Integer i){}\n" +
+ "}\n";
+ String expected = "public class X {\n" +
+ " /**\n" +
+ " * Builds a {@link Level}.\n" +
+ " * <p>\n" +
+ " * Does <b>not</b> set :\n" +
+ " * <ul>\n" +
+ " * <li>{@link Level#setA(Boolean)</li>\n" +
+ " * <li>{@link Level#setB(Long)}</li>\n" +
+ " * <li>{@link Level#setC(Integer)}</li>\n" +
+ " * </ul>\n" +
+ " * </p>\n" +
+ " */\n" +
+ " public static Level buildLevel() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "\n" +
+ "}\n" +
+ "\n" +
+ "class Level {\n" +
+ " void setA(Boolean b) {\n" +
+ " }\n" +
+ "\n" +
+ " void setB(Long l) {\n" +
+ " }\n" +
+ "\n" +
+ " void setC(Integer i) {\n" +
+ " }\n" +
+ "}\n";
+ formatSource(source, expected);
+}
+
+public void testBug464312() throws Exception {
+ String source = "/**/int f;";
+ formatSource(source, source, CodeFormatter.K_STATEMENTS);
+}
+
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
index eaffd2b..adbde74 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
@@ -66,6 +66,7 @@
static {
// TESTS_NUMBERS = new int[] { 783 };
// TESTS_RANGE = new int[] { 734, -1 };
+// TESTS_NAMES = new String[] {"testBug432593"};
}
public static Test suite() {
return buildModelTestSuite(FormatterRegressionTests.class);
@@ -13053,4 +13054,25 @@
"}\n"
);
}
+
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=432593
+public void testBug432593() throws IOException {
+ ICompilationUnit sourceUnit;
+ try {
+ sourceUnit = getCompilationUnit("Formatter" , "", "test432593", getIn("A.java"));
+ String src = sourceUnit.getSource();
+ assertNotNull(src);
+ String source = src.toString();
+ final Map options = JavaCore.getOptions();
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5);
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5);
+ options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5);
+ final CodeFormatter codeFormatter = ToolFactory.createCodeFormatter(options);
+ final TextEdit edit = codeFormatter.format(CodeFormatter.K_COMPILATION_UNIT, source, 0, source.length(), 0, "\r\n");
+ assertTrue(edit != null);
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+}
+
}
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 3806875..a04e279 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
@@ -1013,6 +1013,22 @@
assertTrue("Element should not be present after deletion: " + elementToDelete, !elementToDelete.exists());
}
}
+ protected void assertDeltas(String message, String expected, DeltaListener listener) {
+ assertDeltas(message, expected, expected.length() > 0/*wait for resource delta iff a delta is expected*/, listener);
+ }
+ protected void assertDeltas(String message, String expected, boolean waitForResourceDelta, DeltaListener listener) {
+ if (waitForResourceDelta)
+ listener.waitForResourceDelta();
+ String actual = listener.toString();
+ if (!expected.equals(actual)) {
+ System.out.println(displayString(actual, 2));
+ System.err.println(listener.stackTraces());
+ }
+ assertEquals(
+ message,
+ expected,
+ actual);
+ }
protected void assertDeltas(String message, String expected) {
assertDeltas(message, expected, expected.length() > 0/*wait for resource delta iff a delta is expected*/);
}
@@ -1131,6 +1147,9 @@
/**
* Empties the current deltas.
*/
+ public void clearDeltas(DeltaListener listener) {
+ listener.flush();
+ }
public void clearDeltas() {
this.deltaListener.flush();
}
@@ -2993,6 +3012,22 @@
/**
* Starts listening to element deltas, and queues them in fgDeltas.
*/
+ public void startDeltas(DeltaListener listener) {
+ clearDeltas(listener);
+ JavaCore.addElementChangedListener(listener);
+ getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
+ }
+ /**
+ * Stops listening to element deltas, and clears the current deltas.
+ */
+ public void stopDeltas(DeltaListener listener) {
+ getWorkspace().removeResourceChangeListener(listener);
+ JavaCore.removeElementChangedListener(listener);
+ clearDeltas(listener);
+ }
+ /**
+ * Starts listening to element deltas, and queues them in fgDeltas.
+ */
public void startDeltas() {
clearDeltas();
JavaCore.addElementChangedListener(this.deltaListener);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
index 5b178dc..970c74f 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
@@ -7213,7 +7213,7 @@
map = proj1.getOptions(false);
map.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_1);
proj1.setOptions(map);
-
+ waitForManualRefresh();
assertMarkers("Unexpected markers",
"Incompatible .class files version in required binaries. Project \'P1\' is targeting a 1.1 runtime, but is compiled against \'P1/abc.jar\' which requires a 1.4 runtime", proj1);
eclipsePreferences.removePreferenceChangeListener(prefListener);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
index ac5f4d8..9d47a59 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 IBM Corporation and others.
+ * Copyright (c) 2014, 2015 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
@@ -931,7 +931,10 @@
String completeBehind = "try";
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
- assertResults("tryit[LOCAL_VARIABLE_REF]{tryit, null, I, null, null, tryit, null, [99, 102], 27}", requestor.getResults());
+ assertResults(
+ "tryit[LOCAL_VARIABLE_REF]{tryit, null, I, null, null, tryit, null, [99, 102], 27}\n" +
+ "try[KEYWORD]{try, null, null, null, null, try, null, [99, 102], 28}",
+ requestor.getResults());
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422901, [1.8][code assist] Code assistant sensitive to scope.referenceContext type identity.
public void test422901() throws JavaModelException {
@@ -2334,4 +2337,109 @@
"localmethod2[METHOD_REF]{localmethod2(), LLambdaBug;, ()V, null, null, localmethod2, null, [282, 291], 17}", requestor.getResults());
}
+public void testBug459189_001() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n"+
+ " Integer foo(){\n"+
+ " I <Integer, X> i2 = (x) -> {ret /* type ctrl-space after ret */};\n"+
+ " return 0;\n"+
+ " }\n"+
+ " Integer bar(Integer x) { return null;}\n"+
+ "}\n"+
+ "interface I <T,R> {\n"+
+ " R apply(T t);\n"+
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "ret";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "Retention[TYPE_REF]{java.lang.annotation.Retention, java.lang.annotation, Ljava.lang.annotation.Retention;, null, null, 14}\n"+
+ "RetentionPolicy[TYPE_REF]{java.lang.annotation.RetentionPolicy, java.lang.annotation, Ljava.lang.annotation.RetentionPolicy;, null, null, 14}\n"+
+ "return[KEYWORD]{return, null, null, return, null, 24}",
+ requestor.getResults());
+}
+public void testBug459189_002() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ " Integer bar(Integer x) { return null;}\n"+
+ "public class X {\n"+
+ " Integer foo(){\n"+
+ " I <Integer, X> i2 = (x) -> {/* HERE */ret /* type ctrl-space after ret */};\n"+
+ " return 0;\n"+
+ " }\n"+
+ "}\n"+
+ "interface I <T,R> {\n"+
+ " R apply(T t);\n"+
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "/* HERE */ret";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "Retention[TYPE_REF]{java.lang.annotation.Retention, java.lang.annotation, Ljava.lang.annotation.Retention;, null, null, 14}\n"+
+ "RetentionPolicy[TYPE_REF]{java.lang.annotation.RetentionPolicy, java.lang.annotation, Ljava.lang.annotation.RetentionPolicy;, null, null, 14}\n" +
+ "return[KEYWORD]{return, null, null, return, null, 24}",
+ requestor.getResults());
+}
+public void testBug459189_003() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n"+
+ " Integer foo(){\n"+
+ " I <Integer, X> i2 = (x) -> {try{} /* HERE */\n"+
+ " return 0;\n"+
+ " }\n"+
+ " Integer bar(Integer x) { return null;}\n"+
+ "}\n"+
+ "interface I <T,R> {\n"+
+ " R apply(T t);\n"+
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "/* HERE */";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "catch[KEYWORD]{catch, null, null, catch, null, 24}\n"+
+ "finally[KEYWORD]{finally, null, null, finally, null, 24}",
+ requestor.getResults());
+}
+public void testBug459189_004() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n"+
+ " Integer foo(){\n"+
+ " I <Integer, X> i2 = (x) -> {do{} /* HERE */\n"+
+ " return 0;\n"+
+ " }\n"+
+ " Integer bar(Integer x) { return null;}\n"+
+ "}\n"+
+ "interface I <T,R> {\n"+
+ " R apply(T t);\n"+
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "/* HERE */";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "while[KEYWORD]{while, null, null, while, null, 24}",
+ requestor.getResults());
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveElementsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveElementsTests.java
index ce59caf..d3fd949 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveElementsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveElementsTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -54,14 +54,13 @@
// TESTS_RANGE = new int[] { 21, 38 };
}
public static Test suite() {
- return buildModelTestSuite(CopyMoveElementsTests.class);
+ return buildModelTestSuite(CopyMoveElementsTests.class, BYTECODE_DECLARATION_ORDER);
}
/**
* Cleanup after the previous test.
*/
public void tearDown() throws Exception {
this.deleteProject("P");
-
super.tearDown();
}
public void tearDownSuite() throws Exception {
@@ -394,9 +393,9 @@
}
dests[1] = fieldsSource[0]; //invalid destination
dests[2]= fieldsSource[0];
-
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
boolean e= false;
try {
typeDest.getJavaModel().copy(fieldsSource, dests, null, null, false, null);
@@ -415,18 +414,19 @@
" Y.java[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" Y[*]: {CHILDREN | FINE GRAINED}\n" +
" foo[+]: {}"
- );
+ , listener);
IJavaElement copy= generateHandle(fieldsSource[0], null, typeDest);
assertTrue("Copy should exist", copy.exists());
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
/**
* Ensures that a multi status exception is generated when copying fields.
*/
public void testCopyFieldsMultiStatusInDifferentProject() throws CoreException {
+ DeltaListener listener = new DeltaListener();
try {
this.createFile(
"/P/src/X.java",
@@ -454,7 +454,7 @@
dests[1] = fieldsSource[0]; //invalid destination
dests[2]= fieldsSource[0];
- startDeltas();
+ startDeltas(listener);
boolean e= false;
try {
typeDest.getJavaModel().copy(fieldsSource, dests, null, null, false, null);
@@ -473,12 +473,12 @@
" Y.java[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" Y[*]: {CHILDREN | FINE GRAINED}\n" +
" foo[+]: {}"
- );
+ , listener);
IJavaElement copy= generateHandle(fieldsSource[0], null, typeDest);
assertTrue("Copy should exist", copy.exists());
} finally {
- stopDeltas();
+ stopDeltas(listener);
this.deleteProject("P2");
}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
index 0a4f576..076c201 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -33,8 +33,9 @@
* encountered are thrown.
*/
public IJavaElement copyPositive(IJavaElement element, IJavaElement container, IJavaElement sibling, String rename, boolean force) throws JavaModelException {
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
// if forcing, ensure that a name collision exists
if (force) {
@@ -78,7 +79,7 @@
assertTrue("Did not find package decl", found);
}
}
- IJavaElementDelta destDelta = this.deltaListener.getDeltaFor(container, true);
+ IJavaElementDelta destDelta = listener.getDeltaFor(container, true);
assertTrue("Destination container not changed", destDelta != null && destDelta.getKind() == IJavaElementDelta.CHANGED);
IJavaElementDelta[] deltas = null;
if (force) {
@@ -96,7 +97,7 @@
assertTrue("Added children not correct for element copy", found);
return copy;
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
@@ -106,8 +107,9 @@
* encountered are thrown.
*/
public void movePositive(IJavaElement[] elements, IJavaElement[] destinations, IJavaElement[] siblings, String[] names, boolean force, IProgressMonitor monitor) throws JavaModelException {
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
// if forcing, ensure that a name collision exists
int i;
@@ -169,14 +171,14 @@
}
IJavaElementDelta destDelta = null;
if (isMainType(element, destinations[i]) && names != null && names[i] != null) { //moved/renamed main type to same cu
- destDelta = this.deltaListener.getDeltaFor(moved.getParent());
+ destDelta = listener.getDeltaFor(moved.getParent());
assertTrue("Renamed compilation unit as result of main type not added", destDelta != null && destDelta.getKind() == IJavaElementDelta.ADDED);
IJavaElementDelta[] deltas = destDelta.getAddedChildren();
assertTrue("Added children not correct for element copy", deltas[0].getElement().equals(moved));
assertTrue("flag should be F_MOVED_FROM", (deltas[0].getFlags() & IJavaElementDelta.F_MOVED_FROM) > 0);
assertTrue("moved from handle should be original", deltas[0].getMovedFromElement().equals(element));
} else {
- destDelta = this.deltaListener.getDeltaFor(destinations[i], true);
+ destDelta = listener.getDeltaFor(destinations[i], true);
assertTrue("Destination container not changed", destDelta != null && destDelta.getKind() == IJavaElementDelta.CHANGED);
IJavaElementDelta[] deltas = destDelta.getAddedChildren();
for (int j = 0; j < deltas.length - 1; j++) {
@@ -189,12 +191,12 @@
assertTrue("Added children not correct for element copy", pkgDelta.getElement().equals(moved));
assertTrue("flag should be F_MOVED_FROM", (pkgDelta.getFlags() & IJavaElementDelta.F_MOVED_FROM) > 0);
assertTrue("moved from handle shoud be original", pkgDelta.getMovedFromElement().equals(element));
- IJavaElementDelta sourceDelta = this.deltaListener.getDeltaFor(element, true);
+ IJavaElementDelta sourceDelta = listener.getDeltaFor(element, true);
assertTrue("moved to handle should be original", sourceDelta.getMovedToElement().equals(moved));
}
}
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
/**
@@ -815,6 +817,7 @@
* existing CU.
*/
public void testMoveCU03() throws CoreException {
+ DeltaListener listener = new DeltaListener();
try {
this.createFolder("/P/src/p1");
this.createFile(
@@ -833,7 +836,7 @@
"}"
);
IPackageFragment pkgDest = getPackage("/P/src/p2");
- startDeltas();
+ startDeltas(listener);
movePositive(new IJavaElement[] {cuSource}, new IJavaElement[] {pkgDest}, null, null, true, false, null);
assertDeltas(
"Incorrect delta",
@@ -842,10 +845,10 @@
+ " p1[*]: {CHILDREN}\n"
+ " X.java[-]: {MOVED_TO(X.java [in p2 [in src [in P]]])}\n"
+ " p2[*]: {CHILDREN}\n"
- + " X.java[*]: {CONTENT | PRIMARY RESOURCE}");
+ + " X.java[*]: {CONTENT | PRIMARY RESOURCE}", listener);
}
finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
/**
@@ -872,6 +875,7 @@
* be renamed, overwriting an existing resource.
*/
public void testMoveCU05() throws CoreException {
+ DeltaListener listener = new DeltaListener();
try {
this.createFolder("/P/src/p1");
this.createFile(
@@ -890,7 +894,7 @@
"}"
);
IPackageFragment pkgDest = getPackage("/P/src/p2");
- startDeltas();
+ startDeltas(listener);
movePositive(new IJavaElement[] {cuSource}, new IJavaElement[] {pkgDest}, null, new String[]{"Y.java"}, true, false, null);
assertDeltas(
"Incorrect delta",
@@ -900,10 +904,10 @@
+ " X.java[-]: {MOVED_TO(Y.java [in p2 [in src [in P]]])}\n"
+ " p2[*]: {CHILDREN}\n"
+ " Y.java[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n"
- + " Y[+]: {MOVED_FROM(X [in X.java [in p1 [in src [in P]]]])}");
+ + " Y[+]: {MOVED_FROM(X [in X.java [in p1 [in src [in P]]]])}", listener);
}
finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
/**
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveTests.java
index 8832d85..1ec3a80 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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,10 +59,10 @@
IJavaElement collision = generateHandle(element, rename, container);
assertTrue("Collision does not exist", collision.exists());
}
-
+ DeltaListener listener = new DeltaListener();
IJavaElement copy;
try {
- startDeltas();
+ startDeltas(listener);
// copy
((ISourceManipulation) element).copy(container, sibling, rename, force, null);
@@ -106,12 +106,12 @@
}
if (copy.getElementType() == IJavaElement.IMPORT_DECLARATION)
container = ((ICompilationUnit) container).getImportContainer();
- IJavaElementDelta destDelta = this.deltaListener.getDeltaFor(container, true);
+ IJavaElementDelta destDelta = listener.getDeltaFor(container, true);
assertTrue("Destination container not changed", destDelta != null && destDelta.getKind() == IJavaElementDelta.CHANGED);
IJavaElementDelta[] deltas = destDelta.getAddedChildren();
assertTrue("Added children not correct for element copy", deltas[0].getElement().equals(copy));
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
return copy;
}
@@ -276,9 +276,9 @@
assertTrue("Collision does not exist", collision.exists());
}
}
-
+ DeltaListener listener = new DeltaListener();
try {
- if(checkDelta) startDeltas();
+ if(checkDelta) startDeltas(listener);
// move
getJavaModel().move(elements, destinations, siblings, names, force, monitor);
@@ -347,23 +347,23 @@
if(checkDelta) {
IJavaElementDelta destDelta = null;
if (isMainType(element, destinations[i]) && names != null && names[i] != null) { //moved/renamed main type to same cu
- destDelta = this.deltaListener.getDeltaFor(moved.getParent());
+ destDelta = listener.getDeltaFor(moved.getParent());
assertTrue("Renamed compilation unit as result of main type not added", destDelta != null && destDelta.getKind() == IJavaElementDelta.ADDED);
assertTrue("flag should be F_MOVED_FROM", (destDelta.getFlags() & IJavaElementDelta.F_MOVED_FROM) > 0);
assertTrue("moved from handle should be original", destDelta.getMovedFromElement().equals(element.getParent()));
} else {
- destDelta = this.deltaListener.getDeltaFor(destinations[i], true);
+ destDelta = listener.getDeltaFor(destinations[i], true);
assertTrue("Destination container not changed", destDelta != null && destDelta.getKind() == IJavaElementDelta.CHANGED);
IJavaElementDelta[] deltas = destDelta.getAddedChildren();
assertTrue("Added children not correct for element copy", deltas[i].getElement().equals(moved));
assertTrue("should be K_ADDED", deltas[i].getKind() == IJavaElementDelta.ADDED);
- IJavaElementDelta sourceDelta= this.deltaListener.getDeltaFor(element, false);
+ IJavaElementDelta sourceDelta= listener.getDeltaFor(element, false);
assertTrue("should be K_REMOVED", sourceDelta.getKind() == IJavaElementDelta.REMOVED);
}
}
}
} finally {
- if(checkDelta) stopDeltas();
+ if(checkDelta) stopDeltas(listener);
}
}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations17Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations17Test.java
index a9eef33..cd1e1f2 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations17Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations17Test.java
@@ -108,6 +108,52 @@
}
}
+ public void test1Full_ProjectRoot() throws Exception {
+ // cf. testLibsWithFields but with annotations at the project root:
+ myCreateJavaProject("TestLibs");
+ addLibraryWithExternalAnnotations(this.project, "lib1.jar", "/TestLibs", new String[] {
+ "/UnannotatedLib/libs/Lib1.java",
+ "package libs;\n" +
+ "\n" +
+ "public interface Lib1 {\n" +
+ " String one = \"1\";\n" +
+ " String none = null;\n" +
+ "}\n"
+ }, null);
+ createFileInProject("libs", "Lib1.eea",
+ "class libs/Lib1\n" +
+ "\n" +
+ "one\n" +
+ " Ljava/lang/String;\n" +
+ " L1java/lang/String;\n" +
+ "\n" +
+ "none\n" +
+ " Ljava/lang/String;\n" +
+ " L0java/lang/String;\n" +
+ "\n");
+ IPackageFragment fragment = this.project.getPackageFragmentRoots()[0].createPackageFragment("tests", true, null);
+ ICompilationUnit unit = fragment.createCompilationUnit("Test1.java",
+ "package tests;\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "import libs.Lib1;\n" +
+ "\n" +
+ "public class Test1 {\n" +
+ " @NonNull String test0() {\n" +
+ " return Lib1.none;\n" +
+ " }\n" +
+ " @NonNull String test1() {\n" +
+ " return Lib1.one;\n" +
+ " }\n" +
+ "}\n",
+ true, new NullProgressMonitor()).getWorkingCopy(new NullProgressMonitor());
+ CompilationUnit reconciled = unit.reconcile(AST.JLS8, true, null, new NullProgressMonitor());
+ IProblem[] problems = reconciled.getProblems();
+ assertProblems(problems, new String[] {
+ "Pb(933) Null type mismatch: required '@NonNull String' but the provided value is specified as @Nullable",
+ }, new int[] { 8 });
+ }
+
/** Reconcile an individual CU. */
public void test1Reconcile() throws Exception {
setupJavaProject("Test1");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
index 059530b..a5b6fd3 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
@@ -717,9 +717,9 @@
"Pb(953) Null type mismatch (type annotations): required '@NonNull String' but this expression has type '@Nullable String'",
"Pb(964) Null constraint mismatch: The type '@NonNull String' is not a valid substitute for the type parameter '@Nullable U extends Object'",
"Pb(964) Null constraint mismatch: The type 'String' is not a valid substitute for the type parameter '@NonNull V extends Object'",
- "Pb(964) Null constraint mismatch: The type '@Nullable String' is not a valid substitute for the type parameter '@NonNull W extends @NonNull U extends Object'", // FIXME(stephan): @NonNull before W is bogus, see https://bugs.eclipse.org/456532
+ "Pb(964) Null constraint mismatch: The type '@Nullable String' is not a valid substitute for the type parameter 'W extends @NonNull U extends Object'",
"Pb(964) Null constraint mismatch: The type '@Nullable String' is not a valid substitute for the type parameter '@NonNull X extends Object'",
- "Pb(964) Null constraint mismatch: The type '@Nullable String' is not a valid substitute for the type parameter '@NonNull Y extends @NonNull CharSequence'", // FIXME(see above)
+ "Pb(964) Null constraint mismatch: The type '@Nullable String' is not a valid substitute for the type parameter 'Y extends @NonNull CharSequence'",
}, new int[] { 8, 16, 17, 18, 20, 20 });
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
index cb1114d..43c9805 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -11,19 +11,25 @@
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.IOException;
+import java.util.Hashtable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import junit.framework.Test;
import junit.framework.TestSuite;
+import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.*;
@@ -656,21 +662,21 @@
IJavaProject project= getJavaProject("JavaProjectTests");
IContainer underLyingResource = (IContainer)project.getUnderlyingResource();
IFolder folder= underLyingResource.getFolder(new Path("output"));
-
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
project.setOutputLocation(folder.getFullPath(), null);
assertDeltas(
"Unexpected delta 1",
"JavaProjectTests[*]: {CHILDREN | CONTENT | RAW CLASSPATH CHANGED | RESOLVED CLASSPATH CHANGED}\n" +
" <project root>[*]: {CHILDREN}\n" +
" bin[+]: {}\n" +
- " ResourceDelta(/JavaProjectTests/.classpath)[*]"
- );
+ " ResourceDelta(/JavaProjectTests/.classpath)[*]",
+ listener);
} finally {
- stopDeltas();
+ stopDeltas(listener);
try {
- startDeltas();
+ startDeltas(listener);
folder= underLyingResource.getFolder(new Path("bin"));
project.setOutputLocation(folder.getFullPath(), null);
assertDeltas(
@@ -678,10 +684,10 @@
"JavaProjectTests[*]: {CHILDREN | CONTENT | RAW CLASSPATH CHANGED | RESOLVED CLASSPATH CHANGED}\n" +
" <project root>[*]: {CHILDREN}\n" +
" bin[-]: {}\n" +
- " ResourceDelta(/JavaProjectTests/.classpath)[*]"
- );
+ " ResourceDelta(/JavaProjectTests/.classpath)[*]",
+ listener);
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
}
@@ -724,8 +730,8 @@
IWorkspaceDescription description = workspace.getDescription();
description.setAutoBuilding(true);
workspace.setDescription(description);
-
- startDeltas();
+ DeltaListener listener = new DeltaListener();
+ startDeltas(listener);
IPackageFragment frag = getPackageFragment("JavaProjectTests", "", "x.y");
IFolder folder = (IFolder) frag.getUnderlyingResource();
try {
@@ -734,10 +740,10 @@
"Unexpected delta",
"JavaProjectTests[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
- " x.y[-]: {}"
- );
+ " x.y[-]: {}",
+ listener);
} finally {
- stopDeltas();
+ stopDeltas(listener);
// turn autobuild off
description.setAutoBuilding(autoBuild);
@@ -931,15 +937,16 @@
public void testFolderWithDotName() throws JavaModelException, CoreException {
IPackageFragmentRoot root= getPackageFragmentRoot("JavaProjectTests", "");
IContainer folder= (IContainer)root.getCorrespondingResource();
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
folder.getFolder(new Path("org.eclipse")).create(false, true, null);
assertDeltas(
"Unexpected delta",
"JavaProjectTests[*]: {CONTENT}\n" +
- " ResourceDelta(/JavaProjectTests/org.eclipse)[+]"
- );
- stopDeltas();
+ " ResourceDelta(/JavaProjectTests/org.eclipse)[+]",
+ listener);
+ stopDeltas(listener);
IJavaElement[] children = root.getChildren();
IPackageFragment bogus = root.getPackageFragment("org.eclipse");
@@ -1165,15 +1172,15 @@
// as a package fragment
IContainer underLyingResource = (IContainer)root.getUnderlyingResource();
IFolder newFolder= underLyingResource.getFolder(new Path("bin")).getFolder(new Path("nested"));
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
newFolder.create(false, true, null);
assertDeltas(
"Unexpected delta",
- ""
- );
+ "", listener);
} finally {
- stopDeltas();
+ stopDeltas(listener);
deleteResource(newFolder);
}
}
@@ -1760,17 +1767,17 @@
IJavaProject jproject= getJavaProject("JavaProjectTests");
IProject project= jproject.getProject();
project.close(null);
-
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
project.open(null);
assertDeltas(
"Unexpected delta 2",
"JavaProjectTests[*]: {OPENED}\n" +
- "ResourceDelta(/JavaProjectTests)"
+ "ResourceDelta(/JavaProjectTests)", listener
);
} finally {
- stopDeltas();
+ stopDeltas(listener);
}
}
/**
@@ -1795,17 +1802,17 @@
public void testProjectClose() throws JavaModelException, CoreException {
IJavaProject jproject= getJavaProject("JavaProjectTests");
IProject project= jproject.getProject();
-
+ DeltaListener listener = new DeltaListener();
try {
- startDeltas();
+ startDeltas(listener);
project.close(null);
assertDeltas(
"Unexpected delta 1",
"JavaProjectTests[*]: {CLOSED}\n" +
- "ResourceDelta(/JavaProjectTests)"
+ "ResourceDelta(/JavaProjectTests)", listener
);
} finally {
- stopDeltas();
+ stopDeltas(listener);
project.open(null);
}
}
@@ -2586,4 +2593,47 @@
this.deleteProject("P");
}
}
+/**
+ * Test that conflicting rules between refreshLocal and IProject.touch() invoked by
+ * JDT don't cause an IAE.
+ *
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=462756"
+ */
+@SuppressWarnings("rawtypes")
+public void testBug462756() throws CoreException {
+ Hashtable javaCoreOptions = JavaCore.getOptions();
+ try {
+ IJavaProject proj = this.createJavaProject("P", new String[] {"src"}, new String[]{}, "bin");
+ proj.getProject().open(null);
+ createFolder("/P/.settings");
+ String content = "org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7\n" +
+ "org.eclipse.jdt.core.compiler.compliance=1.7\n" +
+ "org.eclipse.jdt.core.compiler.source=1.7\n";
+
+ IFile file = getFile("/P/.settings/org.eclipse.jdt.core.prefs");
+ try (BufferedWriter output = new BufferedWriter(new FileWriter(file.getLocation().toFile()))) {
+ output.write(content);
+ output.flush();
+ } catch(Exception e) {
+ }
+ final StringBuffer buffer = new StringBuffer();
+ RuntimeLog.addLogListener(new ILogListener() {
+ @Override
+ public void logging(IStatus status, String plugin) {
+ if (status.getSeverity() == IStatus.ERROR && status.toString().contains("java.lang.IllegalArgumentException")) {
+ buffer.append("Should not throw IllegalArgumentException");
+ }
+ }
+ });
+ proj.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
+ waitForManualRefresh();
+ if (buffer.length() > 0) {
+ fail(buffer.toString());
+ }
+ assertEquals("Compliance should be updated", "1.7", proj.getOption("org.eclipse.jdt.core.compiler.compliance", true));
+ } finally {
+ this.deleteProject("P");
+ JavaCore.setOptions(javaCoreOptions);
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NameLookupTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NameLookupTests2.java
index aa9bf62..a529c77 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NameLookupTests2.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NameLookupTests2.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -7,10 +7,16 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Terry Parker <tparker@google.com> - Enable the Java model caches to recover from IO errors - https://bugs.eclipse.org/455042
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;
import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileTime;
+import java.util.Arrays;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
@@ -18,7 +24,10 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
+import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.NameLookup;
@@ -345,5 +354,83 @@
deleteProject("P2");
}
}
+/*
+ * A test for bug 162621. Tests that a library jar that is initially invalid but transitions
+ * to being valid becomes visible in name lookup. Previously the jar would stay in the invalid
+ * archive cache until a classpath change was generated, and would not make it into the project's
+ * JavaProjectElementInfo cache without restarting Eclipse or closing and reopening the project.
+ */
+public void testTransitionFromInvalidToValidJar() throws CoreException, IOException {
+ /*
+ * Since it is difficult to test intermittent IO errors, simulate it
+ * by creating two jars of equal size, one of which has an invalid format.
+ * Set up the classpath with the invalid jar, and then swap in the valid jar
+ * and reset its timestamp to be the same as the original file.
+ */
+ String goodJar = getExternalPath() + "goodJar.jar";
+ String transitioningJar = getExternalPath() + "transitioningJar.jar";
+ java.nio.file.Path goodJarPath = FileSystems.getDefault().getPath(goodJar);
+ java.nio.file.Path transitioningJarPath = FileSystems.getDefault().getPath(transitioningJar);
+ IPath transitioningIPath = Path.fromOSString(transitioningJar);
+
+ try {
+ Util.createJar(
+ new String[] {
+ "test1/IResource.java", //$NON-NLS-1$
+ "package test1;\n" + //$NON-NLS-1$
+ "public class IResource {\n" + //$NON-NLS-1$
+ "}" //$NON-NLS-1$
+ },
+ new String[] {
+ "META-INF/MANIFEST.MF",
+ "Manifest-Version: 1.0\n"
+ },
+ goodJar,
+ JavaCore.VERSION_1_4);
+ char[] invalidContents = new char[(int) goodJarPath.toFile().length()];
+ Arrays.fill(invalidContents, ' ');
+ Util.createFile(transitioningJar, String.copyValueOf(invalidContents));
+
+ // Set up the project with the invalid jar and allow all of the classpath validation
+ // and delta processing to complete.
+ JavaProject proj = (JavaProject) createJavaProject("P", new String[] {}, new String[] {transitioningJar}, "bin");
+ JavaModelManager.getJavaModelManager().getJavaModel().refreshExternalArchives(null, null);
+ waitForAutoBuild();
+
+ assertTrue("The invalid archive cache should report that the jar is invalid",
+ JavaModelManager.getJavaModelManager().isInvalidArchive(transitioningIPath));
+ IType type = getNameLookup(proj).findType("test1.IResource", false, NameLookup.ACCEPT_CLASSES);
+ assertEquals("Name lookup should fail when the jar is invalid", null, type);
+
+ // Substitute the good jar, maintaining the timestamp.
+ FileTime fileTime = Files.getLastModifiedTime(transitioningJarPath);
+ Files.move(goodJarPath, transitioningJarPath, StandardCopyOption.REPLACE_EXISTING);
+ Files.setLastModifiedTime(transitioningJarPath, fileTime);
+
+ // Since the timestamp hasn't changed, an external archive refresh isn't going
+ // to update the caches or cause name lookups to work.
+ JavaModelManager.getJavaModelManager().getJavaModel().refreshExternalArchives(null, null);
+ assertTrue("External archive refresh sees no changes, so the invalid archive cache should be unchanged",
+ JavaModelManager.getJavaModelManager().isInvalidArchive(transitioningIPath));
+ type = getNameLookup(proj).findType("test1.IResource", false, NameLookup.ACCEPT_CLASSES);
+ assertEquals("External archive refresh sees no changes, so the project cache should be unchanged",
+ null, type);
+
+ // Re-validating the jar via validateClasspathEntry() forces eviction from the
+ // invalid archive cache more quickly than waiting for the time-based eviction,
+ // allowing the test to run more quickly.
+ IClasspathEntry transitioningEntry = JavaCore.newLibraryEntry(transitioningIPath, null, null);
+ ClasspathEntry.validateClasspathEntry(proj, transitioningEntry, false, false);
+
+ assertFalse("The invalid archive cache should no longer report the jar as invalid",
+ JavaModelManager.getJavaModelManager().isInvalidArchive(transitioningIPath));
+ type = getNameLookup(proj).findType("test1.IResource", false, NameLookup.ACCEPT_CLASSES);
+ assertFalse("Name lookup should be able to find types in the valid jar", type == null);
+ } finally {
+ Files.deleteIfExists(goodJarPath);
+ Files.deleteIfExists(transitioningJarPath);
+ deleteProject("P");
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SignatureTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SignatureTests.java
index d3e3fe7..ac3fec1 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SignatureTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SignatureTests.java
@@ -857,6 +857,18 @@
"List<java.lang.String>\n",
Signature.getSimpleNames("java.util.List<java.lang.String>"));
}
+public void testGetSignaturesSimpleName01() {
+ assertEquals(
+ "Unexpected simple names",
+ "? extends CharSequence",
+ Signature.getSignatureSimpleName("+Ljava.lang.CharSequence;"));
+}
+public void testGetSignaturesSimpleName02() {
+ assertEquals(
+ "Unexpected simple names",
+ "? extends CharSequence",
+ Signature.getSignatureSimpleName("+QCharSequence;"));
+}
/**
* @see Signature
*/
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test432593/A_in.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test432593/A_in.java
new file mode 100644
index 0000000..85b808b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test432593/A_in.java
@@ -0,0 +1,44 @@
+package com.ibm.icu.util; public class LocaleMatcher {private static final boolean DEBUG=false;private static final double DEFAULT_THRESHOLD=0.5D;private final ULocale defaultLanguage;java.util.Map<ULocale, com.ibm.icu.impl.Row.R2<ULocale, Double>> maximizedLanguageToWeight=new java.util.LinkedHashMap();LanguageMatcherData matcherData;private static LanguageMatcherData defaultWritten=LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$3(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(LanguageMatcherData.access$2(new LanguageMatcherData().addDistance("no","nb",100,"The language no is normally taken as nb in content; we might alias this for lookup."),"nn","nb",96),"nn","no",96).addDistance("da","no",90,"Danish and norwegian are reasonably close."),"da","nb",90).addDistance("hr","br",96,"Serbo-croatian variants are all very close."),"sh","br",96),"sr","br",96),"sh","hr",96),"sr","hr",96),"sh","sr",96).addDistance("sr-Latn","sr-Cyrl",90,"Most serbs can read either script."),"*-Hans","*-Hant",85,true,"Readers of simplified can read traditional much better than reverse.").addDistance("*-Hant","*-Hans",75,true).addDistance("en-*-US","en-*-CA",98,"US is different than others, and Canadian is inbetween."),"en-*-US","en-*-*",97),"en-*-CA","en-*-*",98),"en-*-*","en-*-*",99).addDistance("es-*-ES","es-*-ES",100,"Latin American Spanishes are closer to each other. Approximate by having es-ES be further from everything else."),"es-*-ES","es-*-*",93).addDistance("*","*",1,"[Default value -- must be at end!] Normally there is no comprehension of different languages.").addDistance("*-*","*-*",20,"[Default value -- must be at end!] Normally there is little comprehension of different scripts.").addDistance("*-*-*","*-*-*",96,"[Default value -- must be at end!] Normally there are small differences across regions.").freeze();private static java.util.HashMap<String, String> canonicalMap=new java.util.HashMap();static {LocaleMatcher.canonicalMap.put("iw","he");LocaleMatcher.canonicalMap.put("mo","ro");LocaleMatcher.canonicalMap.put("tl","fil");}public LocaleMatcher(LocalePriorityList languagePriorityList){this(languagePriorityList,LocaleMatcher.defaultWritten);}public LocaleMatcher(String languagePriorityListString){this(LocalePriorityList.add(languagePriorityListString).build());}public LocaleMatcher(LocalePriorityList languagePriorityList,LanguageMatcherData matcherData){this.matcherData=matcherData;r4=languagePriorityList.iterator();while (r4.hasNext()){ULocale language=(ULocale)r4.next();super.add(language,languagePriorityList.getWeight(language));}java.util.Iterator<ULocale> it=languagePriorityList.iterator();this.defaultLanguage=it.hasNext()?(ULocale)it.next():null;}public double match(ULocale desired,ULocale desiredMax,ULocale supported,ULocale supportedMax){return this.matcherData.match(desired,desiredMax,supported,supportedMax);}public ULocale canonicalize(ULocale ulocale){String lang=ulocale.getLanguage();String lang2=(String)LocaleMatcher.canonicalMap.get(lang);String script=ulocale.getScript();String script2=(String)LocaleMatcher.canonicalMap.get(script);String region=ulocale.getCountry();String region2=(String)LocaleMatcher.canonicalMap.get(region);if (lang2 != null || script2 != null || region2 != null)return new ULocale(lang2 == null?lang:lang2,script2 == null?script:script2,region2 == null?region:region2);return ulocale;}public ULocale getBestMatch(LocalePriorityList languageList){double bestWeight=0.0D;ULocale bestTableMatch=null;r6=languageList.iterator();while (r6.hasNext()){ULocale language=(ULocale)r6.next();com.ibm.icu.impl.Row.R2<ULocale, Double> matchRow=super.getBestMatchInternal(language);double weight=((Double)matchRow.get1()).doubleValue() * languageList.getWeight(language).doubleValue();if (weight <= bestWeight){}bestWeight=weight;bestTableMatch=(ULocale)matchRow.get0();}if (bestWeight < 0.5D)bestTableMatch=this.defaultLanguage;return bestTableMatch;}public ULocale getBestMatch(String languageList){return this.getBestMatch(LocalePriorityList.add(languageList).build());}public ULocale getBestMatch(ULocale ulocale){return (ULocale)super.getBestMatchInternal(ulocale).get0();}public String toString(){return "{" + this.defaultLanguage + ", " + this.maximizedLanguageToWeight + "}";}private com.ibm.icu.impl.Row.R2<ULocale, Double> getBestMatchInternal(ULocale languageCode){languageCode=this.canonicalize(languageCode);ULocale maximized=super.addLikelySubtags(languageCode);double bestWeight=0.0D;ULocale bestTableMatch=null;r7=this.maximizedLanguageToWeight.keySet().iterator();while (r7.hasNext()){ULocale tableKey=(ULocale)r7.next();com.ibm.icu.impl.Row.R2<ULocale, Double> row=(com.ibm.icu.impl.Row.R2)this.maximizedLanguageToWeight.get(tableKey);double match=this.match(languageCode,maximized,tableKey,(ULocale)row.get0());double weight=match * ((Double)row.get1()).doubleValue();if (weight <= bestWeight){}bestWeight=weight;bestTableMatch=tableKey;}if (bestWeight < 0.5D)bestTableMatch=this.defaultLanguage;return com.ibm.icu.impl.Row.R2.of(bestTableMatch,Double.valueOf(bestWeight));}private void add(ULocale language,Double weight){language=this.canonicalize(language);com.ibm.icu.impl.Row.R2<ULocale, Double> row=com.ibm.icu.impl.Row.of(super.addLikelySubtags(language),weight);this.maximizedLanguageToWeight.put(language,row);}private ULocale addLikelySubtags(ULocale languageCode){ULocale result=ULocale.addLikelySubtags(languageCode);if (result == null || result.equals(languageCode)){String language=languageCode.getLanguage();String script=languageCode.getScript();String region=languageCode.getCountry();return new ULocale((language.length() == 0?"und":language) + "_" + (script.length() == 0?"Zzzz":script) + "_" + (region.length() == 0?"ZZ":region));}return result;}public static class LanguageMatcherData implements Freezable<LanguageMatcherData>{ScoreData languageScores=new ScoreData(Level.language);ScoreData scriptScores=new ScoreData(Level.script);ScoreData regionScores=new ScoreData(Level.region);private boolean frozen=false;private static int[] $SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level;public double match(ULocale a,ULocale aMax,ULocale b,ULocale bMax){double diff=0.0D;diff=diff + this.languageScores.getScore(a,aMax,a.getLanguage(),aMax.getLanguage(),b,bMax,b.getLanguage(),bMax.getLanguage());diff=diff + this.scriptScores.getScore(a,aMax,a.getScript(),aMax.getScript(),b,bMax,b.getScript(),bMax.getScript());diff=diff + this.regionScores.getScore(a,aMax,a.getCountry(),aMax.getCountry(),b,bMax,b.getCountry(),bMax.getCountry());if (!a.getVariant().equals(b.getVariant()))diff=diff + 1.0D;if (diff < 0.0D)diff=0.0D; else if (diff > 1.0D)diff=1.0D;return 1.0D - diff;}private LanguageMatcherData addDistance(String desired,String supported,int percent){return super.addDistance(desired,supported,percent,false,null);}public LanguageMatcherData addDistance(String desired,String supported,int percent,String comment){return super.addDistance(desired,supported,percent,false,comment);}public LanguageMatcherData addDistance(String desired,String supported,int percent,boolean oneway){return super.addDistance(desired,supported,percent,oneway,null);}private LanguageMatcherData addDistance(String desired,String supported,int percent,boolean oneway,String comment){double score=1.0D - (double)percent / 100.0D;LocalePatternMatcher desiredMatcher=new LocalePatternMatcher(desired);Level desiredLen=desiredMatcher.getLevel();LocalePatternMatcher supportedMatcher=new LocalePatternMatcher(supported);Level supportedLen=supportedMatcher.getLevel();if (desiredLen != supportedLen)throw new IllegalArgumentException();com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data=com.ibm.icu.impl.Row.of(desiredMatcher,supportedMatcher,Double.valueOf(score));com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data2=oneway?null:com.ibm.icu.impl.Row.of(supportedMatcher,desiredMatcher,Double.valueOf(score));switch (desiredLen){case language:String dlanguage=desiredMatcher.getLanguage();String slanguage=supportedMatcher.getLanguage();this.languageScores.addDataToScores(dlanguage,slanguage,data);if (!oneway)this.languageScores.addDataToScores(slanguage,dlanguage,data2);break;case script:String dscript=desiredMatcher.getScript();String sscript=supportedMatcher.getScript();this.scriptScores.addDataToScores(dscript,sscript,data);if (!oneway)this.scriptScores.addDataToScores(sscript,dscript,data2);break;case region:String dregion=desiredMatcher.getRegion();String sregion=supportedMatcher.getRegion();this.regionScores.addDataToScores(dregion,sregion,data);if (!oneway)this.regionScores.addDataToScores(sregion,dregion,data2);break;}return this;}public LanguageMatcherData cloneAsThawed(){LanguageMatcherData result=(LanguageMatcherData)this.clone();result.languageScores=this.languageScores.cloneAsThawed();result.scriptScores=this.scriptScores.cloneAsThawed();result.regionScores=this.regionScores.cloneAsThawed();result.frozen=false;return result;}public LanguageMatcherData freeze(){return this;}public boolean isFrozen(){return this.frozen;}public Object cloneAsThawed(){return this.cloneAsThawed();}public Object freeze(){return this.freeze();}static LanguageMatcherData access$2(LanguageMatcherData arg0,String arg1,String arg2,int arg3){return arg0.addDistance(arg1,arg2,arg3);}static LanguageMatcherData access$3(LanguageMatcherData arg0,String arg1,String arg2,int arg3,boolean arg4,String arg5){return arg0.addDistance(arg1,arg2,arg3,arg4,arg5);}static int[] $SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level(){if (LanguageMatcherData.$SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level == null){}r0=new int[Level.values().length];r0[Level.language.ordinal()]=1;r0[Level.region.ordinal()]=3;r0[Level.script.ordinal()]=2;return LanguageMatcherData.$SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level=r0;}}private static class ScoreData implements Freezable<ScoreData>{java.util.LinkedHashSet<com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double>> scores=new java.util.LinkedHashSet();final double worst;final Level level;private boolean frozen=false;public ScoreData(Level level){this.level=level;this.worst=(double)(1 - (level == Level.language?90:level == Level.script?20:4)) / 100.0D;}void addDataToScores(String desired,String supported,com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data){this.scores.add(data);}double getScore(ULocale desiredLocale,ULocale dMax,String desiredRaw,String desiredMax,ULocale supportedLocale,ULocale sMax,String supportedRaw,String supportedMax){boolean desiredChange=desiredRaw.equals(desiredMax);boolean supportedChange=supportedRaw.equals(supportedMax);if (!desiredMax.equals(supportedMax)){double distance=super.getRawScore(dMax,sMax);if (desiredChange == supportedChange)distance=distance * 0.75D;if (desiredChange)distance=distance * 0.5D;} else if (desiredChange == supportedChange)double distance=0.0D; else double distance=0.25D * this.worst;return distance;}private double getRawScore(ULocale desiredLocale,ULocale supportedLocale){r4=this.scores.iterator();while (r4.hasNext()){com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> datum=(com.ibm.icu.impl.Row.R3)r4.next();if (((LocalePatternMatcher)datum.get0()).matches(desiredLocale) && ((LocalePatternMatcher)datum.get1()).matches(supportedLocale))return ((Double)datum.get2()).doubleValue();}return this.worst;}public String toString(){return this.level + ", " + this.scores;}public ScoreData cloneAsThawed(){ScoreData result=(ScoreData)this.clone();result.scores=(java.util.LinkedHashSet)result.scores.clone();result.frozen=false;return result;}public ScoreData freeze(){return this;}public boolean isFrozen(){return this.frozen;}public Object cloneAsThawed(){return this.cloneAsThawed();}public Object freeze(){return this.freeze();}}private static class LocalePatternMatcher {private String lang;private String script;private String region;private Level level;static java.util.regex.Pattern pattern=java.util.regex.Pattern.compile("([a-zA-Z]{1,8}|\\\\*)(?:-([a-zA-Z]{4}|\\\\*))?(?:-([a-zA-Z]{2}|[0-9]{3}|\\\\*))?");public LocalePatternMatcher(String toMatch){java.util.regex.Matcher matcher=LocalePatternMatcher.pattern.matcher(toMatch);if (!matcher.matches())throw new IllegalArgumentException("Bad pattern: " + toMatch);this.lang=matcher.group(1);this.script=matcher.group(2);this.region=matcher.group(3);this.level=this.region != null?Level.region:this.script != null?Level.script:Level.language;if (this.lang.equals("*"))this.lang=null;if (this.script != null && this.script.equals("*"))this.script=null;if (this.region != null && this.region.equals("*"))this.region=null;}boolean matches(ULocale ulocale){if (this.lang != null && !this.lang.equals(ulocale.getLanguage()))return false;if (this.script != null && !this.script.equals(ulocale.getScript()))return false;if (this.region != null && !this.region.equals(ulocale.getCountry()))return false;return true;}public Level getLevel(){return this.level;}public String getLanguage(){return this.lang == null?"*":this.lang;}public String getScript(){return this.script == null?"*":this.script;}public String getRegion(){return this.region == null?"*":this.region;}public String toString(){String result=this.getLanguage();if (this.level != Level.language){result=result + "-" + this.getScript();if (this.level != Level.script)result=result + "-" + this.getRegion();}return result;}}static enum Level {language,script,region}}
+/*package com.ibm.icu.util; public class LocaleMatcher {
+ private static final boolean DEBUG=false;private static final double DEFAULT_THRESHOLD=0.5D;private final ULocale defaultLanguage;java.util.Map<ULocale, com.ibm.icu.impl.Row.R2<ULocale, Double>> maximizedLanguageToWeight=new java.util.LinkedHashMap();
+ LanguageMatcherData matcherData;
+ private static LanguageMatcherData defaultWritten=
+// LanguageMatcherData.access$2(
+// LanguageMatcherData.access$2(
+// LanguageMatcherData.access$2(
+// LanguageMatcherData.access$3(
+// LanguageMatcherData.access$2(
+// LanguageMatcherData.access$2(
+// LanguageMatcherData.access$2(
+ LanguageMatcherData.access$2(
+ LanguageMatcherData.access$2(
+ LanguageMatcherData.access$2(
+ LanguageMatcherData.access$2(
+ LanguageMatcherData.access$2(new LanguageMatcherData().addDistance("ONE","n",100,"O"),"n","n",96),"n","n",96).addDistance("TWO","n",90,"T"),"d","n",90).addDistance("THREE","b",96,"T"),"s","b",96),"s","b",96),"s","h",96),"s","h",96),"s","s",96).addDistance("FOUR","s",90,"F"),"*","*",85,true,"R").addDistance("SIX","e",98,"S"),"e","e",97),"e","e",98),"e","e",99).freeze();
+// LanguageMatcherData.access$2(new LanguageMatcherData().addDistance("ONE","n",100,"O"),"n","n",96),"n","n",96).addDistance("TWO","n",90,"T"),"d","n",90).addDistance("THREE","b",96,"T"),"s","b",96),"s","b",96),"s","h",96),"s","h",96),"s","s",96).addDistance("FOUR","s",90,"F"),"*","*",85,true,"R").addDistance("FIVE","*",75,true).addDistance("SIX","e",98,"S"),"e","e",97),"e","e",98),"e","e",99).addDistance("SEVEN","e",100,"L"),"e","e",93).addDistance("EIGHT","*",1,"g").addDistance("NINE","*",20,"s").addDistance("TEN","*",96,"e").freeze();
+ private static java.util.HashMap<String, String> canonicalMap=new java.util.HashMap();static {LocaleMatcher.canonicalMap.put("iw","he");LocaleMatcher.canonicalMap.put("mo","ro");LocaleMatcher.canonicalMap.put("tl","fil");}public LocaleMatcher(LocalePriorityList languagePriorityList){this(languagePriorityList,LocaleMatcher.defaultWritten);}public LocaleMatcher(String languagePriorityListString){this(LocalePriorityList.add(languagePriorityListString).build());}public LocaleMatcher(LocalePriorityList languagePriorityList,LanguageMatcherData matcherData){this.matcherData=matcherData;r4=languagePriorityList.iterator();while (r4.hasNext()){ULocale language=(ULocale)r4.next();super.add(language,languagePriorityList.getWeight(language));}java.util.Iterator<ULocale> it=languagePriorityList.iterator();this.defaultLanguage=it.hasNext()?(ULocale)it.next():null;}public double match(ULocale desired,ULocale desiredMax,ULocale supported,ULocale supportedMax){return this.matcherData.match(desired,desiredMax,supported,supportedMax);}public ULocale canonicalize(ULocale ulocale){String lang=ulocale.getLanguage();String lang2=(String)LocaleMatcher.canonicalMap.get(lang);String script=ulocale.getScript();String script2=(String)LocaleMatcher.canonicalMap.get(script);String region=ulocale.getCountry();String region2=(String)LocaleMatcher.canonicalMap.get(region);if (lang2 != null || script2 != null || region2 != null)return new ULocale(lang2 == null?lang:lang2,script2 == null?script:script2,region2 == null?region:region2);return ulocale;}public ULocale getBestMatch(LocalePriorityList languageList){double bestWeight=0.0D;ULocale bestTableMatch=null;r6=languageList.iterator();while (r6.hasNext()){ULocale language=(ULocale)r6.next();com.ibm.icu.impl.Row.R2<ULocale, Double> matchRow=super.getBestMatchInternal(language);double weight=((Double)matchRow.get1()).doubleValue() * languageList.getWeight(language).doubleValue();if (weight <= bestWeight){}bestWeight=weight;bestTableMatch=(ULocale)matchRow.get0();}if (bestWeight < 0.5D)bestTableMatch=this.defaultLanguage;return bestTableMatch;}public ULocale getBestMatch(String languageList){return this.getBestMatch(LocalePriorityList.add(languageList).build());}public ULocale getBestMatch(ULocale ulocale){return (ULocale)super.getBestMatchInternal(ulocale).get0();}public String toString(){return "{" + this.defaultLanguage + ", " + this.maximizedLanguageToWeight + "}";}private com.ibm.icu.impl.Row.R2<ULocale, Double> getBestMatchInternal(ULocale languageCode){languageCode=this.canonicalize(languageCode);ULocale maximized=super.addLikelySubtags(languageCode);double bestWeight=0.0D;ULocale bestTableMatch=null;r7=this.maximizedLanguageToWeight.keySet().iterator();while (r7.hasNext()){ULocale tableKey=(ULocale)r7.next();com.ibm.icu.impl.Row.R2<ULocale, Double> row=(com.ibm.icu.impl.Row.R2)this.maximizedLanguageToWeight.get(tableKey);double match=this.match(languageCode,maximized,tableKey,(ULocale)row.get0());double weight=match * ((Double)row.get1()).doubleValue();if (weight <= bestWeight){}bestWeight=weight;bestTableMatch=tableKey;}if (bestWeight < 0.5D)bestTableMatch=this.defaultLanguage;return com.ibm.icu.impl.Row.R2.of(bestTableMatch,Double.valueOf(bestWeight));}private void add(ULocale language,Double weight){language=this.canonicalize(language);com.ibm.icu.impl.Row.R2<ULocale, Double> row=com.ibm.icu.impl.Row.of(super.addLikelySubtags(language),weight);this.maximizedLanguageToWeight.put(language,row);}private ULocale addLikelySubtags(ULocale languageCode){ULocale result=ULocale.addLikelySubtags(languageCode);if (result == null || result.equals(languageCode)){String language=languageCode.getLanguage();String script=languageCode.getScript();String region=languageCode.getCountry();return new ULocale((language.length() == 0?"und":language) + "_" + (script.length() == 0?"Zzzz":script) + "_" + (region.length() == 0?"ZZ":region));}return result;}public static class LanguageMatcherData implements Freezable<LanguageMatcherData>{ScoreData languageScores=new ScoreData(Level.language);ScoreData scriptScores=new ScoreData(Level.script);ScoreData regionScores=new ScoreData(Level.region);private boolean frozen=false;private static int[] $SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level;
+ public double match(ULocale a,ULocale aMax,ULocale b,ULocale bMax){double diff=0.0D;diff=diff + this.languageScores.getScore(a,aMax,a.getLanguage(),aMax.getLanguage(),b,bMax,b.getLanguage(),bMax.getLanguage());diff=diff + this.scriptScores.getScore(a,aMax,a.getScript(),aMax.getScript(),b,bMax,b.getScript(),bMax.getScript());diff=diff + this.regionScores.getScore(a,aMax,a.getCountry(),aMax.getCountry(),b,bMax,b.getCountry(),bMax.getCountry());if (!a.getVariant().equals(b.getVariant()))diff=diff + 1.0D;if (diff < 0.0D)diff=0.0D; else if (diff > 1.0D)diff=1.0D;return 1.0D - diff;}
+ private LanguageMatcherData addDistance(String desired,String supported,int percent){return super.addDistance(desired,supported,percent,false,null);}public LanguageMatcherData addDistance(String desired,String supported,int percent,String comment){return super.addDistance(desired,supported,percent,false,comment);}public LanguageMatcherData addDistance(String desired,String supported,int percent,boolean oneway){return super.addDistance(desired,supported,percent,oneway,null);}private LanguageMatcherData addDistance(String desired,String supported,int percent,boolean oneway,String comment){double score=1.0D - (double)percent / 100.0D;LocalePatternMatcher desiredMatcher=new LocalePatternMatcher(desired);Level desiredLen=desiredMatcher.getLevel();LocalePatternMatcher supportedMatcher=new LocalePatternMatcher(supported);Level supportedLen=supportedMatcher.getLevel();if (desiredLen != supportedLen)throw new IllegalArgumentException();com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data=com.ibm.icu.impl.Row.of(desiredMatcher,supportedMatcher,Double.valueOf(score));com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data2=oneway?null:com.ibm.icu.impl.Row.of(supportedMatcher,desiredMatcher,Double.valueOf(score));switch (desiredLen){case language:String dlanguage=desiredMatcher.getLanguage();String slanguage=supportedMatcher.getLanguage();this.languageScores.addDataToScores(dlanguage,slanguage,data);if (!oneway)this.languageScores.addDataToScores(slanguage,dlanguage,data2);break;case script:String dscript=desiredMatcher.getScript();String sscript=supportedMatcher.getScript();this.scriptScores.addDataToScores(dscript,sscript,data);if (!oneway)this.scriptScores.addDataToScores(sscript,dscript,data2);break;case region:String dregion=desiredMatcher.getRegion();String sregion=supportedMatcher.getRegion();this.regionScores.addDataToScores(dregion,sregion,data);if (!oneway)this.regionScores.addDataToScores(sregion,dregion,data2);break;}return this;}public LanguageMatcherData cloneAsThawed(){LanguageMatcherData result=(LanguageMatcherData)this.clone();result.languageScores=this.languageScores.cloneAsThawed();result.scriptScores=this.scriptScores.cloneAsThawed();result.regionScores=this.regionScores.cloneAsThawed();result.frozen=false;return result;}public LanguageMatcherData freeze(){return this;}public boolean isFrozen(){return this.frozen;}public Object cloneAsThawed(){return this.cloneAsThawed();}public Object freeze(){return this.freeze();}static LanguageMatcherData access$2(LanguageMatcherData arg0,String arg1,String arg2,int arg3){return arg0.addDistance(arg1,arg2,arg3);}static LanguageMatcherData access$3(LanguageMatcherData arg0,String arg1,String arg2,int arg3,boolean arg4,String arg5){return arg0.addDistance(arg1,arg2,arg3,arg4,arg5);}static int[] $SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level(){if (LanguageMatcherData.$SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level == null){}r0=new int[Level.values().length];r0[Level.language.ordinal()]=1;r0[Level.region.ordinal()]=3;r0[Level.script.ordinal()]=2;return LanguageMatcherData.$SWITCH_TABLE$com$ibm$icu$util$LocaleMatcher$Level=r0;}}private static class ScoreData implements Freezable<ScoreData>{java.util.LinkedHashSet<com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double>> scores=new java.util.LinkedHashSet();final double worst;final Level level;private boolean frozen=false;public ScoreData(Level level){this.level=level;this.worst=(double)(1 - (level == Level.language?90:level == Level.script?20:4)) / 100.0D;}void addDataToScores(String desired,String supported,com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> data){this.scores.add(data);}double getScore(ULocale desiredLocale,ULocale dMax,String desiredRaw,String desiredMax,ULocale supportedLocale,ULocale sMax,String supportedRaw,String supportedMax){boolean desiredChange=desiredRaw.equals(desiredMax);boolean supportedChange=supportedRaw.equals(supportedMax);if (!desiredMax.equals(supportedMax)){double distance=super.getRawScore(dMax,sMax);if (desiredChange == supportedChange)distance=distance * 0.75D;if (desiredChange)distance=distance * 0.5D;} else if (desiredChange == supportedChange)double distance=0.0D; else double distance=0.25D * this.worst;return distance;}private double getRawScore(ULocale desiredLocale,ULocale supportedLocale){r4=this.scores.iterator();while (r4.hasNext()){com.ibm.icu.impl.Row.R3<LocalePatternMatcher, LocalePatternMatcher, Double> datum=(com.ibm.icu.impl.Row.R3)r4.next();if (((LocalePatternMatcher)datum.get0()).matches(desiredLocale) && ((LocalePatternMatcher)datum.get1()).matches(supportedLocale))return ((Double)datum.get2()).doubleValue();}return this.worst;}public String toString(){return this.level + ", " + this.scores;}public ScoreData cloneAsThawed(){ScoreData result=(ScoreData)this.clone();result.scores=(java.util.LinkedHashSet)result.scores.clone();result.frozen=false;return result;}public ScoreData freeze(){return this;}public boolean isFrozen(){return this.frozen;}public Object cloneAsThawed(){return this.cloneAsThawed();}public Object freeze(){return this.freeze();}}private static class LocalePatternMatcher {private String lang;private String script;private String region;private Level level;static java.util.regex.Pattern pattern=java.util.regex.Pattern.compile("([a-zA-Z]{1,8}|\\\\*)(?:-([a-zA-Z]{4}|\\\\*))?(?:-([a-zA-Z]{2}|[0-9]{3}|\\\\*))?");public LocalePatternMatcher(String toMatch){java.util.regex.Matcher matcher=LocalePatternMatcher.pattern.matcher(toMatch);if (!matcher.matches())throw new IllegalArgumentException("Bad pattern: " + toMatch);this.lang=matcher.group(1);this.script=matcher.group(2);this.region=matcher.group(3);this.level=this.region != null?Level.region:this.script != null?Level.script:Level.language;if (this.lang.equals("*"))this.lang=null;if (this.script != null && this.script.equals("*"))this.script=null;if (this.region != null && this.region.equals("*"))this.region=null;}boolean matches(ULocale ulocale){if (this.lang != null && !this.lang.equals(ulocale.getLanguage()))return false;if (this.script != null && !this.script.equals(ulocale.getScript()))return false;if (this.region != null && !this.region.equals(ulocale.getCountry()))return false;return true;}public Level getLevel(){return this.level;}public String getLanguage(){return this.lang == null?"*":this.lang;}public String getScript(){return this.script == null?"*":this.script;}public String getRegion(){return this.region == null?"*":this.region;}public String toString(){String result=this.getLanguage();if (this.level != Level.language){result=result + "-" + this.getScript();if (this.level != Level.script)result=result + "-" + this.getRegion();}return result;}}static enum Level {language,script,region}
+ }
+
+*//*class Y {
+ public Y foo(String s1, String s2, int i) {
+ return foo(s1, s2, i, false, null);
+ }
+ public Y foo(String s1, String s2, int i , String s3) {
+ return foo(s1, s2, i, false, s3);
+ }
+ public Y foo(String s1, String s2, int i, boolean b) {
+ return foo(s1, s2, i, b, null);
+ }
+ public Y foo(String s1, String s2, int i, boolean b, String s3) {
+ return this;
+ }
+ public Y bar() {
+ return this;
+ }
+}
+class X {
+ public static Y defaultWritten = new Y().foo("1", "n", 100, "O").freeze();
+}
+*/
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
index ff198cb..0fdc331 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
@@ -21,13 +21,22 @@
import java.util.Hashtable;
import java.util.List;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.util.Util;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
@@ -43,8 +52,9 @@
private String[] missingPackageHolder = new String[1];
private int mode; // ability to only consider one kind of files (source vs. binaries), by default use both
private String encoding; // only useful if referenced in the source path
+private Hashtable<String, Hashtable<String, String>> packageSecondaryTypes = null;
-ClasspathDirectory(File directory, String encoding, int mode,
+ClasspathDirectory(File directory, String encoding, int mode,
AccessRuleSet accessRuleSet, String destinationPath) {
super(accessRuleSet, destinationPath);
this.mode = mode;
@@ -155,6 +165,11 @@
}
return null;
}
+public NameEnvironmentAnswer findSecondaryInClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) {
+ boolean sourceExists = isPackage(qualifiedPackageName) && ((this.mode & SOURCE) != 0) && doesFileExist( new String(typeName) + SUFFIX_STRING_java, qualifiedPackageName);
+ return sourceExists ? null : findSourceSecondaryType(typeName, qualifiedPackageName, qualifiedBinaryFileName); /* only secondary types */
+}
+
@Override
public boolean hasAnnotationFileFor(String qualifiedTypeName) {
int pos = qualifiedTypeName.lastIndexOf('/');
@@ -164,6 +179,64 @@
}
return false;
}
+
+
+/**
+ * Add all the secondary types in the package
+ */
+private Hashtable<String, String> getPackageTypes(char[] typeName, String qualifiedPackageName) {
+ Hashtable<String, String> packageEntry = new Hashtable<String, String>();
+
+ String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName);
+ if (dirList == this.missingPackageHolder // package exists in another classpath directory or jar
+ || dirList == null)
+ return packageEntry;
+
+ File dir = new File(this.path + qualifiedPackageName);
+ File[] listFiles = dir.isDirectory() ? dir.listFiles() : null;
+ if (listFiles == null) return packageEntry;
+
+ for (int i = 0, l = listFiles.length; i < l; ++i) {
+ File f = listFiles[i];
+ if (f.isDirectory()) continue;
+ String s = f.getAbsolutePath();
+ if (s == null) continue;
+ CompilationUnit cu = new CompilationUnit(null, s, this.encoding, this.destinationPath);
+ CompilationResult compilationResult = new CompilationResult(cu.getContents(), 1, 1, 10);
+ ProblemReporter problemReporter =
+ new ProblemReporter(
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ new CompilerOptions(JavaCore.getOptions()),
+ new DefaultProblemFactory());
+ Parser parser = new Parser(problemReporter, false);
+
+ CompilationUnitDeclaration unit = parser.parse(cu, compilationResult);
+ org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = unit != null ? unit.types : null;
+ if (types == null) continue;
+ for (int j = 0, k = types.length; j < k; j++) {
+ TypeDeclaration type = types[j];
+ char[] name = type.isSecondary() ? type.name : null; // add only secondary types
+ if (name != null)
+ packageEntry.put(new String(name), s);
+ }
+ }
+ return packageEntry;
+}
+private NameEnvironmentAnswer findSourceSecondaryType(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) {
+
+ if (this.packageSecondaryTypes == null) this.packageSecondaryTypes = new Hashtable<String, Hashtable<String,String>>();
+ Hashtable<String, String> packageEntry = this.packageSecondaryTypes.get(qualifiedPackageName);
+ if (packageEntry == null) {
+ packageEntry = getPackageTypes(typeName, qualifiedPackageName);
+ this.packageSecondaryTypes.put(qualifiedPackageName, packageEntry);
+ }
+ String fileName = packageEntry.get(new String(typeName));
+ return fileName != null ? new NameEnvironmentAnswer(new CompilationUnit(null,
+ fileName, this.encoding, this.destinationPath),
+ fetchAccessRestriction(qualifiedBinaryFileName)) : null;
+}
+
+
public char[][][] findTypeNames(String qualifiedPackageName) {
if (!isPackage(qualifiedPackageName)) {
return null; // most common case
@@ -173,7 +246,7 @@
return null;
}
String[] listFiles = dir.list(new FilenameFilter() {
- public boolean accept(File directory, String name) {
+ public boolean accept(File directory1, String name) {
String fileName = name.toLowerCase();
return fileName.endsWith(".class") || fileName.endsWith(".java"); //$NON-NLS-1$ //$NON-NLS-2$
}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index 706a699..b5a4d56 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -4836,11 +4836,11 @@
return new CompletionOnSingleNameReference(assistName, position, isInsideAttributeValue());
} else {
boolean canBeExplicitConstructorCall = false;
- if(kind == K_BLOCK_DELIMITER
+ if((kind == K_BLOCK_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER)
&& this.previousKind == K_BLOCK_DELIMITER
&& this.previousInfo == DO) {
return new CompletionOnKeyword3(assistName, position, Keywords.WHILE);
- } else if(kind == K_BLOCK_DELIMITER
+ } else if((kind == K_BLOCK_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER)
&& this.previousKind == K_BLOCK_DELIMITER
&& this.previousInfo == TRY) {
return new CompletionOnKeyword3(assistName, position, new char[][]{Keywords.CATCH, Keywords.FINALLY});
@@ -4862,7 +4862,7 @@
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=269493: Keywords are not proposed in a for
// loop without block. Completion while at K_CONTROL_STATEMENT_DELIMITER case needs to handled
// similar to the K_BLOCK_DELIMITER with minor differences.
- if(kind == K_BLOCK_DELIMITER || kind == K_CONTROL_STATEMENT_DELIMITER) {
+ if(kind == K_BLOCK_DELIMITER || kind == K_CONTROL_STATEMENT_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER) {
if(this.canBeExplicitConstructor == YES) {
canBeExplicitConstructorCall = true;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
index bef2780..bbfc6c9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -78,7 +78,7 @@
public int problemCount;
public int taskCount;
public ICompilationUnit compilationUnit;
- private Map problemsMap;
+ private Map<CategorizedProblem, ReferenceContext> problemsMap;
private Set firstErrors;
private int maxProblemPerUnit;
public char[][][] qualifiedReferences;
@@ -205,7 +205,7 @@
if (problem.isError()){
priority += P_ERROR;
}
- ReferenceContext context = this.problemsMap == null ? null : (ReferenceContext) this.problemsMap.get(problem);
+ ReferenceContext context = this.problemsMap == null ? null : this.problemsMap.get(problem);
if (context != null){
if (context instanceof AbstractMethodDeclaration){
AbstractMethodDeclaration method = (AbstractMethodDeclaration) context;
@@ -500,6 +500,13 @@
}
}
+ReferenceContext getContext(CategorizedProblem problem) {
+ if (problem != null) {
+ return this.problemsMap.get(problem);
+ }
+ return null;
+}
+
/**
* For now, remember the compiled type using its compound name.
*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
index 963b53a..beef5eb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -17,6 +17,7 @@
package org.eclipse.jdt.internal.compiler;
import java.io.PrintWriter;
+import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
@@ -32,6 +33,7 @@
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.CompilerStats;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
@@ -88,6 +90,8 @@
//public CompilationUnitResult currentCompilationUnitResult;
public CompilationUnitDeclaration[] unitsToProcess;
public int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess
+
+ private Map<String, APTProblem[]> aptProblems;
// name lookup
public LookupEnvironment lookupEnvironment;
@@ -496,6 +500,7 @@
return;
}
} catch (SourceTypeCollisionException e) {
+ backupAptProblems();
reset();
// a generated type was referenced before it was created
// the compiler either created a MissingType or found a BinaryType for it
@@ -511,6 +516,8 @@
return;
}
}
+ // Restore the problems before the results are processed and cleaned up.
+ restoreAptProblems();
processCompiledUnits(0);
} catch (AbortCompilation e) {
this.handleInternalException(e, null);
@@ -526,6 +533,58 @@
}
}
+ class APTProblem {
+ CategorizedProblem problem;
+ ReferenceContext context;
+ APTProblem(CategorizedProblem problem, ReferenceContext context) {
+ this.problem = problem;
+ this.context = context;
+ }
+ }
+
+ protected void backupAptProblems() {
+ if (this.unitsToProcess == null) return;
+ for (CompilationUnitDeclaration unitDecl : this.unitsToProcess) {
+ if (unitDecl == null) continue;
+ CompilationResult result = unitDecl.compilationResult;
+ if (result != null && result.hasErrors()) {
+ CategorizedProblem[] errors = result.getErrors();
+ for (CategorizedProblem problem : errors) {
+ if (problem.getCategoryID() == CategorizedProblem.CAT_UNSPECIFIED) {
+ if (this.aptProblems == null) {
+ this.aptProblems = new HashMap<>();
+ }
+ APTProblem[] problems = this.aptProblems.get(new String(unitDecl.getFileName()));
+ if (problems == null) {
+ this.aptProblems.put(
+ new String(unitDecl.getFileName()),
+ new APTProblem[] { new APTProblem(problem, result.getContext(problem)) });
+ } else {
+ APTProblem[] temp = new APTProblem[problems.length + 1];
+ System.arraycopy(problems, 0, temp, 0, problems.length);
+ temp[problems.length] = new APTProblem(problem, result.getContext(problem));
+ this.aptProblems.put(new String(unitDecl.getFileName()), temp);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected void restoreAptProblems() {
+ if (this.unitsToProcess != null && this.aptProblems!= null) {
+ for (CompilationUnitDeclaration unit : this.unitsToProcess) {
+ APTProblem[] problems = this.aptProblems.get(new String(unit.getFileName()));
+ if (problems != null) {
+ for (APTProblem problem : problems) {
+ unit.compilationResult.record(problem.problem, problem.context);
+ }
+ }
+ }
+ }
+ this.aptProblems = null; // No need for this.
+ }
+
protected void processCompiledUnits(int startingIndex) throws java.lang.Error {
CompilationUnitDeclaration unit = null;
ProcessTaskManager processingTask = null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index 9692df5..f1ef793 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -40,6 +40,7 @@
* Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException)
* Bug 434297 - [1.8] NPE in LamdaExpression.analyseCode with lamda expression nested in a conditional expression
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
+ * Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 378674 - "The method can be declared as static" is wrong
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
@@ -613,9 +614,18 @@
if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) {
checkTypeArgumentRedundancy((ParameterizedTypeBinding) this.resolvedType, scope);
}
- if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
- new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
- .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
+ if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
+ if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
+ new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
+ .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
+ }
+ if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
+ if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
+ TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
+ for (int i = 0; i < this.typeArguments.length; i++)
+ this.typeArguments[i].checkNullConstraints(scope, typeVariables, i);
+ }
+ }
}
//{ObjectTeams: may need to wrap the resolved type
this.resolvedType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(this.resolvedType, scope, this);
@@ -914,7 +924,7 @@
}
public boolean statementExpression() {
- return true;
+ return ((this.bits & ASTNode.ParenthesizedMASK) == 0);
}
//-- interface Invocation: --
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 cc8bae7..2a26380 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
@@ -56,6 +56,7 @@
*
* Annotation
*/
+@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class Annotation extends Expression {
Annotation persistibleAnnotation = this; // Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container.
@@ -987,7 +988,115 @@
return this.resolvedType;
}
+ private static boolean isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) {
+ switch (kind) {
+ case Binding.PACKAGE :
+ if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
+ return true;
+ else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) {
+ SourceTypeBinding sourceType = (SourceTypeBinding) recipient;
+ if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME))
+ return true;
+ }
+ break;
+ case Binding.TYPE_USE :
+ if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
+ // jsr 308
+ return true;
+ }
+ if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
+ // already reported as syntax error; don't report secondary problems
+ return true;
+ }
+ break;
+ case Binding.TYPE :
+ case Binding.GENERIC_TYPE :
+ if (((ReferenceBinding)recipient).isAnnotationType()) {
+ if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0)
+ return true;
+ } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) {
+ return true;
+ } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) {
+ if (CharOperation.equals(((ReferenceBinding) recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME))
+ return true;
+ }
+//{ObjectTeams: allow @Override for roles:
+ if ( (((ReferenceBinding)recipient).isRole())
+ && (annotationType.id == TypeIds.T_JavaLangOverride))
+ return true;
+//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;
+ break;
+//SH}
+ case Binding.METHOD :
+ MethodBinding methodBinding = (MethodBinding) recipient;
+ if (methodBinding.isConstructor()) {
+ if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0)
+ return true;
+ } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) {
+ return true;
+ } 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;
+ }
+ }
+ break;
+ case Binding.FIELD :
+ if ((metaTagBits & TagBits.AnnotationForField) != 0) {
+ return true;
+ } 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;
+ }
+ }
+ break;
+ case Binding.LOCAL :
+ LocalVariableBinding localVariableBinding = (LocalVariableBinding) recipient;
+ if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) {
+ if ((metaTagBits & TagBits.AnnotationForParameter) != 0) {
+ return true;
+ } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
+ if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
+ return true;
+ }
+ }
+ } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) {
+ return true;
+ } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
+ if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
+ return true;
+ }
+ }
+ 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 false;
+ }
+
+ public static boolean isAnnotationTargetAllowed(BlockScope scope, TypeBinding annotationType, Binding recipient) {
+ long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
+ if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
+ return true;
+ }
+ return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits);
+ }
+
static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) {
+
long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
// does not specify any target restriction - all locations supported in Java 7 and before are possible
@@ -1012,102 +1121,7 @@
}
}
}
- switch (kind) {
- case Binding.PACKAGE :
- if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
- return true;
- else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) {
- SourceTypeBinding sourceType = (SourceTypeBinding) annotation.recipient;
- if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME))
- return true;
- }
- break;
- case Binding.TYPE_USE :
- if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
- // jsr 308
- return true;
- }
- if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
- // already reported as syntax error; don't report secondary problems
- return true;
- }
- break;
- case Binding.TYPE :
- case Binding.GENERIC_TYPE :
- if (((ReferenceBinding)annotation.recipient).isAnnotationType()) {
- if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0)
- return true;
- } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) {
- return true;
- } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) {
- if (CharOperation.equals(((ReferenceBinding) annotation.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME))
- return true;
- }
-//{ObjectTeams: allow @Override for roles:
- if ( (((ReferenceBinding)annotation.recipient).isRole())
- && (annotation.resolvedType.id == TypeIds.T_JavaLangOverride))
- return true;
-//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;
- break;
-//SH}
- case Binding.METHOD :
- MethodBinding methodBinding = (MethodBinding) annotation.recipient;
- if (methodBinding.isConstructor()) {
- if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0)
- return true;
- } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) {
- return true;
- } 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;
- }
- }
- break;
- case Binding.FIELD :
- if ((metaTagBits & TagBits.AnnotationForField) != 0) {
- return true;
- } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
- FieldBinding sourceField = (FieldBinding) annotation.recipient;
- SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass;
- FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
- if (isTypeUseCompatible(fieldDeclaration.type, scope)) {
- return true;
- }
- }
- break;
- case Binding.LOCAL :
- LocalVariableBinding localVariableBinding = (LocalVariableBinding) annotation.recipient;
- if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) {
- if ((metaTagBits & TagBits.AnnotationForParameter) != 0) {
- return true;
- } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
- if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
- return true;
- }
- }
- } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) {
- return true;
- } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
- if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
- return true;
- }
- }
- 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 false;
+ return isAnnotationTargetAllowed(annotation.recipient, scope, annotationType, kind, metaTagBits);
}
static void checkAnnotationTarget(Annotation annotation, BlockScope scope, ReferenceBinding annotationType, int kind, Binding recipient, long tagBitsToRevert) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
index c6e5fea..b842bd3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -30,6 +30,7 @@
* Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
* Bug 453483 - [compiler][null][loop] Improve null analysis for loops
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -194,6 +195,8 @@
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
return this.expression.nullStatus(flowInfo, flowContext);
}
@@ -336,6 +339,6 @@
return this.lhs.localVariableBinding();
}
public boolean statementExpression() {
- return true;
+ return ((this.bits & ASTNode.ParenthesizedMASK) == 0);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
index c42e780..4e740a6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
@@ -15,6 +15,7 @@
* bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
* bug 383368 - [compiler][null] syntactic null analysis for field references
* bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check
+ * Bug 440282 - [resource] Resource leak detection false negative with empty finally block
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -60,9 +61,11 @@
flowContext.expireNullCheckedFieldInfo();
}
}
- if (this.explicitDeclarations > 0) {
- // if block has its own scope analyze tracking vars now:
+ if (this.scope != currentScope) {
+ // if block is tracking any resources other than the enclosing 'currentScope', analyse them now:
this.scope.checkUnclosedCloseables(flowInfo, flowContext, null, null);
+ }
+ if (this.explicitDeclarations > 0) {
// cleanup assignment info for locals that are scoped to this block:
LocalVariableBinding[] locals = this.scope.locals;
if (locals != null) {
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 bd9b012..97a4a1d 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -24,6 +24,7 @@
* Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
* Bug 430150 - [1.8][null] stricter checking against type variables
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped
*******************************************************************************/
@@ -591,6 +592,8 @@
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
return this.expression.nullStatus(flowInfo, flowContext);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index 079a108..d285c6d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -24,6 +24,7 @@
* Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
* Bug 418537 - [1.8][null] Fix null type annotation analysis for poly conditional expressions
* Bug 428352 - [1.8][compiler] Resolution errors don't always surface
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -418,6 +419,8 @@
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
return this.nullStatus;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index 6cf57e7..6ef6d1d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -24,6 +24,8 @@
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -379,6 +381,14 @@
if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.OPTIONAL))
return memberValuePairs[j].value instanceof FalseLiteral;
}
+ } else if (annotation.resolvedType.id == TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired) {
+ MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
+ if (memberValuePairs == Annotation.NoValuePairs)
+ return true;
+ for (int j = 0; j < memberValuePairs.length; j++) {
+ if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.REQUIRED))
+ return memberValuePairs[j].value instanceof TrueLiteral;
+ }
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
index 45b882b..1a1f787 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2014 GK Software AG and others.
+ * Copyright (c) 2011, 2015 GK Software AG 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
@@ -13,7 +13,9 @@
package org.eclipse.jdt.internal.compiler.ast;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -33,6 +35,7 @@
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
@@ -182,6 +185,8 @@
return local.closeTracker;
if (!isAnyCloseable(expression.resolvedType))
return null;
+ if ((local.tagBits & TagBits.IsResource) != 0)
+ return null;
// tracking var doesn't yet exist. This happens in finally block
// which is analyzed before the corresponding try block
Statement location = local.declaration;
@@ -237,6 +242,8 @@
ConditionalExpression conditional = (ConditionalExpression) location;
return containsAllocation(conditional.valueIfTrue) || containsAllocation(conditional.valueIfFalse);
}
+ if (location instanceof CastExpression)
+ return containsAllocation(((CastExpression) location).expression);
return false;
}
@@ -246,6 +253,8 @@
preConnectTrackerAcrossAssignment(location, local, flowInfo, (AllocationExpression) expression, closeTracker);
} else if (expression instanceof ConditionalExpression) {
preConnectTrackerAcrossAssignment(location, local, flowInfo, (ConditionalExpression) expression, closeTracker);
+ } else if (expression instanceof CastExpression) {
+ preConnectTrackerAcrossAssignment(location, local, ((CastExpression) expression).expression, flowInfo);
}
}
@@ -273,7 +282,7 @@
if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
// remove unnecessary attempts (closeable is not relevant)
if (allocation.closeTracker != null) {
- scope.removeTrackingVar(allocation.closeTracker);
+ allocation.closeTracker.withdraw();
allocation.closeTracker = null;
}
} else if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable)) {
@@ -328,7 +337,7 @@
if (isWrapper) {
// remove unnecessary attempts (wrapper has no relevant inner)
if (allocation.closeTracker != null) {
- scope.removeTrackingVar(allocation.closeTracker);
+ allocation.closeTracker.withdraw();
allocation.closeTracker = null;
}
} else {
@@ -353,7 +362,7 @@
}
private static FakedTrackingVariable pick(FakedTrackingVariable tracker1, FakedTrackingVariable tracker2, BlockScope scope) {
- scope.removeTrackingVar(tracker2);
+ tracker2.withdraw();
return tracker1;
}
@@ -600,14 +609,14 @@
if (expression instanceof AllocationExpression) {
FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker;
if (tracker != null && tracker.originalBinding == null) {
- currentScope.removeTrackingVar(tracker);
+ tracker.withdraw();
((AllocationExpression) expression).closeTracker = null;
}
} else {
// assignment passing a local into a field?
LocalVariableBinding local = expression.localVariableBinding();
if (local != null && local.closeTracker != null && ((lhsBits & Binding.FIELD) != 0))
- currentScope.removeTrackingVar(local.closeTracker); // TODO: may want to use local.closeTracker.markPassedToOutside(..,true)
+ local.closeTracker.withdraw(); // TODO: may want to use local.closeTracker.markPassedToOutside(..,true)
}
}
@@ -686,7 +695,7 @@
int finallyStatus = currentScope.finallyInfo.nullStatus(local);
if (finallyStatus == FlowInfo.NON_NULL)
return finallyStatus;
- if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL
+ if (finallyStatus != FlowInfo.NULL && currentScope.finallyInfo.hasNullInfoFor(local)) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL
status = FlowInfo.POTENTIALLY_NULL;
}
if (currentScope != outerScope && currentScope.parent instanceof BlockScope)
@@ -701,7 +710,7 @@
do {
flowInfo.markAsDefinitelyNonNull(current.binding);
current.globalClosingState |= CLOSE_SEEN;
- flowContext.markFinallyNullStatus(this.binding, FlowInfo.NON_NULL);
+ flowContext.markFinallyNullStatus(current.binding, FlowInfo.NON_NULL);
current = current.innerTracker;
} while (current != null);
}
@@ -739,44 +748,100 @@
return flowInfo;
}
- /**
- * Pick tracking variables from 'varsOfScope' to establish a proper order of processing:
- * As much as possible pick wrapper resources before their inner resources.
- * Also consider cases of wrappers and their inners being declared at different scopes.
+ /**
+ * Iterator for a set of FakedTrackingVariable, which dispenses the elements
+ * according to the priorities defined by enum {@link Stage}.
+ * Resources whose outer is owned by an enclosing scope are never answered,
+ * unless we are analysing on behalf of an exit (return/throw).
*/
- public static FakedTrackingVariable pickVarForReporting(Set varsOfScope, BlockScope scope, boolean atExit) {
- if (varsOfScope.isEmpty()) return null;
- FakedTrackingVariable trackingVar = (FakedTrackingVariable) varsOfScope.iterator().next();
- while (trackingVar.outerTracker != null) {
- // resource is wrapped, is wrapper defined in this scope?
- if (varsOfScope.contains(trackingVar.outerTracker)) {
- // resource from same scope, travel up the wrapper chain
- trackingVar = trackingVar.outerTracker;
- } else if (atExit) {
- // at an exit point we report against inner despite a wrapper that may/may not be closed later
- break;
- } else {
- BlockScope outerTrackerScope = trackingVar.outerTracker.binding.declaringScope;
- if (outerTrackerScope == scope) {
- // outerTracker is from same scope and already processed -> pick trackingVar now
- break;
- } else {
- // outer resource is from other (outer?) scope
- Scope currentScope = scope;
- while ((currentScope = currentScope.parent) instanceof BlockScope) {
- if (outerTrackerScope == currentScope) {
- // at end of block pass responsibility for inner resource to outer scope holding a wrapper
- varsOfScope.remove(trackingVar); // drop this one
- // pick a next candidate:
- return pickVarForReporting(varsOfScope, scope, atExit);
+ public static class IteratorForReporting implements Iterator<FakedTrackingVariable> {
+
+ private final Set<FakedTrackingVariable> varSet;
+ private final Scope scope;
+ private final boolean atExit;
+
+ private Stage stage;
+ private Iterator<FakedTrackingVariable> iterator;
+ private FakedTrackingVariable next;
+
+ enum Stage {
+ /** 1. prio: all top-level resources, ie., resources with no outer. */
+ OuterLess,
+ /** 2. prio: resources whose outer has already been processed (element of the same varSet). */
+ InnerOfProcessed,
+ /** 3. prio: resources whose outer is not owned by any enclosing scope. */
+ InnerOfNotEnclosing,
+ /** 4. prio: when analysing on behalf of an exit point: anything not picked before. */
+ AtExit
+ }
+
+ public IteratorForReporting(List<FakedTrackingVariable> variables, Scope scope, boolean atExit) {
+ this.varSet = new HashSet<>(variables);
+ this.scope = scope;
+ this.atExit = atExit;
+ setUpForStage(Stage.OuterLess);
+ }
+ @Override
+ public boolean hasNext() {
+ FakedTrackingVariable trackingVar;
+ switch (this.stage) {
+ case OuterLess:
+ while (this.iterator.hasNext()) {
+ trackingVar = this.iterator.next();
+ if (trackingVar.outerTracker == null)
+ return found(trackingVar);
+ }
+ setUpForStage(Stage.InnerOfProcessed);
+ //$FALL-THROUGH$
+ case InnerOfProcessed:
+ while (this.iterator.hasNext()) {
+ trackingVar = this.iterator.next();
+ FakedTrackingVariable outer = trackingVar.outerTracker;
+ if (outer.binding.declaringScope == this.scope && !this.varSet.contains(outer))
+ return found(trackingVar);
+ }
+ setUpForStage(Stage.InnerOfNotEnclosing);
+ //$FALL-THROUGH$
+ case InnerOfNotEnclosing:
+ searchAlien: while (this.iterator.hasNext()) {
+ trackingVar = this.iterator.next();
+ FakedTrackingVariable outer = trackingVar.outerTracker;
+ if (!this.varSet.contains(outer)) {
+ Scope outerTrackerScope = outer.binding.declaringScope;
+ Scope currentScope = this.scope;
+ while ((currentScope = currentScope.parent) instanceof BlockScope) {
+ if (outerTrackerScope == currentScope)
+ break searchAlien;
+ }
+ return found(trackingVar);
}
}
- break; // not parent owned -> pick this var
- }
+ setUpForStage(Stage.AtExit);
+ //$FALL-THROUGH$
+ case AtExit:
+ if (this.atExit && this.iterator.hasNext())
+ return found(this.iterator.next());
+ return false;
+ default: throw new IllegalStateException("Unexpected Stage "+this.stage); //$NON-NLS-1$
}
}
- varsOfScope.remove(trackingVar);
- return trackingVar;
+ private boolean found(FakedTrackingVariable trackingVar) {
+ this.iterator.remove();
+ this.next = trackingVar;
+ return true;
+ }
+ private void setUpForStage(Stage nextStage) {
+ this.iterator = this.varSet.iterator();
+ this.stage = nextStage;
+ }
+ @Override
+ public FakedTrackingVariable next() {
+ return this.next;
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
}
/**
@@ -824,6 +889,11 @@
return false;
}
+ public void withdraw() {
+ // must unregister at the declaringScope, note that twr resources are owned by the scope enclosing the twr
+ this.binding.declaringScope.removeTrackingVar(this);
+ }
+
public void recordErrorLocation(ASTNode location, int nullStatus) {
if ((this.globalClosingState & OWNED_BY_OUTSIDE) != 0) {
return;
@@ -833,14 +903,20 @@
this.recordedLocations.put(location, new Integer(nullStatus));
}
- public boolean reportRecordedErrors(Scope scope, int mergedStatus) {
+ public boolean reportRecordedErrors(Scope scope, int mergedStatus, boolean atDeadEnd) {
FakedTrackingVariable current = this;
while (current.globalClosingState == 0) {
current = current.innerTracker;
if (current == null) {
// no relevant state found -> report:
- reportError(scope.problemReporter(), null, mergedStatus);
- return true;
+ if (atDeadEnd && neverClosedAtLocations())
+ mergedStatus = FlowInfo.NULL;
+ if ((mergedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) {
+ reportError(scope.problemReporter(), null, mergedStatus);
+ return true;
+ } else {
+ break;
+ }
}
}
boolean hasReported = false;
@@ -863,6 +939,15 @@
return hasReported;
}
+ private boolean neverClosedAtLocations() {
+ if (this.recordedLocations != null) {
+ for (Object value : this.recordedLocations.values())
+ if (!value.equals(FlowInfo.NULL))
+ return false;
+ }
+ return true;
+ }
+
public int reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) {
if ((this.globalClosingState & OWNED_BY_OUTSIDE) != 0) {
return 0; // TODO: should we still propagate some flags??
@@ -903,14 +988,6 @@
}
}
- public void resetReportingBits() {
- FakedTrackingVariable current = this;
- do {
- current.globalClosingState &= ~(REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK);
- current = current.innerTracker;
- } while (current != null);
- }
-
public String nameForReporting(ASTNode location, ReferenceContext referenceContext) {
if (this.name == UNASSIGNED_CLOSEABLE_NAME) {
if (location != null && referenceContext != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
index 3796302..3e72271 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
@@ -1,15 +1,17 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
* http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
+ *Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
+import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
@@ -24,6 +26,8 @@
public int bodyStart;
public int bodyEnd;
+ private MethodBinding methodBinding;
+
public Initializer(Block block, int modifiers) {
this.block = block;
this.modifiers = modifiers;
@@ -126,6 +130,17 @@
}
}
+ /** Method used only by DOM to support bindings of initializers. */
+ public MethodBinding getMethodBinding() {
+ if (this.methodBinding == null) {
+ Scope scope = this.block.scope;
+ this.methodBinding = isStatic()
+ ? new MethodBinding(ClassFileConstants.AccStatic, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType())
+ : new MethodBinding(0, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType());
+ }
+ return this.methodBinding;
+ }
+
public void traverse(ASTVisitor visitor, MethodScope scope) {
if (visitor.visit(this, scope)) {
if (this.block != null) this.block.traverse(visitor, scope);
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 fd8c73f..1d7dbf4 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
@@ -52,6 +52,7 @@
* Bug 441734 - [1.8][inference] Generic method with nested parameterized type argument fails on method reference
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
* Jesper S Moller - Contributions for
* Bug 378674 - "The method can be declared as static" is wrong
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
@@ -736,6 +737,8 @@
// SH}
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
if (this.binding.isValidBinding()) {
// try to retrieve null status of this message send from an annotation of the called method:
long tagBits = this.binding.tagBits;
@@ -1632,7 +1635,7 @@
visitor.endVisit(this, blockScope);
}
public boolean statementExpression() {
- return true;
+ return ((this.bits & ASTNode.ParenthesizedMASK) == 0);
}
public boolean receiverIsImplicitThis() {
return this.receiver.isImplicitThis();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index c090aaa..31ebefe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -53,6 +53,7 @@
import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
@@ -64,6 +65,7 @@
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ConstructorDecapsulationException;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.OTQualifiedAllocationExpression;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
@@ -361,9 +363,18 @@
TypeBinding result = resolveTypeForQualifiedAllocationExpression(scope);
if (result != null && !result.isPolyType() && this.binding != null) {
final CompilerOptions compilerOptions = scope.compilerOptions();
- if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
- new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
- .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
+ if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
+ if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
+ new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
+ .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
+ }
+ if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
+ if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
+ TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
+ for (int i = 0; i < this.typeArguments.length; i++)
+ this.typeArguments[i].checkNullConstraints(scope, typeVariables, i);
+ }
+ }
}
}
return result;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
index 96ebe04..281de66 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -17,6 +17,7 @@
* bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files
* Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 411964 - [1.8][null] leverage null type annotation in foreach statement
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -157,6 +158,8 @@
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
FieldBinding fieldBinding = lastFieldBinding();
if (fieldBinding != null) {
if (fieldBinding.isNonNull() || flowContext.isNullcheckedFieldAccess(this)) {
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 a7adb88..a4b0a2c 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
@@ -34,6 +34,7 @@
* Bug 438945 - [1.8] NullPointerException InferenceContext18.checkExpression in java 8 with generics, primitives, and overloading
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound
+ * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf()
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contribution for
* Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
*******************************************************************************/
@@ -57,6 +58,7 @@
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -576,6 +578,7 @@
scope.problemReporter().constructedArrayIncompatible(this, lhsType, this.descriptor.returnType);
return this.resolvedType = null;
}
+ checkNullAnnotations(scope);
return this.resolvedType;
}
@@ -697,44 +700,7 @@
}
scope.problemReporter().unhandledException(methodExceptions[i], this);
}
- if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
- if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) { // otherwise assume it has been reported and we can do nothing here
- // TODO: simplify by using this.freeParameters?
- int len;
- int expectedlen = this.binding.parameters.length;
- int providedLen = this.descriptor.parameters.length;
- if (this.receiverPrecedesParameters)
- providedLen--; // one parameter is 'consumed' as the receiver
- boolean isVarArgs = false;
- if (this.binding.isVarargs()) {
- isVarArgs = (providedLen == expectedlen)
- ? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1])
- : true;
- len = providedLen; // binding parameters will be padded from InferenceContext18.getParameter()
- } else {
- len = Math.min(expectedlen, providedLen);
- }
- for (int i = 0; i < len; i++) {
- TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)];
- TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs);
- NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameter, descriptorParameter, FlowInfo.UNKNOWN);
- if (annotationStatus.isAnyMismatch()) {
- // immediate reporting:
- scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus);
- }
- }
- if (!this.binding.isConstructor() && (this.descriptor.returnType.tagBits & TagBits.AnnotationNonNull) != 0) {
- // since constructors never return null we don't have to check those anyway.
- if ((this.binding.returnType.tagBits & TagBits.AnnotationNonNull) == 0) {
- char[][] providedAnnotationName = ((this.binding.returnType.tagBits & TagBits.AnnotationNullable) != 0) ?
- scope.environment().getNullableAnnotationName() : null;
- scope.problemReporter().illegalReturnRedefinition(this, this.descriptor,
- scope.environment().getNonNullAnnotationName(),
- providedAnnotationName, this.binding.returnType);
- }
- }
- }
- }
+ checkNullAnnotations(scope);
this.freeParameters = null; // not used after method lookup
if (checkInvocationArguments(scope, null, this.receiverType, this.binding, null, descriptorParameters, false, this))
@@ -771,6 +737,45 @@
return this.resolvedType; // Phew !
}
+ protected void checkNullAnnotations(BlockScope scope) {
+ if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
+ if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) { // otherwise assume it has been reported and we can do nothing here
+ // TODO: simplify by using this.freeParameters?
+ int len;
+ int expectedlen = this.binding.parameters.length;
+ int providedLen = this.descriptor.parameters.length;
+ if (this.receiverPrecedesParameters)
+ providedLen--; // one parameter is 'consumed' as the receiver
+ boolean isVarArgs = false;
+ if (this.binding.isVarargs()) {
+ isVarArgs = (providedLen == expectedlen)
+ ? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1])
+ : true;
+ len = providedLen; // binding parameters will be padded from InferenceContext18.getParameter()
+ } else {
+ len = Math.min(expectedlen, providedLen);
+ }
+ for (int i = 0; i < len; i++) {
+ TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)];
+ TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs);
+ NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameter, descriptorParameter, FlowInfo.UNKNOWN);
+ if (annotationStatus.isAnyMismatch()) {
+ // immediate reporting:
+ scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus);
+ }
+ }
+ TypeBinding returnType = this.binding.returnType;
+ if (this.binding.isConstructor() || this.binding == scope.environment().arrayClone) {
+ returnType = scope.environment().createAnnotatedType(this.receiverType, new AnnotationBinding[]{ scope.environment().getNonNullAnnotation() });
+ }
+ NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(this.descriptor.returnType, returnType, FlowInfo.UNKNOWN);
+ if (annotationStatus.isAnyMismatch()) {
+ scope.problemReporter().illegalReturnRedefinition(this, this.descriptor, annotationStatus.isUnchecked(), returnType);
+ }
+ }
+ }
+ }
+
private TypeBinding[] descriptorParametersAsArgumentExpressions() {
if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0)
@@ -950,7 +955,15 @@
@Override
public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
-
+
+ final boolean isConstructorRef = isConstructorReference();
+ if (isConstructorRef && this.receiverType.isArrayType()) {
+ final TypeBinding leafComponentType = this.receiverType.leafComponentType();
+ if (!leafComponentType.isReifiable()) {
+ return false;
+ }
+ }
+
// We get here only when the reference expression is NOT pertinent to applicability.
if (!super.isPertinentToApplicability(targetType, null))
return true;
@@ -980,14 +993,12 @@
}
// 15.13.1
- final boolean isMethodReference = isMethodReference();
this.freeParameters = descriptorParameters;
this.checkingPotentialCompatibility = true;
try {
- MethodBinding compileTimeDeclaration =
- this.exactMethodBinding != null ? this.exactMethodBinding :
- isMethodReference ? scope.getMethod(this.receiverType, this.selector, descriptorParameters, this) :
- scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this);
+ MethodBinding compileTimeDeclaration = this.exactMethodBinding != null ? this.exactMethodBinding : isConstructorRef
+ ? scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this)
+ : scope.getMethod(this.receiverType, this.selector, descriptorParameters, this);
if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB.
this.potentialMethods = new MethodBinding [] { compileTimeDeclaration };
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
index bd01f40..89e198f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -324,6 +324,9 @@
if (this.expression != null) {
this.expression.setExpressionContext(ASSIGNMENT_CONTEXT);
this.expression.setExpectedType(methodType);
+ if (lambda != null && lambda.argumentsTypeElided() && this.expression instanceof CastExpression) {
+ this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
+ }
}
if (methodType == TypeBinding.VOID) {
@@ -370,9 +373,14 @@
if (expressionType.needsUncheckedConversion(methodType)) {
scope.problemReporter().unsafeTypeConversion(this.expression, expressionType, methodType);
}
- if (this.expression instanceof CastExpression
- && (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) {
- CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression);
+ if (this.expression instanceof CastExpression) {
+ if ((this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) {
+ CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression);
+ } else if (lambda != null && lambda.argumentsTypeElided() && (this.expression.bits & ASTNode.UnnecessaryCast) != 0) {
+ if (TypeBinding.equalsEquals(((CastExpression)this.expression).expression.resolvedType, methodType)) {
+ scope.problemReporter().unnecessaryCast((CastExpression)this.expression);
+ }
+ }
}
return;
} else if (isBoxingCompatible(expressionType, methodType, this.expression, scope)) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index db38143..1950dde 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -16,8 +16,9 @@
* bug 383368 - [compiler][null] syntactic null analysis for field references
* Bug 412203 - [compiler] Internal compiler error: java.lang.IllegalArgumentException: info cannot be null
* Bug 458396 - NPE in CodeStream.invoke()
+ * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
* Jesper S Moller - <jesper@selskabet.org> - Contributions for
- * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
+ * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
* bug 378674 - "The method can be declared as static" is wrong
* bug 404657 - [1.8][compiler] Analysis for effectively final variables fails to consider loops
*******************************************************************************/
@@ -901,6 +902,8 @@
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
+ if ((this.implicitConversion & TypeIds.BOXING) != 0)
+ return FlowInfo.NON_NULL;
LocalVariableBinding local = localVariableBinding();
if (local != null) {
return flowInfo.nullStatus(local);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
index 65c07a7..6b1a1ec 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -22,6 +22,8 @@
* bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check
* bug 384380 - False positive on a ?? Potential null pointer access ?? after a continue
* Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch
+ * Bug 371614 - [compiler][resource] Wrong "resource leak" problem on return/throw inside while loop
+ * Bug 444964 - [1.7+][resource] False resource leak warning (try-with-resources for ByteArrayOutputStream - return inside for loop)
* Jesper Steen Moller - Contributions for
* bug 404146 - [1.7][compiler] nested try-catch-finally-blocks leads to unrunnable Java byte code
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
@@ -165,8 +167,8 @@
resourceBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways.
if (resourceBinding.closeTracker != null) {
// this was false alarm, we don't need to track the resource
- this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
- // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block
+ resourceBinding.closeTracker.withdraw();
+ resourceBinding.closeTracker = null;
}
MethodBinding closeMethod = findCloseMethod(resource, resourceBinding);
if (closeMethod != null && closeMethod.isValidBinding() && closeMethod.returnType.id == TypeIds.T_void) {
@@ -279,7 +281,7 @@
resourceBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways.
if (resourceBinding.closeTracker != null) {
// this was false alarm, we don't need to track the resource
- this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
+ resourceBinding.closeTracker.withdraw();
// keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block
}
MethodBinding closeMethod = findCloseMethod(resource, resourceBinding);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
index 27b11b3..87e1254 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -11,6 +11,7 @@
* bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
* bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check
* Bug 453483 - [compiler][null][loop] Improve null analysis for loops
+ * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.flow;
@@ -83,6 +84,7 @@
UnconditionalFlowInfo unconditionalCopy = flowInfo.unconditionalCopy();
unconditionalCopy.iNBit = -1L;
unconditionalCopy.iNNBit = -1L;
+ unconditionalCopy.tagBits |= FlowInfo.UNROOTED;
this.initsOnFinally = unconditionalCopy;
}
ExceptionHandlingFlowContext(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
index 7cecbc2..f1e5d43 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -14,6 +14,7 @@
* bug 332637 - Dead Code detection removing code that isn't dead
* bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional
* Bug 411964 - [1.8][null] leverage null type annotation in foreach statement
+ * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.flow;
@@ -61,6 +62,8 @@
public final static int POTENTIALLY_NULL = 16;
public final static int POTENTIALLY_NON_NULL = 32;
+ public final static int UNROOTED = 64; // marks a flowInfo that may be appended to another flowInfo (accepting incoming nulls/nonnulls, see UFI.iNBit/iNNBit).
+
public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
static {
DEAD_END = new UnconditionalFlowInfo();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
index 210650c..3b49f17 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -23,6 +23,7 @@
* Bug 455557 - [jdt] NPE LoopingFlowContext.recordNullReference
* Bug 455723 - Nonnull argument not correctly inferred in loop
* Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch
+ * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment
* Jesper S Moller - contributions for
* bug 404657 - [1.8][compiler] Analysis for effectively final variables fails to consider loops
*******************************************************************************/
@@ -417,7 +418,7 @@
}
nullStatus = closeTracker.findMostSpecificStatus(flowInfo, scope, null);
closeTracker.recordErrorLocation(this.nullReferences[i], nullStatus);
- closeTracker.reportRecordedErrors(scope, nullStatus);
+ closeTracker.reportRecordedErrors(scope, nullStatus, flowInfo.reachMode() != FlowInfo.REACHABLE);
this.nullReferences[i] = null;
continue;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
index 8b68fd8..4e34ec5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -21,6 +21,7 @@
* bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional
* Bug 453483 - [compiler][null][loop] Improve null analysis for loops
* Bug 454031 - [compiler][null][loop] bug in null analysis; wrong "dead code" detection
+ * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.flow;
@@ -440,10 +441,7 @@
else if (otherInits.extra != null) {
// no storage here, but other has extra storage.
int otherLength = otherInits.extra[0].length;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[otherLength];
- }
+ createExtraSpace(otherLength);
System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0,
otherLength);
}
@@ -528,10 +526,7 @@
if (otherInits.extra != null) {
int mergeLimit = 0, copyLimit = otherInits.extra[0].length;
if (this.extra == null) {
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[copyLimit];
- }
+ createExtraSpace(copyLimit);
if (COVERAGE_TEST_FLAG) {
if (CoverageTestId == 11) {
throw new AssertionFailedException("COVERAGE 11"); //$NON-NLS-1$
@@ -1188,10 +1183,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
if (COVERAGE_TEST_FLAG) {
if (CoverageTestId == 16) {
throw new AssertionFailedException("COVERAGE 16"); //$NON-NLS-1$
@@ -1287,10 +1279,7 @@
mask = 1L << (position % BitCacheSize);
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length ];
- }
+ createExtraSpace(length);
if (COVERAGE_TEST_FLAG) {
if(CoverageTestId == 20) {
throw new AssertionFailedException("COVERAGE 20"); //$NON-NLS-1$
@@ -1355,10 +1344,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1416,10 +1402,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1476,10 +1459,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1543,10 +1523,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1632,10 +1609,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1682,10 +1656,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -1732,10 +1703,7 @@
int vectorIndex = (position / BitCacheSize) - 1;
if (this.extra == null) {
int length = vectorIndex + 1;
- this.extra = new long[extraLength][];
- for (int j = 0; j < extraLength; j++) {
- this.extra[j] = new long[length];
- }
+ createExtraSpace(length);
}
else {
int oldLength; // might need to grow the arrays
@@ -2055,6 +2023,7 @@
copy.iNBit = -1L;
copy.iNNBit = -1L;
copy.tagBits = this.tagBits & ~NULL_FLAG_MASK;
+ copy.tagBits |= UNROOTED;
copy.maxFieldCount = this.maxFieldCount;
if (this.extra != null) {
int length;
@@ -2215,9 +2184,7 @@
}
}
else if (vectorIndex >= 0) {
- for (int j = 0; j < extraLength; j++) {
- copy.extra[j] = new long[length];
- }
+ copy.createExtraSpace(length);
}
if (vectorIndex >= 0) {
mask = ~((1L << (limit % BitCacheSize))-1);
@@ -2261,5 +2228,16 @@
}
}
}
+
+private void createExtraSpace(int length) {
+ this.extra = new long[extraLength][];
+ for (int j = 0; j < extraLength; j++) {
+ this.extra[j] = new long[length];
+ }
+ if ((this.tagBits & UNROOTED) != 0) {
+ Arrays.fill(this.extra[IN], -1L);
+ Arrays.fill(this.extra[INN], -1L);
+ }
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
index a3bf693..29f4311 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
@@ -131,14 +131,14 @@
public abstract int kind();
/*
* Computes a key that uniquely identifies this binding.
- * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding.
+ * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding, a LocalVariableBinding or a PackageBinding (i.e. an ImportBinding).
*/
public char[] computeUniqueKey() {
return computeUniqueKey(true/*leaf*/);
}
/*
* Computes a key that uniquely identifies this binding. Optionally include access flags.
- * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding.
+ * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding, a LocalVariableBinding or a PackageBinding (i.e. an ImportBinding)
*/
public char[] computeUniqueKey(boolean isLeaf) {
return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
index 68b1712..297d3f4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -20,6 +20,10 @@
* bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional
* bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
+ * Bug 371614 - [compiler][resource] Wrong "resource leak" problem on return/throw inside while loop
+ * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment
+ * Bug 444964 - [1.7+][resource] False resource leak warning (try-with-resources for ByteArrayOutputStream - return inside for loop)
+ * Bug 396575 - [compiler][resources] Incorrect Errors/Warnings check for potential resource leak when surrounding with try-catch
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 378674 - "The method can be declared as static" is wrong
* Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class
@@ -27,10 +31,9 @@
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.*;
@@ -1212,7 +1215,7 @@
/** When are no longer interested in this tracking variable - remove it. */
public void removeTrackingVar(FakedTrackingVariable trackingVariable) {
if (trackingVariable.innerTracker != null) {
- removeTrackingVar(trackingVariable.innerTracker);
+ trackingVariable.innerTracker.withdraw();
trackingVariable.innerTracker = null;
}
if (this.trackingVariables != null)
@@ -1242,10 +1245,10 @@
FakedTrackingVariable returnVar = (location instanceof ReturnStatement) ?
FakedTrackingVariable.getCloseTrackingVariable(((ReturnStatement)location).expression, flowInfo, flowContext) : null;
- Set varSet = new HashSet(this.trackingVariables);
- FakedTrackingVariable trackingVar;
- // pick one outer-most variable from the set at a time
- while ((trackingVar = FakedTrackingVariable.pickVarForReporting(varSet, this, location != null)) != null) {
+ // iterate variables according to the priorities defined in FakedTrackingVariable.IteratorForReporting.Stage
+ Iterator<FakedTrackingVariable> iterator = new FakedTrackingVariable.IteratorForReporting(this.trackingVariables, this, location != null);
+ while (iterator.hasNext()) {
+ FakedTrackingVariable trackingVar = iterator.next();
if (returnVar != null && trackingVar.isResourceBeingReturned(returnVar)) {
continue;
@@ -1270,7 +1273,7 @@
if (location == null) // at end of block and not definitely unclosed
{
// problems at specific locations: medium priority
- if (trackingVar.reportRecordedErrors(this, status)) // ... report previously recorded errors
+ if (trackingVar.reportRecordedErrors(this, status, flowInfo.reachMode() != FlowInfo.REACHABLE)) // ... report previously recorded errors
continue;
}
if (status == FlowInfo.POTENTIALLY_NULL) {
@@ -1287,12 +1290,6 @@
for (int i=0; i<this.localIndex; i++)
this.locals[i].closeTracker = null;
this.trackingVariables = null;
- } else {
- int size = this.trackingVariables.size();
- for (int i=0; i<size; i++) {
- FakedTrackingVariable tracker = (FakedTrackingVariable) this.trackingVariables.get(i);
- tracker.resetReportingBits();
- }
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index 5e987f8..4ccb266 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -14,6 +14,7 @@
* Bug 441797 - [1.8] synchronize type annotations on capture and its wildcard
* Bug 456497 - [1.8][null] during inference nullness from target type is lost against weaker hint from applicability analysis
* Bug 456924 - StackOverflowError during compilation
+ * Bug 462790 - [null] NPE in Expression.computeConversion()
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -49,6 +50,7 @@
this.end = end;
this.captureID = captureID;
this.tagBits |= TagBits.HasCapturedWildcard;
+ this.cud = cud;
if (wildcard.hasTypeAnnotations()) {
// register an unannoted version before adding the annotated wildcard:
CaptureBinding unannotated = (CaptureBinding) clone(null);
@@ -64,7 +66,6 @@
} else {
computeId(this.environment);
}
- this.cud = cud;
}
// for subclass CaptureBinding18
@@ -440,6 +441,26 @@
return this.wildcard;
}
+ /*
+ * CaptureBinding needs even more propagation, because we are creating a naked type
+ * (during CaptureBinding(WildcardBinding,ReferenceBinding,int,int,ASTNode,int)
+ * that has no firstBound / superclass / superInterfaces set.
+ */
+ @Override
+ protected TypeBinding[] getDerivedTypesForDeferredInitialization() {
+ TypeBinding[] derived = this.environment.typeSystem.getDerivedTypes(this);
+ if (derived.length > 0) {
+ int count = 0;
+ for (int i = 0; i < derived.length; i++) {
+ if (derived[i] != null && derived[i].id == this.id)
+ derived[count++] = derived[i];
+ }
+ if (count < derived.length)
+ System.arraycopy(derived, 0, derived = new TypeBinding[count], 0, count);
+ }
+ return derived;
+ }
+
public String toString() {
if (this.wildcard != null) {
StringBuffer buffer = new StringBuffer(10);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index 508c72d..f76562d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -22,6 +22,7 @@
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
* Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class
* Bug 444024 - [1.8][compiler][null] Type mismatch error in annotation generics assignment which happens "sometimes"
+ * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf()
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes
* het@google.com - Bug 456986 - Bogus error when annotation processor generates annotation type
@@ -617,6 +618,12 @@
fields[i].modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
}
}
+ if (isEnum && compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
+ // mark return types of values & valueOf as nonnull (needed to wait till after setMethods() to avoid reentrance):
+ LookupEnvironment environment = this.environment();
+ ((SyntheticMethodBinding)methodBindings[0]).markNonNull(environment);
+ ((SyntheticMethodBinding)methodBindings[1]).markNonNull(environment);
+ }
}
//{ObjectTeams: accessible to sub-class:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index ee19b24..1056a1c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -40,6 +40,7 @@
* Bug 446434 - [1.8][null] Enable interned captures also when analysing null type annotations
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
* Bug 456508 - Unexpected RHS PolyTypeBinding for: <code-snippet>
+ * Bug 390064 - [compiler][resource] Resource leak warning missing when extending parameterized class
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -102,6 +103,7 @@
if (enclosingType != null && enclosingType.hasNullTypeAnnotations())
this.tagBits |= TagBits.HasNullTypeAnnotation;
this.tagBits |= TagBits.HasUnresolvedTypeVariables; // cleared in resolve()
+ this.typeBits = type.typeBits;
}
/**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 61007e1..e436088 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -36,9 +36,12 @@
* Bug 440759 - [1.8][null] @NonNullByDefault should never affect wildcards and uses of a type variable
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Bug 446442 - [1.8] merge null annotations from super methods
+ * Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages
* Jesper S Moller - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -1026,10 +1029,20 @@
}
break;
case 6:
- if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.ITYPEBINDING, this.compoundName[5]))
- return;
- if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_CORE_DOM_ITYPEBINDING, this.compoundName))
- this.typeBits |= TypeIds.BitUninternedType;
+ if (CharOperation.equals(TypeConstants.ORG, this.compoundName[0])) {
+ if (CharOperation.equals(TypeConstants.SPRING, this.compoundName[1])) {
+ if (CharOperation.equals(TypeConstants.AUTOWIRED, this.compoundName[5])) {
+ if (CharOperation.equals(TypeConstants.ORG_SPRING_AUTOWIRED, this.compoundName)) {
+ this.id = TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired;
+ }
+ }
+ return;
+ }
+ if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.ITYPEBINDING, this.compoundName[5]))
+ return;
+ if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_CORE_DOM_ITYPEBINDING, this.compoundName))
+ this.typeBits |= TypeIds.BitUninternedType;
+ }
break;
case 7 :
if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.TYPEBINDING, this.compoundName[6]))
@@ -2051,15 +2064,24 @@
protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) {
if (options.isAnnotationBasedNullAnalysisEnabled) {
- // restore applied null annotation from tagBits:
- if ((this.tagBits & TagBits.AnnotationNonNull) != 0) {
- char[][] nonNullAnnotationName = options.nonNullAnnotationName;
- nameBuffer.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]).append(' ');
- }
- if ((this.tagBits & TagBits.AnnotationNullable) != 0) {
- char[][] nullableAnnotationName = options.nullableAnnotationName;
- nameBuffer.append('@').append(nullableAnnotationName[nullableAnnotationName.length-1]).append(' ');
- }
+ if (options.usesNullTypeAnnotations()) {
+ for (AnnotationBinding annotation : this.typeAnnotations) {
+ TypeBinding annotationType = annotation.getAnnotationType();
+ if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull || annotation.type.id == TypeIds.T_ConfiguredAnnotationNullable) {
+ nameBuffer.append('@').append(annotationType.shortReadableName()).append(' ');
+ }
+ }
+ } else {
+ // restore applied null annotation from tagBits:
+ if ((this.tagBits & TagBits.AnnotationNonNull) != 0) {
+ char[][] nonNullAnnotationName = options.nonNullAnnotationName;
+ nameBuffer.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]).append(' ');
+ }
+ if ((this.tagBits & TagBits.AnnotationNullable) != 0) {
+ char[][] nullableAnnotationName = options.nullableAnnotationName;
+ nameBuffer.append('@').append(nullableAnnotationName[nullableAnnotationName.length-1]).append(' ');
+ }
+ }
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 032efd5..51b02a7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -1713,13 +1713,13 @@
ObjectVector found = new ObjectVector(3);
CompilationUnitScope unitScope = compilationUnitScope();
unitScope.recordTypeReferences(argumentTypes);
-
+ List<TypeBinding> visitedTypes = new ArrayList<TypeBinding>();
if (receiverTypeIsInterface) {
unitScope.recordTypeReference(receiverType);
MethodBinding[] receiverMethods = receiverType.getMethods(selector, argumentTypes.length);
if (receiverMethods.length > 0)
found.addAll(receiverMethods);
- findMethodInSuperInterfaces(receiverType, selector, found, null, invocationSite);
+ findMethodInSuperInterfaces(receiverType, selector, found, visitedTypes, invocationSite);
//{ObjectTeams: confined types don't proceed to java.lang.Object:
if (!(TypeAnalyzer.isConfined(receiverType)))
// SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index c108d8b..c1c2ede 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -26,6 +26,7 @@
* bug 391376 - [1.8] check interaction of default methods with bridge methods and generics
* Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
+ * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
* Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled
* Bug 416172 - [1.8][compiler][null] null type annotation not evaluated on method return type
* Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
@@ -1158,16 +1159,27 @@
return uniqueKey;
}
-//{ObjectTeams: allow access from Dependencies:
-public
-// SH}
-void faultInTypesForFieldsAndMethods() {
- if (!isPrototype()) throw new IllegalStateException();
+private void checkAnnotationsInType() {
// check @Deprecated annotation
getAnnotationTagBits(); // marks as deprecated by side effect
ReferenceBinding enclosingType = enclosingType();
if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !isDeprecated())
this.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
+
+ for (int i = 0, length = this.memberTypes.length; i < length; i++)
+ ((SourceTypeBinding) this.memberTypes[i]).checkAnnotationsInType();
+}
+
+//{ObjectTeams: allow access from Dependencies:
+public
+// SH}
+void faultInTypesForFieldsAndMethods() {
+ if (!isPrototype()) throw new IllegalStateException();
+ checkAnnotationsInType();
+ internalFaultInTypeForFieldsAndMethods();
+}
+
+private void internalFaultInTypeForFieldsAndMethods() {
fields();
methods();
@@ -1180,7 +1192,7 @@
for (int i = 0; i < this.memberTypes.length; i++)
if (!this.memberTypes[i].isBinaryBinding()) // roles could be binary contained in source
//carp}
- ((SourceTypeBinding) this.memberTypes[i]).faultInTypesForFieldsAndMethods();
+ ((SourceTypeBinding) this.memberTypes[i]).internalFaultInTypeForFieldsAndMethods();
}
// NOTE: the type of each field of a source type is resolved when needed
public FieldBinding[] fields() {
@@ -2519,7 +2531,7 @@
arg.type.resolvedType :
arg.type.resolveType(methodDecl.scope, true /* check bounds*/);
// orig:
-// parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/);
+// parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/);
} finally {
if (deferRawTypeCheck) {
arg.type.bits &= ~ASTNode.IgnoreRawTypeCheck;
@@ -2755,8 +2767,7 @@
methodDecl.createArgumentBindings();
// add implicit annotations (inherited(?) & default):
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
- new ImplicitNullAnnotationVerifier(this.scope.environment(), compilerOptions.inheritNullAnnotations)
- .checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
+ new ImplicitNullAnnotationVerifier(this.scope.environment()).checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
index 73a188d..133ff43 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -11,6 +11,7 @@
* Technical University Berlin - extended API and implementation
* Stephan Herrmann - Contribution for
* bug 400710 - [1.8][compiler] synthetic access to default method generates wrong code
+ * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf()
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
*******************************************************************************/
@@ -458,6 +459,14 @@
this.modifiers = ClassFileConstants.AccSynthetic | ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
this.returnType = arrayType;
+ LookupEnvironment environment = declaringClass.environment;
+ if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
+ // mark X[]::new and X[]::clone as returning 'X @NonNull' (don't wait (cf. markNonNull()), because we're called as late as codeGen):
+ if (environment.usesNullTypeAnnotations())
+ this.returnType = environment.createAnnotatedType(this.returnType, new AnnotationBinding[]{ environment.getNonNullAnnotation() });
+ else
+ this.tagBits |= TagBits.AnnotationNonNull;
+ }
this.parameters = new TypeBinding[] { purpose == SyntheticMethodBinding.ArrayConstructor ? TypeBinding.INT : (TypeBinding) arrayType};
this.thrownExceptions = Binding.NO_EXCEPTIONS;
this.purpose = purpose;
@@ -673,4 +682,27 @@
public LambdaExpression sourceLambda() {
return this.lambda;
}
+
+ public void markNonNull(LookupEnvironment environment) {
+ // deferred update of the return type
+ switch (this.purpose) {
+ case EnumValues:
+ if (environment.usesNullTypeAnnotations()) {
+ TypeBinding elementType = ((ArrayBinding)this.returnType).leafComponentType();
+ AnnotationBinding nonNullAnnotation = environment.getNonNullAnnotation();
+ elementType = environment.createAnnotatedType(elementType, new AnnotationBinding[]{ environment.getNonNullAnnotation() });
+ this.returnType = environment.createArrayType(elementType, 1, new AnnotationBinding[]{ nonNullAnnotation, null });
+ } else {
+ this.tagBits |= TagBits.AnnotationNonNull;
+ }
+ return;
+ case EnumValueOf:
+ if (environment.usesNullTypeAnnotations()) {
+ this.returnType = environment.createAnnotatedType(this.returnType, new AnnotationBinding[]{ environment.getNonNullAnnotation() });
+ } else {
+ this.tagBits |= TagBits.AnnotationNonNull;
+ }
+ return;
+ }
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index c9611a2..0284bd1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -22,6 +22,8 @@
* Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -119,6 +121,7 @@
char[] TYPEBINDING = "TypeBinding".toCharArray(); //$NON-NLS-1$
char[] DOM = "dom".toCharArray(); //$NON-NLS-1$
char[] ITYPEBINDING = "ITypeBinding".toCharArray(); //$NON-NLS-1$
+ char[] SPRING = "springframework".toCharArray(); //$NON-NLS-1$
// Constant compound names
char[][] JAVA_LANG = {JAVA, LANG};
@@ -330,6 +333,13 @@
// detail for the above:
char[] OPTIONAL = "optional".toCharArray(); //$NON-NLS-1$
+ // Spring @Autowired annotation
+ char [] AUTOWIRED = "Autowired".toCharArray(); //$NON-NLS-1$
+ char [] BEANS = "beans".toCharArray(); //$NON-NLS-1$
+ char [] FACTORY = "factory".toCharArray(); //$NON-NLS-1$
+ char[][] ORG_SPRING_AUTOWIRED = new char[][] {ORG, SPRING, BEANS, FACTORY, ANNOTATION, AUTOWIRED};
+ char[] REQUIRED = "required".toCharArray(); //$NON-NLS-1$
+
// Constraints for generic type argument inference
int CONSTRAINT_EQUAL = 0; // Actual = Formal
int CONSTRAINT_EXTENDS = 1; // Actual << Formal
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 cc71148..1693a65 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -16,6 +16,8 @@
* bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -127,11 +129,16 @@
// new in 3.9 to identify known @Inject annotations
final int T_JavaxInjectInject = 80;
final int T_ComGoogleInjectInject = 81;
+
+ // @Autowired
+ final int T_OrgSpringframeworkBeansFactoryAnnotationAutowired = 82;
+
// Java 8 - JEP 120
final int T_JavaLangAnnotationRepeatable = 90;
// If you add new type id, make sure to bump up T_LastWellKnownTypeId if there is a cross over.
final int T_LastWellKnownTypeId = 128;
+
final int NoId = Integer.MAX_VALUE;
public static final int IMPLICIT_CONVERSION_MASK = 0xFF;
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 c1abf52..df79020 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
@@ -33,6 +33,8 @@
* Bug 456497 - [1.8][null] during inference nullness from target type is lost against weaker hint from applicability analysis
* Bug 456459 - Discrepancy between Eclipse compiler and javac - Enums, interfaces, and generics
* Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief
+ * Bug 462790 - [null] NPE in Expression.computeConversion()
+ * Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -944,6 +946,27 @@
return readableName;
}
+ protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) {
+ int oldSize = nameBuffer.length();
+ super.appendNullAnnotation(nameBuffer, options);
+ if (oldSize == nameBuffer.length()) { // nothing appended in super.appendNullAnnotation()?
+ if (hasNullTypeAnnotations()) {
+ // see if the prototype has null type annotations:
+ TypeVariableBinding[] typeVariables = null;
+ if (this.declaringElement instanceof ReferenceBinding) {
+ typeVariables = ((ReferenceBinding) this.declaringElement).typeVariables();
+ } else if (this.declaringElement instanceof MethodBinding) {
+ typeVariables = ((MethodBinding) this.declaringElement).typeVariables();
+ }
+ if (typeVariables != null && typeVariables.length > this.rank) {
+ TypeVariableBinding prototype = typeVariables[this.rank];
+ if (prototype != this)//$IDENTITY-COMPARISON$
+ prototype.appendNullAnnotation(nameBuffer, options);
+ }
+ }
+ }
+ }
+
public TypeBinding unannotated() {
return this.hasTypeAnnotations() ? this.environment.getUnannotatedType(this) : this;
}
@@ -1032,10 +1055,11 @@
public TypeBinding setFirstBound(TypeBinding firstBound) {
this.firstBound = firstBound;
if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
- TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this);
+ TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- annotatedType.firstBound = firstBound;
+ if (annotatedType.firstBound == null)
+ annotatedType.firstBound = firstBound;
}
}
if (firstBound != null && firstBound.hasNullTypeAnnotations())
@@ -1048,10 +1072,11 @@
public ReferenceBinding setSuperClass(ReferenceBinding superclass) {
this.superclass = superclass;
if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
- TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this);
+ TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- annotatedType.superclass = superclass;
+ if (annotatedType.superclass == null)
+ annotatedType.superclass = superclass;
}
}
return superclass;
@@ -1062,15 +1087,20 @@
public ReferenceBinding [] setSuperInterfaces(ReferenceBinding[] superInterfaces) {
this.superInterfaces = superInterfaces;
if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
- TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this);
+ TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- annotatedType.superInterfaces = superInterfaces;
+ if (annotatedType.superInterfaces == null)
+ annotatedType.superInterfaces = superInterfaces;
}
}
return superInterfaces;
}
+ protected TypeBinding[] getDerivedTypesForDeferredInitialization() {
+ return this.environment.getAnnotatedTypes(this);
+ }
+
public TypeBinding combineTypeAnnotations(TypeBinding substitute) {
if (hasTypeAnnotations()) {
// may need to merge annotations from the original variable and from substitution:
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 fd36d24..689813b 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
@@ -59,6 +59,8 @@
* Bug 446442 - [1.8] merge null annotations from super methods
* Bug 455723 - Nonnull argument not correctly inferred in loop
* Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
+ * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf()
+ * Bug 461878 - [1.7][1.8][compiler][null] ECJ compiler does not allow to use null annotations on annotations
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -68,6 +70,8 @@
* bug 419209 - [1.8] Repeating container annotations should be rejected in the presence of annotation it contains
* Bug 429384 - [1.8][null] implement conformance rules for null-annotated lower / upper type bounds
* Bug 416182 - [1.8][compiler][null] Contradictory null annotations not rejected
+ * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
+ * bug 386692 - Missing "unused" warning on "autowired" fields
********************************************************************************/
package org.eclipse.jdt.internal.compiler.problem;
@@ -6366,8 +6370,15 @@
String[] shortArguments = new String[] {
String.valueOf(annotation.resolvedType.shortReadableName())
};
+ int severity = ProblemSeverities.Error | ProblemSeverities.Fatal;
+ if (annotation.recipient instanceof ReferenceBinding) {
+ if (((ReferenceBinding) annotation.recipient).isAnnotationType())
+ severity = ProblemSeverities.Warning; // special case for https://bugs.eclipse.org/461878
+ }
handle(IProblem.NullAnnotationUnsupportedLocation,
- arguments, shortArguments, annotation.sourceStart, annotation.sourceEnd);
+ arguments, shortArguments,
+ severity,
+ annotation.sourceStart, annotation.sourceEnd);
}
public void nullAnnotationUnsupportedLocation(TypeReference type) {
int sourceEnd = type.sourceEnd;
@@ -9527,6 +9538,7 @@
break;
case TypeIds.T_JavaxInjectInject:
case TypeIds.T_ComGoogleInjectInject:
+ case TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired:
if (problemId != IProblem.UnusedPrivateField)
return true; // @Inject on method/ctor does constitute a relevant use, just on fields it doesn't
break;
@@ -13802,8 +13814,7 @@
location.sourceEnd);
}
public void illegalReturnRedefinition(ASTNode location, MethodBinding descriptorMethod,
- char[][] nonNullAnnotationName,
- char/*@Nullable*/[][] providedAnnotationName, TypeBinding providedType) {
+ boolean isUnchecked, TypeBinding providedType) {
StringBuffer methodSignature = new StringBuffer()
.append(descriptorMethod.declaringClass.readableName())
.append('.')
@@ -13812,22 +13823,16 @@
.append(descriptorMethod.declaringClass.shortReadableName())
.append('.')
.append(descriptorMethod.shortReadableName());
- StringBuffer providedPrefix = new StringBuffer();
- StringBuffer providedShortPrefix = new StringBuffer();
- if (providedAnnotationName != null) {
- providedPrefix.append('@').append(CharOperation.toString(providedAnnotationName)).append(' ');
- providedShortPrefix.append('@').append(providedAnnotationName[providedAnnotationName.length-1]).append(' ');
- }
this.handle(
- providedAnnotationName == null
+ isUnchecked
? IProblem.ReferenceExpressionReturnNullRedefUnchecked
: IProblem.ReferenceExpressionReturnNullRedef,
new String[] { methodSignature.toString(),
- CharOperation.toString(nonNullAnnotationName), String.valueOf(descriptorMethod.returnType.readableName()),
- providedPrefix.toString(), String.valueOf(providedType.readableName())},
+ String.valueOf(descriptorMethod.returnType.nullAnnotatedReadableName(this.options, false)),
+ String.valueOf(providedType.nullAnnotatedReadableName(this.options, false))},
new String[] { shortSignature.toString(),
- String.valueOf(nonNullAnnotationName[nonNullAnnotationName.length-1]), String.valueOf(descriptorMethod.returnType.shortReadableName()),
- providedShortPrefix.toString(), String.valueOf(providedType.shortReadableName())},
+ String.valueOf(descriptorMethod.returnType.nullAnnotatedReadableName(this.options, true)),
+ String.valueOf(providedType.nullAnnotatedReadableName(this.options, true))},
location.sourceStart,
location.sourceEnd);
}
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 c8fe886..c1fdaa4 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
@@ -817,8 +817,8 @@
956 = Null type safety (type annotations): The expression of type ''{1}'' needs unchecked conversion to conform to ''{0}'', corresponding supertype is ''{2}''
957 = Null type mismatch at parameter {0}: required ''{1}'' but provided ''{2}'' via method descriptor {3}
958 = Null type safety: parameter {0} provided via method descriptor {3} needs unchecked conversion to conform to ''{1}''
-959 = Null type mismatch at method return type: Method descriptor {0} promises ''@{1} {2}'' but referenced method provides ''{3}{4}''
-960 = Null type safety at method return type: Method descriptor {0} promises ''@{1} {2}'' but referenced method provides ''{3}{4}''
+959 = Null type mismatch at method return type: Method descriptor {0} promises ''{1}'' but referenced method provides ''{2}''
+960 = Null type safety at method return type: Method descriptor {0} promises ''{1}'' but referenced method provides ''{2}''
961 = Redundant null check: comparing ''{0}'' against null
962 = The nullness annotation ''{0}'' is not applicable at this location
963 = Nullness annotations are not applicable at this location
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
index 151d5da..74844eb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -1115,7 +1115,14 @@
}
}
} else if (typeBinding.isNestedType()) {
- classFile.recordInnerClasses(typeBinding);
+ TypeBinding enclosingType = typeBinding;
+ do {
+ if (!enclosingType.canBeSeenBy(classFile.referenceBinding.scope))
+ break;
+ enclosingType = enclosingType.enclosingType();
+ } while (enclosingType != null);
+ if (enclosingType == null)
+ classFile.recordInnerClasses(typeBinding);
}
}
/*
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index 72390f4..5ba061e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -61,6 +61,7 @@
import org.eclipse.jdt.internal.core.CancelableProblemFactory;
import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress;
import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.LocalVariable;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.SourceRefElement;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
@@ -764,9 +765,15 @@
}
intList.add(i);
} else {
- // binary member
+ // binary member or method argument
try {
- String key = ((BinaryMember) element).getKey(true/*open to get resolved info*/);
+ String key;
+ if (element instanceof BinaryMember)
+ key = ((BinaryMember) element).getKey(true/*open to get resolved info*/);
+ else if (element instanceof LocalVariable)
+ key = ((LocalVariable) element).getKey(true/*open to get resolved info*/);
+ else
+ throw new IllegalArgumentException(element + " has an unexpected type"); //$NON-NLS-1$
binaryElementPositions.put(key, i);
} catch (JavaModelException e) {
throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index ae99a7a..675fa1e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -7,9 +7,11 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
- * Stephan Herrmann - Contribution for Bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -25,6 +27,7 @@
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression;
@@ -56,6 +59,7 @@
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
@@ -283,6 +287,13 @@
* Method declared on BindingResolver.
*/
synchronized IMethodBinding getMethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding) {
+ return getMethodOrLambdaBinding(methodBinding, null, null);
+ }
+
+ private synchronized IMethodBinding getMethodOrLambdaBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding,
+ org.eclipse.jdt.internal.compiler.lookup.MethodBinding descriptor,
+ IBinding enclosingBinding)
+ {
if (methodBinding != null && !methodBinding.isValidBinding()) {
org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding problemMethodBinding =
(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) methodBinding;
@@ -297,7 +308,11 @@
if (binding != null) {
return binding;
}
- binding = new MethodBinding(this, methodBinding);
+ if (descriptor != null && enclosingBinding != null) {
+ binding = new MethodBinding.LambdaMethod(this, descriptor, methodBinding, enclosingBinding);
+ } else {
+ binding = new MethodBinding(this, methodBinding);
+ }
this.bindingTables.compilerBindingsToASTBindings.put(methodBinding, binding);
return binding;
}
@@ -390,6 +405,11 @@
* Method declared on BindingResolver.
*/
synchronized ITypeBinding getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding) {
+ return internalGetTypeBinding(referenceBinding, null);
+ }
+
+ private synchronized ITypeBinding internalGetTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding, IBinding declaringMember) {
+ // may also create an TypeBinding.AnonymousTypeBinding
if (referenceBinding == null) {
return null;
} else if (!referenceBinding.isValidBinding()) {
@@ -403,7 +423,7 @@
if (binding != null) {
return binding;
}
- binding = new TypeBinding(this, binding2);
+ binding = TypeBinding.createTypeBinding(this, binding2, declaringMember);
this.bindingTables.compilerBindingsToASTBindings.put(binding2, binding);
return binding;
}
@@ -417,7 +437,7 @@
return binding;
}
if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
- binding = new TypeBinding(this, referenceBinding);
+ binding = TypeBinding.createTypeBinding(this, referenceBinding, declaringMember);
} else {
binding = new RecoveredTypeBinding(this, referenceBinding);
}
@@ -433,7 +453,7 @@
if (binding != null) {
return binding;
}
- binding = new TypeBinding(this, referenceBinding);
+ binding = TypeBinding.createTypeBinding(this, referenceBinding, declaringMember);
this.bindingTables.compilerBindingsToASTBindings.put(referenceBinding, binding);
return binding;
}
@@ -948,7 +968,12 @@
Object oldNode = this.newAstToOldAst.get(lambda);
if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.LambdaExpression) {
org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression = (org.eclipse.jdt.internal.compiler.ast.LambdaExpression) oldNode;
- IMethodBinding methodBinding = getMethodBinding(lambdaExpression.getMethodBinding());
+ IMethodBinding methodBinding = null;
+ if (lambdaExpression.descriptor != null) {
+ IBinding declaringMember = getDeclaringMember(lambdaExpression, lambdaExpression.enclosingScope);
+ if (declaringMember != null)
+ methodBinding = getMethodOrLambdaBinding(lambdaExpression.getMethodBinding(), lambdaExpression.descriptor, declaringMember);
+ }
if (methodBinding == null) {
return null;
}
@@ -961,6 +986,48 @@
}
return null;
}
+
+ private IBinding getDeclaringMember(org.eclipse.jdt.internal.compiler.ast.ASTNode node, Scope currentScope) {
+ MethodScope methodScope = currentScope != null ? currentScope.methodScope() : null;
+ if (methodScope != null) {
+ if (methodScope.isInsideInitializer()) {
+ org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingType = methodScope.referenceType();
+ if (enclosingType.fields != null) {
+ for (int i = 0; i < enclosingType.fields.length; i++) {
+ FieldDeclaration field = enclosingType.fields[i];
+ if (field.declarationSourceStart <= node.sourceStart && node.sourceEnd <= field.declarationSourceEnd) {
+ if (field instanceof org.eclipse.jdt.internal.compiler.ast.Initializer)
+ return getMethodBinding(((org.eclipse.jdt.internal.compiler.ast.Initializer) field).getMethodBinding());
+ else
+ return getVariableBinding(field.binding);
+ }
+ }
+ }
+ } else {
+ if (methodScope.isLambdaScope()) {
+ org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression = (org.eclipse.jdt.internal.compiler.ast.LambdaExpression) methodScope.referenceContext;
+ IMethodBinding methodBinding = null;
+ if (lambdaExpression.descriptor != null) {
+ IBinding declaringMember = getDeclaringMember(lambdaExpression, lambdaExpression.enclosingScope);
+ if (declaringMember != null)
+ methodBinding = getMethodOrLambdaBinding(lambdaExpression.getMethodBinding(), lambdaExpression.descriptor, declaringMember);
+ }
+ if (methodBinding == null) {
+ return null;
+ }
+ String key = methodBinding.getKey();
+ if (key != null) {
+ this.bindingTables.bindingKeysToBindings.put(key, methodBinding);
+ }
+ return methodBinding;
+ } else {
+ return getMethodBinding(methodScope.referenceMethodBinding());
+ }
+ }
+ }
+ return null;
+ }
+
/*
* Method declared on BindingResolver.
*/
@@ -1765,7 +1832,8 @@
org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(type);
if (node != null && (node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) {
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
- ITypeBinding typeBinding = this.getTypeBinding(anonymousLocalTypeDeclaration.binding);
+ IBinding declaringMember = getDeclaringMember(anonymousLocalTypeDeclaration, anonymousLocalTypeDeclaration.scope);
+ ITypeBinding typeBinding = internalGetTypeBinding(anonymousLocalTypeDeclaration.binding, declaringMember);
if (typeBinding == null) {
return null;
}
@@ -1926,7 +1994,8 @@
final Object node = this.newAstToOldAst.get(type);
if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
- ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
+ IBinding declaringMember = getDeclaringMember(typeDeclaration, typeDeclaration.scope);
+ ITypeBinding typeBinding = internalGetTypeBinding(typeDeclaration.binding, declaringMember);
if (typeBinding == null) {
return null;
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
index 36bbf3d..d9b6034 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -8,6 +8,8 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -87,6 +89,31 @@
public ITypeBinding getDeclaringClass();
/**
+ * If this method binding represents a lambda expression then:
+ * <ul>
+ * <li>If the lambda expression is declared in the body of a method,
+ * answers the binding of that declaring method.
+ * </li>
+ * <li>Otherwise, if the lambda expression is declared in the
+ * initializer of a field, answers the binding of that declaring field.
+ * </li>
+ * <li>Otherwise, if the lambda expression is declared in a static initializer or an
+ * instance initializer, a method binding is returned to represent that initializer
+ * (selector is an empty string in this case).
+ * </li>
+ * </ul>
+ * <p>
+ * If this method binding does not represent a lambda expression,
+ * <code>null</code> is returned.
+ * </p>
+ * @return a method binding or field binding representing the member that
+ * contains the lambda expression represented by this method binding,
+ * or null for regular method bindings.
+ * @since 3.11
+ */
+ public IBinding getDeclaringMember();
+
+ /**
* Returns the resolved default value of an annotation type member,
* or <code>null</code> if the member has no default value, or if this
* is not the binding for an annotation type member.
@@ -293,6 +320,8 @@
* <li>For references to a signature polymorphic method from class MethodHandle,
* returns the declaration of the method. In the reference binding, the parameter types and
* the return type are determined by the concrete invocation context.</li>
+ * <li>For lambda methods, returns the (possibly parameterized) single abstract method
+ * of the functional type.</li>
* <li>For other method bindings, this returns the same binding.</li>
* </ul>
*
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
index 5da4239..0d17f9e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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,6 +9,8 @@
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -261,6 +263,30 @@
public IMethodBinding getDeclaringMethod();
/**
+ * If this type binding represents a local type, possibly an anonymous class, then:
+ * <ul>
+ * <li>If the local type is declared in the body of a method,
+ * answers the binding of that declaring method.
+ * </li>
+ * <li>Otherwise, if the local type (an anonymous class in this case) is declared
+ * in the initializer of a field, answers the binding of that declaring field.
+ * </li>
+ * <li>Otherwise, if the local type is declared in a static initializer or
+ * an instance initializer, a method binding is returned to represent that initializer
+ * (selector is an empty string in this case).
+ * </li>
+ * </ul>
+ * <p>
+ * If this type binding does not represent a local type, <code>null</code> is returned.
+ * </p>
+ * @return a method binding or field binding representing the member that
+ * contains the local type represented by this type binding,
+ * or null for non-local type bindings.
+ * @since 3.11
+ */
+ public IBinding getDeclaringMember();
+
+ /**
* Returns the dimensionality of this array type, or <code>0</code> if this
* is not an array type binding.
*
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
index 52c98a0..90eab94 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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,12 +9,15 @@
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
@@ -40,8 +43,8 @@
Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.STRICTFP | Modifier.DEFAULT;
private static final ITypeBinding[] NO_TYPE_BINDINGS = new ITypeBinding[0];
- private org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding;
- private BindingResolver resolver;
+ protected org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding;
+ protected BindingResolver resolver;
private ITypeBinding[] parameterTypes;
private ITypeBinding[] exceptionTypes;
private String name;
@@ -133,6 +136,11 @@
return this.declaringClass;
}
+ @Override
+ public IBinding getDeclaringMember() {
+ return null;
+ }
+
public IAnnotationBinding[] getParameterAnnotations(int index) {
if (getParameterTypes() == NO_TYPE_BINDINGS) {
return AnnotationBinding.NoAnnotations;
@@ -497,4 +505,69 @@
return this.binding.copyInheritanceSrc != null;
}
// SH}
+
+ /*
+ * Method binding representing a lambda expression.
+ * Most properties are read from the SAM descriptor,
+ * but key, parameter types, and annotations are taken from the lambda implementation.
+ * Additionally we store the declaring member (see #getDeclaringMember()).
+ */
+ static class LambdaMethod extends MethodBinding {
+
+ private MethodBinding implementation;
+ private IBinding declaringMember;
+
+ public LambdaMethod(DefaultBindingResolver resolver,
+ org.eclipse.jdt.internal.compiler.lookup.MethodBinding lambdaDescriptor,
+ org.eclipse.jdt.internal.compiler.lookup.MethodBinding implementation,
+ IBinding declaringMember)
+ {
+ super(resolver, lambdaDescriptor);
+ this.implementation = new MethodBinding(resolver, implementation);
+ this.declaringMember = declaringMember;
+ }
+
+ /**
+ * @see IBinding#getModifiers()
+ */
+ public int getModifiers() {
+ return super.getModifiers() & ~ClassFileConstants.AccAbstract;
+ }
+
+ /**
+ * @see IBinding#getKey()
+ */
+ public String getKey() {
+ return this.implementation.getKey();
+ }
+
+ @Override
+ public ITypeBinding[] getParameterTypes() {
+ return this.implementation.getParameterTypes();
+ }
+
+ @Override
+ public IAnnotationBinding[] getParameterAnnotations(int paramIndex) {
+ return this.implementation.getParameterAnnotations(paramIndex);
+ }
+
+ public IAnnotationBinding[] getAnnotations() {
+ return this.implementation.getAnnotations();
+ }
+
+ @Override
+ public IBinding getDeclaringMember() {
+ return this.declaringMember;
+ }
+
+ @Override
+ public IMethodBinding getMethodDeclaration() {
+ return this.resolver.getMethodBinding(this.binding);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString().replace("public abstract ", "public "); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
index e907680..6335af3 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
@@ -14,6 +14,8 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory;
import org.eclipse.jdt.internal.compiler.batch.FileSystem;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
@@ -41,8 +43,29 @@
}
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
checkCanceled();
- return super.findType(typeName, packageName);
+ NameEnvironmentAnswer answer = super.findType(typeName, packageName);
+ if (answer == null) {
+ NameEnvironmentAnswer suggestedAnswer = null;
+ String qualifiedPackageName = new String(CharOperation.concatWith(packageName, '/'));
+ String qualifiedTypeName = new String(CharOperation.concatWith(packageName, typeName, '/'));
+ String qualifiedBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
+ for (int i = 0, length = this.classpaths.length; i < length; i++) {
+ if (!(this.classpaths[i] instanceof ClasspathDirectory)) continue;
+ ClasspathDirectory classpathDirectory = (ClasspathDirectory) this.classpaths[i];
+ answer = classpathDirectory.findSecondaryInClass(typeName, qualifiedPackageName, qualifiedBinaryFileName);
+ if (answer != null) {
+ if (!answer.ignoreIfBetter()) {
+ if (answer.isBetter(suggestedAnswer))
+ return answer;
+ } else if (answer.isBetter(suggestedAnswer))
+ // remember suggestion and keep looking
+ suggestedAnswer = answer;
+ }
+ }
+ }
+ return answer;
}
+
public NameEnvironmentAnswer findType(char[][] compoundName) {
checkCanceled();
return super.findType(compoundName);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
index 39b4144..98ed738 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2014 IBM Corporation and others.
+ * Copyright (c) 2007, 2015 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
@@ -8,6 +8,8 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -166,6 +168,14 @@
}
/* (non-Javadoc)
+ * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaringMember()
+ */
+ @Override
+ public IBinding getDeclaringMember() {
+ return null;
+ }
+
+ /* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ITypeBinding#getDimensions()
*/
public int getDimensions() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
index 30f628c..eeb5f7f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -11,6 +11,7 @@
* Technical University Berlin - extended API and implementation
* Stephan Herrmann - Contribution for
* Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -30,7 +31,6 @@
import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18;
-import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
@@ -79,7 +79,7 @@
org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding;
private TypeBinding prototype = null;
private String key;
- private BindingResolver resolver;
+ protected BindingResolver resolver;
private IVariableBinding[] fields;
private IAnnotationBinding[] annotations;
private IAnnotationBinding[] typeAnnotations;
@@ -90,6 +90,18 @@
private ITypeBinding[] bounds;
private ITypeBinding[] typeParameters;
+ /**
+ * Create either a regular TypeBinding or an AnonymousTypeBinding (if declaringMember is given).
+ */
+ public static TypeBinding createTypeBinding(BindingResolver resolver,
+ org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding,
+ IBinding declaringMember)
+ {
+ return declaringMember != null
+ ? new LocalTypeBinding(resolver, referenceBinding, declaringMember)
+ : new TypeBinding(resolver, referenceBinding);
+ }
+
public TypeBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding) {
this.binding = binding;
this.resolver = resolver;
@@ -435,8 +447,8 @@
* @see ITypeBinding#getDeclaringMethod()
*/
public synchronized IMethodBinding getDeclaringMethod() {
- if (this.binding instanceof LocalTypeBinding) {
- LocalTypeBinding localTypeBinding = (LocalTypeBinding) this.binding;
+ if (this.binding instanceof org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding) {
+ org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding localTypeBinding = (org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding) this.binding;
MethodBinding methodBinding = localTypeBinding.enclosingMethod;
if (methodBinding != null) {
try {
@@ -506,6 +518,11 @@
return null;
}
+ @Override
+ public IBinding getDeclaringMember() {
+ return null;
+ }
+
/*
* @see ITypeBinding#getDimensions()
*/
@@ -1643,4 +1660,22 @@
this.typeAnnotations = resolveAnnotationBindings(this.binding.getTypeAnnotations(), true);
return this.typeAnnotations;
}
+
+ static class LocalTypeBinding extends TypeBinding {
+
+ private IBinding declaringMember;
+
+ public LocalTypeBinding(BindingResolver resolver,
+ org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding,
+ IBinding declaringMember)
+ {
+ super(resolver, binding);
+ this.declaringMember = declaringMember;
+ }
+
+ @Override
+ public IBinding getDeclaringMember() {
+ return this.declaringMember;
+ }
+ }
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
index 7b833e3..3a1e2ad 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -8,6 +8,8 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.core.dom;
@@ -156,6 +158,9 @@
case ASTNode.METHOD_DECLARATION :
MethodDeclaration methodDeclaration = (MethodDeclaration) node;
return methodDeclaration.resolveBinding();
+ case ASTNode.LAMBDA_EXPRESSION :
+ LambdaExpression lambdaExpression = (LambdaExpression) node;
+ return lambdaExpression.resolveMethodBinding();
default:
node = node.getParent();
}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
index 9daae6c..e31367b 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] IndexOutOfBoundsException in TokenManager - https://bugs.eclipse.org/462945
*******************************************************************************/
package org.eclipse.jdt.internal.formatter;
@@ -19,6 +20,7 @@
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRPAREN;
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral;
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameWHITESPACE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamepackage;
import java.util.ArrayList;
import java.util.Arrays;
@@ -119,6 +121,12 @@
}
@Override
+ public boolean preVisit2(ASTNode node) {
+ boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0;
+ return !isMalformed;
+ }
+
+ @Override
public boolean visit(LineComment node) {
int commentIndex = this.tm.firstIndexIn(node, TokenNameCOMMENT_LINE);
handleLineComment(commentIndex);
@@ -425,7 +433,7 @@
commentToken.putLineBreaksAfter(previous.getLineBreaksAfter());
previous.clearLineBreaksAfter();
} else if (existingBreaksAfter <= existingBreaksBefore && next != null
- && commentIndex > 0 /* doesn't apply to a comment before the package declaration */) {
+ && next.tokenType != TokenNamepackage /* doesn't apply to a comment before the package declaration */) {
commentToken.putLineBreaksBefore(next.getLineBreaksBefore());
next.clearLineBreaksBefore();
}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
index 7b035b0..d6f5d69 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] IndexOutOfBoundsException in TokenManager - https://bugs.eclipse.org/462945
*******************************************************************************/
package org.eclipse.jdt.internal.formatter;
@@ -84,6 +85,12 @@
}
@Override
+ public boolean preVisit2(ASTNode node) {
+ boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0;
+ return !isMalformed;
+ }
+
+ @Override
public boolean visit(CompilationUnit node) {
List<ImportDeclaration> imports = node.imports();
if (!imports.isEmpty()) {
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
index 119643e..95c3cff 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] IndexOutOfBoundsException in TokenManager - https://bugs.eclipse.org/462945
*******************************************************************************/
package org.eclipse.jdt.internal.formatter;
@@ -103,6 +104,12 @@
}
@Override
+ public boolean preVisit2(ASTNode node) {
+ boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0;
+ return !isMalformed;
+ }
+
+ @Override
public boolean visit(TypeDeclaration node) {
if (node.getName().getStartPosition() == -1)
return true; // this is a fake type created by parsing in class body mode
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
index 25a0af5..0640b73 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -10,6 +10,8 @@
* IBM Corporation - added J2SE 1.5 support
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 463533 - Signature.getSignatureSimpleName() returns different results for resolved and unresolved extends
*******************************************************************************/
package org.eclipse.jdt.core;
@@ -1921,12 +1923,21 @@
}
if(dotCount > 0) {
+ int typeStart = 0;
for(int i = 0; i < qualifiedType.length; i++) {
- if(qualifiedType[i] == '.') {
- dotCount--;
+ switch (qualifiedType[i]) {
+ case '.':
+ dotCount--;
+ break;
+ case ' ':
+ typeStart = i+1;
+ break;
}
if(dotCount <= 0) {
- return CharOperation.subarray(qualifiedType, i + 1, qualifiedType.length);
+ char[] simpleName = CharOperation.subarray(qualifiedType, i + 1, qualifiedType.length);
+ if (typeStart > 0 && typeStart < qualifiedType.length)
+ return CharOperation.concat(CharOperation.subarray(qualifiedType, 0, typeStart), simpleName);
+ return simpleName;
}
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
index d8dc589..8984deb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -102,7 +102,7 @@
Plugin jdtCorePlugin = JavaCore.getPlugin();
if (jdtCorePlugin == null) return null;
- IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.FORMATTER_EXTPOINT_ID);
+ IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.FORMATTER_EXTPOINT_ID);
if (extension != null) {
IExtension[] extensions = extension.getExtensions();
for(int i = 0; i < extensions.length; i++){
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
index a24a91a..fdc1e21 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
@@ -175,11 +175,15 @@
if (annotationPath == null)
return null;
+
IWorkspaceRoot workspaceRoot = project.getProject().getWorkspace().getRoot();
- IFile annotationZip = workspaceRoot.getFile(annotationPath);
- if (annotationZip.exists())
- return null;
-
+
+ if (annotationPath.segmentCount() > 1) {
+ IFile annotationZip = workspaceRoot.getFile(annotationPath);
+ if (annotationZip.exists())
+ return null;
+ }
+
annotationPath = annotationPath.append(binaryTypeName).addFileExtension(ExternalAnnotationProvider.ANNOTION_FILE_EXTENSION);
return workspaceRoot.getFile(annotationPath);
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index e71ffb1..e86c4a5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -13,6 +13,7 @@
* Stephan Herrmann - Contribution for
* Bug 458577 - IClassFile.getWorkingCopy() may lead to NPE in BecomeWorkingCopyOperation
* Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
+ * Bug 462768 - [null] NPE when using linked folder for external annotations
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -33,6 +34,7 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
@@ -394,12 +396,22 @@
{
// try resolve path within the workspace:
IWorkspaceRoot root = project.getWorkspace().getRoot();
- IResource resource = root.getFolder(externalAnnotationPath);
+ IResource resource = externalAnnotationPath.segmentCount() == 1
+ ? root.getProject(externalAnnotationPath.lastSegment())
+ : root.getFolder(externalAnnotationPath);
if (!resource.exists())
resource = root.getFile(externalAnnotationPath);
- String resolvedPath = resource.exists()
- ? resource.getLocation().toString() // workspace lookup succeeded -> resolve it
- : externalAnnotationPath.toString(); // not in workspace, use as is
+ String resolvedPath;
+ if (resource.exists()) {
+ if (resource.isVirtual()) {
+ Util.log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
+ "Virtual resource "+externalAnnotationPath+" cannot be used as annotationpath for project "+project.getName())); //$NON-NLS-1$ //$NON-NLS-2$
+ return;
+ }
+ resolvedPath = resource.getLocation().toString(); // workspace lookup succeeded -> resolve it
+ } else {
+ resolvedPath = externalAnnotationPath.toString(); // not in workspace, use as is
+ }
try {
annotationZip = reader.setExternalAnnotationProvider(resolvedPath, typeName, annotationZip, new ClassFileReader.ZipFileProducer() {
@Override public ZipFile produce() throws IOException {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index b5acca9..a003b2b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -11,6 +11,8 @@
* Thirumala Reddy Mutchukota <thirumala@google.com> - Avoid optional library classpath entries validation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=412882
* Stephan Herrmann - Contribution for
* Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
+ * Bug 462768 - [null] NPE when using linked folder for external annotations
+ * Bug 465296 - precedence of extra attributes on a classpath container
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -343,9 +345,9 @@
IClasspathAttribute[] combinedAttributes = this.extraAttributes;
int lenRefer = referringExtraAttributes.length;
if (lenRefer > 0) {
- int lenCombined = combinedAttributes.length;
- System.arraycopy(combinedAttributes, 0, combinedAttributes=new IClasspathAttribute[lenCombined+lenRefer], 0, lenCombined);
- System.arraycopy(referringExtraAttributes, 0, combinedAttributes, lenCombined, lenRefer);
+ int lenEntry = combinedAttributes.length;
+ System.arraycopy(combinedAttributes, 0, combinedAttributes=new IClasspathAttribute[lenEntry+lenRefer], lenRefer, lenEntry);
+ System.arraycopy(referringExtraAttributes, 0, combinedAttributes, 0, lenRefer);
}
return new ClasspathEntry(
getContentKind(),
@@ -1282,11 +1284,13 @@
if (!resolve)
return annotationPath;
- if (annotationPath.segmentCount() > 1) {
- // try Workspace-absolute:
- IProject targetProject = project.getWorkspace().getRoot().getProject(annotationPath.segment(0));
- if (targetProject.exists())
+ // try Workspace-absolute:
+ IProject targetProject = project.getWorkspace().getRoot().getProject(annotationPath.segment(0));
+ if (targetProject.exists()) {
+ if (annotationPath.segmentCount() > 1)
return targetProject.getLocation().append(annotationPath.removeFirstSegments(1));
+ else
+ return targetProject.getLocation();
}
// absolute, not in workspace, must be Filesystem-absolute:
return annotationPath;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
index c77be25..9d912ad 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -30,7 +30,6 @@
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -41,7 +40,6 @@
import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
/**
@@ -815,26 +813,7 @@
}
if (projectsToTouch.length > 0) {
if (asynchronous){
- WorkspaceJob touchJob = new WorkspaceJob(Messages.updating_external_archives_jobName) {
-
- public IStatus runInWorkspace(IProgressMonitor progressMonitor) throws CoreException {
- try {
- if (progressMonitor != null)
- progressMonitor.beginTask("", projectsToTouch.length); //$NON-NLS-1$
- touchProjects(projectsToTouch, progressMonitor);
- }
- finally {
- if (progressMonitor != null)
- progressMonitor.done();
- }
- return Status.OK_STATUS;
- }
-
- public boolean belongsTo(Object family) {
- return ResourcesPlugin.FAMILY_MANUAL_REFRESH == family;
- }
- };
- touchJob.schedule();
+ this.manager.touchProjects(projectsToTouch, monitor);
}
else {
// touch the projects to force them to be recompiled while taking the workspace lock
@@ -873,18 +852,6 @@
}
}
- protected void touchProjects(final IProject[] projectsToTouch, IProgressMonitor progressMonitor)
- throws CoreException {
- for (int i = 0; i < projectsToTouch.length; i++) {
- IProgressMonitor monitor = progressMonitor == null ? null: new SubProgressMonitor(progressMonitor, 1);
- IProject project = projectsToTouch[i];
- // touch to force a build of this project
- if (JavaBuilder.DEBUG)
- System.out.println("Touching project " + project.getName() + " due to external jar file change"); //$NON-NLS-1$ //$NON-NLS-2$
- project.touch(monitor);
- }
- }
-
/*
* Check if external archives have changed for the given elements and create the corresponding deltas.
* Returns whether at least one delta was created.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
index 972bfcf..fd6da1c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
@@ -44,6 +44,7 @@
static class DirectoryNode {
DirectoryNode parent;
+ IPath path;
/** Key is a full workspace path. */
Map<IPath,DirectoryNode> children;
@@ -54,8 +55,9 @@
Map<IPath, ClassFile> classFiles;
IPackageFragmentRoot modelRoot; // TODO: for handling zipped annotations
- public DirectoryNode(DirectoryNode parent) {
+ public DirectoryNode(DirectoryNode parent, IPath path) {
this.parent = parent;
+ this.path = path;
}
Map<IPath, DirectoryNode> getChildren() {
@@ -80,9 +82,9 @@
}
}
void unregisterDirectory(DirectoryNode child) {
- if (this.children == null) return;
- this.children.remove(child);
- if (this.children.isEmpty() && this.parent != null)
+ if (this.children != null)
+ this.children.remove(child.path);
+ if ((this.children == null || this.children.isEmpty()) && this.parent != null)
this.parent.unregisterDirectory(this);
}
@@ -106,10 +108,13 @@
count += child.numClassFiles();
return count;
}
+ boolean isEmpty() {
+ return (this.children == null || this.children.isEmpty()) && (this.classFiles == null || this.classFiles.isEmpty());
+ }
}
/** The tree of tracked annotation bases and class files. */
- DirectoryNode tree = new DirectoryNode(null);
+ DirectoryNode tree = new DirectoryNode(null, null);
private static ExternalAnnotationTracker singleton;
private ExternalAnnotationTracker() { }
@@ -170,7 +175,7 @@
Map<IPath, DirectoryNode> children = current.getChildren(); // create if necessary
DirectoryNode nextHeadNode = children.get(nextHead);
if (nextHeadNode == null)
- children.put(nextHead, nextHeadNode = new DirectoryNode(current));
+ children.put(nextHead, nextHeadNode = new DirectoryNode(current, nextHead));
if (baseDepth == nextDepth)
return nextHeadNode;
return getAnnotationBase(nextHeadNode, annotationBase, baseDepth, nextDepth+1);
@@ -207,14 +212,16 @@
traverseForDirectories(childDir, child);
}
}
- }
+ }
+ if (directoryNode.isEmpty())
+ directoryNode.parent.children.remove(matchedDelta.getFullPath());
}
// traversal of delta nodes to be matched against map of class files:
private void traverseForClassFiles(Map<IPath, ClassFile> classFiles, IResourceDelta matchedDelta, int baseDepth) {
for (IResourceDelta delta : matchedDelta.getAffectedChildren()) {
IPath deltaRelativePath = delta.getFullPath().removeFirstSegments(baseDepth);
- ClassFile classFile = classFiles.get(deltaRelativePath);
+ ClassFile classFile = classFiles.remove(deltaRelativePath);
if (classFile != null) {
try {
// the payload: unload the class file corresponding to a changed external annotation file:
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index 009e003..6b8b4d6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -17,6 +17,7 @@
* Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425
* Thirumala Reddy Mutchukota <thirumala@google.com> - Contribution to bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=411423
* Terry Parker <tparker@google.com> - [performance] Low hit rates in JavaModel caches - https://bugs.eclipse.org/421165
+ * Terry Parker <tparker@google.com> - Enable the Java model caches to recover from IO errors - https://bugs.eclipse.org/455042
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -102,7 +103,6 @@
public class JavaModelManager implements ISaveParticipant, IContentTypeChangeListener {
private static ServiceRegistration<DebugOptionsListener> DEBUG_REGISTRATION;
private static final String NON_CHAINING_JARS_CACHE = "nonChainingJarsCache"; //$NON-NLS-1$
- private static final String INVALID_ARCHIVES_CACHE = "invalidArchivesCache"; //$NON-NLS-1$
private static final String EXTERNAL_FILES_CACHE = "externalFilesCache"; //$NON-NLS-1$
private static final String ASSUMED_EXTERNAL_FILES_CACHE = "assumedExternalFilesCache"; //$NON-NLS-1$
@@ -1457,11 +1457,14 @@
* A set of IPaths for jars that are known to not contain a chaining (through MANIFEST.MF) to another library
*/
private Set nonChainingJars;
-
+
+ // The amount of time from when an invalid archive is first sensed until that state is considered stale.
+ private static long INVALID_ARCHIVE_TTL_MILLISECONDS = 2 * 60 * 1000;
+
/*
- * A set of IPaths for jars that are known to be invalid - such as not being a valid/known format
+ * A map of IPaths for jars that are known to be invalid (such as not being in a valid/known format), to an eviction timestamp.
*/
- private Set invalidArchives;
+ private Map<IPath, Long> invalidArchives;
/*
* A set of IPaths for files that are known to be external to the workspace.
@@ -1528,19 +1531,16 @@
propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE)) {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
IJavaModel model = manager.getJavaModel();
- IJavaProject[] projects;
+ IJavaProject[] jProjects;
try {
- projects = model.getJavaProjects();
- for (int i = 0, pl = projects.length; i < pl; i++) {
- JavaProject javaProject = (JavaProject) projects[i];
+ jProjects = model.getJavaProjects();
+ IProject[] projects = new IProject[jProjects.length];
+ for (int i = 0, pl = jProjects.length; i < pl; i++) {
+ JavaProject javaProject = (JavaProject) jProjects[i];
+ projects[i] = javaProject.getProject();
manager.deltaState.addClasspathValidation(javaProject);
- try {
- // need to touch the project to force validation by DeltaProcessor
- javaProject.getProject().touch(null);
- } catch (CoreException e) {
- // skip
- }
}
+ manager.touchProjects(projects, null);
} catch (JavaModelException e) {
// skip
}
@@ -1608,7 +1608,6 @@
if (Platform.isRunning()) {
this.indexManager = new IndexManager();
this.nonChainingJars = loadClasspathListCache(NON_CHAINING_JARS_CACHE);
- this.invalidArchives = loadClasspathListCache(INVALID_ARCHIVES_CACHE);
this.externalFiles = loadClasspathListCache(EXTERNAL_FILES_CACHE);
this.assumedExternalFiles = loadClasspathListCache(ASSUMED_EXTERNAL_FILES_CACHE);
String includeContainerReferencedLib = System.getProperty(RESOLVE_REFERENCED_LIBRARIES_FOR_CONTAINERS);
@@ -1632,11 +1631,9 @@
public void addInvalidArchive(IPath path) {
// unlikely to be null
if (this.invalidArchives == null) {
- this.invalidArchives = Collections.synchronizedSet(new HashSet());
+ this.invalidArchives = Collections.synchronizedMap(new HashMap());
}
- if(this.invalidArchives != null) {
- this.invalidArchives.add(path);
- }
+ this.invalidArchives.put(path, System.currentTimeMillis() + INVALID_ARCHIVE_TTL_MILLISECONDS);
}
/**
@@ -2650,8 +2647,11 @@
* @exception CoreException If unable to create/open the ZipFile
*/
public ZipFile getZipFile(IPath path) throws CoreException {
+ return getZipFile(path, true);
+ }
- if (isInvalidArchive(path))
+ private ZipFile getZipFile(IPath path, boolean checkInvalidArchiveCache) throws CoreException {
+ if (checkInvalidArchiveCache && isInvalidArchive(path))
throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, new ZipException()));
ZipCache zipCache;
@@ -3067,6 +3067,36 @@
*/
}
+ void touchProjects(final IProject[] projectsToTouch, IProgressMonitor progressMonitor) throws JavaModelException {
+ WorkspaceJob touchJob = new WorkspaceJob(Messages.synchronizing_projects_job) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ try {
+ if (monitor != null) {
+ monitor.beginTask("", projectsToTouch.length); //$NON-NLS-1$
+ }
+ for (IProject iProject : projectsToTouch) {
+ IProgressMonitor subMonitor = monitor == null ? null: new SubProgressMonitor(monitor, 1);
+ if (JavaBuilder.DEBUG) {
+ System.out.println("Touching project " + iProject.getName()); //$NON-NLS-1$
+ }
+ iProject.touch(subMonitor);
+ }
+ }
+ finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ public boolean belongsTo(Object family) {
+ return ResourcesPlugin.FAMILY_MANUAL_REFRESH == family;
+ }
+ };
+ touchJob.schedule();
+ }
+
private HashSet getClasspathBeingResolved() {
HashSet result = (HashSet) this.classpathsBeingResolved.get();
if (result == null) {
@@ -3093,12 +3123,41 @@
}
public boolean isInvalidArchive(IPath path) {
- return this.invalidArchives != null && this.invalidArchives.contains(path);
+ if (this.invalidArchives == null)
+ return false;
+ Long evictionTime = this.invalidArchives.get(path);
+ if (evictionTime == null)
+ return false;
+ long now = System.currentTimeMillis();
+
+ // If the TTL for this cache entry has expired, directly check whether the archive is still invalid.
+ // If it transitioned to being valid, remove it from the cache and force an update to project caches.
+ if (now > evictionTime) {
+ try {
+ getZipFile(path, false);
+ removeFromInvalidArchiveCache(path);
+ return false;
+ } catch (CoreException e) {
+ // Archive is still invalid, fall through to reporting it is invalid.
+ }
+ }
+ return true;
}
public void removeFromInvalidArchiveCache(IPath path) {
if (this.invalidArchives != null) {
- this.invalidArchives.remove(path);
+ if (this.invalidArchives.remove(path) != null) {
+ try {
+ // Bug 455042: Force an update of the JavaProjectElementInfo project caches.
+ for (IJavaProject project : getJavaModel().getJavaProjects()) {
+ if (project.findPackageFragmentRoot(path) != null) {
+ ((JavaProject) project).resetCaches();
+ }
+ }
+ } catch (JavaModelException e) {
+ Util.log(e, "Unable to retrieve the Java model."); //$NON-NLS-1$
+ }
+ }
}
}
@@ -3214,8 +3273,6 @@
private Set getClasspathListCache(String cacheName) throws CoreException {
if (cacheName == NON_CHAINING_JARS_CACHE)
return getNonChainingJarsCache();
- else if (cacheName == INVALID_ARCHIVES_CACHE)
- return this.invalidArchives;
else if (cacheName == EXTERNAL_FILES_CACHE)
return this.externalFiles;
else if (cacheName == ASSUMED_EXTERNAL_FILES_CACHE)
@@ -4322,7 +4379,6 @@
case ISaveContext.FULL_SAVE : {
// save non-chaining jar, invalid jar and external file caches on full save
saveClasspathListCache(NON_CHAINING_JARS_CACHE);
- saveClasspathListCache(INVALID_ARCHIVES_CACHE);
saveClasspathListCache(EXTERNAL_FILES_CACHE);
saveClasspathListCache(ASSUMED_EXTERNAL_FILES_CACHE);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
index 1e5dedf..f05213b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
@@ -459,6 +459,19 @@
return true;
}
+ /**
+ * @see org.eclipse.jdt.internal.compiler.lookup.Binding#computeUniqueKey()
+ */
+ public String getKey(boolean forceOpen) throws JavaModelException {
+ if (this.parent.getElementType() == IJavaElement.METHOD) {
+ StringBuilder buf = new StringBuilder(((IMethod)this.parent).getKey());
+ buf.append('#');
+ buf.append(this.name);
+ return buf.toString();
+ }
+ return null;
+ }
+
protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
buffer.append(tabString(tab));
if (info != NO_INFO) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
index 78f79aa..560ddfe 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for Bug 464615 - [dom] ASTParser.createBindings() ignores parameterization of a method invocation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -33,6 +34,10 @@
return this.uniqueKey;
}
+ public String getKey(boolean forceOpen) {
+ return this.uniqueKey;
+ }
+
/* (non-Javadoc)
* @see org.eclipse.jdt.core.IField#isResolved()
*/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
index d36c8d4..7715122 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 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
@@ -7,9 +7,12 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for Bug 464615 - [dom] ASTParser.createBindings() ignores parameterization of a method invocation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
+import org.eclipse.jdt.core.JavaModelException;
+
/**
* Handle representing a binary method that is resolved.
* The uniqueKey contains the genericSignature of the resolved method. Use BindingKey to decode it.
@@ -31,6 +34,12 @@
public String getKey() {
return this.uniqueKey;
}
+
+ @Override
+ public String getKey(boolean forceOpen) throws JavaModelException {
+ return this.uniqueKey;
+ }
+
/* (non-Javadoc)
* @see org.eclipse.jdt.core.IMethod#isResolved()
*/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
index 1c5d2e7..88b72ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for Bug 464615 - [dom] ASTParser.createBindings() ignores parameterization of a method invocation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -38,6 +39,11 @@
public String getKey() {
return this.uniqueKey;
}
+
+ @Override
+ public String getKey(boolean forceOpen) throws JavaModelException {
+ return this.uniqueKey;
+ }
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.core.BinaryType#isResolved()
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
index a46552b..cd63189 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
@@ -18,6 +18,7 @@
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
@@ -55,6 +56,44 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public class BindingKeyResolver extends BindingKeyParser {
+
+ /** Synthetic bindings for local variables (method arguments) restored from a binding key. */
+ private final class SyntheticLocalVariableBinding extends LocalVariableBinding {
+
+ private final MethodBinding enclosingMethod;
+ private char[] key;
+
+ SyntheticLocalVariableBinding(char[] name, TypeBinding type, MethodBinding enclosingMethod) {
+ super(name, type, 0, true);
+ this.enclosingMethod = enclosingMethod;
+ }
+
+ @Override
+ public char[] computeUniqueKey() {
+ if (this.key == null) {
+ // have no scope to find the enclosing method, so use the captured method:
+ StringBuilder buf = new StringBuilder().append(this.enclosingMethod.computeUniqueKey());
+ buf.append('#');
+ buf.append(this.name);
+ int length = buf.length();
+ this.key = new char[length];
+ buf.getChars(0, length, this.key, 0);
+ }
+ return this.key;
+ }
+
+ @Override
+ public int hashCode() {
+ return CharOperation.hashCode(computeUniqueKey());
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SyntheticLocalVariableBinding))
+ return false;
+ return CharOperation.equals(computeUniqueKey(), ((SyntheticLocalVariableBinding) obj).computeUniqueKey());
+ }
+ }
+
Compiler compiler;
Binding compilerBinding;
@@ -290,15 +329,30 @@
if (this.scope == null) {
if (this.methodBinding == null)
return;
- this.scope = this.methodBinding.sourceMethod().scope;
+ AbstractMethodDeclaration sourceMethod = this.methodBinding.sourceMethod();
+ if (sourceMethod != null) {
+ this.scope = sourceMethod.scope;
+ } else {
+ char[][] parameterNames = this.methodBinding.parameterNames;
+ for (int i = 0; i < parameterNames.length; i++) {
+ if (CharOperation.equals(parameterNames[i], varName)) {
+ // we don't have a compiler binding for this argument, but we can craft one:
+ this.compilerBinding = new SyntheticLocalVariableBinding(varName, this.methodBinding.parameters[i], this.methodBinding);
+ this.methodBinding = null;
+ return;
+ }
+ }
+ }
}
- for (int i = 0; i < this.scope.localIndex; i++) {
- LocalVariableBinding local = this.scope.locals[i];
- if (CharOperation.equals(local.name, varName)
- && occurrenceCount-- == 0) {
- this.methodBinding = null;
- this.compilerBinding = local;
- return;
+ if (this.scope != null) {
+ for (int i = 0; i < this.scope.localIndex; i++) {
+ LocalVariableBinding local = this.scope.locals[i];
+ if (CharOperation.equals(local.name, varName)
+ && occurrenceCount-- == 0) {
+ this.methodBinding = null;
+ this.compilerBinding = local;
+ return;
+ }
}
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
index 64b668e..fbcc410 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * Copyright (c) 2005, 2015 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
@@ -8,12 +8,18 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contributions for
+ * Bug 463330 - [dom] DOMFinder doesn't find the VariableBinding corresponding to a method argument
+ * Bug 464463 - [dom] DOMFinder doesn't find an ITypeParameter
+ * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
*******************************************************************************/
package org.eclipse.jdt.internal.core.util;
import org.eclipse.jdt.core.IInitializer;
+import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
@@ -29,6 +35,7 @@
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.Initializer;
+import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
@@ -36,10 +43,12 @@
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.RoleTypeDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeParameter;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.internal.core.LambdaMethod;
import org.eclipse.jdt.internal.core.SourceRefElement;
public class DOMFinder extends ASTVisitor {
@@ -68,8 +77,11 @@
public ASTNode search() throws JavaModelException {
ISourceRange range = null;
- if (this.element instanceof IMember && !(this.element instanceof IInitializer))
+ if (this.element instanceof IMember && !(this.element instanceof IInitializer)
+ && !(this.element instanceof LambdaMethod) && !(this.element instanceof org.eclipse.jdt.internal.core.LambdaExpression))
range = ((IMember) this.element).getNameRange();
+ else if (this.element instanceof ITypeParameter || this.element instanceof ILocalVariable)
+ range = this.element.getNameRange();
else
range = this.element.getSourceRange();
this.rangeStart = range.getOffset();
@@ -207,4 +219,16 @@
this.foundBinding = node.resolveBinding();
return true;
}
+
+ public boolean visit(SingleVariableDeclaration node) {
+ if (found(node, node.getName()) && this.resolveBinding)
+ this.foundBinding = node.resolveBinding();
+ return true;
+ }
+
+ public boolean visit(LambdaExpression node) {
+ if (found(node, node) && this.resolveBinding)
+ this.foundBinding = node.resolveMethodBinding();
+ return true;
+ }
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
index 4e52a9e..ceb402f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -192,7 +192,7 @@
public static String cache_invalidLoadFactor;
public static String savedState_jobName;
public static String refreshing_external_folders;
- public static String updating_external_archives_jobName;
+ public static String synchronizing_projects_job;
public static String convention_unit_nullName;
public static String convention_unit_notJavaName;
public static String convention_classFile_nullName;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
index d5908f8..bf3c646 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
@@ -191,7 +191,7 @@
cache_invalidLoadFactor = Incorrect load factor
savedState_jobName = Processing Java changes since last activation
refreshing_external_folders = Refreshing external folders
-updating_external_archives_jobName = Refreshing external archives
+synchronizing_projects_job = Synchronizing projects
## java model initialization
javamodel_initialization = Initializing Java tooling
diff --git a/org.eclipse.jdt.core/plugin.properties b/org.eclipse.jdt.core/plugin.properties
index 8f99944..1f11bc3 100644
--- a/org.eclipse.jdt.core/plugin.properties
+++ b/org.eclipse.jdt.core/plugin.properties
@@ -30,3 +30,4 @@
jarManifestName=JAR Manifest File
traceComponentLabel=JDT Core
javaFormatterName=Java Formatter
+defaultJavaFormatterName=Eclipse [built-in]
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
index 2f48730..76e3e99 100644
--- a/org.eclipse.jdt.core/plugin.xml
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -291,7 +291,7 @@
<javaFormatter
class="org.eclipse.jdt.internal.formatter.DefaultCodeFormatter"
id="org.eclipse.jdt.core.defaultJavaFormatter"
- name="Eclipse [built-in]">
+ name="%defaultJavaFormatterName">
</javaFormatter>
</extension>
diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml
index b4dbbf6..71c98d4 100644
--- a/org.eclipse.jdt.core/pom.xml
+++ b/org.eclipse.jdt.core/pom.xml
@@ -29,7 +29,6 @@
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
- <version>1.7</version>
<executions>
<execution>
<phase>prepare-package</phase>
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
index 7eeac86..53684c9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -301,7 +301,11 @@
* Returns null if the path doesn't correspond to a project.
*/
private static IJavaProject getJavaProject(IPath path, IJavaModel model) {
- IJavaProject project = model.getJavaProject(path.lastSegment());
+ String lastSeg = path.lastSegment();
+ if (lastSeg == null) {
+ lastSeg = path.toOSString();
+ }
+ IJavaProject project = model.getJavaProject(lastSeg);
if (project.exists()) {
return project;
}