diff options
111 files changed, 3162 insertions, 5142 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java index 816aac968..a11f6ac20 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -2448,4 +2448,66 @@ public void test55() { expectedReplacedSource, testName); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=291040 +public void test56() { + + String str = + "class X {\n" + + " void foo() {\n" + + " new X(null) {\n" + + " void goo() {\n" + + " new X(zoo()) {\n" + + " void voo() {\n" + + " }\n" + + " };\n" + + " }\n" + + "\n" + + " Object zoo() {\n" + + " return null;\n" + + " }\n" + + " };\n" + + " }\n" + + "\n" + + " X(Object k) {\n" + + " }\n" + + "}\n"; + + String selection = "zoo"; + + String expectedCompletionNodeToString = "<SelectOnMessageSend:zoo()>"; + + String completionIdentifier = "zoo"; + String expectedUnitDisplayString = + "class X {\n" + + " void foo() {\n" + + " new X(null) {\n" + + " void goo() {\n" + + " new X(<SelectOnMessageSend:zoo()>) {\n" + + " void voo() {\n" + + " }\n" + + " };\n" + + " }\n" + + " Object zoo() {\n" + + " }\n" + + " };\n" + + " }\n" + + " X(Object k) {\n" + + " }\n" + + "}\n"; + String expectedReplacedSource = "zoo()"; + String testName = "<select>"; + + int selectionStart = str.indexOf(selection); + int selectionEnd = str.indexOf(selection) + selection.length() - 1; + + this.checkMethodParse( + str.toCharArray(), + selectionStart, + selectionEnd, + expectedCompletionNodeToString, + expectedUnitDisplayString, + completionIdentifier, + expectedReplacedSource, + testName); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java index d63b9d0f2..925533c13 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java @@ -17,6 +17,7 @@ * bug 359721 - [options] add command line option for new warning token "resource" * bug 186342 - [compiler][null] Using annotations for null checking * bug 365208 - [compiler][batch] command line options for annotation based null analysis + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -1772,10 +1773,9 @@ public void test012b(){ " nullable|nonnull|nonnullbydefault annotation types\n" + " optionally specified using fully qualified names\n" + " nullDereference + missing null check\n" + - " nullFields + null analysis for fields\n" + - " over-ann missing @Override annotation (superclass)\n" + - " paramAssign assignment to a parameter\n" + - " pkgDefaultMethod + attempt to override package-default method\n" + + " over-ann missing @Override annotation (superclass)\n" + + " paramAssign assignment to a parameter\n" + + " pkgDefaultMethod + attempt to override package-default method\n" + " raw + usage of raw type\n" + " resource + (pot.) unsafe usage of resource of type Closeable\n" + //OT: @@ -1912,7 +1912,6 @@ public void test012b(){ " <option key=\"org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.forbiddenReference\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock\" value=\"warning\"/>\n" + - " <option key=\"org.eclipse.jdt.core.compiler.problem.includeFieldsInNullAnalysis\" value=\"disabled\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts\" value=\"disabled\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch\" value=\"ignore\"/>\n" + @@ -1967,7 +1966,7 @@ public void test012b(){ " <option key=\"org.eclipse.jdt.core.compiler.problem.typeParameterHiding\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems\" value=\"enabled\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation\" value=\"warning\"/>\n" + - " <option key=\"org.eclipse.jdt.core.compiler.problem.unclosedCloseable\" value=\"ignore\"/>\n" + + " <option key=\"org.eclipse.jdt.core.compiler.problem.unclosedCloseable\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock\" value=\"ignore\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.unhandledWarningToken\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.unnecessaryElse\" value=\"ignore\"/>\n" + @@ -12457,36 +12456,6 @@ public void test310b_warn_options() { } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=325342 -// -warn option - regression tests to check option nulLFields -// Null warnings should be flagged on fields -public void test311_warn_options() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " void foo() {\n" + - " if (o == null && o.toString() == \"\"){}\n" + - " else {}\n" + - " o.toString();\n" + // toString() call above defuses null info, so no warning here - " }\n" + - "}\n", - }, - "\"" + OUTPUT_DIR + File.separator + "X.java\"" - + " -sourcepath \"" + OUTPUT_DIR + "\"" - + " -warn:null,nullFields -proc:none -d \"" + OUTPUT_DIR + "\"", - "", - "----------\n" + - "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 4)\n" + - " if (o == null && o.toString() == \"\"){}\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + - "1 problem (1 warning)", - true); -} - -// https://bugs.eclipse.org/bugs/show_bug.cgi?id=325342 // -warn option - regression tests to check option nullAnnot (with args) // Null warnings because of annotations - custom annotation types used - challenging various kinds of diagnostics public void test312_warn_options() { @@ -12690,7 +12659,8 @@ public void test314_warn_options() { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=325342 // -warn option - regression tests to check option nullAnnot // Null warnings because of annotations, global nonNullByDefault -public void test315_warn_options() { +// DISABLED due to dysfunctional global default after Bug 366063 - Compiler should not add synthetic @NonNull annotations +public void _test315_warn_options() { this.runConformTest( new String[] { "p/X.java", diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java index 3d036f95d..6a306e4b6 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java @@ -702,7 +702,6 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("MissingEnclosingInstanceForConstructorCall", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("MissingEnumConstantCase", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("MissingOverrideAnnotation", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); - expectedProblemAttributes.put("MissingNullAnnotationType", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH)); expectedProblemAttributes.put("MissingOverrideAnnotationForInterfaceMethodImplementation", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); expectedProblemAttributes.put("MissingReturnType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("MissingSemiColon", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); @@ -730,7 +729,6 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("NonGenericConstructor", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("NonGenericMethod", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("NonGenericType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); - expectedProblemAttributes.put("NonNullFieldComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); @@ -743,9 +741,6 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("NotVisibleField", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("NotVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("NotVisibleType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); - expectedProblemAttributes.put("NullFieldComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); - expectedProblemAttributes.put("NullFieldInstanceofYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); - expectedProblemAttributes.put("NullFieldReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); @@ -789,7 +784,6 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); expectedProblemAttributes.put("PotentiallyUnclosedCloseable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("PotentiallyUnclosedCloseableAtExit", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); - expectedProblemAttributes.put("PotentialNullFieldReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("PotentialNullMessageSendReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("PublicClassMustMatchFileName", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); @@ -799,13 +793,10 @@ public void _test011_problem_categories() { expectedProblemAttributes.put("RedefinedArgument", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("RedefinedLocal", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("RedundantSpecificationOfTypeArguments", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE)); - expectedProblemAttributes.put("RedundantFieldNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantLocalVariableNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantNullAnnotation", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE)); - expectedProblemAttributes.put("RedundantNullCheckOnNonNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantNullCheckOnNonNullLocalVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantNullCheckOnNonNullMessageSend", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); - expectedProblemAttributes.put("RedundantNullCheckOnNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantNullCheckOnNullLocalVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantNullDefaultAnnotation", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE)); expectedProblemAttributes.put("RedundantNullDefaultAnnotationPackage", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE)); @@ -1486,7 +1477,6 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("MissingEnclosingInstance", SKIP); expectedProblemAttributes.put("MissingEnclosingInstanceForConstructorCall", SKIP); expectedProblemAttributes.put("MissingEnumConstantCase", new ProblemAttributes(JavaCore.COMPILER_PB_INCOMPLETE_ENUM_SWITCH)); - expectedProblemAttributes.put("MissingNullAnnotationType", SKIP); expectedProblemAttributes.put("MissingOverrideAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION)); expectedProblemAttributes.put("MissingOverrideAnnotationForInterfaceMethodImplementation", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION)); expectedProblemAttributes.put("MissingReturnType", SKIP); @@ -1515,7 +1505,6 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("NonGenericConstructor", SKIP); expectedProblemAttributes.put("NonGenericMethod", SKIP); expectedProblemAttributes.put("NonGenericType", SKIP); - expectedProblemAttributes.put("NonNullFieldComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER)); expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER)); @@ -1528,9 +1517,6 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("NotVisibleField", SKIP); expectedProblemAttributes.put("NotVisibleMethod", SKIP); expectedProblemAttributes.put("NotVisibleType", SKIP); - expectedProblemAttributes.put("NullFieldComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); - expectedProblemAttributes.put("NullFieldInstanceofYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); - expectedProblemAttributes.put("NullFieldReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE)); expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE)); @@ -1574,7 +1560,6 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION)); expectedProblemAttributes.put("PotentiallyUnclosedCloseable", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE)); expectedProblemAttributes.put("PotentiallyUnclosedCloseableAtExit", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE)); - expectedProblemAttributes.put("PotentialNullFieldReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE)); expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE)); expectedProblemAttributes.put("PotentialNullMessageSendReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE)); expectedProblemAttributes.put("PublicClassMustMatchFileName", SKIP); @@ -1584,13 +1569,10 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("RedefinedArgument", SKIP); expectedProblemAttributes.put("RedefinedLocal", SKIP); expectedProblemAttributes.put("RedundantSpecificationOfTypeArguments", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_TYPE_ARGUMENTS)); - expectedProblemAttributes.put("RedundantFieldNullAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantLocalVariableNullAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantNullAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_ANNOTATION)); - expectedProblemAttributes.put("RedundantNullCheckOnNonNullField", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantNullCheckOnNonNullLocalVariable", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantNullCheckOnNonNullMessageSend", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); - expectedProblemAttributes.put("RedundantNullCheckOnNullField", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantNullCheckOnNullLocalVariable", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); expectedProblemAttributes.put("RedundantNullDefaultAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_ANNOTATION)); expectedProblemAttributes.put("RedundantNullDefaultAnnotationPackage", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_ANNOTATION)); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java index 669345c58..4e758287b 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2011 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 @@ -31,7 +31,7 @@ import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; public class FlowAnalysisTest extends AbstractRegressionTest { static { -// TESTS_NAMES = new String[] { "testInnerClassesWithFields1" }; +// TESTS_NAMES = new String[] { "testLocalClassInInitializer1" }; // TESTS_NUMBERS = new int[] { 69 }; } public FlowAnalysisTest(String name) { @@ -2496,119 +2496,6 @@ public void testLocalClassInInitializer2() { "continue cannot be used outside of a loop\n" + "----------\n"); } -// final field in anonymous nested class -// witness a regression during working on Bug 247564 - [compiler][null] Detecting null field reference -public void testFinalFieldInNested1() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " void print4() {\n" + - " for (int i=0; i<4; i++)\n" + - " new Runnable() {\n" + - " final String s1local;\n" + - " public void run() {\n" + - " s1local.toString();\n" + - " }\n" + - " }.run();\n" + - " }\n" + - "}\n" - }, - "----------\n" + - "1. ERROR in X.java (at line 4)\n" + - " new Runnable() {\n" + - " ^^^^^^^^^^\n" + - "The blank final field s1local may not have been initialized\n" + - "----------\n"); -} -// witness a regression during working on Bug 247564 - [compiler][null] Detecting null field reference -// local variable in inner class triggered IAE in StackMapFrame.addStackItem -public void testInnerClassesWithFields1() { - if (this.complianceLevel >= ClassFileConstants.JDK1_6) { // we're specifically interested in StackMap generation - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " int f1, f2, f3;\n" + - " class I1 {\n" + - " int f4;\n" + - " String m(boolean b) {\n" + - " String l1 = \"Hello\";\n" + - " if (b) {\n" + - " l1 += \" world!\";\n" + - " } else {\n" + - " l1 += \" test.\";\n" + - " }\n" + - " return l1;\n" + - " }\n" + - " }\n" + - " class I2 {\n" + - " int f5, f6, f7;\n" + - " }\n" + - "}\n" - }, - ""); - } -} -// witness a regression during working on Bug 247564 - [compiler][null] Detecting null field reference -// local variable in local class triggered IAE in StackMapFrame.addStackItem -public void testInnerClassesWithFields1a() { - if (this.complianceLevel >= ClassFileConstants.JDK1_6) { // we're specifically interested in StackMap generation - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " int f1, f2, f3;\n" + - " void foo() {\n" + - " class I1 {\n" + - " int f4;\n" + - " String m(boolean b) {\n" + - " String l1 = \"Hello\";\n" + - " if (b) {\n" + - " l1 += \" world!\";\n" + - " } else {\n" + - " l1 += \" test.\";\n" + - " }\n" + - " return l1;\n" + - " }\n" + - " }\n" + - " }\n" + - " class I2 {\n" + - " int f5, f6, f7;\n" + - " }\n" + - "}\n" - }, - ""); - } -} -// witness a regression during working on Bug 247564 - [compiler][null] Detecting null field reference -// final fields in parameterized nested were reported as uninitialized -public void testInnerClassesWithFields2() { - if (this.complianceLevel >= ClassFileConstants.JDK1_5) { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " static final String f1 = \"f1\";\n" + - " static final String f2 = \"f2\";\n" + - " String f3;\n" + - " X() {\n" + - " f3 = \"f3\";\n" + - " }\n" + - " protected abstract class I<T> {\n" + - " final String f5, f6;\n" + - " T f7;\n" + - " I(T a) {\n" + - " f5 = \"f5\";\n" + - " f6 = \"f6\";\n" + - " f7 = a;\n" + - " }\n" + - " }\n" + - "}\n" - }, - ""); - } -} public static Class testClass() { return FlowAnalysisTest.class; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InitializationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InitializationTests.java index 0309b5f19..23d941007 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InitializationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InitializationTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 IBM Corporation and others. + * Copyright (c) 2010, 2011 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 @@ -464,44 +464,6 @@ public void testBug324178d() { "The local variable b2 may not have been initialized\n" + "----------\n"); } -// https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564 -// Change in the way field id's are calculated should not affect initializations -public void testBug247564j() { - this.runNegativeTest( - new String[] { - "Z.java", - "public class Z {\n" + - " final int field1 = 0;\n" + - " {\n" + - " class ZInner {\n" + - " final int fieldz1;\n" + - " final int fieldz2 = 0;\n" + - " }\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. WARNING in Z.java (at line 4)\n" + - " class ZInner {\n" + - " ^^^^^^\n" + - "The type ZInner is never used locally\n" + - "----------\n" + - "2. ERROR in Z.java (at line 4)\n" + - " class ZInner {\n" + - " ^^^^^^\n" + - "The blank final field fieldz1 may not have been initialized\n" + - "----------\n" + - "3. WARNING in Z.java (at line 5)\n" + - " final int fieldz1;\n" + - " ^^^^^^^\n" + - "The value of the field ZInner.fieldz1 is not used\n" + - "----------\n" + - "4. WARNING in Z.java (at line 6)\n" + - " final int fieldz2 = 0;\n" + - " ^^^^^^^\n" + - "The value of the field ZInner.fieldz2 is not used\n" + - "----------\n" - ); -} public static Class testClass() { return InitializationTests.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 1b1d69ca0..ebd5df08b 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 @@ -53,7 +53,7 @@ public NullAnnotationTest(String name) { // Static initializer to specify tests subset using TESTS_* static variables // All specified tests which do not belong to the class are skipped... static { -// TESTS_NAMES = new String[] { "test_redundant_annotation_" }; +// TESTS_NAMES = new String[] { "test_message_send_in_control_structure_02" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -762,6 +762,43 @@ public void test_nonnull_local_001() { true /* shouldFlush*/); } +// assigning potential null to a nonnull local variable - separate decl and assignment +public void test_nonnull_local_002() { + runNegativeTest( + new String[] { + "X.java", + "import org.eclipse.jdt.annotation.*;\n" + + "public class X {\n" + + " void foo(boolean b, Object p) {\n" + + " @NonNull Object o1;\n" + + " o1 = b ? null : new Object();\n" + + " @NonNull String o2;\n" + + " o2 = \"\";\n" + + " o2 = null;\n" + + " @NonNull Object o3;\n" + + " o3 = p;\n" + + " }\n" + + "}\n"}, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " o1 = b ? null : new Object();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + + "----------\n" + + "2. ERROR in X.java (at line 8)\n" + + " o2 = null;\n" + + " ^^^^\n" + + "Type mismatch: required \'@NonNull String\' but the provided value is null\n" + + "----------\n" + + "3. WARNING in X.java (at line 10)\n" + + " o3 = p;\n" + + " ^\n" + + "Potential type mismatch: required \'@NonNull Object\' but nullness of the provided value is unknown\n" + + "----------\n", + this.LIBS, + true /* shouldFlush*/); +} + // a method tries to tighten the type specification, super declares parameter o as @Nullable // other parameters: s is redefined from not constrained to @Nullable which is OK // third is redefined from not constrained to @NonNull which is bad, too @@ -1877,15 +1914,14 @@ public void test_annotation_import_006() { "----------\n", JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); } -// using nullness defaulting to nonnull, missing annotation types +// using nullness defaulting to nonnull, missing annotation types, no longer a problem public void test_annotation_import_007() { Map customOptions = getCompilerOptions(); customOptions.put(JavaCore.COMPILER_PB_NULL_SPECIFICATION_INSUFFICIENT_INFO, JavaCore.ERROR); customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.MayBeNull"); customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.MustNotBeNull"); customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); - runNegativeTest( - true/*shouldFlushOutputDirectory*/, + runConformTestWithLibs( new String[] { "Lib.java", "public class Lib {\n" + @@ -1898,15 +1934,8 @@ public void test_annotation_import_007() { " }\n" + "}\n" }, - this.LIBS, customOptions, - "----------\n" + - "1. ERROR in Lib.java (at line 1)\n" + - " public class Lib {\n" + - " ^\n" + - "Buildpath problem: the type org.foo.MustNotBeNull, which is configured as a null annotation type, cannot be resolved\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); + ""); } // a null annotation is illegally used on a class: @@ -2085,11 +2114,13 @@ public void test_illegal_annotation_007() { public void test_default_nullness_002() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); - customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); +// This option currently does nothing: +// customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); runNegativeTestWithLibs( new String[] { "X.java", "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + "public class X {\n" + " Object getObject(@Nullable Object o) {\n" + " return new Object();\n" + @@ -2097,6 +2128,7 @@ public void test_default_nullness_002() { "}\n", "Y.java", "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + "public class Y extends X {\n" + " @Override\n" + " @Nullable Object getObject(Object o) {\n" + // complain illegal return redef and inherited annot is not repeated @@ -2107,13 +2139,13 @@ public void test_default_nullness_002() { customOptions, // main error: "----------\n" + - "1. ERROR in Y.java (at line 4)\n" + + "1. ERROR in Y.java (at line 5)\n" + " @Nullable Object getObject(Object o) {\n" + " ^^^^^^^^^^^^^^^^\n" + "The return type is incompatible with the @NonNull return from X.getObject(Object)\n" + "----------\n" + // additional error: - "2. ERROR in Y.java (at line 4)\n" + + "2. ERROR in Y.java (at line 5)\n" + " @Nullable Object getObject(Object o) {\n" + " ^^^^^^\n" + "Illegal redefinition of parameter o, inherited method from X declares this parameter as @Nullable\n" + @@ -2162,7 +2194,7 @@ public void test_default_nullness_003() { "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + "----------\n"); } -// package level default is consumed from package-info.class +// package level default is consumed from package-info.class, similarly for type level default public void test_default_nullness_003a() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); @@ -2219,7 +2251,7 @@ public void test_default_nullness_003a() { "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + "----------\n"); } -//same as test_default_nullness_003b, but default-induced annotations are combined with explicit ones (not null related) +// same as test_default_nullness_003a, but default-induced annotations are combined with explicit ones (not null related) public void test_default_nullness_003b() { Map customOptions = getCompilerOptions(); runConformTestWithLibs( @@ -2373,7 +2405,8 @@ public void test_default_nullness_006() { "----------\n"); } // global default nonnull, but return may be null -public void test_default_nullness_007() { +// DISABLED due to dysfunctional global default after Bug 366063 - Compiler should not add synthetic @NonNull annotations +public void _test_default_nullness_007() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); @@ -2828,7 +2861,8 @@ public void test_redundant_annotation_02g() { } // redundant default annotations - package / class / method vs global default -public void test_redundant_annotation_03() { +// DISABLED due to dysfunctional global default after Bug 366063 - Compiler should not add synthetic @NonNull annotations +public void _test_redundant_annotation_03() { Map customOptions = getCompilerOptions(); customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); runConformTestWithLibs( @@ -2956,11 +2990,13 @@ public void test_contradictory_annotations_01() { public void test_nonnull_var_in_constrol_structure_1() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); - customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); +// This option currently does nothing: +// customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); runNegativeTestWithLibs( new String[] { "X.java", "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + "public class X {\n" + " void print4(@NonNull String s) {\n" + " for (int i=0; i<4; i++)\n" + @@ -2983,22 +3019,22 @@ public void test_nonnull_var_in_constrol_structure_1() { }, customOptions, "----------\n" + - "1. WARNING in X.java (at line 3)\n" + + "1. WARNING in X.java (at line 4)\n" + " void print4(@NonNull String s) {\n" + " ^^^^^^^^^^^^^^^^^\n" + "The nullness annotation is redundant with a default that applies to this location\n" + "----------\n" + - "2. ERROR in X.java (at line 9)\n" + + "2. ERROR in X.java (at line 10)\n" + " print(s);\n" + " ^\n" + "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + "----------\n" + - "3. ERROR in X.java (at line 14)\n" + + "3. ERROR in X.java (at line 15)\n" + " print(s);\n" + " ^\n" + "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + "----------\n" + - "4. WARNING in X.java (at line 16)\n" + + "4. WARNING in X.java (at line 17)\n" + " void print(@NonNull String s) {\n" + " ^^^^^^^^^^^^^^^^^\n" + "The nullness annotation is redundant with a default that applies to this location\n" + @@ -3008,11 +3044,13 @@ public void test_nonnull_var_in_constrol_structure_1() { public void test_nonnull_var_in_constrol_structure_2() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); - customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); +// This option currently does nothing: +// customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); runNegativeTestWithLibs( new String[] { "X.java", - "import org.eclipse.jdt.annotation.*;\n" + + "import org.eclipse.jdt.annotation.*;" + + "@NonNullByDefault\n" + "public class X {\n" + " void print4(String s) {\n" + " try { /*empty*/ } finally {\n" + @@ -3183,6 +3221,54 @@ public void test_message_send_in_control_structure_01() { "Null comparison always yields false: The variable enclosingSourceType cannot be null at this location\n" + "----------\n"); } +// Bug 370930 - NonNull annotation not considered for enhanced for loops +public void test_message_send_in_control_structure_02() { + runNegativeTestWithLibs( + new String[] { + "Bug370930.java", + "import org.eclipse.jdt.annotation.*;\n" + + "import java.util.*;\n" + + "public class Bug370930 {\n" + + " void loop(Collection<String> list) {\n" + + " for(@NonNull String s: list) { // warning here: insufficient info on elements\n" + + " expectNonNull(s); // no warning here\n" + + " }\n" + + " }\n" + + " \n" + + " void expectNonNull(@NonNull String s) {}\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in Bug370930.java (at line 5)\n" + + " for(@NonNull String s: list) { // warning here: insufficient info on elements\n" + + " ^^^^\n" + + "Potential type mismatch: required \'@NonNull String\' but nullness of the provided value is unknown\n" + + "----------\n"); +} +//Bug 370930 - NonNull annotation not considered for enhanced for loops +public void test_message_send_in_control_structure_03() { + runNegativeTestWithLibs( + new String[] { + "Bug370930.java", + "import org.eclipse.jdt.annotation.*;\n" + + "import java.util.*;\n" + + "public class Bug370930 {\n" + + " void loop(Collection<String> list) {\n" + + " for(@Nullable String s: list) {\n" + + " expectNonNull(s); // warning here\n" + + " }\n" + + " }\n" + + " \n" + + " void expectNonNull(@NonNull String s) {}\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Bug370930.java (at line 6)\n" + + " expectNonNull(s); // warning here\n" + + " ^\n" + + "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + + "----------\n"); +} public void test_assignment_expression_1() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); @@ -3217,11 +3303,13 @@ public void test_assignment_expression_1() { public void test_nesting_1() { Map customOptions = getCompilerOptions(); // customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); - customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); +// This option currently does nothing: +// customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); runNegativeTestWithLibs( new String[] { "X.java", "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + "public class X {\n" + " void print4(final String s1) {\n" + " for (int i=0; i<3; i++)\n" + @@ -3256,12 +3344,12 @@ public void test_nesting_1() { }, customOptions, "----------\n" + - "1. ERROR in X.java (at line 15)\n" + + "1. ERROR in X.java (at line 16)\n" + " print(s2);\n" + " ^^\n" + "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + "----------\n" + - "2. ERROR in X.java (at line 24)\n" + + "2. ERROR in X.java (at line 25)\n" + " @NonNull String s3R = s3;\n" + " ^^\n" + "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java index 2bb4c6175..95af131fd 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 IBM Corporation and others. + * Copyright (c) 2005, 2010 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 @@ -37,7 +37,6 @@ import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; /** * A tests series especially meant to validate the internals of our null @@ -1084,21 +1083,18 @@ public FlowInfo copy() { return copy; } -public void markAsDefinitelyNonNull(VariableBinding local) { - int position = local.getAnalysisId(this.maxFieldCount); - grow(position); +public void markAsDefinitelyNonNull(LocalVariableBinding local) { + grow(local.id + this.maxFieldCount); super.markAsDefinitelyNonNull(local); } -public void markAsDefinitelyNull(VariableBinding local) { - int position = local.getAnalysisId(this.maxFieldCount); - grow(position); +public void markAsDefinitelyNull(LocalVariableBinding local) { + grow(local.id + this.maxFieldCount); super.markAsDefinitelyNull(local); } -public void markAsDefinitelyUnknown(VariableBinding local) { - int position = local.getAnalysisId(this.maxFieldCount); - grow(position); +public void markAsDefinitelyUnknown(LocalVariableBinding local) { + grow(local.id + this.maxFieldCount); super.markAsDefinitelyUnknown(local); } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java index 6e8dfa6cc..31f6af6cf 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java @@ -49,7 +49,7 @@ public NullReferenceTest(String name) { // Only the highest compliance level is run; add the VM argument // -Dcompliance=1.4 (for example) to lower it if needed static { -// TESTS_NAMES = new String[] { "testBug247564n_3" }; +// TESTS_NAMES = new String[] { "testBug360328" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -72,7 +72,6 @@ protected Map getCompilerOptions() { defaultOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR); defaultOptions.put(CompilerOptions.OPTION_ReportRawTypeReference, CompilerOptions.IGNORE); defaultOptions.put(CompilerOptions.OPTION_IncludeNullInfoFromAsserts, CompilerOptions.ENABLED); - defaultOptions.put(CompilerOptions.OPTION_IncludeFieldsInNullAnalysis, CompilerOptions.ENABLED); } return defaultOptions; } @@ -110,12 +109,13 @@ public void test0002_simple_field() { " o.toString();\n" + " }\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + "" +// "----------\n" + +// "1. ERROR in X.java (at line 5)\n" + +// " o.toString();\n" + +// " ^\n" + +// "The field o is likely null; it was either set to null or checked for null when last used\n" + +// "----------\n" ); } @@ -346,12 +346,13 @@ public void test0014_field_with_explicit_this_access() { " this.o.toString();\n" + " }\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " this.o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + "" +// "----------\n" + +// "1. ERROR in X.java (at line 5)\n" + +// " this.o.toString();\n" + +// " ^^^^^^\n" + +// "The field o is likely null; it was either set to null or checked for null when last used\n" + +// "----------\n" ); } @@ -367,12 +368,13 @@ public void test0015_field_with_explicit_this_access() { " o.toString();\n" + " }\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + "" +// "----------\n" + +// "1. ERROR in X.java (at line 5)\n" + +// " o.toString();\n" + +// " ^\n" + +// "The field o is likely null; it was either set to null or checked for null when last used\n" + +// "----------\n" ); } @@ -422,12 +424,13 @@ public void test0018_field_of_enclosing_object() { " }\n" + " }\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 6)\n" + - " X.this.o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + "" +// "----------\n" + +// "1. ERROR in X.java (at line 6)\n" + +// " X.this.o.toString();\n" + +// " ^^^^^^^^\n" + +// "The field o is likely null; it was either set to null or checked for null when last used\n" + +// "----------\n" ); } @@ -446,12 +449,13 @@ public void test0019_field_synchronized() { " }\n" + " void bar() {/* */}\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + "" +// "----------\n" + +// "1. ERROR in X.java (at line 5)\n" + +// " o.toString();\n" + +// " ^\n" + +// "The field o is likely null; it was either set to null or checked for null when last used\n" + +// "----------\n" ); } @@ -3095,7 +3099,7 @@ public void test0412_while_if_nested() { // null analysis -- while public void test0413_while_unknown_field() { - this.runNegativeTest( + this.runConformTest( new String[] { "X.java", "public class X {\n" + @@ -3107,12 +3111,7 @@ public void test0413_while_unknown_field() { " o.toString();\n" + " }\n" + "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 7)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n"); + ""); } // null analysis -- while @@ -15456,2709 +15455,4 @@ public void testBug360328d() { "",/* expected error */ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); } - -// null analysis -- simple case for field -public void testBug247564a() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " void foo() {\n" + - " if (o == null && o.toString() == \"\"){}\n" + - " else {}\n" + - " o.toString();\n" + // toString() call above defuses null info, so no warning here - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 4)\n" + - " if (o == null && o.toString() == \"\"){}\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for field -// no redundant null check warnings should be obtained since value of field -// may be changed in another thread. -public void testBug247564a_1() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " void foo() {\n" + - " o = null;" + - " if (o == null){}\n" + - " if (o != null){}\n" + - " o.toString();\n" + // warn here - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 6)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for field -public void testBug247564a_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " void foo() {\n" + - " if (o == null){\n" + // o is null inside the if block - " o.toString();\n" + - " }\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for field -// null info from one method should not be present in the other (for instance fields) -public void testBug247564a_3() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " void foo() {\n" + - " o = null;\n" + - " }\n" + - " void foo1() {\n" + - " o.toString();\n" + - " }\n" + - "}\n"}, - "" - ); -} - -//null analysis -- simple case for field -public void testBug247564a_4() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " int foo() {\n" + - " if (o != null && o.toString() == \"\") {\n" + - " } else {\n" + - " }\n" + - " return o.hashCode();\n" + // the above check has shed doubts so give a warning here - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 7)\n" + - " return o.hashCode();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- field accessed inside control structure -// from https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564#c121 -public void testBug247564a_5() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object field;\n" + - " void goo(Object var) throws Exception{\n" + - " if (field != null) field.hashCode();\n" + - " int i = 20;\n" + - " while (i<10) {\n" + - " if (field == null) { \n" + - " field = new Object();\n" + - " }\n" + - " field.toString(); // Wrong outcome was: Pot. NPE\n" + - " i--;\n" + - " }\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- simple case for static final field -// once dereferenced, treat as non null. Consistent with local variables. -public void testBug247564b() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o = null;\n" + - " static final Object o1 = new Object();\n" + - " void foo() {\n" + - " if (o.toString() == \"\") {}\n" + - " if (o == null) {}\n" + - " if (o != null) {}\n" + - " if (o1 == null) {}\n" + - " if (o1 != null) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " if (o.toString() == \"\") {}\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 6)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Null comparison always yields false: The field o cannot be null at this location\n" + - "----------\n" + - "3. WARNING in X.java (at line 6)\n" + - " if (o == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "4. ERROR in X.java (at line 7)\n" + - " if (o != null) {}\n" + - " ^\n" + - "Redundant null check: The field o cannot be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 8)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Null comparison always yields false: The field o1 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 8)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 9)\n" + - " if (o1 != null) {}\n" + - " ^^\n" + - "Redundant null check: The field o1 cannot be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for static final field -public void testBug247564b_1() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1;\n" + - " static {\n" + - " o = null;\n" + - " o1 = new Object();\n" + - " }\n" + - " void foo() {\n" + - " if (o.toString() == \"\") {}\n" + - " if (o == null) {}\n" + - " if (o != null) {}\n" + - " if (o1 == null) {}\n" + - " if (o1 != null) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 9)\n" + - " if (o.toString() == \"\") {}\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 10)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Null comparison always yields false: The field o cannot be null at this location\n" + - "----------\n" + - "3. WARNING in X.java (at line 10)\n" + - " if (o == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "4. ERROR in X.java (at line 11)\n" + - " if (o != null) {}\n" + - " ^\n" + - "Redundant null check: The field o cannot be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 12)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Null comparison always yields false: The field o1 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 12)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 13)\n" + - " if (o1 != null) {}\n" + - " ^^\n" + - "Redundant null check: The field o1 cannot be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for static final field -public void testBug247564b_1_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o;\n" + - " static final Object o1;\n" + - " static {\n" + - " o = null;\n" + - " o1 = new Object();\n" + - " }\n" + - " void foo() {\n" + - " if (o.toString() == \"\") {}\n" + - " if (o == null) {}\n" + - " if (o != null) {}\n" + - " if (o1 == null) {}\n" + - " if (o1 != null) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 35)\n" + - " if (o.toString() == \"\") {}\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 36)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Null comparison always yields false: The field o cannot be null at this location\n" + - "----------\n" + - "3. WARNING in X.java (at line 36)\n" + - " if (o == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "4. ERROR in X.java (at line 37)\n" + - " if (o != null) {}\n" + - " ^\n" + - "Redundant null check: The field o cannot be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 38)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Null comparison always yields false: The field o1 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 38)\n" + - " if (o1 == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 39)\n" + - " if (o1 != null) {}\n" + - " ^^\n" + - "Redundant null check: The field o1 cannot be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// checked before use -public void testBug247564b_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " if (o == null) \n" + - " return;\n" + - " o.toString();\n" + // cant be null for sure, dont complain - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// checked before use -public void testBug247564b_2_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " if (o == null) \n" + - " return;\n" + - " o.toString();\n" + // cant be null for sure, dont complain - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// Check pot. NPE case for constant fields -// Once dereferenced, treat as non null. Just like locals. -public void testBug247564b_3() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo() {\n" + - " if (o.toString() == \"\") {}\n" + - " if (o == null) {}\n" + - " if (o != null) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 12)\n" + - " if (o.toString() == \"\") {}\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 13)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Null comparison always yields false: The field o cannot be null at this location\n" + - "----------\n" + - "3. WARNING in X.java (at line 13)\n" + - " if (o == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "4. ERROR in X.java (at line 14)\n" + - " if (o != null) {}\n" + - " ^\n" + - "Redundant null check: The field o cannot be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// Check pot. NPE case for constant fields -// Once dereferenced, treat as non null. Just like locals. -public void testBug247564b_3_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo() {\n" + - " if (o.toString() == \"\") {}\n" + - " if (o == null) {}\n" + - " if (o != null) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 38)\n" + - " if (o.toString() == \"\") {}\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 39)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Null comparison always yields false: The field o cannot be null at this location\n" + - "----------\n" + - "3. WARNING in X.java (at line 39)\n" + - " if (o == null) {}\n" + - " ^^\n" + - "Dead code\n" + - "----------\n" + - "4. ERROR in X.java (at line 40)\n" + - " if (o != null) {}\n" + - " ^\n" + - "Redundant null check: The field o cannot be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// checked before use -public void testBug247564b_4() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " if (o == null) {\n" + - " o.toString(); // danger\n" + - " return;\n" + - " }\n" + - " o.toString(); // safe\n" + - " }\n" + - " void foo2() {\n" + - " if (o != null) {\n" + - " o.toString(); // safe (2)\n" + - " }\n" + - " o.toString(); // uncertain\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 13)\n" + - " o.toString(); // danger\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 22)\n" + - " o.toString(); // uncertain\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// checked before use -public void testBug247564b_4_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " if (o == null) {\n" + - " o.toString(); // danger\n" + - " return;\n" + - " }\n" + - " o.toString(); // safe\n" + - " }\n" + - " void foo2() {\n" + - " if (o != null) {\n" + - " o.toString(); // safe (2)\n" + - " }\n" + - " o.toString(); // uncertain\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 39)\n" + - " o.toString(); // danger\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 48)\n" + - " o.toString(); // uncertain\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. -public void testBug247564b_5() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static final Object o2 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o == null) {\n" + // don't know o's nullness, so silent - " o.toString();\n" + // report NPE - " }\n" + - " local.toString();\n" + // try to diffuse status for o / o2 - " o.toString();\n" + // already reported NPE above. So silent. Same behaviour as 'local' - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 14)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 15)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 19)\n" + - " o.toString();\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "5. WARNING in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. This test is for constructors -public void testBug247564b_6() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static final Object o2 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " public X() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o == null) {\n" + // don't know o's nullness, so silent - " o.toString();\n" + // report NPE - " }\n" + - " local.toString();\n" + // try to diffuse status for o / o2 - " o.toString();\n" + // already reported NPE above. So silent. Same behaviour as 'local' - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 14)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 15)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 19)\n" + - " o.toString();\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "5. WARNING in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. This test is for constructors -public void testBug247564b_6_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o;\n" + - " static final Object o1 = new Object();\n" + - " static final Object o2 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " public X() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o == null) {\n" + // don't know o's nullness, so silent - " o.toString();\n" + // report NPE - " }\n" + - " local.toString();\n" + // try to diffuse status for o / o2 - " o.toString();\n" + // already reported NPE above. So silent. Same behaviour as 'local' - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 40)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 41)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 45)\n" + - " o.toString();\n" + - " ^\n" + - "Null pointer access: The field o can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 49)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "5. WARNING in X.java (at line 49)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. Also, null info of constant field from static block is available in methods -public void testBug247564b_7() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o;\n" + - " static final Object o1 = null;\n" + - " static final Object o2 = new Object();\n" + - " static {\n" + - " if (o1.hashCode() == 2){\n" + // report NPE. But dereferenced here, so later it should be treated as non null - " o = new Object();\n" + - " } else {\n" + - " o = null;\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o1 == null) {\n" + // can't be null, was dereferenced in static initializer - " o1.toString();\n" + // dead - " }\n" + - " local.toString();\n" + // try to diffuse status for o1 / o2 - " o1.toString();\n" + // safe - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 6)\n" + - " if (o1.hashCode() == 2){\n" + - " ^^\n" + - "Null pointer access: The field o1 can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 14)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 15)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 18)\n" + - " if (o1 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o1 cannot be null at this location\n" + - "----------\n" + - "5. WARNING in X.java (at line 18)\n" + - " if (o1 == null) {\n" + - " o1.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "6. ERROR in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "7. WARNING in X.java (at line 23)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. This test is for more than 64 fields to check for extra bits. -public void testBug247564b_8() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - "static final Object o1 = null;\n" + - "static final Object o2 = new Object();\n" + - " void foo1() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o1 == null) {\n" + // report redundant null check - " o1.toString();\n" + // report NPE - " }\n" + - " local.toString();\n" + // try to diffuse status for o1 / o2 - " o1.toString();\n" + // already reported NPE above. So silent. Same behaviour as 'local' - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 32)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 33)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 36)\n" + - " if (o1 == null) {\n" + - " ^^\n" + - "Redundant null check: The field o1 can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 37)\n" + - " o1.toString();\n" + - " ^^\n" + - "Null pointer access: The field o1 can only be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 41)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 41)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- case for static final field initialized inside static block where some locals are also present -// check if the resetting works properly -public void testBug247564b_9() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - " static final Object o1;\n" + - " static final Object o2 = new Object();\n" + - " static {\n" + - " int i = 10;\n" + - " o1 = null;\n" + - " }\n" + - " void foo1() {\n" + - " final Object local = null;\n" + - " if (local == null) {\n" + - " local.toString();\n" + - " }\n" + - " local.toString();\n" + - " if (o1 == null) {\n" + // report redundant null check - " o1.toString();\n" + // report NPE - " }\n" + - " local.toString();\n" + // try to diffuse status for o1 / o2 - " o1.toString();\n" + // already reported NPE above. So silent. Same behaviour as 'local' - " if (o2 == null) {\n" + // report always false null check - " o2.toString();\n" + // dead code - " }\n" + - " o2.toString();" + - " }\n" + - "}\n"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 10)\n" + - " if (local == null) {\n" + - " ^^^^^\n" + - "Redundant null check: The variable local can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " local.toString();\n" + - " ^^^^^\n" + - "Null pointer access: The variable local can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 14)\n" + - " if (o1 == null) {\n" + - " ^^\n" + - "Redundant null check: The field o1 can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 15)\n" + - " o1.toString();\n" + - " ^^\n" + - "Null pointer access: The field o1 can only be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 19)\n" + - " if (o2 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 19)\n" + - " if (o2 == null) {\n" + - " o2.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. -// Boundary condition: field <boundary> constant local -public void testBug247564b_10() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63;\n" + - "static final Object static64 = null;\n" + - " void foo1(Object local65) {\n" + - " if (field63 == null) {\n" + - " field63.toString(); // report NPE\n" + - " }\n" + - " if (static64 == null) { // redundant\n" + - " static64.toString(); // report NPE\n" + - " }\n" + - " if (local65 == null) {\n" + - " local65.toString(); // report NPE\n" + - " }\n" + - " if (field63 == null) {\n" + - " this.toString();\n" + - " field63.toString();\n" + // wiped by method call - " }\n" + - " if (static64 == null) { // always false\n" + // because we're past static64.toString() - " this.toString(); // dead\n" + - " static64.toString();\n" + - " }\n" + - " if (local65 == null) { // alwayws false\n" + // because we're past local65.toString() - " this.toString(); // dead\n" + - " local65.toString();\n" + - " }\n" + - " }\n" + - "}\n"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 22)\n" + - " field63.toString(); // report NPE\n" + - " ^^^^^^^\n" + - "Potential null pointer access: The field field63 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 24)\n" + - " if (static64 == null) { // redundant\n" + - " ^^^^^^^^\n" + - "Redundant null check: The field static64 can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 25)\n" + - " static64.toString(); // report NPE\n" + - " ^^^^^^^^\n" + - "Null pointer access: The field static64 can only be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 28)\n" + - " local65.toString(); // report NPE\n" + - " ^^^^^^^\n" + - "Null pointer access: The variable local65 can only be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 34)\n" + - " if (static64 == null) { // always false\n" + - " ^^^^^^^^\n" + - "Null comparison always yields false: The field static64 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 34)\n" + - " if (static64 == null) { // always false\n" + - " this.toString(); // dead\n" + - " static64.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 38)\n" + - " if (local65 == null) { // alwayws false\n" + - " ^^^^^^^\n" + - "Null comparison always yields false: The variable local65 cannot be null at this location\n" + - "----------\n" + - "8. WARNING in X.java (at line 38)\n" + - " if (local65 == null) { // alwayws false\n" + - " this.toString(); // dead\n" + - " local65.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- case for static final field initialized inside static block with different values -// check if the resetting works properly i.e. null status for constant fields should not be -// reset on method calls. -// Boundary condition: constant field <boundary> local -public void testBug247564b_11() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61;\n" + - "static final Object static62 = null;\n" + - "Object field63;" + - " void foo1(Object local64) {\n" + - " if (static62 == null) { // redundant\n" + - " static62.toString(); // report NPE\n" + - " }\n" + - " if (field63 == null) {\n" + - " field63.toString(); // report NPE\n" + - " }\n" + - " if (local64 == null) {\n" + - " local64.toString(); // report NPE\n" + - " }\n" + - " if (static62 == null) { // always false\n" + // because we're past static64.toString() - " this.toString(); // dead\n" + - " static62.toString();\n" + - " }\n" + - " if (field63 == null) {\n" + - " this.toString(); //\n" + - " field63.toString();\n" + // wiped by method call - " }\n" + - " if (local64 == null) { // alwayws false\n" + // because we're past local64.toString() - " this.toString(); // dead\n" + - " local64.toString();\n" + - " }\n" + - " }\n" + - "}\n"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 21)\n" + - " if (static62 == null) { // redundant\n" + - " ^^^^^^^^\n" + - "Redundant null check: The field static62 can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 22)\n" + - " static62.toString(); // report NPE\n" + - " ^^^^^^^^\n" + - "Null pointer access: The field static62 can only be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 25)\n" + - " field63.toString(); // report NPE\n" + - " ^^^^^^^\n" + - "Potential null pointer access: The field field63 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 28)\n" + - " local64.toString(); // report NPE\n" + - " ^^^^^^^\n" + - "Null pointer access: The variable local64 can only be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 30)\n" + - " if (static62 == null) { // always false\n" + - " ^^^^^^^^\n" + - "Null comparison always yields false: The field static62 cannot be null at this location\n" + - "----------\n" + - "6. WARNING in X.java (at line 30)\n" + - " if (static62 == null) { // always false\n" + - " this.toString(); // dead\n" + - " static62.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 38)\n" + - " if (local64 == null) { // alwayws false\n" + - " ^^^^^^^\n" + - "Null comparison always yields false: The variable local64 cannot be null at this location\n" + - "----------\n" + - "8. WARNING in X.java (at line 38)\n" + - " if (local64 == null) { // alwayws false\n" + - " this.toString(); // dead\n" + - " local64.toString();\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- fields in synchronized methods -// check that null analysis for fields in synchronized methods -// behave as it does in ordinary methods. -public void testBug247564c() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " Object o1;\n" + - " static final Object o2 = null;\n" + - " static final Object o3 = new Object();\n" + - " synchronized void foo() {\n" + - " o = null;\n" + - " if (o == null) {\n" + - " o.toString();\n" + - " }\n" + - " o1 = new Object();\n" + - " if (o1 == null) {\n" + - " o1.toString();\n" + - " }\n" + - " if (o2 != null) {\n" + - " }\n" + - " else {\n" + - " o2.toString();\n" + - " }\n" + - " if (o3 == null) {\n" + - " }\n" + - " else {\n" + - " o3.toString();\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " o.toString();\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 9)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 13)\n" + - " o1.toString();\n" + - " ^^\n" + - "Potential null pointer access: The field o1 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 15)\n" + - " if (o2 != null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 can only be null at this location\n" + - "----------\n" + - "4. WARNING in X.java (at line 15)\n" + - " if (o2 != null) {\n" + - " }\n" + - " ^^^^^\n" + - "Dead code\n" + - "----------\n" + - "5. ERROR in X.java (at line 18)\n" + - " o2.toString();\n" + - " ^^\n" + - "Null pointer access: The field o2 can only be null at this location\n" + - "----------\n" + - "6. ERROR in X.java (at line 20)\n" + - " if (o3 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o3 cannot be null at this location\n" + - "----------\n" + - "7. WARNING in X.java (at line 20)\n" + - " if (o3 == null) {\n" + - " }\n" + - " ^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- fields in synchronized methods -// check that null analysis for fields in synchronized methods -// behave as it does in ordinary methods. Higher no. of fields -public void testBug247564c_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " Object o1;\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o2 = null;\n" + - " static final Object o3 = new Object();\n" + - " synchronized void foo() {\n" + - " o = null;\n" + - " if (o == null) {\n" + - " o.toString();\n" + - " }\n" + - " o1 = new Object();\n" + - " if (o1 == null) {\n" + - " o1.toString();\n" + - " }\n" + - " if (o2 != null) {\n" + - " }\n" + - " else {\n" + - " o2.toString();\n" + - " }\n" + - " if (o3 == null) {\n" + - " }\n" + - " else {\n" + - " o3.toString();\n" + - " }\n" + - " }\n" + - " void foo1() {\n" + - " o.toString();\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 35)\n" + - " o.toString();\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 39)\n" + - " o1.toString();\n" + - " ^^\n" + - "Potential null pointer access: The field o1 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 41)\n" + - " if (o2 != null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o2 can only be null at this location\n" + - "----------\n" + - "4. WARNING in X.java (at line 41)\n" + - " if (o2 != null) {\n" + - " }\n" + - " ^^^^^\n" + - "Dead code\n" + - "----------\n" + - "5. ERROR in X.java (at line 44)\n" + - " o2.toString();\n" + - " ^^\n" + - "Null pointer access: The field o2 can only be null at this location\n" + - "----------\n" + - "6. ERROR in X.java (at line 46)\n" + - " if (o3 == null) {\n" + - " ^^\n" + - "Null comparison always yields false: The field o3 cannot be null at this location\n" + - "----------\n" + - "7. WARNING in X.java (at line 46)\n" + - " if (o3 == null) {\n" + - " }\n" + - " ^^^^^\n" + - "Dead code\n" + - "----------\n" - ); -} - -// null analysis -- test redundant instanceof warning for static final field -public void testBug247564d() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " static final Object o = null;\n" + - " static final Object o1 = new Object();\n" + - " void foo() {\n" + - " if (o instanceof String) {}\n" + - " if (o1 instanceof String) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " if (o instanceof String) {}\n" + - " ^\n" + - "instanceof always yields false: The field o can only be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- test redundant instanceof warning for static final field. More fields -public void testBug247564d_1() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - " static final Object o = null;\n" + - " static final Object o1 = new Object();\n" + - " void foo() {\n" + - " if (o instanceof String) {}\n" + - " if (o1 instanceof String) {}\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 31)\n" + - " if (o instanceof String) {}\n" + - " ^\n" + - "instanceof always yields false: The field o can only be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- test potential null ptr access warning because of static field access through object returned by method call -public void testBug247564f() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - " static Object o;\n" + - " static Object o1;\n" + - " Object o2;\n" + - " X getX() { return new X();\n}\n" + - " void foo() {\n" + - " if (getX().o == null && this.o.hashCode() == 0) return;\n" + - " if (getX().o2 == null && this.o2.hashCode() == 0) return;\n" + - " }\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 8)\n" + - " if (getX().o == null && this.o.hashCode() == 0) return;\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- test potential null ptr access warning because of static field access through object returned by method call -public void testBug247564f_1() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - " static Object o;\n" + - " X getX() { return new X();\n}\n" + - " Y getY() { return new Y();\n}\n" + - " void foo() {\n" + - " if (getY().o == null && this.o.hashCode() == 0) return;\n" + - " if (getX().o == null && this.o.hashCode() == 0) return;\n" + - " }\n" + - "}\n" + - "class Y{\n" + - " static Object o;\n" + - "}\n"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 9)\n" + - " if (getX().o == null && this.o.hashCode() == 0) return;\n" + - " ^\n" + - "Potential null pointer access: The field o may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- test field analysis in case of more than 64 fields -public void testBug247564g() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - false, - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64, \n" + - "field65, field66, field67, field68, \n" + - "field69, field70, field71, field72, \n" + - "field73, field74, field75, field76, \n" + - "field77, field78, field79, field80, \n" + - "field81, field82, field83, field84, \n" + - "field85, field86, field87, field88, \n" + - "field89, field90, field91, field92, \n" + - "field93, field94, field95, field96, \n" + - "field97, field98, field99;\n" + - "static final Object field100 = null;\n" + - " void foo() {\n" + - " int i = 0;" + - " while (i<10){\n" + - " i++;\n" + - " if (this.field99 == null && this.field99.hashCode() == 0){}\n" + - " this.field98 = null;\n" + - " }\n" + - " if (this.field98.hashCode() == 0) {}\n" + - " this.field97 = null;\n" + - " if (this.field97.hashCode() == 0) {}\n" + - " if (this.field100.hashCode() == 0) {}\n" + - " }\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 32)\n" + - " if (this.field99 == null && this.field99.hashCode() == 0){}\n" + - " ^^^^^^^\n" + - "Potential null pointer access: The field field99 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 35)\n" + - " if (this.field98.hashCode() == 0) {}\n" + - " ^^^^^^^\n" + - "Potential null pointer access: The field field98 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 37)\n" + - " if (this.field97.hashCode() == 0) {}\n" + - " ^^^^^^^\n" + - "Potential null pointer access: The field field97 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 38)\n" + - " if (this.field100.hashCode() == 0) {}\n" + - " ^^^^^^^^\n" + - "Null pointer access: The field field100 can only be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); -} - -// null analysis -- simple case for field for inner class -// to make sure field id's of inner and outer classes are not same for flow analysis -public void testBug247564h() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object o;\n" + - " class X1 {\n" + - " Object x;" + - " Object x1;" + - " Object x2;" + - " void goo() {\n" + - " if (o == null && x.toString() == \"\"){}\n" + - " if (o2 == null && o2.toString() == \"\"){}\n" + - " if (o2 == null && x2.toString() == \"\"){}\n" + - " }\n" + - - " }\n" + - " Object o1;\n" + - " static Object o2;\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 6)\n" + - " if (o2 == null && o2.toString() == \"\"){}\n" + - " ^^\n" + - "Potential null pointer access: The field o2 may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for field for inner class -// to make sure that id's of local variables in inner classes don't conflict with those of fields. -public void testBug247564h_1() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object field0;\n" + - " Object field1;\n" + - " class X1 {\n" + - " Object field2;" + - " Object field3;" + - " void goo(Object var) {\n" + - " if (var == null && field2.toString() == \"\"){}\n" + - " if (var == null && field3.toString() == \"\"){}\n" + - " if (field2 == null && field2.toString() == \"\"){}\n" + - " }\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 8)\n" + - " if (field2 == null && field2.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field2 may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for field for inner class -// to make sure that id's of local variables in inner classes don't conflict with those of fields. -public void testBug247564h_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " Object field0;\n" + - " Object field1;\n" + - " class X1 {\n" + - " Object field2;\n" + - " Object field3;\n" + - " class X2 {\n" + - " Object field4;\n" + - " Object field5;\n" + - " void goo(Object var) {\n" + - " if (var == null && field4.toString() == \"\"){}\n" + - " if (var == null && field5.toString() == \"\"){}\n" + - " if (field3 == null && field3.toString() == \"\"){}\n" + - " if (field3 == null && field1.toString() == \"\"){}\n" + - " }\n" + - " }\n" + - " Object field22;\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 13)\n" + - " if (field3 == null && field3.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field3 may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- simple case for static fields -// to make sure that static field only of the current type is assigned potentially null when compared against null -// Static fields belonging to any other class should be ignored -// Qualified access to static fields should also work -public void testBug247564i_1() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "public class X {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " Y getY(){ return new Y();}\n" + - " X getX() { return new X();}\n" + - " void goo(Object var) {\n" + - " if (Y.yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (Y.yField1 == null && this.field0.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + // warn, qualified access - " if (Y.yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (this.field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (X.field0 == null && this.field0.toString() == \"\"){}\n" + // warn - " if (X.field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn (diffused by getX() call) - " }\n" + - "}\n" + - "class Y{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;" + - " static X xiny;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 9)\n" + - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 12)\n" + - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 13)\n" + - " if (this.field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 14)\n" + - " if (X.field0 == null && this.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} - -// null analysis -- static fields accessed via MessageSend -// to make sure that static field only of the current type is assigned potentially null when compared against null -// Static fields belonging to any other class should be ignored -// Qualified access to static fields should also work -public void testBug247564i_2() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "public class X {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " Y getY(){ return new Y();}\n" + - " X getX() { return new X();}\n" + - " void goo(Object var) {\n" + - " if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && this.field0.toString() == \"\"){}\n" + // no warn - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && this.field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn, getX() wipes out null info - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn, qualified access - // fields from other types, don't warn - " if (new Y().getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getX().field0 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " }\n" + - "}\n" + - "class Y{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 10)\n" + - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 12)\n" + - " if (getX().field0 == null && this.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 14)\n" + - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} - -// null analysis -- static fields accessed from Member type -// Qualified access to static fields should also work -public void testBug247564i_3() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "public class X {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " static Y getY(){ return new Y();}\n" + - " static X getX() { return new X();}\n" + - " static class XInner{\n" + - " static Object xinnerfield;\n" + - " XInner getXInner() { return new XInner();\n}" + - " void goo(Object var) {\n" + - " if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn, getX() wipes out null info - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn, qualified access - " if (getXInner().xinnerfield == null && xinnerfield.toString() == \"\"){}\n" + // warn - " if (getXInner().xinnerfield == null && this.xinnerfield.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && this.xinnerfield.toString() == \"\"){}\n" + // no warn - " if (getXInner().xinnerfield == null && field0.toString() == \"\"){}\n" + // no warn - // fields from other types, don't warn - " if (new Y().getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getX().field0 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - // qualified accesses - " if (Y.yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + // warn, qualified access - " if (Y.yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (X.field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn - " }\n" + - " }\n" + - "}\n" + - "class Y{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;\n" + - " static X xiny;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 12)\n" + - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 13)\n" + - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 15)\n" + - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 16)\n" + - " if (getXInner().xinnerfield == null && xinnerfield.toString() == \"\"){}\n" + - " ^^^^^^^^^^^\n" + - "Potential null pointer access: The field xinnerfield may be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 17)\n" + - " if (getXInner().xinnerfield == null && this.xinnerfield.toString() == \"\"){}\n" + - " ^^^^^^^^^^^\n" + - "Potential null pointer access: The field xinnerfield may be null at this location\n" + - "----------\n" + - "6. ERROR in X.java (at line 24)\n" + - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "7. ERROR in X.java (at line 27)\n" + - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} - -// null analysis -- static fields accessed from a local type -// Qualified access to static fields should also work -public void testBug247564i_4() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "public class X {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " Y getY(){ return new Y();}\n" + - " X getX() { return new X();}\n" + - " void goo(Object var) {\n" + - " class Local{\n" + - " void localfoo(){\n " + - " if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn, getX() wipes out null info - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn, qualified access - // fields from other types, don't warn - " if (new Y().getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getX().field0 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - // qualified accesses - " if (Y.yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + // warn, qualified access - " if (Y.yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (X.field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn - " }\n" + - " }\n" + - " }\n" + - "}\n" + - "class Y{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;\n" + - " static X xiny;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. WARNING in X.java (at line 7)\n" + - " class Local{\n" + - " ^^^^^\n" + - "The type Local is never used locally\n" + - "----------\n" + - "2. WARNING in X.java (at line 8)\n" + - " void localfoo(){\n" + - " ^^^^^^^^^^\n" + - "The method localfoo() from the type Local is never used locally\n" + - "----------\n" + - "3. ERROR in X.java (at line 11)\n" + - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 12)\n" + - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 14)\n" + - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "6. ERROR in X.java (at line 19)\n" + - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "7. ERROR in X.java (at line 22)\n" + - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} - -// null analysis -- static fields from an anonymous type -// Qualified access to static fields should also work -public void testBug247564i_5() { - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "interface Anon{}\n" + - "public class X {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " Y getY(){ return new Y();}\n" + - " X getX() { return new X();}\n" + - " void goo(Object var) {\n" + - " new Anon(){\n" + - " void localfoo(){\n " + - " if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn, getX() wipes out null info - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn, qualified access - // fields from other types, don't warn - " if (new Y().getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getX().field0 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - // qualified accesses - " if (Y.yField1 == null && field0.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + // warn, qualified access - " if (Y.yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (X.field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn - " }\n" + - " };\n" + - " }\n" + - "}\n" + - "class Y{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;\n" + - " static X xiny;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. WARNING in X.java (at line 9)\n" + - " void localfoo(){\n" + - " ^^^^^^^^^^\n" + - "The method localfoo() from the type new Anon(){} is never used locally\n" + - "----------\n" + - "2. ERROR in X.java (at line 12)\n" + - " if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 13)\n" + - " if (getX().field0 == null && field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "4. ERROR in X.java (at line 15)\n" + - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "5. ERROR in X.java (at line 20)\n" + - " if (Y.xiny.field0 == null && Y.xiny.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "6. ERROR in X.java (at line 23)\n" + - " if (X.field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} -// null analysis -- static fields -// to check static field access from fieldReference and QualifiedReference when the type is parameterized -public void testBug247564i_6() { - if (this.complianceLevel < ClassFileConstants.JDK1_5) return; - Map compilerOptions = getCompilerOptions(); - compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE); - this.runNegativeTest( - true, - new String[] { - "X.java", - "public class X<T> {\n" + - " static Object field0;\n" + - " static Object field1;\n" + - " Y getY(){ return new Y();}\n" + - " X getX() { return new X();}\n" + - " void goo(Object var) {\n" + - " if (new Y().getY().yField1 == null && X.field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && X.field0.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && this.field0.toString() == \"\"){}\n" + // no warn - " if (new Y().getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && this.field0.toString() == \"\"){}\n" + // warn - " if (getX().field0 == null && getX().field0.toString() == \"\"){}\n" + // no warn, getX() wipes out null info - // fields from other types, don't warn - " if (new Y().getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getY().yField1 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " if (getX().field0 == null && Y.yField1.toString() == \"\"){}\n" + // no warn - " }\n" + - "}\n" + - "class Y<K>{\n" + - " Y getY(){ return new Y();}\n" + - " X getX(){ return new X();}\n" + - " static Object yField1;\n" + - "}"}, - null, - compilerOptions, - "----------\n" + - "1. ERROR in X.java (at line 10)\n" + - " if (new Y().getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " if (getX().field0 == null && X.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n" + - "3. ERROR in X.java (at line 12)\n" + - " if (getX().field0 == null && this.field0.toString() == \"\"){}\n" + - " ^^^^^^\n" + - "Potential null pointer access: The field field0 may be null at this location\n" + - "----------\n", - JavacTestOptions.Excuse.EclipseWarningConfiguredAsError - ); -} -//null analysis -- simple case for field of parent type -public void testBug247564j() { - this.runConformTest( - new String[] { - "X.java", - "public class X extends Y {\n" + - " private Object fieldx;\n" + - " void goo(Object var) {\n" + - " if (fieldx == null && fieldy.toString() == \"\"){}\n" + // don't flag fieldy, nothing known - " }\n" + - "}\n" + - "class Y{\n" + - " protected Object fieldy = null;\n" + - "}\n" + - ""}, - "" - ); -} - -// null analysis -- simple case for field in try-finally -public void testBug247564k() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object f;\n" + - " void goo(Object var) {\n" + - " try {\n" + - " int i = 10;\n" + - " while (i<20){\n" + - " if (i == 15) {\n" + - " f = null;\n" + - " break;\n" + - " }\n" + - " i++;\n" + - " }\n" + - " return;\n" + - " } finally {\n" + - " if (f != null && f.hashCode() == 0){}\n" + - " }\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- simple case for field in try-finally -// presence or absence of throw should not affect the behaviour -public void testBug247564k_1() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object f;\n" + - " void goo(Object var) throws Exception{\n" + - " try {\n" + - " int i = 10;\n" + - " } catch(Exception e) {\n" + - " f = null;\n" + - " throw e;\n" + - " } finally {\n" + - " if (f != null && f.hashCode() == 0){}\n" + - " }\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- simple case for field in try-finally -// presence or absence of method call in finally should not affect the behaviour -public void testBug247564k_2() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object f;\n" + - " void gooCalls(){}\n" + - " void goo(Object var) throws Exception{\n" + - " try {\n" + - " if (f != null) {}\n" + - " } finally {\n" + - " if (f != null ) {\n" + - " gooCalls();\n" + - " f.toString();\n" + - " }\n" + // silent - " }\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- simple case for constant field in try-catch-finally -// presence or absence of method call in finally should not affect the behaviour -public void testBug247564k_3() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - " private static final Object f = null;\n" + - " void gooCalls() throws NumberFormatException{}\n" + - " void goo(Object var) throws Exception{\n" + - " try {\n" + - " gooCalls();\n" + - " } catch(NumberFormatException e) {\n" + - " if (f.hashCode() == 0){}\n" + - " } finally {\n" + - " gooCalls();\n" + - " if (f.hashCode() == 0){}\n" + - " }\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 8)\n" + - " if (f.hashCode() == 0){}\n" + - " ^\n" + - "Null pointer access: The field f can only be null at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " if (f.hashCode() == 0){}\n" + - " ^\n" + - "Null pointer access: The field f can only be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- potentially redundant checks against the same field -public void testBug247564l_1() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object f;\n" + - " int foo() throws Exception{\n" + - " if (f == null && f != null)\n" + - " return 13;\n" + - " return -13;\n" + - " }\n" + - " int goo() throws Exception{\n" + - " if (f == null && f == null)\n" + - " return 14;\n" + - " return -14;\n" + - " }\n" + - " boolean hoo() throws Exception{\n" + - " if (f == null)\n" + - " return f != null;\n" + - " return f == null;\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- fields assigned a def. non null value in a loop -// comment 121 -public void testBug247564l_2() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - " private Object field;\n" + - " void foo() throws Exception{\n" + - " if (field != null) field.hashCode();\n" + - " int i = 10;\n" + - " while (i<20) {\n" + - " if (field == null) field = new Object();\n" + - " field.toString();\n" + // should not warn - " i++;\n" + - " }\n" + - " }\n" + - "}\n"}, - "" - ); -} - -// null analysis -- checked and unchecked exceptions -public void testBug247564m() { - this.runNegativeTest( - new String[] { - "X.java", - "class MyException extends Exception{}\n" + - "public class X {\n" + - " private Object f;\n" + - " void gooCalls() throws MyException{}\n" + - " void goo(){\n" + - " try {\n" + - " if (f == null) return;\n" + - " gooCalls();\n" + - " } catch(MyException e) {\n" + // checked Exception - " f.toString();\n" + // silent - at gooCalls() in 'try', f is not going to be null - " } catch(NumberFormatException e) {\n" + // unchecked Exception - " f.toString();\n" + // could have come from anywhere, f can be null as doubted in 'try' - " }\n" + - " }\n" + - "}\n"}, - "----------\n" + - "1. WARNING in X.java (at line 1)\n" + - " class MyException extends Exception{}\n" + - " ^^^^^^^^^^^\n" + - "The serializable class MyException does not declare a static final serialVersionUID field of type long\n" + - "----------\n" + - "2. ERROR in X.java (at line 12)\n" + - " f.toString();\n" + - " ^\n" + - "Potential null pointer access: The field f may be null at this location\n" + - "----------\n" - ); -} - -// null analysis -- check resetting of large no. of fields -// https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564#c161 -public void testBug247564n() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64; \n" + - " static final Object o2 = new Object();\n" + - " public X() {\n" + - " field23 = null;\n" + - " o2.toString();\n" + - " if (field23.hashCode() == 0){}\n" + // don't warn - " }\n" + - "}\n"}, - "" - ); -} -// null analysis -- check resetting of large no. of fields -// see also https://bugs.eclipse.org/bugs/show_bug.cgi?id=369381 -public void testBug247564n_2() { - this.runNegativeTest( - new String[] { - "X.java", - "public class X {\n" + - "Object field0, \n" + // more than 64 fields - "field1, field2, field3, field4, \n" + - "field5, field6, field7, field8, \n" + - "field9, field10, field11, field12, \n" + - "field13, field14, field15, field16, \n" + - "field17, field18, field19, field20, \n" + - "field21, field22, field23, field24, \n" + - "field25, field26, field27, field28, \n" + - "field29, field30, field31, field32, \n" + - "field33, field34, field35, field36, \n" + - "field37, field38, field39, field40, \n" + - "field41, field42, field43, field44, \n" + - "field45, field46, field47, field48, \n" + - "field49, field50, field51, field52, \n" + - "field53, field54, field55, field56, \n" + - "field57, field58, field59, field60, \n" + - "field61, field62, field63, field64; \n" + - " static final Object o2 = new Object();\n" + - " public X() {\n" + - " Object l0, l1, l2, l3, l4, l5, l6, l7, l8, l9,\n" + // more than 64 locals - " l10, l11, l12, l13, l14, l15, l16, l17, l18, l19,\n" + - " l20, l21, l22, l23, l24, l25, l26, l27, l28, l29,\n" + - " l30, l31, l32, l33, l34, l35, l36, l37, l38, l39,\n" + - " l40, l41, l42, l43, l44, l45, l46, l47, l48, l49,\n" + - " l50, l51, l52, l53, l54, l55, l56, l57, l58, l59,\n" + - " l60, l61, l62, l63, l64, l65, l66, l67, l68, l69;\n" + - " l69 = null;\n" + // l69 has bits in extra[x][1] - " o2.toString();\n" + // resetNullInfoForFields() must not reset any bits in extra[x][1] - " l69.toString();\n" + // warn! - " }\n" + - "}\n"}, - "----------\n" + - "1. ERROR in X.java (at line 30)\n" + - " l69.toString();\n" + - " ^^^\n" + - "Null pointer access: The variable l69 can only be null at this location\n" + - "----------\n" - ); -} - -// null analysis - should not throw NPE -// see also https://bugs.eclipse.org/bugs/show_bug.cgi?id=369381 -public void testBug369381() { - this.runConformTest( - new String[] { - "X.java", - "public class X extends XParent{\n" + - " public void foo(X x, int i) {\n" + - " if (this.field0.length == i){}\n" + // declaring class of 'length' is null. Dont throw NPE - " }\n" + - "}\n" + - "class XParent {\n" + - " protected Object[] field0 = {new Object()}; \n" + - "}\n" - }, - "" - ); -} - -// null analysis -- with large no. of fields, no AIOOBE should be thrown -// no. of static final fields less than no. of final-only fields -public void _testBug369381a() { - this.runConformTest( - new String[] { - "X.java", - "public class X {\n" + - "static final Object field0 = null;\n " + - "static final Object field1 = null;\n " + - "static final Object field2 = null;\n " + - "static final Object field3 = null;\n " + - "static final Object field4 = null;\n " + - "static final Object field5 = null;\n " + - "static final Object field6 = null;\n " + - "static final Object field7 = null;\n " + - "static final Object field8 = null;\n " + - "static final Object field9 = null;\n " + - "static final Object field10 = null;\n" + - "static final Object field11 = null;\n" + - "static final Object field12 = null;\n" + - "static final Object field13 = null;\n" + - "static final Object field14 = null;\n" + - "static final Object field15 = null;\n" + - "static final Object field16 = null;\n" + - "static final Object field17 = null;\n" + - "static final Object field18 = null;\n" + - "static final Object field19 = null;\n" + - "static final Object field20 = null;\n" + - "static final Object field21 = null;\n" + - "static final Object field22 = null;\n" + - "static final Object field23 = null;\n" + - "static final Object field24 = null;\n" + - "static final Object field25 = null;\n" + - "static final Object field26 = null;\n" + - "static final Object field27 = null;\n" + - "static final Object field28 = null;\n" + - "static final Object field29 = null;\n" + - "static final Object field30 = null;\n" + - "static final Object field31 = null;\n" + - "static final Object field32 = null;\n" + - "static final Object field33 = null;\n" + - "static final Object field34 = null;\n" + - "static final Object field35 = null;\n" + - "static final Object field36 = null;\n" + - "static final Object field37 = null;\n" + - "static final Object field38 = null;\n" + - "static final Object field39 = null;\n" + - "static final Object field40 = null;\n" + - "static final Object field41 = null;\n" + - "static final Object field42 = null;\n" + - "static final Object field43 = null;\n" + - "static final Object field44 = null;\n" + - "static final Object field45 = null;\n" + - "static final Object field46 = null;\n" + - "static final Object field47 = null;\n" + - "static final Object field48 = null;\n" + - "static final Object field49 = null;\n" + - "static final Object field50 = null;\n" + - "static final Object field51 = null;\n" + - "static final Object field52 = null;\n" + - "static final Object field53 = null;\n" + - "static final Object field54 = null;\n" + - "static final Object field55 = null;\n" + - "static final Object field56 = null;\n" + - "static final Object field57 = null;\n" + - "static final Object field58 = null;\n" + - "static final Object field59 = null;\n" + - "static final Object field60 = null;\n" + - "static final Object field61 = null;\n" + - "static final Object field62 = null;\n" + - "static final Object field63 = null;\n" + - "static final Object field64 = null;\n" + - "static final Object field65 = null;\n" + - "static final Object field66 = null;\n" + - "static final Object field67 = null;\n" + - "static final Object field68 = null;\n" + - "static final Object field69 = null;\n" + - "final Object field00 = null; \n" + - "final Object field01 = null; \n" + - "final Object field02 = null; \n" + - "final Object field03 = null; \n" + - "final Object field04 = null; \n" + - "final Object field05 = null; \n" + - "final Object field06 = null; \n" + - "final Object field07 = null; \n" + - "final Object field08 = null; \n" + - "final Object field09 = null; \n" + - "final Object field010 = null;\n" + - "final Object field011 = null;\n" + - "final Object field012 = null;\n" + - "final Object field013 = null;\n" + - "final Object field014 = null;\n" + - "final Object field015 = null;\n" + - "final Object field016 = null;\n" + - "final Object field017 = null;\n" + - "final Object field018 = null;\n" + - "final Object field019 = null;\n" + - "final Object field020 = null;\n" + - "final Object field021 = null;\n" + - "final Object field022 = null;\n" + - "final Object field023 = null;\n" + - "final Object field024 = null;\n" + - "final Object field025 = null;\n" + - "final Object field026 = null;\n" + - "final Object field027 = null;\n" + - "final Object field028 = null;\n" + - "final Object field029 = null;\n" + - "final Object field030 = null;\n" + - "final Object field031 = null;\n" + - "final Object field032 = null;\n" + - "final Object field033 = null;\n" + - "final Object field034 = null;\n" + - "final Object field035 = null;\n" + - "final Object field036 = null;\n" + - "final Object field037 = null;\n" + - "final Object field038 = null;\n" + - "final Object field039 = null;\n" + - "final Object field040 = null;\n" + - "final Object field041 = null;\n" + - "final Object field042 = null;\n" + - "final Object field043 = null;\n" + - "final Object field044 = null;\n" + - "final Object field045 = null;\n" + - "final Object field046 = null;\n" + - "final Object field047 = null;\n" + - "final Object field048 = null;\n" + - "final Object field049 = null;\n" + - "final Object field050 = null;\n" + - "final Object field051 = null;\n" + - "final Object field052 = null;\n" + - "final Object field053 = null;\n" + - "final Object field054 = null;\n" + - "final Object field055 = null;\n" + - "final Object field056 = null;\n" + - "final Object field057 = null;\n" + - "final Object field058 = null;\n" + - "final Object field059 = null;\n" + - "final Object field060 = null;\n" + - "final Object field061 = null;\n" + - "final Object field062 = null;\n" + - "final Object field063 = null;\n" + - "final Object field064 = null;\n" + - "final Object field065 = null;\n" + - "final Object field066 = null;\n" + - "final Object field067 = null;\n" + - "final Object field068 = null;\n" + - "final Object field069 = null;\n" + - " public X() {\n" + - " }\n" + - "}\n"}, - "" - ); -} -} +}
\ No newline at end of file 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 c587eaf6c..beeb07b6f 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 @@ -26,7 +26,7 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; public class ResourceLeakTests extends AbstractRegressionTest { static { -// TESTS_NAMES = new String[] { "testBug368709"}; +// TESTS_NAMES = new String[] { "test066"}; // TESTS_NUMBERS = new int[] { 50 }; // TESTS_RANGE = new int[] { 11, -1 }; } @@ -1489,7 +1489,7 @@ public void test056y() { " final FileReader reader23 = new FileReader(\"file\");\n" + " provider = new ResourceProvider() {\n" + " public FileReader provide() {\n" + - " return reader23;\n" + + " return reader23;\n" + // responsibility now lies at the caller of this method " }\n" + " };\n" + " }\n" + @@ -1500,11 +1500,6 @@ public void test056y() { " final FileReader reader31 = new FileReader(\"file\");\n" + " ^^^^^^^^\n" + "Potential resource leak: 'reader31' may not be closed\n" + - "----------\n" + - "2. WARNING in X.java (at line 17)\n" + - " final FileReader reader23 = new FileReader(\"file\");\n" + - " ^^^^^^^^\n" + - "Potential resource leak: 'reader23' may not be closed\n" + "----------\n", null, true, @@ -3143,12 +3138,7 @@ public void testBug368709a() { "}\n" }, "----------\n" + - "1. ERROR in X.java (at line 15)\n" + - " return wc.open(getObjectId(), type).openStream();\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Resource leak: \'in\' is not closed at this location\n" + - "----------\n" + - "2. ERROR in X.java (at line 18)\n" + + "1. ERROR in X.java (at line 18)\n" + " return new ObjectStream.Filter(type, size, in);\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Potential resource leak: \'in\' may not be closed at this location\n" + @@ -3189,4 +3179,535 @@ public void testBug368709b() { true, options); } + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 3 +public void test064() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + this.runNegativeTest(new String[] { + "Test064.java", + "import java.io.*;\n" + + "public class Test064 {\n" + + " void foo(File outfile) {\n" + + " OutputStream out= System.out;\n" + + " if (outfile != null) {\n" + + " try {\n" + + " out = new FileOutputStream(outfile);\n" + + " } catch (java.io.IOException e) {\n" + + " throw new RuntimeException(e);\n" + + " }\n" + + " }\n" + + " setOutput(out);\n" + + " }\n" + + " private void setOutput(OutputStream out) { }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test064.java (at line 7)\n" + + " out = new FileOutputStream(outfile);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Potential resource leak: \'out\' may not be closed\n" + + "----------\n", + null, + true, + options); +} +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 10 +// disabled, because basic null-analysis machinery doesn't support this pattern +// see also Bug 370424 - [compiler][null] throw-catch analysis for null flow could be more precise +public void _test065() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test065.java", + "import java.io.*;\n" + + "class MyException extends Exception{}\n" + + "public class Test065 {\n" + + " void foo(String fileName) throws IOException, MyException {\n" + + " FileReader fileRead = new FileReader(fileName);\n" + + " BufferedReader bufRead = new BufferedReader(fileRead);\n" + + " LineNumberReader lineReader = new LineNumberReader(bufRead);\n" + + " try {\n" + + " while (lineReader.readLine() != null) {\n" + + " bufRead.close();\n" + + " callSome(); // only this can throw MyException\n" + + " }\n" + + " } catch (MyException e) {\n" + + " throw e; // Pot. leak reported here\n" + + " }\n" + + " bufRead.close(); \n" + + " }\n" + + " private void callSome() throws MyException\n" + + " {\n" + + " \n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 11 +public void test066() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test066.java", + "import java.io.*;\n" + + "class MyException extends Exception{}\n" + + "public class Test066 {\n" + + " void countFileLines(String fileName) throws IOException {\n" + + " FileReader fileRead = new FileReader(fileName);\n" + + " BufferedReader bufRead = new BufferedReader(fileRead);\n" + + " LineNumberReader lineReader = new LineNumberReader(bufRead);\n" + + " while (lineReader.readLine() != null) {\n" + + " if (lineReader.markSupported())\n" + + " throw new IOException();\n" + + " bufRead.close();\n" + + " }\n" + + " bufRead.close();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test066.java (at line 10)\n" + + " throw new IOException();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Potential resource leak: \'lineReader\' may not be closed at this location\n" + + "----------\n", + null, + true, + options); +} +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 11 - variant with closing top-level resource +public void test066b() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test066.java", + "import java.io.*;\n" + + "class MyException extends Exception{}\n" + + "public class Test066 {\n" + + " void countFileLines(String fileName) throws IOException {\n" + + " FileReader fileRead = new FileReader(fileName);\n" + + " BufferedReader bufRead = new BufferedReader(fileRead);\n" + + " LineNumberReader lineReader = new LineNumberReader(bufRead);\n" + + " while (lineReader.readLine() != null) {\n" + + " if (lineReader.markSupported())\n" + + " throw new IOException();\n" + + " lineReader.close();\n" + + " }\n" + + " lineReader.close();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test066.java (at line 10)\n" + + " throw new IOException();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Potential resource leak: \'lineReader\' may not be closed at this location\n" + + "----------\n", + null, + true, + options); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 12 +// disabled because null info after try-catch is too weak, +// see also Bug 370424 - [compiler][null] throw-catch analysis for null flow could be more precise +public void _test067() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test067.java", + "import java.io.*;\n" + + "public class Test067 {\n" + + " public void comment12() throws IOException {\n" + + " LineNumberReader o = null;\n" + + " try {\n" + + " o = new LineNumberReader(null); \n" + + " } catch (NumberFormatException e) { \n" + + " }\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 12 +// disabled because null info after try-catch is too weak, +// see also Bug 370424 - [compiler][null] throw-catch analysis for null flow could be more precise +public void _test067b() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test067.java", + "import java.io.*;\n" + + "public class Test067 {\n" + + " public void comment12b() throws IOException {\n" + + " LineNumberReader o = new LineNumberReader(null);\n" + + " try {\n" + + " o.close();\n" + + " } catch (NumberFormatException e) {\n" + + " }\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 13 +public void test068() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test068.java", + "import java.io.*;\n" + + "public class Test068 {\n" + + " class ProcessingStep extends OutputStream {\n" + + " public void write(int b) throws IOException {}\n" + + " public OutputStream getDestination() { return null; }\n" + + " }\n" + + " class ArtifactOutputStream extends OutputStream {\n" + + " public void write(int b) throws IOException {}\n" + + " }" + + " ArtifactOutputStream comment13(OutputStream stream) {\n" + + " OutputStream current = stream;\n" + + " while (current instanceof ProcessingStep)\n" + + " current = ((ProcessingStep) current).getDestination();\n" + // we previously saw a bogus warning here. + " if (current instanceof ArtifactOutputStream)\n" + + " return (ArtifactOutputStream) current;\n" + + " return null;\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// example from comment 16 +public void test069() { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; // generics used + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test069.java", + "import java.io.*;\n" + + "import java.util.Collection;\n" + + "public class Test069 {\n" + + " class Profile {}\n" + + " class CoreException extends Exception {}\n" + + " void writeProfilesToStream(Collection<Profile> p, OutputStream s, String enc) {}\n" + + " CoreException createException(IOException ioex, String message) { return new CoreException(); }\n" + + " public void comment16(Collection<Profile> profiles, File file, String encoding) throws CoreException {\n" + + " final OutputStream stream;\n" + + " try {\n" + + " stream= new FileOutputStream(file);\n" + + " try {\n" + + " writeProfilesToStream(profiles, stream, encoding);\n" + + " } finally {\n" + + " try { stream.close(); } catch (IOException e) { /* ignore */ }\n" + + " }\n" + + " } catch (IOException e) {\n" + + " throw createException(e, \"message\"); // should not shout here\n" + + " }\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// referenced in array initializer +public void test070() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test070.java", + "import java.io.*;\n" + + "public class Test070 {\n" + + " void storeInArray(String fileName) throws IOException {\n" + + " FileReader fileRead = new FileReader(fileName);\n" + + " closeThemAll(new FileReader[] { fileRead });\n" + + " }\n" + + " void closeThemAll(FileReader[] readers) { }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test070.java (at line 4)\n" + + " FileReader fileRead = new FileReader(fileName);\n" + + " ^^^^^^^^\n" + + "Potential resource leak: \'fileRead\' may not be closed\n" + + "----------\n", + null, + true, + options); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// referenced in array initializer +public void test071() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test071.java", + "import java.io.*;\n" + + "public class Test071 {\n" + + " class ReaderHolder {\n" + + " FileReader reader;\n" + + " }\n" + + " private FileReader getReader() {\n" + + " return null;\n" + + " }\n" + + " void invokeCompiler(ReaderHolder readerHolder, boolean flag) throws FileNotFoundException {\n" + + " FileReader reader = readerHolder.reader;\n" + + " if (reader == null)\n" + + " reader = getReader();\n" + + " try {\n" + + " return;\n" + + " } finally {\n" + + " try {\n" + + " if (flag)\n" + + " reader.close();\n" + + " } catch (IOException e) {\n" + + " // nop\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test071.java (at line 14)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Potential resource leak: \'reader\' may not be closed at this location\n" + + "----------\n", + null, + true, + options); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// referenced in array initializer +// disabled because it would require correlation analysis between the tracking variable and its original +// need to pass to downstream: either (nonnull & open) or (null) +public void _test071b() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test071b.java", + "import java.io.*;\n" + + "public class Test071b {\n" + + " private FileReader getReader() {\n" + + " return null;\n" + + " }\n" + + " void invokeCompiler(boolean flag) throws FileNotFoundException {\n" + + " FileReader reader = null;\n" + + " if (flag)\n" + + " reader = new FileReader(\"file\");\n" + + " if (reader == null)\n" + + " reader = getReader();\n" + + " try {\n" + + " return;\n" + + " } finally {\n" + + " try {\n" + + " if (flag)\n" + + " reader.close();\n" + + " } catch (IOException e) {\n" + + " // nop\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test071b.java (at line 13)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Potential resource leak: \'reader\' may not be closed at this location\n" + + "----------\n", + null, + true, + options); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// throw inside loop inside try - while closed in finally +public void test072() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test072.java", + "import java.io.*;\n" + + "public class Test072 {\n" + + " void readState(File file) {\n" + + " DataInputStream in = null;\n" + + " try {\n" + + " in= new DataInputStream(new BufferedInputStream(new FileInputStream(file)));\n" + + " int sizeOfFlags = in.readInt();\n" + + " for (int i = 0; i < sizeOfFlags; ++i) {\n" + + " String childPath = in.readUTF();\n" + + " if (childPath.length() == 0)\n" + + " throw new IOException();\n" + + " }\n" + + " }\n" + + " catch (IOException ioe) { /* nop */ }\n" + + " finally {\n" + + " if (in != null) {\n" + + " try {in.close();} catch (IOException ioe) {}\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// unspecific parameter is casted into a resource, yet need to mark as OWNED_BY_OUTSIDE +public void test073() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runConformTest(new String[] { + "Test073.java", + "import java.io.*;\n" + + "public class Test073 {\n" + + " String getEncoding(Object reader) {\n" + + " if (reader instanceof FileReader) {\n" + + " final FileReader fr = (FileReader) reader;\n" + + " return fr.getEncoding();\n" + + " }\n" + + " return null;\n" + + " }\n" + + "}\n" + }, + "", + null, + true, + null, + options, + null); +} + +// Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +// status after nested try-finally +public void test074() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE); + this.runNegativeTest(new String[] { + "Test074.java", + "import java.io.*;\n" + + "public class Test074 {\n" + + " void foo() throws FileNotFoundException {\n" + + " FileOutputStream out = null;\n" + + " try {\n" + + " out = new FileOutputStream(\"outfile\");\n" + + " } finally {\n" + + " try {\n" + + " out.flush();\n" + + " out.close();\n" + + " } catch (IOException e) {\n" + + " e.printStackTrace();\n" + + " }\n" + + " out = null;\n" + // unclosed if exception occurred on flush() + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Test074.java (at line 14)\n" + + " out = null;\n" + + " ^^^^^^^^^^\n" + + "Potential resource leak: \'out\' may not be closed at this location\n" + + "----------\n", + null, + true, + options); +} +// Bug 370639 - [compiler][resource] restore the default for resource leak warnings +// check that the default is warning +public void test075() { + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader = new FileReader(file);\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 7)\n" + + " FileReader fileReader = new FileReader(file);\n" + + " ^^^^^^^^^^\n" + + "Resource leak: 'fileReader' is never closed\n" + + "----------\n"); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java index 6f4e1fde3..cdba7bab9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java @@ -23,7 +23,7 @@ public class TestVerifier { boolean reuseVM = true; //{ObjectTeams: support reuse even in presence of vmargs, if unchanged: - protected String[] vmArguments = null; + protected String[] fVMArguments = null; // SH} String[] classpathCache; LocalVirtualMachine vm; @@ -119,7 +119,7 @@ private void compileVerifyTests(String verifierDir) { } String fileName = dir + File.separator + simpleName + ".java"; Util.writeToFile(getVerifyTestsCode(), fileName); - BatchCompiler.compile("\"" + fileName + "\" -d \"" + verifierDir + "\" -classpath \"" + Util.getJavaClassLibsAsString() + "\" -warn:-resource", new PrintWriter(System.out), new PrintWriter(System.err), null/*progress*/); + BatchCompiler.compile("\"" + fileName + "\" -d \"" + verifierDir + "\" -warn:-resource -classpath \"" + Util.getJavaClassLibsAsString() + "\"", new PrintWriter(System.out), new PrintWriter(System.err), null/*progress*/); } public void execute(String className, String[] classpaths) { this.outputBuffer = new StringBuffer(); @@ -148,236 +148,257 @@ public String getExecutionError(){ */ private String getVerifyTestsCode() { return - "/*******************************************************************************" + - " * Copyright (c) 2000, 2005 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:" + - " * IBM Corporation - initial API and implementation" + - " *******************************************************************************/" + - "package org.eclipse.jdt.core.tests.util;\n" + - "\n" + - "import java.lang.reflect.*;\n" + - "import java.io.*;\n" + - "import java.net.*;\n" + - "import java.util.*;\n" + - "\n" + - "/******************************************************\n" + - " * \n" + - " * IMPORTANT NOTE: If modifying this class, copy the source to TestVerifier#getVerifyTestsCode()\n" + - " * (see this method for details)\n" + - " * \n" + - " ******************************************************/\n" + - "\n" + - "public class VerifyTests {\n" + - " int portNumber;\n" + - " Socket socket;\n" + - "\n" + - "/**\n" + - " * NOTE: Code copied from junit.util.TestCaseClassLoader.\n" + - " *\n" + - " * A custom class loader which enables the reloading\n" + - " * of classes for each test run. The class loader\n" + - " * can be configured with a list of package paths that\n" + - " * should be excluded from loading. The loading\n" + - " * of these packages is delegated to the system class\n" + - " * loader. They will be shared across test runs.\n" + - " * <p>\n" + - " * The list of excluded package paths is specified in\n" + - " * a properties file \"excluded.properties\" that is located in \n" + - " * the same place as the TestCaseClassLoader class.\n" + - " * <p>\n" + - " * <b>Known limitation:</b> the VerifyClassLoader cannot load classes\n" + - " * from jar files.\n" + - " */\n" + - "\n" + - "\n" + - "public class VerifyClassLoader extends ClassLoader {\n" + - " /** scanned class path */\n" + - " private String[] fPathItems;\n" + - " \n" + - " /** excluded paths */\n" + - " private String[] fExcluded= {};\n" + - "\n" + - " /**\n" + - " * Constructs a VerifyClassLoader. It scans the class path\n" + - " * and the excluded package paths\n" + - " */\n" + - " public VerifyClassLoader() {\n" + - " super();\n" + - " String classPath= System.getProperty(\"java.class.path\");\n" + - " String separator= System.getProperty(\"path.separator\");\n" + - " \n" + - " // first pass: count elements\n" + - " StringTokenizer st= new StringTokenizer(classPath, separator);\n" + - " int i= 0;\n" + - " while (st.hasMoreTokens()) {\n" + - " st.nextToken();\n" + - " i++;\n" + - " }\n" + - " // second pass: split\n" + - " fPathItems= new String[i];\n" + - " st= new StringTokenizer(classPath, separator);\n" + - " i= 0;\n" + - " while (st.hasMoreTokens()) {\n" + - " fPathItems[i++]= st.nextToken();\n" + - " }\n" + - "\n" + - " }\n" + - " public java.net.URL getResource(String name) {\n" + - " return ClassLoader.getSystemResource(name);\n" + - " }\n" + - " public InputStream getResourceAsStream(String name) {\n" + - " return ClassLoader.getSystemResourceAsStream(name);\n" + - " }\n" + - " protected boolean isExcluded(String name) {\n" + - " // exclude the \"java\" packages.\n" + - " // They always need to be excluded so that they are loaded by the system class loader\n" + - " if (name.startsWith(\"java\"))\n" + + "/*******************************************************************************\n" + + " * Copyright (c) 2000, 2011 IBM Corporation and others.\n" + + " * All rights reserved. This program and the accompanying materials\n" + + " * are made available under the terms of the Eclipse Public License v1.0\n" + + " * which accompanies this distribution, and is available at\n" + + " * http://www.eclipse.org/legal/epl-v10.html\n" + + " *\n" + + " * Contributors:\n" + + " * IBM Corporation - initial API and implementation\n" + + " *******************************************************************************/\n" + + "package org.eclipse.jdt.core.tests.util;\n" + + "\n" + + "import java.io.DataInputStream;\n" + + "import java.io.DataOutputStream;\n" + + "import java.io.File;\n" + + "import java.io.FileInputStream;\n" + + "import java.io.FileNotFoundException;\n" + + "import java.io.IOException;\n" + + "import java.io.InputStream;\n" + + "import java.lang.reflect.InvocationTargetException;\n" + + "import java.lang.reflect.Method;\n" + + "import java.net.ServerSocket;\n" + + "import java.net.Socket;\n" + + "import java.util.StringTokenizer;\n" + + "\n" + + "/******************************************************\n" + + " *\n" + + " * IMPORTANT NOTE: If modifying this class, copy the source to TestVerifier#getVerifyTestsCode()\n" + + " * (see this method for details)\n" + + " *\n" + + " ******************************************************/\n" + + "\n" + + "public class VerifyTests {\n" + + " int portNumber;\n" + + " Socket socket;\n" + + "\n" + + "/**\n" + + " * NOTE: Code copied from junit.util.TestCaseClassLoader.\n" + + " *\n" + + " * A custom class loader which enables the reloading\n" + + " * of classes for each test run. The class loader\n" + + " * can be configured with a list of package paths that\n" + + " * should be excluded from loading. The loading\n" + + " * of these packages is delegated to the system class\n" + + " * loader. They will be shared across test runs.\n" + + " * <p>\n" + + " * The list of excluded package paths is specified in\n" + + " * a properties file \"excluded.properties\" that is located in\n" + + " * the same place as the TestCaseClassLoader class.\n" + + " * <p>\n" + + " * <b>Known limitation:</b> the VerifyClassLoader cannot load classes\n" + + " * from jar files.\n" + + " */\n" + + "\n" + + "\n" + + "public class VerifyClassLoader extends ClassLoader {\n" + + " /** scanned class path */\n" + + " private String[] pathItems;\n" + + "\n" + + " /** excluded paths */\n" + + " private String[] excluded= {};\n" + + "\n" + + " /**\n" + + " * Constructs a VerifyClassLoader. It scans the class path\n" + + " * and the excluded package paths\n" + + " */\n" + + " public VerifyClassLoader() {\n" + + " super();\n" + + " String classPath= System.getProperty(\"java.class.path\");\n" + + " String separator= System.getProperty(\"path.separator\");\n" + + "\n" + + " // first pass: count elements\n" + + " StringTokenizer st= new StringTokenizer(classPath, separator);\n" + + " int i= 0;\n" + + " while (st.hasMoreTokens()) {\n" + + " st.nextToken();\n" + + " i++;\n" + + " }\n" + + " // second pass: split\n" + + " this.pathItems= new String[i];\n" + + " st= new StringTokenizer(classPath, separator);\n" + + " i= 0;\n" + + " while (st.hasMoreTokens()) {\n" + + " this.pathItems[i++]= st.nextToken();\n" + + " }\n" + + "\n" + + " }\n" + + " public java.net.URL getResource(String name) {\n" + + " return ClassLoader.getSystemResource(name);\n" + + " }\n" + + " public InputStream getResourceAsStream(String name) {\n" + + " return ClassLoader.getSystemResourceAsStream(name);\n" + + " }\n" + + " protected boolean isExcluded(String name) {\n" + + " // exclude the \"java\" packages.\n" + + " // They always need to be excluded so that they are loaded by the system class loader\n" + + " if (name.startsWith(\"java\"))\n" + + " return true;\n" + + "\n" + +//{ObjectTeams: don't process core OT-classes either (unpacked .class not available on classpath): + " if (name.startsWith(\"org.objectteams\"))\n" + " return true;\n" + " \n" + -//{ObjectTeams: don't process core OT-classes either (unpacked .class not available on classpath): -" if (name.startsWith(\"org.objectteams\"))\n" + -" return true;\n" + -" \n" + -" if (name.startsWith(\"org.eclipse.objectteams.otre\"))\n" + -" return true;\n" + -" \n" + -" if (name.startsWith(\"org.apache.bcel\"))\n" + -" return true;\n" + -" \n" + -" if (name.startsWith(\"sun\"))\n" + // have a test that needs sun/reflect/SerializationConstructorAccessorImpl -" return true;\n" + -" \n" + -// SH} - " // exclude the user defined package paths\n" + - " for (int i= 0; i < fExcluded.length; i++) {\n" + - " if (name.startsWith(fExcluded[i])) {\n" + - " return true;\n" + - " }\n" + - " }\n" + - " return false; \n" + - " }\n" + - " public synchronized Class loadClass(String name, boolean resolve)\n" + - " throws ClassNotFoundException {\n" + + " if (name.startsWith(\"org.eclipse.objectteams.otre\"))\n" + + " return true;\n" + " \n" + - " Class c= findLoadedClass(name);\n" + - " if (c != null)\n" + - " return c;\n" + - " //\n" + - " // Delegate the loading of excluded classes to the\n" + - " // standard class loader.\n" + - " //\n" + - " if (isExcluded(name)) {\n" + - " try {\n" + - " c= findSystemClass(name);\n" + - " return c;\n" + - " } catch (ClassNotFoundException e) {\n" + - " // keep searching\n" + - " }\n" + - " }\n" + - " File file= locate(name);\n" + - " if (file == null)\n" + - " throw new ClassNotFoundException();\n" + - " byte data[]= loadClassData(file);\n" + - " c= defineClass(name, data, 0, data.length);\n" + - " if (resolve) \n" + - " resolveClass(c);\n" + - " return c;\n" + - " }\n" + - " private byte[] loadClassData(File f) throws ClassNotFoundException {\n" + - " try {\n" + - " //System.out.println(\"loading: \"+f.getPath());\n" + - " FileInputStream stream= new FileInputStream(f);\n" + + " if (name.startsWith(\"org.apache.bcel\"))\n" + + " return true;\n" + + " \n" + + " if (name.startsWith(\"sun\"))\n" + // have a test that needs sun/reflect/SerializationConstructorAccessorImpl + " return true;\n" + " \n" + - " try {\n" + - " byte[] b= new byte[stream.available()];\n" + - " stream.read(b);\n" + - " stream.close();\n" + - " return b;\n" + - " }\n" + - " catch (IOException e) {\n" + - " throw new ClassNotFoundException();\n" + - " }\n" + - " }\n" + - " catch (FileNotFoundException e) {\n" + - " throw new ClassNotFoundException();\n" + - " }\n" + - " }\n" + - " /**\n" + - " * Locate the given file.\n" + - " * @return Returns null if file couldn\'t be found.\n" + - " */\n" + - " private File locate(String fileName) { \n" + - " if (fileName != null) {\n" + - " fileName= fileName.replace(\'.\', \'/\')+\".class\";\n" + - " File path= null;\n" + - " for (int i= 0; i < fPathItems.length; i++) {\n" + - " path= new File(fPathItems[i], fileName);\n" + - " if (path.exists())\n" + - " return path;\n" + - " }\n" + - " }\n" + - " return null;\n" + - " }\n" + - "}\n" + - " \n" + - "public void loadAndRun(String className) throws Throwable {\n" + - " //System.out.println(\"Loading \" + className + \"...\");\n" + - " Class testClass = new VerifyClassLoader().loadClass(className);\n" + - " //System.out.println(\"Loaded \" + className);\n" + - " try {\n" + - " Method main = testClass.getMethod(\"main\", new Class[] {String[].class});\n" + - " //System.out.println(\"Running \" + className);\n" + - " main.invoke(null, new Object[] {new String[] {}});\n" + - " //System.out.println(\"Finished running \" + className);\n" + - " } catch (NoSuchMethodException e) {\n" + - " return;\n" + - " } catch (InvocationTargetException e) {\n" + - " throw e.getTargetException();\n" + - " }\n" + - "}\n" + - "public static void main(String[] args) throws IOException {\n" + - " VerifyTests verify = new VerifyTests();\n" + - " verify.portNumber = Integer.parseInt(args[0]);\n" + - " verify.run();\n" + - "}\n" + - "public void run() throws IOException {\n" + - " ServerSocket server = new ServerSocket(this.portNumber);\n" + - " this.socket = server.accept();\n" + - " this.socket.setTcpNoDelay(true);\n" + - " server.close();\n" + - "\n" + - " final DataInputStream in = new DataInputStream(this.socket.getInputStream());\n" + - " final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());\n" + - " while (true) {\n" + - " final String className = in.readUTF();\n" + - " Thread thread = new Thread() {\n" + - " public void run() {\n" + - " try {\n" + - " loadAndRun(className);\n" + - " out.writeBoolean(true);\n" + - " System.err.println(VerifyTests.class.getName());\n" + - " System.out.println(VerifyTests.class.getName());\n" + - " } catch (Throwable e) {\n" + - " e.printStackTrace();\n" + - " try {\n" + - " System.err.println(VerifyTests.class.getName());\n" + - " System.out.println(VerifyTests.class.getName());\n" + - " out.writeBoolean(false);\n" + - " } catch (IOException e1) {\n" + - " // ignore\n" + - " }\n" + - " }\n" + - " }\n" + - " };\n" + - " thread.start();\n" + - " }\n" + - "}\n" + - "}\n"; +// SH} + " // exclude the user defined package paths\n" + + " for (int i= 0; i < this.excluded.length; i++) {\n" + + " if (name.startsWith(this.excluded[i])) {\n" + + " return true;\n" + + " }\n" + + " }\n" + + " return false;\n" + + " }\n" + + " public synchronized Class loadClass(String name, boolean resolve)\n" + + " throws ClassNotFoundException {\n" + + "\n" + + " Class c= findLoadedClass(name);\n" + + " if (c != null)\n" + + " return c;\n" + + " //\n" + + " // Delegate the loading of excluded classes to the\n" + + " // standard class loader.\n" + + " //\n" + + " if (isExcluded(name)) {\n" + + " try {\n" + + " c= findSystemClass(name);\n" + + " return c;\n" + + " } catch (ClassNotFoundException e) {\n" + + " // keep searching\n" + + " }\n" + + " }\n" + + " File file= locate(name);\n" + + " if (file == null)\n" + + " throw new ClassNotFoundException();\n" + + " byte data[]= loadClassData(file);\n" + + " c= defineClass(name, data, 0, data.length);\n" + + " if (resolve)\n" + + " resolveClass(c);\n" + + " return c;\n" + + " }\n" + + " private byte[] loadClassData(File f) throws ClassNotFoundException {\n" + + " FileInputStream stream = null;\n" + + " try {\n" + + " //System.out.println(\"loading: \"+f.getPath());\n" + + " stream = new FileInputStream(f);\n" + + "\n" + + " try {\n" + + " byte[] b= new byte[stream.available()];\n" + + " stream.read(b);\n" + + " return b;\n" + + " }\n" + + " catch (IOException e) {\n" + + " throw new ClassNotFoundException();\n" + + " }\n" + + " }\n" + + " catch (FileNotFoundException e) {\n" + + " throw new ClassNotFoundException();\n" + + " } finally {\n" + + " if (stream != null) {\n" + + " try {\n" + + " stream.close();\n" + + " } catch (IOException e) {\n" + + " /* ignore */\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " /**\n" + + " * Locate the given file.\n" + + " * @return Returns null if file couldn't be found.\n" + + " */\n" + + " private File locate(String fileName) {\n" + + " if (fileName != null) {\n" + + " fileName= fileName.replace('.', '/')+\".class\";\n" + + " File path= null;\n" + + " for (int i= 0; i < this.pathItems.length; i++) {\n" + + " path= new File(this.pathItems[i], fileName);\n" + + " if (path.exists())\n" + + " return path;\n" + + " }\n" + + " }\n" + + " return null;\n" + + " }\n" + + "}\n" + + "\n" + + "public void loadAndRun(String className) throws Throwable {\n" + + " //System.out.println(\"Loading \" + className + \"...\");\n" + + " Class testClass = new VerifyClassLoader().loadClass(className);\n" + + " //System.out.println(\"Loaded \" + className);\n" + + " try {\n" + + " Method main = testClass.getMethod(\"main\", new Class[] {String[].class});\n" + + " //System.out.println(\"Running \" + className);\n" + + " main.invoke(null, new Object[] {new String[] {}});\n" + + " //System.out.println(\"Finished running \" + className);\n" + + " } catch (NoSuchMethodException e) {\n" + + " return;\n" + + " } catch (InvocationTargetException e) {\n" + + " throw e.getTargetException();\n" + + " }\n" + + "}\n" + + "public static void main(String[] args) throws IOException {\n" + + " VerifyTests verify = new VerifyTests();\n" + + " verify.portNumber = Integer.parseInt(args[0]);\n" + + " verify.run();\n" + + "}\n" + + "public void run() throws IOException {\n" + + " ServerSocket server = new ServerSocket(this.portNumber);\n" + + " this.socket = server.accept();\n" + + " this.socket.setTcpNoDelay(true);\n" + + " server.close();\n" + + "\n" + + " DataInputStream in = new DataInputStream(this.socket.getInputStream());\n" + + " final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());\n" + + " while (true) {\n" + + " final String className = in.readUTF();\n" + + " Thread thread = new Thread() {\n" + + " public void run() {\n" + + " try {\n" + + " loadAndRun(className);\n" + + " out.writeBoolean(true);\n" + + " System.err.println(VerifyTests.class.getName());\n" + + " System.out.println(VerifyTests.class.getName());\n" + + " } catch (Throwable e) {\n" + + " e.printStackTrace();\n" + + " try {\n" + + " System.err.println(VerifyTests.class.getName());\n" + + " System.out.println(VerifyTests.class.getName());\n" + + " out.writeBoolean(false);\n" + + " } catch (IOException e1) {\n" + + " e1.printStackTrace();\n" + + " }\n" + + " }\n" + + " try {\n" + + " out.flush();\n" + + " } catch (IOException e) {\n" + + " e.printStackTrace();\n" + + " }\n" + + " }\n" + + " };\n" + + " thread.start();\n" + + " }\n" + + "}\n" + + "}"; } private void launchAndRun(String className, String[] classpaths, String[] programArguments, String[] vmArguments) { // we won't reuse the vm, shut the existing one if running @@ -669,12 +690,12 @@ private void waitForFullBuffers() { } //{ObjectTeams: helper public boolean vmArgsEqual(String[] newArgs) { - if (this.vmArguments == null || newArgs == null) - return this.vmArguments == null && newArgs == null; - if (this.vmArguments.length != newArgs.length) + if (this.fVMArguments == null || newArgs == null) + return this.fVMArguments == null && newArgs == null; + if (this.fVMArguments.length != newArgs.length) return false; for (int i=0; i<newArgs.length; i++) - if (!this.vmArguments[i].equals(newArgs[i])) + if (!this.fVMArguments[i].equals(newArgs[i])) return false; return true; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java index 5a659373d..45404f9c9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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,10 +10,18 @@ *******************************************************************************/ package org.eclipse.jdt.core.tests.util; -import java.lang.reflect.*; -import java.io.*; -import java.net.*; -import java.util.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.StringTokenizer; /****************************************************** * diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java index 38e73744e..09935f502 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2012 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 @@ -603,7 +603,6 @@ public class CompletionTestsRequestor2 extends CompletionRequestor { public boolean canUseDiamond(int proposalNo) { if (proposalNo < this.proposals.length && this.proposals[proposalNo] != null) { - System.out.println(this.proposals[proposalNo]); return this.proposals[proposalNo].canUseDiamond(this.context); } return false; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java index b6003f803..99548b538 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java @@ -94,7 +94,7 @@ public class JavaSearchBugsTests extends AbstractJavaSearchTests { // Debug static { // org.eclipse.jdt.internal.core.search.BasicSearchEngine.VERBOSE = true; -// TESTS_NAMES = new String[] {"testBug306223"}; +// TESTS_NAMES = new String[] {"testBug324189d"}; } public JavaSearchBugsTests(String name) { @@ -13408,7 +13408,7 @@ public void testBug324189d() throws CoreException, IOException { }, new HashMap(), libPath); - IJavaProject javaProject = createJavaProject("P", new String[0], new String[] {libPath}, ""); + IJavaProject javaProject = createJavaProject("P", new String[0], new String[] {libPath, "JCL_LIB"}, ""); waitUntilIndexesReady(); int mask = IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SOURCES ; IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { javaProject }, mask); @@ -13751,4 +13751,5 @@ public void testBug241834() throws CoreException { } } +// Add new tests in JavaSearchBugsTests2 }
\ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java new file mode 100644 index 000000000..0caa88863 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java @@ -0,0 +1,456 @@ +/******************************************************************************* + * Copyright (c) 2012 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.tests.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchPattern; + +// The size of JavaSearchBugsTests.java is very big, Hence continuing here. +public class JavaSearchBugsTests2 extends AbstractJavaSearchTests { + + public JavaSearchBugsTests2(String name) { + super(name); + this.endChar = ""; + } + + static { + //TESTS_NAMES = new String[] {"testBug123836"}; + } + + public static Test suite() { + return buildModelTestSuite(JavaSearchBugsTests2.class); + } + + class TestCollector extends JavaSearchResultCollector { + public List matches = new ArrayList(); + + public void acceptSearchMatch(SearchMatch searchMatch) throws CoreException { + super.acceptSearchMatch(searchMatch); + this.matches.add(searchMatch); + } + } + + protected void setUp() throws Exception { + super.setUp(); + this.resultCollector = new TestCollector(); + this.resultCollector.showAccuracy(true); + } + + /** + * Test that missing types in the class shouldn't impact the search of a type in an inner class + */ + public void testBug362633() throws CoreException, IOException { + try { + IJavaProject p = createJavaProject("P", new String[] {}, new String[] { "/P/lib325418.jar", "JCL15_LIB" }, "", "1.5"); + org.eclipse.jdt.core.tests.util.Util.createJar(new String[] { + "p325418M/Missing.java", + "package p325418M;\n" + + "public class Missing{}\n" }, + p.getProject().getLocation().append("lib325418M.jar").toOSString(), "1.5"); + + org.eclipse.jdt.core.tests.util.Util.createJar( + new String[] { + "p325418/Test.java", + "package p325418;\n" + + "public class Test{\n" + + " public void foo(p325418M.Missing a) {}\n" + + " public <T> T foo(int a) {\n" + + " return new Inner<T>() {T run() { return null; }}.run();\n" + + " }\n" + "}\n", + "p325418/Inner.java", + "package p325418;\n" + + "abstract class Inner <T> {\n" + + " abstract T run();\n" + "}\n" }, + null, + p.getProject().getLocation().append("lib325418.jar").toOSString(), + new String[] { p.getProject().getLocation().append("lib325418M.jar").toOSString() }, + "1.5"); + refresh(p); + int mask = IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SOURCES; + IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { p }, mask); + search("Inner.run()", IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, scope, this.resultCollector); + assertSearchResults( + "Unexpected search results!", + "lib325418.jar T p325418.Inner.run() [No source] EXACT_MATCH\n" + + "lib325418.jar T p325418.<anonymous>.run() [No source] EXACT_MATCH", + this.resultCollector); + } finally { + deleteProject("P"); + } + } + + /** + * @bug 123836: [1.5][search] for references to overriding method with bound type variable is not polymorphic + * @test Search for references to an overridden method with bound variables should yield. + * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836" + */ + public void testBug123836a() throws CoreException { + IJavaProject project = null; + try + { + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Sub.java", + "abstract class Sup<C> {\n" + + " protected void m(C classifier) {}\n"+ + " public void use(C owner) { m (owner); }\n" + + "}\n" + + "public class Sub extends Sup<String>{\n" + + " @Override\n"+ + " protected void m(String classifier) {}\n"+ + "}\n"); + IType type = getCompilationUnit("/P/Sub.java").getType("Sub"); + IMethod method = type.getMethod("m", new String[]{"QString;"}); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Sub.java void Sup.use(C) [m (owner)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // Search for a non-overriden method with same name as which could have been overriden should + // not have results + public void testBug123836b() throws CoreException { + IJavaProject project = null; + try + { + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Sub.java", + "abstract class Sup<C> {\n" + + " protected void m(C classifier) {}\n"+ + " public void use(C owner) { m (owner); }\n" + + "}\n" + + "public class Sub extends Sup<String>{\n" + + " @Override\n"+ + " protected void m(String classifier) {}\n"+ + " protected void m(Sub classifier) {}\n"+ + "}\n" ); + // search + IType type = getCompilationUnit("/P/Sub.java").getType("Sub"); + IMethod method = type.getMethod("m", new String[]{"QSub;"}); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults(""); + + } finally { + deleteProject(project); + } + } + // another variant of the testcase + public void testBug123836c() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}\n"+ + "class StringProperty extends Property<String> {\n"+ + " @Override public void compute(String e) {\n"+ + " System.out.println(e);\n"+ + " }"); + IType type = getCompilationUnit("/P/Test.java").getType("StringProperty"); + IMethod method = type.getMethod("compute", new String[]{"QString;"}); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // Test inner class + public void testBug123836d() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + " class StringProperty extends Property<String> {\n"+ + " @Override public void compute(String e) {\n"+ + " System.out.println(e);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + + IType type = getCompilationUnit("/P/Test.java").getType("Test").getType("StringProperty"); + IMethod method = type.getMethod("compute", new String[]{"QString;"}); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // Test local class + public void testBug123836e() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " class StringProperty extends Property<String> {\n"+ + " @Override public void compute(String e) {\n"+ + " System.out.println(e);\n"+ + " }\n"+ + " }\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 3); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // test inner class + public void testBug123836f() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " new Property<String>() {\n"+ + " @Override public void compute(String e) {\n"+ + " System.out.println(e);\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 3); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // test in initializer block + public void testBug123836g() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " {\n" + + " new Property<String>() {\n" + + " @Override public void compute(String e) {}\n" + + " };\n"+ + " }\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 1); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // test in static initializer + public void testBug123836h() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " static {\n" + + " new Property<String>() {\n" + + " @Override public void compute(String e) {}\n" + + " };\n"+ + " }\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 1); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // test in static initializer + public void testBug123836i() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " Property <?>p = new Property<String>() {\n" + + " @Override public void compute(String e) {}\n" + + " };\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 1); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + public void testBug123836j() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property<? extends Serializable> p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property<E> {\n"+ + " public abstract void compute(E e);\n"+ + "}\n"+ + "class StringProperty extends Property<String> {\n"+ + " @Override public void compute(String e) {\n"+ + " new Property<String>() {\n"+ + " @Override public void compute(String e) {\n"+ + " new Property<String>() {\n"+ + " @Override public void compute(String e) {}\n"+ + " };\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + "}"); + IMethod method = selectMethod(getCompilationUnit("/P/Test.java"), "compute", 6); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property<? extends Serializable>) [compute(null)] EXACT_MATCH"); + } finally { + deleteProject(project); + } + } + // test search of name + public void _testBug123836g1() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Sub.java", + "abstract class Sup<C> {\n" + + " protected void m(C classifier) {}\n"+ + " public void use(C owner) { m (owner); }\n" + + "}\n" + + "public class Sub extends Sup<String>{\n" + + " @Override\n"+ + " protected void m(String classifier) {}\n"+ + " protected void m(Sub classifier) {}\n"+ + "}\n" ); + waitUntilIndexesReady(); + // search + SearchPattern pattern = SearchPattern.createPattern("Sub.m(String)", METHOD, REFERENCES, EXACT_RULE); + search(pattern, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Sub.java void Sup.use(C) [m (owner)] EXACT_MATCH"); + + } finally { + deleteProject(project); + } + } + // test search of name (negative) + public void _testBug123836h1() throws CoreException { + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Sub.java", + "abstract class Sup<C> {\n" + + " protected void m(C classifier) {}\n"+ + " public void use(C owner) { m (owner); }\n" + + "}\n" + + "public class Sub extends Sup<String>{\n" + + " @Override\n"+ + " protected void m(String classifier) {}\n"+ + " protected void m(Sub classifier) {}\n"+ + "}\n" ); + // search + SearchPattern pattern = SearchPattern.createPattern("Sub.m(Sub)", METHOD, REFERENCES, EXACT_RULE); + search(pattern, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults(""); + + } finally { + deleteProject(project); + } + } +} diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java index 923d15386..316b1c7ec 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -2168,8 +2168,8 @@ public void testSearchFieldInBinaryWithResolution() throws CoreException { search("MissingFieldType.*", FIELD, DECLARATIONS, getJavaSearchScope()); assertSearchResults( "AbortCompilation.jar AbortCompilation.MissingFieldType.field [No source] EXACT_MATCH\n" + - "AbortCompilation.jar AbortCompilation.MissingFieldType.otherField [No source] EXACT_MATCH\n" + - "AbortCompilation.jar AbortCompilation.MissingFieldType.missing [No source] POTENTIAL_MATCH" + "AbortCompilation.jar AbortCompilation.MissingFieldType.missing [No source] EXACT_MATCH\n" + + "AbortCompilation.jar AbortCompilation.MissingFieldType.otherField [No source] EXACT_MATCH" ); } finally { // reset classpath @@ -2229,8 +2229,8 @@ public void testSearchMethodInBinaryWithResolution() throws CoreException { search("MissingArgumentType.foo*", METHOD, DECLARATIONS, getJavaSearchScope()); assertSearchResults( "AbortCompilation.jar void AbortCompilation.MissingArgumentType.foo() [No source] EXACT_MATCH\n" + - "AbortCompilation.jar void AbortCompilation.MissingArgumentType.foo2() [No source] EXACT_MATCH\n" + - "AbortCompilation.jar void AbortCompilation.MissingArgumentType.foo(java.util.EventListener) [No source] POTENTIAL_MATCH" + "AbortCompilation.jar void AbortCompilation.MissingArgumentType.foo(java.util.EventListener) [No source] EXACT_MATCH\n" + + "AbortCompilation.jar void AbortCompilation.MissingArgumentType.foo2() [No source] EXACT_MATCH" ); } finally { // reset classpath diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java index d38f045a4..82e5422f0 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java @@ -67,8 +67,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { return FileLocator.toFileURL(libEntry).getPath(); } - - public void testConvertedSourceType1() throws CoreException, InterruptedException { + // DISABLED due to dysfunctional global default after Bug 366063 - Compiler should not add synthetic @NonNull annotations + public void _testConvertedSourceType1() throws CoreException, InterruptedException { try { // Resources creation IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); @@ -119,7 +119,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { } } - public void testBinaryType1() throws CoreException, InterruptedException, IOException { + // DISABLED due to dysfunctional global default after Bug 366063 - Compiler should not add synthetic @NonNull annotations + public void _testBinaryType1() throws CoreException, InterruptedException, IOException { try { // Resources creation IJavaProject p = createJavaProject("P", new String[] {""}, @@ -161,7 +162,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { } } - public void testMissingAnnotation1() throws CoreException { + // DISABLED: no longer a problem since bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + public void _testMissingAnnotation1() throws CoreException { try { // Resources creation IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); @@ -197,7 +199,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { } } - public void testMissingAnnotation2() throws CoreException { + // DISABLED: no longer a problem since bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + public void _testMissingAnnotation2() throws CoreException { Hashtable javaOptions = JavaCore.getOptions(); try { // Resources creation @@ -241,7 +244,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { // Bug 363858 - [dom] early throwing of AbortCompilation causes NPE in CompilationUnitResolver // currently not actually challenging the NPE, because we no longer report // "Cannot use the unqualified name \'invalid\' as an annotation name for null specification" - public void testMissingAnnotation3() throws CoreException { + // DISABLED: no longer a problem since bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + public void _testMissingAnnotation3() throws CoreException { try { // Resources creation IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); @@ -357,7 +361,8 @@ public class NullAnnotationModelTests extends ReconcilerTests { // - triggered from resolveTypesFor(MethodBinding) // - default is defined in package-info.java: // must detect missing non-null annotation and report against the project - public void testMissingAnnotation5() throws CoreException, InterruptedException { + // DISABLED: no longer a problem since bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + public void _testMissingAnnotation5() throws CoreException, InterruptedException { try { // Resources creation IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests.java index 429a4cb70..73f1d9d43 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -2686,4 +2686,43 @@ public void testMethodParameter() throws JavaModelException { ); assertTrue("Not a parameter", ((ILocalVariable)elements[0]).isParameter()); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=244544 +public void testConstantInLocal() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Resolve/src/Test2.java", + "class X {\n" + + " public static void main(String[] args) {\n" + + " class Local {\n" + + " private static final long CONSTANT = 1L; // code select fails\n" + + " }\n" + + " new X() {\n" + + " private static final long FINAL = 1L; // code select fails\n" + + " };\n" + + " }\n" + + "}\n"); + + String str = this.workingCopies[0].getSource(); + String selectAt = "FINAL"; + String selection = "FINAL"; + int start = str.indexOf(selectAt); + int length = selection.length(); + IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length, this.wcOwner); + + assertElementsEqual( + "Unexpected elements", + "FINAL [in <anonymous #1> [in main(String[]) [in X [in [Working copy] Test2.java [in <default> [in src [in Resolve]]]]]]]", + elements); + + selectAt = "CONSTANT"; + selection = "CONSTANT"; + start = str.indexOf(selectAt); + length = selection.length(); + elements = this.workingCopies[0].codeSelect(start, length, this.wcOwner); + + assertElementsEqual( + "Unexpected elements", + "CONSTANT [in Local [in main(String[]) [in X [in [Working copy] Test2.java [in <default> [in src [in Resolve]]]]]]]", + elements); +} } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchGenericTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchGenericTests.java index d33e9c53f..0a06040ec 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchGenericTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchGenericTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -45,6 +45,7 @@ public static Test suite() { AbstractJavaSearchTests.JAVA_SEARCH_SUITES = new ArrayList(Arrays.asList(getJavaSearchTestClasses())); List allClasses = new ArrayList(AbstractJavaSearchTests.JAVA_SEARCH_SUITES); allClasses.add(JavaSearchBugsTests.class); + allClasses.add(JavaSearchBugsTests2.class); // Reset forgotten subsets of tests TestCase.TESTS_PREFIX = null; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java index 2d7d864fc..36977b7d8 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -58,6 +58,7 @@ public class RunJavaSearchTests extends junit.framework.TestCase { // Get all classes List allClasses = new ArrayList(TEST_CLASSES); allClasses.add(JavaSearchBugsTests.class); + allClasses.add(JavaSearchBugsTests2.class); allClasses.add(JavaSearchMultipleProjectsTests.class); allClasses.add(SearchTests.class); allClasses.add(JavaSearchScopeTests.class); diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/b317264.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/b317264.jar Binary files differnew file mode 100644 index 000000000..d0ad2767e --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/b317264.jar diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index b1098e2bd..be20e274d 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -3549,11 +3549,6 @@ private void handleErrorOrWarningToken(String token, boolean isEnabling, int sev setSeverity(CompilerOptions.OPTION_ReportRedundantNullCheck, ProblemSeverities.Ignore, isEnabling); } return; - } else if (token.equals("nullFields")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_IncludeFieldsInNullAnalysis, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; } else if (token.startsWith("nullAnnot")) { //$NON-NLS-1$ String annotationNames = Util.EMPTY_STRING; int start = token.indexOf('('); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties index 394bb175b..3ded165c0 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2011 IBM Corporation and others. +# Copyright (c) 2000, 2012 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,7 +20,7 @@ #Format: compiler.name = word1 word2 word3 compiler.name = Eclipse Compiler for Java(TM) #Format: compiler.version = 0.XXX[, other words (don't forget the comma if adding other words)] -compiler.version = 0.C33, 3.8.0 M5 +compiler.version = 0.C35, 3.8.0 M6 compiler.copyright = Copyright IBM Corp 2000, 2011. All rights reserved. ###{ObjectTeams: @@ -345,7 +345,6 @@ misc.usage.warn = {1} {2}\n\ \ nullable|nonnull|nonnullbydefault annotation types\n\ \ optionally specified using fully qualified names\n\ \ nullDereference + missing null check\n\ -\ nullFields + null analysis for fields\n\ \ over-ann missing @Override annotation (superclass)\n\ \ paramAssign assignment to a parameter\n\ \ pkgDefaultMethod + attempt to override package-default method\n\ diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html index 41570a4e9..4e0c6127c 100644 --- a/org.eclipse.jdt.core/buildnotes_jdt-core.html +++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html @@ -42,11 +42,56 @@ </td> </tr> </table> +<a name="v_C35"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - February 21, 2012 - 3.8.0 M6 +<br>Project org.eclipse.jdt.core v_C35 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C35">cvs</a>). +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=365499">365499</a> +Add a system property to control for JavaModelManager's jar type cache size +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=368152">368152</a> +ConcurrentModificationException on startup in ExternalFoldersManager.createPendingFolders +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=244544">244544</a> +codeSelect fails on constant declaration in anonymous and local classes +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=291040">291040</a> +codeSelect(..) does not work for a deeply nested method invocation in nested and anonymous class +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=370930">370930</a> +NonNull annotation not considered for enhanced for loops +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=366063">366063</a> +Compiler should not add synthetic @NonNull annotations +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=365531">365531</a> +[compiler][null] investigate alternative strategy for internally encoding nullness defaults +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=370639">370639</a> +[compiler][resource] restore the default for resource leak warnings + +<a name="v_C34"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - February 14, 2012 +<br> +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836">123836</a> +[1.5][search] for references to overriding method with bound type variable is not polymorphic +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=368546">368546</a> +[compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=364254">364254</a> +Reduce console output during JDT/Core junits execution. +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=362633">362633</a> +NPE while trying to rename a class + <a name="v_C33"></a> <hr><h1> Eclipse Platform Build Notes<br> Java development tools core</h1> -Eclipse SDK 3.8.0 - %date% - 3.8.0 M5 +Eclipse SDK 3.8.0 - January 25, 2012 - 3.8.0 M5 <br> <h2>What's new in this drop</h2> @@ -65,8 +110,6 @@ Eclipse SDK 3.8.0 - January 24, 2012 <h3>Problem Reports Fixed</h3> <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=366829">366829</a> Batch compiler option and SuppressWarnings token for Overriding a Synchronized Method with a Non-synchronized Method -<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=369381">369381</a> -[null][compiler] 'Adding potential null mark in unexpected state' assertion while compiling <a name="v_C31"></a> <hr><h1> @@ -110,45 +153,6 @@ Eclipse SDK 3.8.0 - January 20, 2012 String SOURCE_ATTACHMENT_ENCODING = "source_encoding"; </pre> </li> -<li> New JavaCore option to control null analysis for fields -<pre> - /** - * Compiler option ID: Raise null related errors or warnings on fields. - * - * When enabled, the compiler will flag all null related errors or warnings that have been enabled by the user - * on fields, in addition to local variables. - * When disabled, the compiler will not flag null related errors or warnings on fields. - * - * Option id:<code>"org.eclipse.jdt.core.compiler.problem.includeFieldsInNullAnalysis"</code> - * Possible values:<code>{ "enabled", "disabled" }</code> - * Default:<code>"disabled"</code> - * - * @since 3.8 - * @category CompilerOptionID - */ - public static final String COMPILER_PB_INCLUDE_FIELDS_IN_NULL_ANALYSIS = PLUGIN_ID + ".compiler.problem.includeFieldsInNullAnalysis"; -</pre> -</li> -<li> New IProblems for messages relating to null analysis for fields -<pre> - /** @since 3.8*/ - int NullFieldReference = Internal + FieldRelated + 670; - /** @since 3.8*/ - int PotentialNullFieldReference = Internal + FieldRelated + 671; - /** @since 3.8*/ - int RedundantNullCheckOnNullField = Internal + FieldRelated + 672; - /** @since 3.8*/ - int NullFieldComparisonYieldsFalse = Internal + FieldRelated + 673; - /** @since 3.8*/ - int RedundantNullCheckOnNonNullField = Internal + FieldRelated + 674; - /** @since 3.8*/ - int NonNullFieldComparisonYieldsFalse = Internal + FieldRelated + 675; - /** @since 3.8*/ - int RedundantFieldNullAssignment = Internal + FieldRelated + 676; - /** @since 3.8*/ - int NullFieldInstanceofYieldsFalse = Internal + FieldRelated + 677; -</pre> -</li> <li> New IProblems for messages relating to contradictory or redundant null annotations <pre> /** @since 3.8 */ @@ -171,8 +175,6 @@ Allow to specify encoding for source attachments FUP of bug 361938: Other error code pattern <br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=365662">365662</a> [compiler][null] warn on contradictory and redundant null annotations -<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564">247564</a> -[compiler][null] Detecting null field reference <a name="v_C29"></a> <hr><h1> diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 14b0ec016..30e7f9cab 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -128,7 +128,6 @@ * RequiredNonNullButProvidedNull * RequiredNonNullButProvidedPotentialNull * RequiredNonNullButProvidedUnknown - * MissingNullAnnotationType * NullAnnotationNameMustBeQualified * IllegalReturnNullityRedefinition * IllegalRedefinitionToNonNullParameter @@ -1291,26 +1290,6 @@ void setSourceStart(int sourceStart); /** @since 3.4 */ int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660; - /** - * Null analysis for fields - */ - /** @since 3.8*/ - int NullFieldReference = Internal + FieldRelated + 670; - /** @since 3.8*/ - int PotentialNullFieldReference = Internal + FieldRelated + 671; - /** @since 3.8*/ - int RedundantNullCheckOnNullField = Internal + FieldRelated + 672; - /** @since 3.8*/ - int NullFieldComparisonYieldsFalse = Internal + FieldRelated + 673; - /** @since 3.8*/ - int RedundantNullCheckOnNonNullField = Internal + FieldRelated + 674; - /** @since 3.8*/ - int NonNullFieldComparisonYieldsFalse = Internal + FieldRelated + 675; - /** @since 3.8*/ - int RedundantFieldNullAssignment = Internal + FieldRelated + 676; - /** @since 3.8*/ - int NullFieldInstanceofYieldsFalse = Internal + FieldRelated + 677; - /** * Corrupted binaries */ @@ -1468,8 +1447,7 @@ void setSourceStart(int sourceStart); int RequiredNonNullButProvidedPotentialNull = TypeRelated + 911; /** @since 3.8 */ int RequiredNonNullButProvidedUnknown = TypeRelated + 912; - /** @since 3.8 */ - int MissingNullAnnotationType = ImportRelated + 913; + // removed during 3.8 M6: ImportRelated + 913 /** @since 3.8 */ int IllegalReturnNullityRedefinition = MethodRelated + 914; /** @since 3.8 */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java index 704c40465..bbdca1654 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -4064,7 +4064,6 @@ public class ClassFile implements TypeConstants, TypeIds { // retrieve the enclosing one guaranteed to be the one matching the propagated flow info // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) - // see also https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564#c65 this.codeStream.maxFieldCount = aType.scope.outerMostClassScope().referenceType().maxFieldCount; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java index 500d00356..061779986 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -13,11 +13,11 @@ * bug 186342 - [compiler][null] Using annotations for null checking * bug 367203 - [compiler][null] detect assigning null to nonnull argument * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; import java.util.List; -import java.util.Arrays; import org.eclipse.jdt.core.compiler.*; import org.eclipse.jdt.internal.compiler.*; @@ -216,41 +216,6 @@ public abstract class AbstractMethodDeclaration } /** - * Materialize a non-null annotation that has been added from the current default, - * in order to ensure that this annotation will be generated into the .class file, too. - */ - public void addNonNullAnnotation(ReferenceBinding annotationBinding) { - this.annotations = addAnnotation(this, this.annotations, annotationBinding); - } - - /** - * Materialize a non-null parameter annotation that has been added from the current default, - * in order to ensure that this annotation will be generated into the .class file, too. - */ - public void addParameterNonNullAnnotation(Argument argument, ReferenceBinding annotationBinding) { - if (argument.type != null) // null happens for constructors of anonymous classes - argument.annotations = addAnnotation(argument.type, argument.annotations, annotationBinding); - } - - private Annotation[] addAnnotation(ASTNode location, Annotation[] oldAnnotations, ReferenceBinding annotationBinding) { - long pos = ((long)location.sourceStart<<32) + location.sourceEnd; - long[] poss = new long[annotationBinding.compoundName.length]; - Arrays.fill(poss, pos); - MarkerAnnotation annotation = new MarkerAnnotation(new QualifiedTypeReference(annotationBinding.compoundName, poss), location.sourceStart); - annotation.declarationSourceEnd = location.sourceEnd; - annotation.resolvedType = annotationBinding; - annotation.bits = IsSynthetic; - if (oldAnnotations == null) { - oldAnnotations = new Annotation[] {annotation}; - } else { - int len = oldAnnotations.length; - System.arraycopy(oldAnnotations, 0, oldAnnotations=new Annotation[len+1], 1, len); - oldAnnotations[0] = annotation; - } - return oldAnnotations; - } - - /** * When a method is accessed via SourceTypeBinding.resolveTypesFor(MethodBinding) * we create the argument binding and resolve annotations in order to compute null annotation tagbits. */ 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 6608e849e..f84c47219 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 @@ -15,6 +15,8 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 358903 - Filter practically unimportant resource leak warnings + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -85,7 +87,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // process arguments if (this.arguments != null) { - boolean hasResourceWrapperType = this.resolvedType instanceof ReferenceBinding + boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; + boolean hasResourceWrapperType = analyseResources + && this.resolvedType instanceof ReferenceBinding && ((ReferenceBinding)this.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable); for (int i = 0, count = this.arguments.length; i < count; i++) { flowInfo = @@ -93,7 +97,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl .analyseCode(currentScope, flowContext, flowInfo) .unconditionalInits(); // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) - if (!hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially + if (analyseResources && !hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); } if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { @@ -103,9 +107,6 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } - if (FakedTrackingVariable.isAnyCloseable(this.resolvedType)) - FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this); - // record some dependency information for exception types ReferenceBinding[] thrownExceptions; if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { @@ -120,6 +121,11 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo.unconditionalCopy(), currentScope); } + + // after having analysed exceptions above start tracking newly allocated resource: + if (FakedTrackingVariable.isAnyCloseable(this.resolvedType) && currentScope.compilerOptions().analyseResourceLeaks) + FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this); + if (this.binding.declaringClass.isMemberType() && !this.binding.declaringClass.isStatic()) { // allocating a non-static member type without an enclosing instance of parent type // https://bugs.eclipse.org/bugs/show_bug.cgi?id=335845 diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java index afe4153ca..41027f8bb 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2012 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,9 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contributions for + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -32,8 +35,13 @@ public class ArrayInitializer extends Expression { public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { if (this.expressions != null) { + boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; for (int i = 0, max = this.expressions.length; i < max; i++) { flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + + if (analyseResources && FakedTrackingVariable.isAnyCloseable(this.expressions[i].resolvedType)) { + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expressions[i], flowInfo, false); + } } } return flowInfo; 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 9a87b4963..af54844e0 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 @@ -17,6 +17,7 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 358903 - Filter practically unimportant resource leak warnings + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -74,46 +75,44 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // record setting a variable: various scenarii are possible, setting an array reference, // a field reference, a blank final field reference, a field of an enclosing instance or // just a local variable. - VariableBinding var = this.lhs.variableBinding(currentScope); + LocalVariableBinding local = this.lhs.localVariableBinding(); if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } FlowInfo preInitInfo = null; - LocalVariableBinding localToAnalyseAsResource = null; - if (var instanceof LocalVariableBinding - && flowInfo.reachMode() == FlowInfo.REACHABLE + boolean shouldAnalyseResource = local != null + && flowInfo.reachMode() == FlowInfo.REACHABLE + && currentScope.compilerOptions().analyseResourceLeaks && (FakedTrackingVariable.isAnyCloseable(this.expression.resolvedType) - || this.expression.resolvedType == TypeBinding.NULL)) { - localToAnalyseAsResource = (LocalVariableBinding) var; - + || this.expression.resolvedType == TypeBinding.NULL); + if (shouldAnalyseResource) { preInitInfo = flowInfo.unconditionalCopy(); // analysis of resource leaks needs additional context while analyzing the RHS: - FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, localToAnalyseAsResource, this.expression); + FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, local, this.expression); } flowInfo = ((Reference) this.lhs) .analyseAssignment(currentScope, flowContext, flowInfo, this, false) .unconditionalInits(); - if (localToAnalyseAsResource != null) { - FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, this, this.expression, localToAnalyseAsResource); - } else { + if (shouldAnalyseResource) + FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, this, this.expression, local); + else FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression); - } int nullStatus = this.expression.nullStatus(flowInfo); - if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) { + if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { if (nullStatus == FlowInfo.NULL) { - flowContext.recordUsingNullReference(currentScope, var, this.lhs, + flowContext.recordUsingNullReference(currentScope, local, this.lhs, FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo); } } - nullStatus = checkAssignmentAgainstNullAnnotation(currentScope, flowContext, var, nullStatus, this.expression); - if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo.markNullStatus(var, nullStatus); + nullStatus = checkAssignmentAgainstNullAnnotation(currentScope, flowContext, local, nullStatus, this.expression); + if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { + flowInfo.markNullStatus(local, nullStatus); if (flowContext.initsOnFinally != null) - flowContext.initsOnFinally.markNullStatus(var, nullStatus); + flowContext.initsOnFinally.markNullStatus(local, nullStatus); } return flowInfo; } @@ -291,7 +290,4 @@ public void traverse(ASTVisitor visitor, BlockScope scope) { public LocalVariableBinding localVariableBinding() { return this.lhs.localVariableBinding(); } -public VariableBinding variableBinding(Scope scope) { - return this.lhs.variableBinding(scope); -} } 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 eec56b734..0f273c7ba 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 @@ -8,9 +8,11 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation + * Stephan Herrmann - Contributions for + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -50,9 +52,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); } } - if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now: - this.scope.checkUnclosedCloseables(flowInfo, null, null); + this.scope.checkUnclosedCloseables(flowInfo, flowContext, null, null); return flowInfo; } /** 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 a870ad4de..08c2de848 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, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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,7 +36,6 @@ 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.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; @@ -546,13 +545,6 @@ public LocalVariableBinding localVariableBinding() { return this.expression.localVariableBinding(); } -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#variableBinding(Scope) - */ -public VariableBinding variableBinding(Scope scope) { - return this.expression.variableBinding(scope); -} - public int nullStatus(FlowInfo flowInfo) { return this.expression.nullStatus(flowInfo); } 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 75637404f..9e79a9141 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 @@ -14,6 +14,7 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 361407 - Resource leak warning when resource is assigned to a field outside of constructor + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -308,7 +309,7 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial constructorContext.complainIfUnusedExceptionHandlers(this); // check unused parameters this.scope.checkUnusedParameters(this.binding); - this.scope.checkUnclosedCloseables(flowInfo, null/*don't report against a specific location*/, null); + this.scope.checkUnclosedCloseables(flowInfo, null, null/*don't report against a specific location*/, null); } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java index 5c08d86ba..134ccdb9e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -39,43 +39,43 @@ public class EqualExpression extends BinaryExpression { // TODO: handle all kinds of expressions (cf. also https://bugs.eclipse.org/364326) } - VariableBinding var = this.left.variableBinding(scope); - if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) { - checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, var, rightStatus, this.left); + LocalVariableBinding local = this.left.localVariableBinding(); + if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { + checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, rightStatus, this.left); } - var = this.right.variableBinding(scope); - if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) { - checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, var, leftStatus, this.right); + local = this.right.localVariableBinding(); + if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { + checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, leftStatus, this.right); } } - private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, VariableBinding var, int nullStatus, Expression reference) { + private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) { switch (nullStatus) { case FlowInfo.NULL : if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - flowContext.recordUsingNullReference(scope, var, reference, + flowContext.recordUsingNullReference(scope, local, reference, FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNull(var); // from thereon it is set - initsWhenFalse.markAsComparedEqualToNonNull(var); // from thereon it is set + initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set + initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set } else { - flowContext.recordUsingNullReference(scope, var, reference, + flowContext.recordUsingNullReference(scope, local, reference, FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNonNull(var); // from thereon it is set - initsWhenFalse.markAsComparedEqualToNull(var); // from thereon it is set + initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set + initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set } if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { - flowInfo.markedAsNullOrNonNullInAssertExpression(var); + flowInfo.markedAsNullOrNonNullInAssertExpression(local); } break; case FlowInfo.NON_NULL : if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - flowContext.recordUsingNullReference(scope, var, reference, + flowContext.recordUsingNullReference(scope, local, reference, FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNonNull(var); // from thereon it is set + initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { - initsWhenTrue.markedAsNullOrNonNullInAssertExpression(var); + initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local); } } else { - flowContext.recordUsingNullReference(scope, var, reference, + flowContext.recordUsingNullReference(scope, local, reference, FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo); } break; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java index 47941f11e..13ac321a4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java @@ -14,6 +14,7 @@ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE * bug 186342 - [compiler][null] Using annotations for null checking * bug 361407 - Resource leak warning when resource is assigned to a field outside of constructor + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -136,13 +137,16 @@ public class ExplicitConstructorCall extends Statement implements InvocationSite } // process arguments if (this.arguments != null) { + boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; for (int i = 0, max = this.arguments.length; i < max; i++) { flowInfo = this.arguments[i] .analyseCode(currentScope, flowContext, flowInfo) .unconditionalInits(); - // if argument is an AutoCloseable insert info that it *may* be closed (by the target constructor, i.e.) - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + if (analyseResources) { + // if argument is an AutoCloseable insert info that it *may* be closed (by the target constructor, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + } if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java index 31ce9271f..59588d2b2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -43,7 +43,6 @@ import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; import org.eclipse.jdt.internal.compiler.util.Messages; @@ -711,22 +710,22 @@ boolean handledByGeneratedMethod(Scope scope, TypeBinding castType, TypeBinding * @param flowInfo the upstream flow info; caveat: may get modified */ public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { - VariableBinding var = variableBinding(scope); - if (var != null && - (var.type.tagBits & TagBits.IsBaseType) == 0) { + LocalVariableBinding local = localVariableBinding(); + if (local != null && + (local.type.tagBits & TagBits.IsBaseType) == 0) { if ((this.bits & ASTNode.IsNonNull) == 0) { - flowContext.recordUsingNullReference(scope, var, this, + flowContext.recordUsingNullReference(scope, local, this, FlowContext.MAY_NULL, flowInfo); } - flowInfo.markAsComparedEqualToNonNull(var ); + flowInfo.markAsComparedEqualToNonNull(local); // from thereon it is set if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { - flowInfo.markedAsNullOrNonNullInAssertExpression(var); + flowInfo.markedAsNullOrNonNullInAssertExpression(local); } if (flowContext.initsOnFinally != null) { - flowContext.initsOnFinally.markAsComparedEqualToNonNull(var); + flowContext.initsOnFinally.markAsComparedEqualToNonNull(local); if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { - flowContext.initsOnFinally.markedAsNullOrNonNullInAssertExpression(var); + flowContext.initsOnFinally.markedAsNullOrNonNullInAssertExpression(local); } } } @@ -1058,9 +1057,9 @@ public int nullStatus(FlowInfo flowInfo) { this.constant != null && this.constant != Constant.NotAConstant) return FlowInfo.NON_NULL; // constant expression cannot be null - VariableBinding var = variableBinding(null); - if (var != null) - return flowInfo.nullStatus(var); + LocalVariableBinding local = localVariableBinding(); + if (local != null) + return flowInfo.nullStatus(local); return FlowInfo.NON_NULL; } @@ -1298,15 +1297,4 @@ public void traverse(ASTVisitor visitor, BlockScope scope) { public void traverse(ASTVisitor visitor, ClassScope scope) { // nothing to do } - -/** - * Returns the field or local variable referenced by this node. Can be a direct reference (SingleNameReference) - * or thru a cast expression etc... - * This is used for the purpose of obtaining a local variable or field binding for the purpose of null analysis. - * @param scope This is the current scope in which binding is requested and is needed to ascertain if a static field - * belongs to the current type for null analysis. A <code>null</code> value may be passed to this parameter -*/ -public VariableBinding variableBinding(Scope scope) { - return null; -} } 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 6343221f6..4ac6c2fac 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 @@ -109,6 +109,7 @@ public class FakedTrackingVariable extends LocalDeclaration { scope.getJavaLangObject(), // dummy, just needs to be a reference type 0, false); + this.binding.closeTracker = this; this.binding.declaringScope = scope; this.binding.setConstant(Constant.NotAConstant); this.binding.useFlag = LocalVariableBinding.USED; @@ -336,18 +337,35 @@ public class FakedTrackingVariable extends LocalDeclaration { disconnectedTracker = previousTracker; // report error below, unless we have a self-wrap assignment } + rhsAnalyis: if (rhs.resolvedType != TypeBinding.NULL) { // new value is AutoCloseable, start tracking, possibly re-using existing tracker var: FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs); if (rhsTrackVar != null) { // 1. if RHS has a tracking variable... if (local.closeTracker == null) { - // null shouldn't occur but let's play safe + // null shouldn't occur but let's play safe: if (rhsTrackVar.originalBinding != null) - local.closeTracker = rhsTrackVar; // a.: let fresh LHS share it + local.closeTracker = rhsTrackVar; // a.: let fresh LHS share it + if (rhsTrackVar.currentAssignment == location) { + // pre-set tracker from lhs - passed from outside? + // now it's a fresh resource + rhsTrackVar.globalClosingState &= ~(SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE); + } } else { - if (rhsTrackVar == disconnectedTracker && rhs instanceof AllocationExpression) - return; // b.: self wrapper: res = new Wrap(res); -> done! - local.closeTracker = rhsTrackVar; // c.: conflicting LHS and RHS, proceed with recordErrorLocation below + if (rhs instanceof AllocationExpression) { + if (rhsTrackVar == disconnectedTracker) + return; // b.: self wrapper: res = new Wrap(res); -> done! + if (local.closeTracker == rhsTrackVar + && ((rhsTrackVar.globalClosingState & OWNED_BY_OUTSIDE) != 0)) { + // c.: assigning a fresh resource (pre-connected alloc) + // to a local previously holding an alien resource -> start over + local.closeTracker = new FakedTrackingVariable(local, location); + flowInfo.markAsDefinitelyNull(local.closeTracker.binding); + // still check disconnectedTracker below + break rhsAnalyis; + } + } + local.closeTracker = rhsTrackVar; // d.: conflicting LHS and RHS, proceed with recordErrorLocation below } // keep close-status of RHS unchanged across this assignment } else if (previousTracker != null) { // 2. re-use tracking variable from the LHS? @@ -420,8 +438,11 @@ public class FakedTrackingVariable extends LocalDeclaration { FakedTrackingVariable tracker = new FakedTrackingVariable(local, location); tracker.globalClosingState |= SHARED_WITH_OUTSIDE; flowInfo.markPotentiallyNullBit(tracker.binding); // shed some doubt - return tracker; - } else if ((expression.bits & RestrictiveFlagMASK) == Binding.FIELD) + return tracker; + } else if ( + (expression.bits & RestrictiveFlagMASK) == Binding.FIELD + ||((expression instanceof QualifiedNameReference) + && ((QualifiedNameReference) expression).isFieldAccess())) { // responsibility for this resource probably lies at a higher level FakedTrackingVariable tracker = new FakedTrackingVariable(local, location); @@ -440,7 +461,12 @@ public class FakedTrackingVariable extends LocalDeclaration { if (local.closeTracker != null) // (c): inner has already been analyzed: -> re-use track var return local.closeTracker; - return new FakedTrackingVariable(local, location); + FakedTrackingVariable newTracker = new FakedTrackingVariable(local, location); + LocalVariableBinding rhsLocal = expression.localVariableBinding(); + if (rhsLocal != null && rhsLocal.isParameter()) { + newTracker.globalClosingState |= OWNED_BY_OUTSIDE; + } + return newTracker; } public static void cleanUpAfterAssignment(BlockScope currentScope, int lhsBits, Expression expression) { @@ -552,8 +578,8 @@ public class FakedTrackingVariable extends LocalDeclaration { flowInfo.markAsDefinitelyNonNull(current.binding); current.globalClosingState |= CLOSE_SEEN; //TODO(stephan): this might be useful, but I could not find a test case for it: -// if (flowContext.initsOnFinally != null) -// flowContext.initsOnFinally.markAsDefinitelyNonNull(this.binding); + if (flowContext.initsOnFinally != null) + flowContext.initsOnFinally.markAsDefinitelyNonNull(this.binding); current = current.innerTracker; } while (current != null); } @@ -631,6 +657,35 @@ public class FakedTrackingVariable extends LocalDeclaration { return trackingVar; } + /** + * Answer true if we know for sure that no resource is bound to this variable + * at the point of 'flowInfo'. + */ + public boolean hasDefinitelyNoResource(FlowInfo flowInfo) { + if (this.originalBinding == null) return false; // shouldn't happen but keep quiet. + if (flowInfo.isDefinitelyNull(this.originalBinding)) { + return true; + } + if (!(flowInfo.isDefinitelyAssigned(this.originalBinding) + || flowInfo.isPotentiallyAssigned(this.originalBinding))) { + return true; + } + return false; + } + + public boolean isClosedInFinallyOfEnclosing(BlockScope scope) { + BlockScope currentScope = scope; + while (true) { + if (currentScope.finallyInfo != null + && currentScope.finallyInfo.isDefinitelyNonNull(this.binding)) { + return true; // closed in enclosing finally + } + if (!(currentScope.parent instanceof BlockScope)) { + return false; + } + currentScope = (BlockScope) currentScope.parent; + } + } /** * If current is the same as 'returnedResource' or a wrapper thereof, * mark as reported and return true, otherwise false. @@ -648,6 +703,9 @@ public class FakedTrackingVariable extends LocalDeclaration { } public void recordErrorLocation(ASTNode location, int nullStatus) { + if ((this.globalClosingState & OWNED_BY_OUTSIDE) != 0) { + return; + } if (this.recordedLocations == null) this.recordedLocations = new HashMap(); this.recordedLocations.put(location, new Integer(nullStatus)); @@ -684,12 +742,15 @@ public class FakedTrackingVariable extends LocalDeclaration { } 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?? + } // which degree of problem? boolean isPotentialProblem = false; if (nullStatus == FlowInfo.NULL) { if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0) isPotentialProblem = true; - } else if (nullStatus == FlowInfo.POTENTIALLY_NULL) { + } else if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) { isPotentialProblem = true; } // report: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java index 0dde07bc0..a629d9958 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -111,13 +111,6 @@ public FlowInfo analyseCode(MethodScope initializationScope, FlowContext flowCon .analyseCode(initializationScope, flowContext, flowInfo) .unconditionalInits(); flowInfo.markAsDefinitelyAssigned(this.binding); - if (this.binding.isFinal() && this.binding.isStatic()) { - int nullStatus = this.initialization.nullStatus(flowInfo); - // static final field being initialized. Record its null status for future reference - // since the flowInfo from an initialization wont be available in a method - flowInfo.markNullStatus(this.binding, nullStatus); -// this.binding.setNullStatusForStaticFinalField(nullStatus); - } } return flowInfo; } @@ -167,6 +160,12 @@ public boolean isStatic() { return (this.modifiers & ClassFileConstants.AccStatic) != 0; } +public boolean isFinal() { + if (this.binding != null) + return this.binding.isFinal(); + return (this.modifiers & ClassFileConstants.AccFinal) != 0; +} + public StringBuffer printStatement(int indent, StringBuffer output) { if (this.javadoc != null) { this.javadoc.print(indent, output); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java index a1d5c9909..64331cdac 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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,12 +21,10 @@ import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.codegen.Opcodes; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; @@ -43,7 +41,6 @@ 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; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; @@ -835,22 +832,4 @@ public void traverse(ASTVisitor visitor, BlockScope scope) { } visitor.endVisit(this, scope); } - -public VariableBinding variableBinding(Scope scope) { - if (scope != null) { - CompilerOptions options = scope.compilerOptions(); - if(!options.includeFieldsInNullAnalysis) return null; - if (this.receiver.isThis()) return this.binding; - if (this.binding != null && this.binding.declaringClass != null && this.binding.isStatic()) { - // does the static field belong to the current type or one of the enclosing ones? - ClassScope enclosingClass = scope.enclosingClassScope(); - while (enclosingClass != null) { - TypeDeclaration type = enclosingClass.referenceContext; - if (type != null && (this.binding.declaringClass.original() == type.binding)) return this.binding; - enclosingClass = enclosingClass.enclosingClassScope(); - } - } - } - return null; -} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java index e2f171173..85f3b5915 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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,8 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Technical University Berlin - extended API and implementation + * Stephan Herrmann - Contribution for + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 370930 - NonNull annotation not considered for enhanced for loops *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -29,6 +31,7 @@ import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config; @@ -96,9 +99,10 @@ public class ForeachStatement extends Statement { this.collection.checkNPE(currentScope, flowContext, flowInfo); flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo); FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy()); + LocalVariableBinding elementVarBinding = this.elementVariable.binding; // element variable will be assigned when iterating - condInfo.markAsDefinitelyAssigned(this.elementVariable.binding); + condInfo.markAsDefinitelyAssigned(elementVarBinding); this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo); @@ -108,7 +112,17 @@ public class ForeachStatement extends Statement { this.continueLabel, this.scope); UnconditionalFlowInfo actionInfo = condInfo.nullInfoLessUnconditionalCopy(); - actionInfo.markAsDefinitelyUnknown(this.elementVariable.binding); + actionInfo.markAsDefinitelyUnknown(elementVarBinding); + if (currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { + // this currently produces an unavoidable warning against all @NonNull element vars: + int nullStatus = this.elementVariable.checkAssignmentAgainstNullAnnotation(currentScope, flowContext, + elementVarBinding, FlowInfo.UNKNOWN, this.collection); + // TODO (stephan): once we have JSR 308 fetch nullStatus from the collection element type + // and feed the result into the above check (instead of FlowInfo.UNKNOWN) + if ((elementVarBinding.type.tagBits & TagBits.IsBaseType) == 0) { + actionInfo.markNullStatus(elementVarBinding, nullStatus); + } + } FlowInfo exitBranch; if (!(this.action == null || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { @@ -142,7 +156,7 @@ public class ForeachStatement extends Statement { switch(this.kind) { case ARRAY : if (!hasEmptyAction - || this.elementVariable.binding.resolvedPosition != -1) { + || elementVarBinding.resolvedPosition != -1) { this.collectionVariable.useFlag = LocalVariableBinding.USED; if (this.continueLabel != null) { this.indexVariable.useFlag = LocalVariableBinding.USED; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java index f65a1f3cb..5b16a03f4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2010 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 @@ -63,16 +63,16 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl if (this.roleCheckExpr != null) return this.roleCheckExpr.analyseCode(currentScope, flowContext, flowInfo); // SH} - VariableBinding variable = this.expression.variableBinding(currentScope); - if (variable != null && (variable.type.tagBits & TagBits.IsBaseType) == 0) { + LocalVariableBinding local = this.expression.localVariableBinding(); + if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo). unconditionalInits(); FlowInfo initsWhenTrue = flowInfo.copy(); - initsWhenTrue.markAsComparedEqualToNonNull(variable ); + initsWhenTrue.markAsComparedEqualToNonNull(local); if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { - initsWhenTrue.markedAsNullOrNonNullInAssertExpression(variable); + initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local); } - flowContext.recordUsingNullReference(currentScope, variable, + flowContext.recordUsingNullReference(currentScope, local, this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo); // no impact upon enclosing try context return FlowInfo.conditional(initsWhenTrue, flowInfo.copy()); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java index 264537078..6414c6b3e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -17,6 +17,7 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 358903 - Filter practically unimportant resource leak warnings + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -121,8 +122,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl FlowInfo preInitInfo = null; boolean shouldAnalyseResource = this.binding != null - && flowInfo.reachMode() == FlowInfo.REACHABLE - && FakedTrackingVariable.isAnyCloseable(this.initialization.resolvedType); + && flowInfo.reachMode() == FlowInfo.REACHABLE + && FakedTrackingVariable.isAnyCloseable(this.initialization.resolvedType) + && currentScope.compilerOptions().analyseResourceLeaks; if (shouldAnalyseResource) { preInitInfo = flowInfo.unconditionalCopy(); // analysis of resource leaks needs additional context while analyzing the RHS: 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 bb46f0d9e..88470f819 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 @@ -16,6 +16,7 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 358903 - Filter practically unimportant resource leak warnings + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -153,7 +154,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl boolean nonStatic = !this.binding.isStatic(); flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); // recording the closing of AutoCloseable resources: - if (CharOperation.equals(TypeConstants.CLOSE, this.selector)) + boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; + if (analyseResources && CharOperation.equals(TypeConstants.CLOSE, this.selector)) { FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.receiver); if (trackingVariable != null) { // null happens if receiver is not a local variable or not an AutoCloseable @@ -185,8 +187,10 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + if (analyseResources) { + // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + } } analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } @@ -203,11 +207,6 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // NullReferenceTest#test0510 } manageSyntheticAccessIfNecessary(currentScope, flowInfo); - // a method call can result in changed values for fields, - // so wipe out null info for fields collected till now. - CompilerOptions options = currentScope.compilerOptions(); - if(options.includeFieldsInNullAnalysis) - flowInfo.resetNullInfoForFields(); //{ObjectTeams: base calls via super: flowInfo = checkBaseCallsIfSuper(currentScope, flowInfo); // SH} @@ -249,6 +248,11 @@ protected FlowInfo checkBaseCallsIfSuper(BlockScope currentScope, FlowInfo flowI return flowInfo; } // SH} +public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { + super.checkNPE(scope, flowContext, flowInfo); + if ((nullStatus(flowInfo) & FlowInfo.POTENTIALLY_NULL) != 0) + scope.problemReporter().messageSendPotentialNullReference(this.binding, this); +} /** * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) */ @@ -396,11 +400,6 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean } codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector } -public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { - super.checkNPE(scope, flowContext, flowInfo); - if ((nullStatus(flowInfo) & FlowInfo.POTENTIALLY_NULL) != 0) - scope.problemReporter().messageSendPotentialNullReference(this.binding, this); -} /** * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java index 3d0cfdec2..882980cdb 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -192,7 +193,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { } } - this.scope.checkUnclosedCloseables(flowInfo, null/*don't report against a specific location*/, null); + this.scope.checkUnclosedCloseables(flowInfo, null, null/*don't report against a specific location*/, null); } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } 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 74cbe549f..7fa536777 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -13,6 +13,8 @@ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -148,9 +150,12 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc // process arguments if (this.arguments != null) { + boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; for (int i = 0, count = this.arguments.length; i < count; i++) { - // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + if (analyseResources) { + // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, false); + } flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo); if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); @@ -178,6 +183,12 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc flowInfo.unconditionalCopy(), currentScope); } + + // after having analysed exceptions above start tracking newly allocated resource: + if (FakedTrackingVariable.isAnyCloseable(this.resolvedType) && currentScope.compilerOptions().analyseResourceLeaks) { + FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); manageSyntheticAccessIfNecessary(currentScope, flowInfo); return flowInfo; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java index e855731ba..06751b820 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java @@ -14,6 +14,7 @@ * bug 185682 - Increment/decrement operators mark local variables as read * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -909,7 +910,12 @@ private void accessAsCalloutToField(ReferenceBinding enclosingReceiver, FieldBin setSyntheticAccessor(baseclassField, idx, new SyntheticMethodBinding(fakedAccessorBinding, SyntheticMethodBinding.InferredCalloutToField)); } // SH} - +public boolean isFieldAccess() { + if (this.otherBindings != null) { + return true; + } + return (this.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD; +} public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { //If inlinable field, forget the access emulation, the code gen will directly target it if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) { @@ -1298,32 +1304,4 @@ public void traverse(ASTVisitor visitor, ClassScope scope) { public String unboundReferenceErrorName() { return new String(this.tokens[0]); } - -public VariableBinding variableBinding(Scope scope) { - // if this is a *static* field and its actualResolvedType is the type in which we currently are asking for the binding, - // we can safely return the field binding - if (scope != null) { - CompilerOptions options = scope.compilerOptions(); - if(!options.includeFieldsInNullAnalysis) return null; - if (this.binding != null && (this.bits & RestrictiveFlagMASK) == Binding.FIELD) { - FieldBinding fieldBinding; - if (this.otherBindings == null) { - fieldBinding = (FieldBinding) this.binding; - } else { - fieldBinding = this.otherBindings[this.otherBindings.length - 1]; - } - if (fieldBinding.isStatic()) { - // does the static field belong to the current type or one of the enclosing ones? - ClassScope enclosingClass = scope.enclosingClassScope(); - while (enclosingClass != null) { - TypeDeclaration type = enclosingClass.referenceContext; - if (type != null && fieldBinding.declaringClass.original() == type.binding) - return fieldBinding; - enclosingClass = enclosingClass.enclosingClassScope(); - } - } - } - } - return super.variableBinding(scope); -} } 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 b149e34d4..ecf9f979c 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 @@ -16,6 +16,8 @@ * bug 365835 - [compiler][null] inconsistent error reporting. * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 358903 - Filter practically unimportant resource leak warnings + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -56,12 +58,14 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } if (flowInfo.reachMode() == FlowInfo.REACHABLE) checkAgainstNullAnnotation(currentScope, flowContext, this.expression.nullStatus(flowInfo)); - FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.expression); - if (trackingVariable != null) { - if (methodScope != trackingVariable.methodScope) - trackingVariable.markClosedInNestedMethod(); - // by returning the method passes the responsibility to the caller: - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expression, flowInfo, true); + if (currentScope.compilerOptions().analyseResourceLeaks) { + FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.expression); + if (trackingVariable != null) { + if (methodScope != trackingVariable.methodScope) + trackingVariable.markClosedInNestedMethod(); + // by returning the method passes the responsibility to the caller: + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expression, flowInfo, true); + } } } this.initStateIndex = @@ -135,7 +139,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } } } - currentScope.checkUnclosedCloseables(flowInfo, this, currentScope); + currentScope.checkUnclosedCloseables(flowInfo, flowContext, this, currentScope); return FlowInfo.DEAD_END; } void checkAgainstNullAnnotation(BlockScope scope, FlowContext flowContext, int nullStatus) { 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 46b0d62ea..0c23109b7 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -839,20 +839,6 @@ public LocalVariableBinding localVariableBinding() { return null; } -public VariableBinding variableBinding(Scope scope) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : - // reading a field - if (scope != null) { - CompilerOptions options = scope.compilerOptions(); - if(!options.includeFieldsInNullAnalysis) return null; - } - //$FALL-THROUGH$ - case Binding.LOCAL : // reading a local variable - return (VariableBinding) this.binding; - } - return null; -} public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { //If inlinable field, forget the access emulation, the code gen will directly target it if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) { @@ -921,10 +907,11 @@ public int nullStatus(FlowInfo flowInfo) { } switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // reading a field + return FlowInfo.UNKNOWN; case Binding.LOCAL : // reading a local variable - VariableBinding variable = (VariableBinding) this.binding; - if (variable != null) - return flowInfo.nullStatus(variable); + LocalVariableBinding local = (LocalVariableBinding) this.binding; + if (local != null) + return flowInfo.nullStatus(local); } return FlowInfo.NON_NULL; // never get there } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java index deec8bc27..73eeaea0d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -15,6 +15,8 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking * bug 365983 - [compiler][null] AIOOB with null annotation analysis and varargs + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370930 - NonNull annotation not considered for enhanced for loops *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -71,6 +73,7 @@ public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowCo public static final int COMPLAINED_FAKE_REACHABLE = 1; public static final int COMPLAINED_UNREACHABLE = 2; + /** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */ protected void analyseArguments(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments) { @@ -109,13 +112,17 @@ protected void analyseArguments(BlockScope currentScope, FlowContext flowContext /** Check null-ness of 'local' against a possible null annotation */ protected int checkAssignmentAgainstNullAnnotation(BlockScope currentScope, FlowContext flowContext, - VariableBinding var, int nullStatus, Expression expression) + LocalVariableBinding local, int nullStatus, Expression expression) { - if (var != null - && (var.tagBits & TagBits.AnnotationNonNull) != 0 - && nullStatus != FlowInfo.NON_NULL) { - flowContext.recordNullityMismatch(currentScope, expression, nullStatus, var.type); - nullStatus=FlowInfo.NON_NULL; + if (local != null) { + if ((local.tagBits & TagBits.AnnotationNonNull) != 0 + && nullStatus != FlowInfo.NON_NULL) { + flowContext.recordNullityMismatch(currentScope, expression, nullStatus, local.type); + return FlowInfo.NON_NULL; + } else if ((local.tagBits & TagBits.AnnotationNullable) != 0 + && nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type? + return FlowInfo.POTENTIALLY_NULL; // -> use more specific info from the annotation + } } return nullStatus; } @@ -153,7 +160,7 @@ public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previo /* OT: */ if (shouldReport) scope.problemReporter().unreachableCode(this); if (endOfBlock) - scope.checkUnclosedCloseables(flowInfo, null, null); + scope.checkUnclosedCloseables(flowInfo, null, null, null); } return COMPLAINED_UNREACHABLE; } else { @@ -162,7 +169,7 @@ public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previo // SH} scope.problemReporter().fakeReachable(this); if (endOfBlock) - scope.checkUnclosedCloseables(flowInfo, null, null); + scope.checkUnclosedCloseables(flowInfo, null, null, null); } return COMPLAINED_FAKE_REACHABLE; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java index 252962940..d8fdce8bb 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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,9 +8,11 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation + * Stephan Herrmann - Contributions for + * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -47,7 +49,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.exception.checkNPE(currentScope, flowContext, flowInfo); // need to check that exception thrown is actually caught somewhere flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope); - currentScope.checkUnclosedCloseables(flowInfo, this, currentScope); + currentScope.checkUnclosedCloseables(flowInfo, flowContext, this, currentScope); return FlowInfo.DEAD_END; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java index 237f5220a..9063edd1c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java @@ -110,7 +110,7 @@ public class TypeDeclaration extends Statement implements ProblemSeverities, Ref public MethodScope initializerScope; public MethodScope staticInitializerScope; public boolean ignoreFurtherInvestigation = false; - public int maxFieldCount; // maximum cumulative number of fields of this type and its inners (see updateMaxFieldCount()) + public int maxFieldCount; public int declarationSourceStart; public int declarationSourceEnd; public int bodyStart; @@ -545,6 +545,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + updateMaxFieldCount(); // propagate down the max field count internalAnalyseCode(flowContext, flowInfo); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; @@ -560,7 +561,9 @@ public void analyseCode(ClassScope enclosingClassScope) { if (this.ignoreFurtherInvestigation) return; try { - internalAnalyseCode(null, FlowInfo.initial(this.scope.outerMostClassScope().referenceType().maxFieldCount)); + // propagate down the max field count + updateMaxFieldCount(); + internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount)); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; } @@ -580,6 +583,7 @@ public void analyseCode(ClassScope currentScope, FlowContext flowContext, FlowIn localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + updateMaxFieldCount(); // propagate down the max field count internalAnalyseCode(flowContext, flowInfo); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; @@ -1202,11 +1206,6 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { staticInitializerContext.handledExceptions = Binding.ANY_EXCEPTION; // tolerate them all, and record them /*}*/ staticFieldInfo = field.analyseCode(this.staticInitializerScope, staticInitializerContext, staticFieldInfo); - if (field.binding != null && this.scope.compilerOptions().includeFieldsInNullAnalysis - && ((field.binding.modifiers & ClassFileConstants.AccFinal) != 0)) { - // we won't reset null Info for constant fields - staticFieldInfo.updateConstantFieldsMask(field.binding); - } // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable // branch, since the previous initializer already got the blame. if (staticFieldInfo == FlowInfo.DEAD_END) { @@ -1254,18 +1253,7 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { // SH} if (this.methods != null) { UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy(); - UnconditionalFlowInfo staticFieldUnconditionalInfo = staticFieldInfo.unconditionalInits(); - FlowInfo constructorInfo; - if (this.scope.compilerOptions().includeFieldsInNullAnalysis) { - flowInfo.addNullInfoFrom(staticFieldUnconditionalInfo.discardNonFieldInitializations()); - flowInfo.addConstantFieldsMask(staticFieldUnconditionalInfo); // prevent resetting null info for constant fields inside methods - flowInfo.resetNullInfoForFields(); // only preserve null info for constant fields - constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(flowInfo); - constructorInfo.addConstantFieldsMask(staticFieldUnconditionalInfo); // prevent resetting null info for constant fields inside c'tor too - } else { - constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo); - } - + FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo); for (int i = 0, count = this.methods.length; i < count; i++) { AbstractMethodDeclaration method = this.methods[i]; if (method.ignoreFurtherInvestigation) @@ -1280,7 +1268,7 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { ((Clinit)method).analyseCode( this.scope, staticInitializerContext, - staticFieldUnconditionalInfo.addInitializationsFrom(outerInfo)); + staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo)); } else { // constructor ((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode()); } @@ -1756,6 +1744,8 @@ public void resolve() { } } // SH} + // this.maxFieldCount might already be set + int localMaxFieldCount = 0; int lastVisibleFieldID = -1; boolean hasEnumConstants = false; FieldDeclaration[] enumConstantsWithoutBody = null; @@ -1765,43 +1755,6 @@ public void resolve() { this.typeParameters[i].resolve(this.scope); } } - // field count from enclosing and supertypes should be included in maxFieldCount, - // to make field-ids unique among all fields in scope. - // 1.: enclosing: - TypeBinding original = sourceType.original(); - int fieldAnalysisOffset = 0; - if (original instanceof NestedTypeBinding) { - // note: local types have no enclosingType in the AST but only in the binding: - fieldAnalysisOffset = ((NestedTypeBinding)original).enclosingType.cumulativeFieldCount; - } - // 2.: supers: - ReferenceBinding superClassBinding = sourceType.superclass; - while (superClassBinding != null) { - FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields(); - if (unResolvedFields != null) { - for (int i=unResolvedFields.length-1; i>=0; i--) { - // if the field is an initializer we do not want to update the count - switch (unResolvedFields[i].kind()) { - case AbstractVariableDeclaration.FIELD: - case AbstractVariableDeclaration.ENUM_CONSTANT: - fieldAnalysisOffset++; - } - } - } - fieldAnalysisOffset += findFieldCountFromSuperInterfaces(superClassBinding.superInterfaces()); - superClassBinding = superClassBinding.superclass(); - } - ReferenceBinding[] superInterfacesBinding = sourceType.superInterfaces; - fieldAnalysisOffset += findFieldCountFromSuperInterfaces(superInterfacesBinding); -//{ObjectTeams: also count type value parameters into maxFieldCount - if (this.typeParameters != null) - fieldAnalysisOffset += TypeValueParameter.count(this); -// SH} - - sourceType.cumulativeFieldCount += fieldAnalysisOffset; - sourceType.fieldAnalysisOffset = fieldAnalysisOffset; - this.maxFieldCount = sourceType.cumulativeFieldCount; - if (this.memberTypes != null) { //{ObjectTeams: don't cache count, array may grow during this loop! /* orig: @@ -1815,7 +1768,7 @@ public void resolve() { //{ObjectTeams: should we work at all? Config config = Config.getConfig(); boolean fieldsAndMethods = config.verifyMethods; - if (fieldsAndMethods) + if (fieldsAndMethods) { // SH} if (this.fields != null) { for (int i = 0, count = this.fields.length; i < count; i++) { @@ -1843,6 +1796,7 @@ public void resolve() { && TypeBinding.LONG == fieldBinding.type) { needSerialVersion = false; } + localMaxFieldCount++; lastVisibleFieldID = field.binding.id; break; @@ -1853,6 +1807,14 @@ public void resolve() { field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope); } } +//{ObjectTeams: also count type value parameters into maxFieldCount + if (this.typeParameters != null) + TypeValueParameter.updateMaxFieldCount(this); + } +// SH} + if (this.maxFieldCount < localMaxFieldCount) { + this.maxFieldCount = localMaxFieldCount; + } if (needSerialVersion) { //check that the current type doesn't extend javax.rmi.CORBA.Stub TypeBinding javaxRmiCorbaStub = this.scope.getType(TypeConstants.JAVAX_RMI_CORBA_STUB, 4); @@ -1961,19 +1923,6 @@ public void resolve() { } } -private int findFieldCountFromSuperInterfaces(ReferenceBinding[] superinterfaces) { - int numOfFields = 0; - if (superinterfaces == null) - return numOfFields ; - for (int i = 0; i < superinterfaces.length; i++) { - FieldBinding[] unResolvedFields = superinterfaces[i].unResolvedFields(); - // no need to check field kinds as initializer cannot occur inside interfaces - numOfFields += unResolvedFields != null ? unResolvedFields.length : 0; - numOfFields += findFieldCountFromSuperInterfaces(superinterfaces[i].superInterfaces()); - } - return numOfFields; -} - /** * Resolve a local type declaration */ @@ -2214,9 +2163,9 @@ public void traverse(ASTVisitor visitor, BlockScope blockScope) { if (this.fields != null) { int length = this.fields.length; for (int i = 0; i < length; i++) { - FieldDeclaration field; - if ((field = this.fields[i]).isStatic()) { - // local type cannot have static fields + FieldDeclaration field = this.fields[i]; + if (field.isStatic() && !field.isFinal()) { + // local type cannot have static fields that are not final, https://bugs.eclipse.org/bugs/show_bug.cgi?id=244544 } else { field.traverse(visitor, this.initializerScope); } @@ -2301,21 +2250,21 @@ public void traverse(ASTVisitor visitor, ClassScope classScope) { /** * MaxFieldCount's computation is necessary so as to reserve space for * the flow info field portions. It corresponds to the maximum amount of - * accumulated fields this class or one of its innertypes have. + * fields this class or one of its innertypes have. * - * During buildFields() accumulative field counts are gather per class, - * which include fields of outer and super types. - * During resolve, the maximum of these counts is collected inside out. + * During name resolution, types are traversed, and the max field count is recorded + * on the outermost type. It is then propagated down during the flow analysis. + * + * This method is doing either up/down propagation. */ -//{ObjectTeams: make accessible for ClassScope.addGeneratedField(): -public -// SH} void updateMaxFieldCount() { if (this.binding == null) return; // error scenario TypeDeclaration outerMostType = this.scope.outerMostClassScope().referenceType(); if (this.maxFieldCount > outerMostType.maxFieldCount) { outerMostType.maxFieldCount = this.maxFieldCount; // up + } else { + this.maxFieldCount = outerMostType.maxFieldCount; // down } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java index 4689bf890..5cb416656 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -13,7 +13,6 @@ package org.eclipse.jdt.internal.compiler.flow; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; /** * Record conditional initialization status during definite assignment analysis @@ -74,120 +73,121 @@ public FlowInfo initsWhenTrue() { return this.initsWhenTrue; } -public boolean isDefinitelyAssigned(VariableBinding var) { +public boolean isDefinitelyAssigned(FieldBinding field) { - return this.initsWhenTrue.isDefinitelyAssigned(var) - && this.initsWhenFalse.isDefinitelyAssigned(var); + return this.initsWhenTrue.isDefinitelyAssigned(field) + && this.initsWhenFalse.isDefinitelyAssigned(field); } -public boolean isDefinitelyNonNull(VariableBinding var) { - return this.initsWhenTrue.isDefinitelyNonNull(var) - && this.initsWhenFalse.isDefinitelyNonNull(var); +public boolean isDefinitelyAssigned(LocalVariableBinding local) { + + return this.initsWhenTrue.isDefinitelyAssigned(local) + && this.initsWhenFalse.isDefinitelyAssigned(local); } -public boolean isDefinitelyNull(VariableBinding var) { - return this.initsWhenTrue.isDefinitelyNull(var) - && this.initsWhenFalse.isDefinitelyNull(var); +public boolean isDefinitelyNonNull(LocalVariableBinding local) { + return this.initsWhenTrue.isDefinitelyNonNull(local) + && this.initsWhenFalse.isDefinitelyNonNull(local); } -public boolean isDefinitelyUnknown(VariableBinding var) { - return this.initsWhenTrue.isDefinitelyUnknown(var) - && this.initsWhenFalse.isDefinitelyUnknown(var); +public boolean isDefinitelyNull(LocalVariableBinding local) { + return this.initsWhenTrue.isDefinitelyNull(local) + && this.initsWhenFalse.isDefinitelyNull(local); } -public boolean isPotentiallyAssigned(VariableBinding var) { - return this.initsWhenTrue.isPotentiallyAssigned(var) - || this.initsWhenFalse.isPotentiallyAssigned(var); +public boolean isDefinitelyUnknown(LocalVariableBinding local) { + return this.initsWhenTrue.isDefinitelyUnknown(local) + && this.initsWhenFalse.isDefinitelyUnknown(local); } -public boolean isPotentiallyNonNull(VariableBinding var) { - return this.initsWhenTrue.isPotentiallyNonNull(var) - || this.initsWhenFalse.isPotentiallyNonNull(var); +public boolean isPotentiallyAssigned(FieldBinding field) { + return this.initsWhenTrue.isPotentiallyAssigned(field) + || this.initsWhenFalse.isPotentiallyAssigned(field); } -public boolean isPotentiallyNull(VariableBinding var) { - return this.initsWhenTrue.isPotentiallyNull(var) - || this.initsWhenFalse.isPotentiallyNull(var); +public boolean isPotentiallyAssigned(LocalVariableBinding local) { + return this.initsWhenTrue.isPotentiallyAssigned(local) + || this.initsWhenFalse.isPotentiallyAssigned(local); } -public boolean isPotentiallyUnknown(VariableBinding var) { - return this.initsWhenTrue.isPotentiallyUnknown(var) - || this.initsWhenFalse.isPotentiallyUnknown(var); +public boolean isPotentiallyNonNull(LocalVariableBinding local) { + return this.initsWhenTrue.isPotentiallyNonNull(local) + || this.initsWhenFalse.isPotentiallyNonNull(local); } -public boolean isProtectedNonNull(VariableBinding var) { - return this.initsWhenTrue.isProtectedNonNull(var) - && this.initsWhenFalse.isProtectedNonNull(var); +public boolean isPotentiallyNull(LocalVariableBinding local) { + return this.initsWhenTrue.isPotentiallyNull(local) + || this.initsWhenFalse.isPotentiallyNull(local); } -public boolean isProtectedNull(VariableBinding var) { - return this.initsWhenTrue.isProtectedNull(var) - && this.initsWhenFalse.isProtectedNull(var); +public boolean isPotentiallyUnknown(LocalVariableBinding local) { + return this.initsWhenTrue.isPotentiallyUnknown(local) + || this.initsWhenFalse.isPotentiallyUnknown(local); } -public void markAsComparedEqualToNonNull(VariableBinding var) { - this.initsWhenTrue.markAsComparedEqualToNonNull(var); - this.initsWhenFalse.markAsComparedEqualToNonNull(var); +public boolean isProtectedNonNull(LocalVariableBinding local) { + return this.initsWhenTrue.isProtectedNonNull(local) + && this.initsWhenFalse.isProtectedNonNull(local); } -public void markAsComparedEqualToNull(VariableBinding var) { - this.initsWhenTrue.markAsComparedEqualToNull(var); - this.initsWhenFalse.markAsComparedEqualToNull(var); +public boolean isProtectedNull(LocalVariableBinding local) { + return this.initsWhenTrue.isProtectedNull(local) + && this.initsWhenFalse.isProtectedNull(local); } -public void markAsDefinitelyAssigned(VariableBinding var) { - this.initsWhenTrue.markAsDefinitelyAssigned(var); - this.initsWhenFalse.markAsDefinitelyAssigned(var); +public void markAsComparedEqualToNonNull(LocalVariableBinding local) { + this.initsWhenTrue.markAsComparedEqualToNonNull(local); + this.initsWhenFalse.markAsComparedEqualToNonNull(local); } -public void markAsDefinitelyNonNull(VariableBinding var) { - this.initsWhenTrue.markAsDefinitelyNonNull(var); - this.initsWhenFalse.markAsDefinitelyNonNull(var); +public void markAsComparedEqualToNull(LocalVariableBinding local) { + this.initsWhenTrue.markAsComparedEqualToNull(local); + this.initsWhenFalse.markAsComparedEqualToNull(local); } -public void markAsDefinitelyNull(VariableBinding var) { - this.initsWhenTrue.markAsDefinitelyNull(var); - this.initsWhenFalse.markAsDefinitelyNull(var); +public void markAsDefinitelyAssigned(FieldBinding field) { + this.initsWhenTrue.markAsDefinitelyAssigned(field); + this.initsWhenFalse.markAsDefinitelyAssigned(field); } -public void resetNullInfo(VariableBinding var) { - this.initsWhenTrue.resetNullInfo(var); - this.initsWhenFalse.resetNullInfo(var); +public void markAsDefinitelyAssigned(LocalVariableBinding local) { + this.initsWhenTrue.markAsDefinitelyAssigned(local); + this.initsWhenFalse.markAsDefinitelyAssigned(local); } -public void resetNullInfoForFields() { - this.initsWhenTrue.resetNullInfoForFields(); - this.initsWhenFalse.resetNullInfoForFields(); +public void markAsDefinitelyNonNull(LocalVariableBinding local) { + this.initsWhenTrue.markAsDefinitelyNonNull(local); + this.initsWhenFalse.markAsDefinitelyNonNull(local); } -public void updateConstantFieldsMask(FieldBinding field) { - this.initsWhenTrue.updateConstantFieldsMask(field); - this.initsWhenFalse.updateConstantFieldsMask(field); +public void markAsDefinitelyNull(LocalVariableBinding local) { + this.initsWhenTrue.markAsDefinitelyNull(local); + this.initsWhenFalse.markAsDefinitelyNull(local); } -public void addConstantFieldsMask(UnconditionalFlowInfo other) { - this.initsWhenTrue.addConstantFieldsMask(other); - this.initsWhenFalse.addConstantFieldsMask(other); +public void resetNullInfo(LocalVariableBinding local) { + this.initsWhenTrue.resetNullInfo(local); + this.initsWhenFalse.resetNullInfo(local); } -public void markPotentiallyNullBit(VariableBinding var) { - this.initsWhenTrue.markPotentiallyNullBit(var); - this.initsWhenFalse.markPotentiallyNullBit(var); +public void markPotentiallyNullBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyNullBit(local); + this.initsWhenFalse.markPotentiallyNullBit(local); } -public void markPotentiallyNonNullBit(VariableBinding var) { - this.initsWhenTrue.markPotentiallyNonNullBit(var); - this.initsWhenFalse.markPotentiallyNonNullBit(var); +public void markPotentiallyNonNullBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyNonNullBit(local); + this.initsWhenFalse.markPotentiallyNonNullBit(local); } -public void markAsDefinitelyUnknown(VariableBinding var) { - this.initsWhenTrue.markAsDefinitelyUnknown(var); - this.initsWhenFalse.markAsDefinitelyUnknown(var); +public void markAsDefinitelyUnknown(LocalVariableBinding local) { + this.initsWhenTrue.markAsDefinitelyUnknown(local); + this.initsWhenFalse.markAsDefinitelyUnknown(local); } -public void markPotentiallyUnknownBit(VariableBinding var) { - this.initsWhenTrue.markPotentiallyUnknownBit(var); - this.initsWhenFalse.markPotentiallyUnknownBit(var); +public void markPotentiallyUnknownBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyUnknownBit(local); + this.initsWhenFalse.markPotentiallyUnknownBit(local); } public FlowInfo setReachMode(int reachMode) { @@ -243,18 +243,18 @@ public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() { mergedWith(this.initsWhenFalse.unconditionalInits()); } -public void markedAsNullOrNonNullInAssertExpression(VariableBinding var) { - this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(var); - this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(var); +public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) { + this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local); + this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(local); } -public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding var) { - return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(var) - || this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(var)); +public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) { + return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local) + || this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local)); } -public void resetAssignmentInfo(LocalVariableBinding var) { - this.initsWhenTrue.resetAssignmentInfo(var); - this.initsWhenFalse.resetAssignmentInfo(var); +public void resetAssignmentInfo(LocalVariableBinding local) { + this.initsWhenTrue.resetAssignmentInfo(local); + this.initsWhenFalse.resetAssignmentInfo(local); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java index ea64a1adf..76784ee23 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java @@ -10,6 +10,7 @@ * Stephan Herrmann - Contributions for * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -34,8 +35,10 @@ public class FinallyFlowContext extends FlowContext { VariableBinding[] finalVariables; int assignCount; - VariableBinding[] nullVariables; - Expression[] nullReferences; + // the following three arrays are in sync regarding their indices: + LocalVariableBinding[] nullLocals; + ASTNode[] nullReferences; // Expressions for null checking, Statements for resource analysis + // cast to Expression is safe if corresponding nullCheckType != EXIT_RESOURCE int[] nullCheckTypes; int nullCount; // see also the related field FlowContext#expectedTypes @@ -59,13 +62,13 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { boolean complained = false; // remember if have complained on this final assignment if (variable instanceof FieldBinding) { // final field - if (flowInfo.isPotentiallyAssigned(variable)) { + if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) { complained = true; scope.problemReporter().duplicateInitializationOfBlankFinalField((FieldBinding)variable, this.finalAssignments[i]); } } else { // final local variable - if (flowInfo.isPotentiallyAssigned(variable)) { + if (flowInfo.isPotentiallyAssigned((LocalVariableBinding)variable)) { complained = true; scope.problemReporter().duplicateInitializationOfFinalLocal( (LocalVariableBinding) variable, @@ -89,29 +92,30 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative for (int i = 0; i < this.nullCount; i++) { if (this.nullCheckTypes[i] == ASSIGN_TO_NONNULL) - this.parent.recordNullityMismatch(scope, this.nullReferences[i], - flowInfo.nullStatus(this.nullVariables[i]), this.expectedTypes[i]); + this.parent.recordNullityMismatch(scope, (Expression)this.nullReferences[i], + flowInfo.nullStatus(this.nullLocals[i]), this.expectedTypes[i]); else - this.parent.recordUsingNullReference(scope, this.nullVariables[i], + this.parent.recordUsingNullReference(scope, this.nullLocals[i], this.nullReferences[i], this.nullCheckTypes[i], flowInfo); + } } else { // no enclosing loop, be as precise as possible right now for (int i = 0; i < this.nullCount; i++) { - Expression expression = this.nullReferences[i]; + ASTNode location = this.nullReferences[i]; // final local variable - VariableBinding var = this.nullVariables[i]; + LocalVariableBinding local = this.nullLocals[i]; switch (this.nullCheckTypes[i]) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: - if (flowInfo.isDefinitelyNonNull(var)) { + if (flowInfo.isDefinitelyNonNull(local)) { if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(var, expression); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(var, expression); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } } continue; @@ -121,46 +125,47 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: - if (flowInfo.isDefinitelyNull(var)) { + Expression expression = (Expression) location; + if (flowInfo.isDefinitelyNull(local)) { switch(this.nullCheckTypes[i] & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(var, expression); + scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); } continue; case FlowContext.IN_COMPARISON_NON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(var, expression); + scope.problemReporter().localVariableNullComparedToNonNull(local, expression); } continue; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(var, expression); + scope.problemReporter().localVariableRedundantNullAssignment(local, expression); continue; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(var, expression); + scope.problemReporter().localVariableNullInstanceof(local, expression); continue; } - } else if (flowInfo.isPotentiallyNull(var)) { + } else if (flowInfo.isPotentiallyNull(local)) { switch(this.nullCheckTypes[i] & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; case FlowContext.IN_COMPARISON_NON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; @@ -168,19 +173,19 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { } break; case MAY_NULL: - if (flowInfo.isDefinitelyNull(var)) { - scope.problemReporter().variableNullReference(var, expression); + if (flowInfo.isDefinitelyNull(local)) { + scope.problemReporter().localVariableNullReference(local, location); continue; } - if (flowInfo.isPotentiallyNull(var)) { - scope.problemReporter().variablePotentialNullReference(var, expression); + if (flowInfo.isPotentiallyNull(local)) { + scope.problemReporter().localVariablePotentialNullReference(local, location); } break; case ASSIGN_TO_NONNULL: - int nullStatus = flowInfo.nullStatus(var); + int nullStatus = flowInfo.nullStatus(local); if (nullStatus != FlowInfo.NON_NULL) { char[][] annotationName = scope.environment().getNonNullAnnotationName(); - scope.problemReporter().nullityMismatch(expression, this.expectedTypes[i], nullStatus, annotationName); + scope.problemReporter().nullityMismatch((Expression) location, this.expectedTypes[i], nullStatus, annotationName); } break; default: @@ -228,9 +233,9 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { return true; } - public void recordUsingNullReference(Scope scope, VariableBinding var, - Expression reference, int checkType, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 && !flowInfo.isDefinitelyUnknown(var)) { + public void recordUsingNullReference(Scope scope, LocalVariableBinding local, + ASTNode location, int checkType, FlowInfo flowInfo) { + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 && !flowInfo.isDefinitelyUnknown(local)) { if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative switch (checkType) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: @@ -239,68 +244,69 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: - if (flowInfo.cannotBeNull(var)) { + Expression reference = (Expression) location; + if (flowInfo.cannotBeNull(local)) { if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(var, reference); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } else if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(var, reference); + scope.problemReporter().localVariableNonNullComparedToNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } return; } - if (flowInfo.canOnlyBeNull(var)) { + if (flowInfo.canOnlyBeNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(var, reference); + scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(var, reference); + scope.problemReporter().localVariableNullComparedToNonNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(var, reference); + scope.problemReporter().localVariableRedundantNullAssignment(local, reference); return; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(var, reference); + scope.problemReporter().localVariableNullInstanceof(local, reference); return; } - } else if (flowInfo.isPotentiallyNull(var)) { + } else if (flowInfo.isPotentiallyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; @@ -308,11 +314,11 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { } break; case MAY_NULL : - if (flowInfo.cannotBeNull(var)) { + if (flowInfo.cannotBeNull(local)) { return; } - if (flowInfo.canOnlyBeNull(var)) { - scope.problemReporter().variableNullReference(var, reference); + if (flowInfo.canOnlyBeNull(local)) { + scope.problemReporter().localVariableNullReference(local, location); return; } break; @@ -324,19 +330,19 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { switch (checkType) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: - if (flowInfo.isDefinitelyNonNull(var)) { + if (flowInfo.isDefinitelyNonNull(local)) { if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(var, reference); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(var, reference); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } @@ -347,50 +353,51 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: - if (flowInfo.isDefinitelyNull(var)) { + Expression reference = (Expression) location; + if (flowInfo.isDefinitelyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(var, reference); + scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(var, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(var, reference); + scope.problemReporter().localVariableNullComparedToNonNull(local, reference); } - if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) { + if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(var, reference); + scope.problemReporter().localVariableRedundantNullAssignment(local, reference); return; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(var, reference); + scope.problemReporter().localVariableNullInstanceof(local, reference); return; } - } else if (flowInfo.isPotentiallyNull(var)) { + } else if (flowInfo.isPotentiallyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(var, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; @@ -398,15 +405,15 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { } break; case MAY_NULL : - if (flowInfo.isDefinitelyNull(var)) { - scope.problemReporter().variableNullReference(var, reference); + if (flowInfo.isDefinitelyNull(local)) { + scope.problemReporter().localVariableNullReference(local, location); return; } - if (flowInfo.isPotentiallyNull(var)) { - scope.problemReporter().variablePotentialNullReference(var, reference); + if (flowInfo.isPotentiallyNull(local)) { + scope.problemReporter().localVariablePotentialNullReference(local, location); return; } - if (flowInfo.isDefinitelyNonNull(var)) { + if (flowInfo.isDefinitelyNonNull(local)) { return; // shortcut: cannot be null } break; @@ -419,7 +426,7 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { if(((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) || checkType == MAY_NULL || (checkType & CONTEXT_MASK) == FlowContext.IN_ASSIGNMENT || (checkType & CONTEXT_MASK) == FlowContext.IN_INSTANCEOF) { - recordNullReference(var, reference, checkType); + recordNullReference(local, location, checkType); } // prepare to re-check with try/catch flow info } @@ -435,17 +442,17 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { } } -protected void recordNullReference(VariableBinding var, - Expression expression, int status) { +protected void recordNullReference(LocalVariableBinding local, + ASTNode expression, int status) { if (this.nullCount == 0) { - this.nullVariables = new VariableBinding[5]; + this.nullLocals = new LocalVariableBinding[5]; this.nullReferences = new Expression[5]; this.nullCheckTypes = new int[5]; } - else if (this.nullCount == this.nullVariables.length) { + else if (this.nullCount == this.nullLocals.length) { int newLength = this.nullCount * 2; - System.arraycopy(this.nullVariables, 0, - this.nullVariables = new VariableBinding[newLength], 0, + System.arraycopy(this.nullLocals, 0, + this.nullLocals = new LocalVariableBinding[newLength], 0, this.nullCount); System.arraycopy(this.nullReferences, 0, this.nullReferences = new Expression[newLength], 0, @@ -454,7 +461,7 @@ protected void recordNullReference(VariableBinding var, this.nullCheckTypes = new int[newLength], 0, this.nullCount); } - this.nullVariables[this.nullCount] = var; + this.nullLocals[this.nullCount] = local; this.nullReferences[this.nullCount] = expression; this.nullCheckTypes[this.nullCount++] = status; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java index 33fd6c5f5..489bb1d43 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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,7 @@ * Stephan Herrmann - Contributions for * bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis * bug 186342 - [compiler][null] Using annotations for null checking + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -19,6 +20,7 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.LabeledStatement; import org.eclipse.jdt.internal.compiler.ast.Reference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -74,6 +76,8 @@ public static final int CAN_ONLY_NON_NULL = 0x0002; public static final int MAY_NULL = 0x0003; //check binding a value to a @NonNull variable public final static int ASSIGN_TO_NONNULL = 0x0080; +//check against unclosed resource at early exit: +public static final int EXIT_RESOURCE = 0x0800; // check against null, with potential values -- NPE guard public static final int CHECK_MASK = 0x00FF; public static final int IN_COMPARISON_NULL = 0x0100; @@ -556,6 +560,18 @@ public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) // default implementation: do nothing } +/** + * Record that we found an early exit from a method while a resource is in scope. + * @param scope enclosing scope + * @param flowInfo flowInfo at the point of the early exit + * @param trackingVar representation of the resource + * @param reference the return or throw statement marking the early exit + * @return true if the situation has been handled by this flow context. + */ +public boolean recordExitAgainstResource(BlockScope scope, FlowInfo flowInfo, FakedTrackingVariable trackingVar, ASTNode reference) { + return false; // not handled +} + protected void recordExpectedType(TypeBinding expectedType, int nullCount) { if (nullCount == 0) { this.expectedTypes = new TypeBinding[5]; @@ -580,7 +596,9 @@ protected boolean recordFinalAssignment(VariableBinding variable, Reference fina * Record a null reference for use by deferred checks. Only looping or * finally contexts really record that information. * @param local the local variable involved in the check - * @param expression the expression within which local lays + * @param location the location triggering the analysis, for normal null dereference + * this is an expression resolving to 'local', for resource leaks it is an + * early exit statement. * @param status the status against which the check must be performed; one of * {@link #CAN_ONLY_NULL CAN_ONLY_NULL}, {@link #CAN_ONLY_NULL_NON_NULL * CAN_ONLY_NULL_NON_NULL}, {@link #MAY_NULL MAY_NULL}, @@ -588,8 +606,8 @@ protected boolean recordFinalAssignment(VariableBinding variable, Reference fina * combined with a context indicator (one of {@link #IN_COMPARISON_NULL}, * {@link #IN_COMPARISON_NON_NULL}, {@link #IN_ASSIGNMENT} or {@link #IN_INSTANCEOF}) */ -protected void recordNullReference(VariableBinding local, - Expression expression, int status) { +protected void recordNullReference(LocalVariableBinding local, + ASTNode location, int status) { // default implementation: do nothing } @@ -620,7 +638,9 @@ public void recordSettingFinal(VariableBinding variable, Reference finalReferenc * context). * @param scope the scope into which the check is performed * @param local the local variable involved in the check - * @param reference the expression within which local lies + * @param location the location triggering the analysis, for normal null dereference + * this is an expression resolving to 'local', for resource leaks it is an + * early exit statement. * @param checkType the status against which the check must be performed; one * of {@link #CAN_ONLY_NULL CAN_ONLY_NULL}, {@link #CAN_ONLY_NULL_NON_NULL * CAN_ONLY_NULL_NON_NULL}, {@link #MAY_NULL MAY_NULL}, potentially @@ -631,8 +651,8 @@ public void recordSettingFinal(VariableBinding variable, Reference finalReferenc * be known at the time of calling this method (they are influenced by * code that follows the current point) */ -public void recordUsingNullReference(Scope scope, VariableBinding local, - Expression reference, int checkType, FlowInfo flowInfo) { +public void recordUsingNullReference(Scope scope, LocalVariableBinding local, + ASTNode location, int checkType, FlowInfo flowInfo) { if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || flowInfo.isDefinitelyUnknown(local)) { return; @@ -643,14 +663,14 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, if (flowInfo.isDefinitelyNonNull(local)) { if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(local, reference); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(local, reference); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); @@ -666,15 +686,16 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: + Expression reference = (Expression)location; if (flowInfo.isDefinitelyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, reference); + scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); @@ -682,34 +703,34 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, return; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, reference); + scope.problemReporter().localVariableNullComparedToNonNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(local, reference); + scope.problemReporter().localVariableRedundantNullAssignment(local, reference); return; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(local, reference); + scope.problemReporter().localVariableNullInstanceof(local, reference); return; } } else if (flowInfo.isPotentiallyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; @@ -720,11 +741,11 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, break; case MAY_NULL : if (flowInfo.isDefinitelyNull(local)) { - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, location); return; } if (flowInfo.isPotentiallyNull(local)) { - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, location); return; } break; @@ -732,7 +753,7 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, // never happens } if (this.parent != null) { - this.parent.recordUsingNullReference(scope, local, reference, checkType, + this.parent.recordUsingNullReference(scope, local, location, checkType, flowInfo); } } 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 1328b34c8..177ceaf3b 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, 2011 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,7 +20,6 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallTrackingVariable; /** @@ -65,7 +64,7 @@ public abstract class FlowInfo { DEAD_END = new UnconditionalFlowInfo(); DEAD_END.tagBits = UNREACHABLE; } - + /** * Add other inits to this flow info, then return this. The operation semantics * are to match as closely as possible the application to this flow info of all @@ -107,42 +106,39 @@ abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits); } /** - * Check whether a given field or local variable is known to be unable to gain a definite + * Check whether a given local variable is known to be unable to gain a definite * non null or definite null status by the use of an enclosing flow info. The * semantics are that if the current flow info marks the variable as potentially * unknown or else as being both potentially null and potentially non null, * then it won't ever be promoted as definitely null or definitely non null. (It * could still get promoted to definite unknown). - * @param binding the field or local variable to check - * @return true iff this flow info prevents field or local from being promoted to + * @param local the variable to check + * @return true iff this flow info prevents local from being promoted to * definite non null or definite null against an enclosing flow info */ -public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding binding) { - return isPotentiallyUnknown(binding) || - isPotentiallyNonNull(binding) && isPotentiallyNull(binding); +public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) { + return isPotentiallyUnknown(local) || + isPotentiallyNonNull(local) && isPotentiallyNull(local); } /** - * Check whether a given field or local variable is known to be non null, either because + * Check whether a given local variable is known to be non null, either because * it is definitely non null, or because is has been tested against non null. - * @param binding the field or local to check - * @return true iff field or local cannot be null for this flow info + * @param local the variable to ckeck + * @return true iff local cannot be null for this flow info */ -public boolean cannotBeNull(VariableBinding binding) { - return isDefinitelyNonNull(binding) || isProtectedNonNull(binding); +public boolean cannotBeNull(LocalVariableBinding local) { + return isDefinitelyNonNull(local) || isProtectedNonNull(local); } /** - * Check whether a given field or local variable is known to be null, either because it - * is definitely null, or because is has been tested against null. Note that for fields, - * this method only takes compile time analysis into account and there's no - * guarantee of the field being definitely null during runtime - * since it can be modified in some other thread. - * @param binding the field or local to check - * @return true iff field or local can only be null for this flow info + * Check whether a given local variable is known to be null, either because it + * is definitely null, or because is has been tested against null. + * @param local the variable to ckeck + * @return true iff local can only be null for this flow info */ -public boolean canOnlyBeNull(VariableBinding binding) { - return isDefinitelyNull(binding) || isProtectedNull(binding); +public boolean canOnlyBeNull(LocalVariableBinding local) { + return isDefinitelyNull(local) || isProtectedNull(local); } /** @@ -154,7 +150,6 @@ public boolean canOnlyBeNull(VariableBinding binding) { public static UnconditionalFlowInfo initial(int maxFieldCount) { UnconditionalFlowInfo info = new UnconditionalFlowInfo(); info.maxFieldCount = maxFieldCount; - info.constantFieldsMask = 0L; return info; } @@ -181,202 +176,196 @@ abstract public FlowInfo initsWhenFalse(); abstract public FlowInfo initsWhenTrue(); /** - * Check status of definite assignment for a local or field. + * Check status of definite assignment for a field. + */ + abstract public boolean isDefinitelyAssigned(FieldBinding field); + + /** + * Check status of definite assignment for a local. */ - abstract public boolean isDefinitelyAssigned(VariableBinding var); + public abstract boolean isDefinitelyAssigned(LocalVariableBinding local); /** - * Check status of definite non-null value for a given field or local variable. Note that for fields, this method only - * takes compile time analysis into account and there's no guarantee of the field being definitely non null during runtime - * since it can be modified in some other thread. - * @param binding the field or local to check - * @return true iff field or local is definitely non null for this flow info + * Check status of definite non-null value for a given local variable. + * @param local the variable to ckeck + * @return true iff local is definitely non null for this flow info */ - public abstract boolean isDefinitelyNonNull(VariableBinding binding); + public abstract boolean isDefinitelyNonNull(LocalVariableBinding local); /** - * Check status of definite null value for a given field or local variable. Note that for fields, this method only - * takes compile time analysis into account and there's no guarantee of the field being definitely null during runtime - * since it can be modified in some other thread. - * @param binding the field or local to check - * @return true iff field or local is definitely null for this flow info + * Check status of definite null value for a given local variable. + * @param local the variable to ckeck + * @return true iff local is definitely null for this flow info */ -public abstract boolean isDefinitelyNull(VariableBinding binding); +public abstract boolean isDefinitelyNull(LocalVariableBinding local); /** - * Check status of definite unknown value for a given field or local variable. - * @param binding the field or local to check - * @return true iff field or local is definitely unknown for this flow info + * Check status of definite unknown value for a given local variable. + * @param local the variable to ckeck + * @return true iff local is definitely unknown for this flow info */ -public abstract boolean isDefinitelyUnknown(VariableBinding binding); +public abstract boolean isDefinitelyUnknown(LocalVariableBinding local); /** - * Check status of potential assignment for a local variable or a field. + * Check status of potential assignment for a field. */ + abstract public boolean isPotentiallyAssigned(FieldBinding field); - abstract public boolean isPotentiallyAssigned(VariableBinding var); + /** + * Check status of potential assignment for a local variable. + */ + + abstract public boolean isPotentiallyAssigned(LocalVariableBinding field); /** - * Check status of potential null assignment for a field or local. Return true if there + * Check status of potential null assignment for a local. Return true if there * is a reasonable expectation that the variable be non null at this point. - * @param binding VariableBinding - the binding for the checked field or local - * @return true if there is a reasonable expectation that the field or local be non null at + * @param local LocalVariableBinding - the binding for the checked local + * @return true if there is a reasonable expectation that local be non null at * this point */ -public abstract boolean isPotentiallyNonNull(VariableBinding binding); +public abstract boolean isPotentiallyNonNull(LocalVariableBinding local); /** - * Check status of potential null assignment for a field or local. Return true if there + * Check status of potential null assignment for a local. Return true if there * is a reasonable expectation that the variable be null at this point. This * includes the protected null case, so as to augment diagnostics, but does not * really check that someone deliberately assigned to null on any specific * path - * @param binding VariableBinding - the binding for the checked field or local - * @return true if there is a reasonable expectation that the field or local be null at + * @param local LocalVariableBinding - the binding for the checked local + * @return true if there is a reasonable expectation that local be null at * this point */ -public abstract boolean isPotentiallyNull(VariableBinding binding); +public abstract boolean isPotentiallyNull(LocalVariableBinding local); /** - * Return true if the given field or local may have been assigned to an unknown value. - * @param binding the field or local to check - * @return true if the given field or local may have been assigned to an unknown value + * Return true if the given local may have been assigned to an unknown value. + * @param local the local to check + * @return true if the given local may have been assigned to an unknown value */ -public abstract boolean isPotentiallyUnknown(VariableBinding binding); +public abstract boolean isPotentiallyUnknown(LocalVariableBinding local); /** - * Return true if the given field or local is protected by a test against a non null + * Return true if the given local is protected by a test against a non null * value. - * @param binding the field or local to check - * @return true if the given field or local is protected by a test against a non null + * @param local the local to check + * @return true if the given local is protected by a test against a non null */ -public abstract boolean isProtectedNonNull(VariableBinding binding); +public abstract boolean isProtectedNonNull(LocalVariableBinding local); /** - * Return true if the given field or local is protected by a test against null. - * @param binding the field or local to check - * @return true if the given field or local is protected by a test against null + * Return true if the given local is protected by a test against null. + * @param local the local to check + * @return true if the given local is protected by a test against null */ -public abstract boolean isProtectedNull(VariableBinding binding); +public abstract boolean isProtectedNull(LocalVariableBinding local); /** - * Record that a field or local variable got checked to be non null. - * @param binding the checked field or local variable + * Record that a local variable got checked to be non null. + * @param local the checked local variable */ -abstract public void markAsComparedEqualToNonNull(VariableBinding binding); +abstract public void markAsComparedEqualToNonNull(LocalVariableBinding local); /** - * Record that a field or local variable got checked to be null. - * @param binding the checked field or local variable + * Record that a local variable got checked to be null. + * @param local the checked local variable */ -abstract public void markAsComparedEqualToNull(VariableBinding binding); +abstract public void markAsComparedEqualToNull(LocalVariableBinding local); /** - * Record a field or local got definitely assigned to a non-null value. + * Record a field got definitely assigned. */ - abstract public void markAsDefinitelyNonNull(VariableBinding binding); + abstract public void markAsDefinitelyAssigned(FieldBinding field); /** - * Record a field or local got definitely assigned to null. + * Record a local got definitely assigned to a non-null value. */ - abstract public void markAsDefinitelyNull(VariableBinding binding); + abstract public void markAsDefinitelyNonNull(LocalVariableBinding local); /** - * Reset all null-information about a given field or local. + * Record a local got definitely assigned to null. */ - abstract public void resetNullInfo(VariableBinding binding); + abstract public void markAsDefinitelyNull(LocalVariableBinding local); /** - * variant of {@link #resetNullInfo(VariableBinding)} for resetting null info for all fields - * Note that each fields status after the reset will become def. unknown i.e. 1001 - * Also this method does not reset constant fields - */ - abstract public void resetNullInfoForFields(); - - /** - * exclude a new field from being reset by {@link #resetNullInfoForFields()} - */ - abstract public void updateConstantFieldsMask(FieldBinding field); - - /** - * add the constant fields info from the other flow info + * Reset all null-information about a given local. */ - abstract public void addConstantFieldsMask(UnconditionalFlowInfo other); - + abstract public void resetNullInfo(LocalVariableBinding local); + /** - * Record a field or local may have got assigned to unknown (set the bit on existing info). + * Record a local may have got assigned to unknown (set the bit on existing info). */ - abstract public void markPotentiallyUnknownBit(VariableBinding binding); + abstract public void markPotentiallyUnknownBit(LocalVariableBinding local); /** - * Record a field or local may have got assigned to null (set the bit on existing info). + * Record a local may have got assigned to null (set the bit on existing info). */ - abstract public void markPotentiallyNullBit(VariableBinding binding); + abstract public void markPotentiallyNullBit(LocalVariableBinding local); /** - * Record a field or local may have got assigned to non-null (set the bit on existing info). + * Record a local may have got assigned to non-null (set the bit on existing info). */ - abstract public void markPotentiallyNonNullBit(VariableBinding binding); + abstract public void markPotentiallyNonNullBit(LocalVariableBinding local); /** - * Record a local or field got definitely assigned. + * Record a local got definitely assigned. */ - abstract public void markAsDefinitelyAssigned(VariableBinding var); + abstract public void markAsDefinitelyAssigned(LocalVariableBinding local); /** - * Record a field or local got definitely assigned to an unknown value. + * Record a local got definitely assigned to an unknown value. */ -abstract public void markAsDefinitelyUnknown(VariableBinding binding); +abstract public void markAsDefinitelyUnknown(LocalVariableBinding local); /** - * Mark the null status of the given field or local according to the given status - * @param binding + * Mark the null status of the given local according to the given status + * @param local * @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL */ -public void markNullStatus(VariableBinding binding, int nullStatus) { +public void markNullStatus(LocalVariableBinding local, int nullStatus) { switch(nullStatus) { // definite status? case FlowInfo.UNKNOWN : - markAsDefinitelyUnknown(binding); + markAsDefinitelyUnknown(local); break; case FlowInfo.NULL : - markAsDefinitelyNull(binding); + markAsDefinitelyNull(local); break; case FlowInfo.NON_NULL : - markAsDefinitelyNonNull(binding); + markAsDefinitelyNonNull(local); break; default: // collect potential status: - resetNullInfo(binding); + resetNullInfo(local); if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0) - markPotentiallyUnknownBit(binding); + markPotentiallyUnknownBit(local); if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) - markPotentiallyNullBit(binding); + markPotentiallyNullBit(local); if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0) - markPotentiallyNonNullBit(binding); + markPotentiallyNonNullBit(local); if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0) - markAsDefinitelyUnknown(binding); + markAsDefinitelyUnknown(local); } } /** - * Answer the null status of the given field or local - * @param binding + * Answer the null status of the given local + * @param local * @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL */ -public int nullStatus(VariableBinding binding) { - if (isDefinitelyUnknown(binding)) +public int nullStatus(LocalVariableBinding local) { + if (isDefinitelyUnknown(local)) return FlowInfo.UNKNOWN; - if (isDefinitelyNull(binding)) + if (isDefinitelyNull(local)) return FlowInfo.NULL; - if (isDefinitelyNonNull(binding)) + if (isDefinitelyNonNull(local)) return FlowInfo.NON_NULL; int status = 0; - if (isPotentiallyUnknown(binding)) + if (isPotentiallyUnknown(local)) status |= FlowInfo.POTENTIALLY_UNKNOWN; - if (isPotentiallyNull(binding)) + if (isPotentiallyNull(local)) status |= FlowInfo.POTENTIALLY_NULL; - if (isPotentiallyNonNull(binding)) + if (isPotentiallyNonNull(local)) status |= FlowInfo.POTENTIALLY_NON_NULL; if (status > 0) return status; @@ -624,14 +613,14 @@ abstract public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect(); * where this variable is being checked against null */ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448 -abstract public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding); +abstract public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local); /** * Returns true if the local variable being checked for was marked as null or not null * inside an assert expression due to comparison against null. */ //https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448 -abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding); +abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local); /** * Resets the definite and potential initialization info for the given local variable 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 cbf63e589..225783588 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 @@ -11,6 +11,7 @@ * bug 336428 - [compiler][null] bogus warning "redundant null check" in condition of do {} while() loop * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -18,6 +19,7 @@ import java.util.ArrayList; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.Reference; import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -48,8 +50,10 @@ public class LoopingFlowContext extends SwitchFlowContext { VariableBinding finalVariables[]; int assignCount = 0; - VariableBinding[] nullVariables; - Expression[] nullReferences; + // the following three arrays are in sync regarding their indices: + LocalVariableBinding[] nullLocals; + ASTNode[] nullReferences; // Expressions for null checking, Statements for resource analysis + // cast to Expression is safe if corresponding nullCheckType != EXIT_RESOURCE int[] nullCheckTypes; int nullCount; // see also the related field FlowContext#expectedTypes @@ -101,14 +105,14 @@ public void complainOnDeferredFinalChecks(BlockScope scope, FlowInfo flowInfo) { if (variable == null) continue; boolean complained = false; // remember if have complained on this final assignment if (variable instanceof FieldBinding) { - if (flowInfo.isPotentiallyAssigned(variable)) { + if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) { complained = true; scope.problemReporter().duplicateInitializationOfBlankFinalField( (FieldBinding) variable, this.finalAssignments[i]); } } else { - if (flowInfo.isPotentiallyAssigned(variable)) { + if (flowInfo.isPotentiallyAssigned((LocalVariableBinding)variable)) { complained = true; scope.problemReporter().duplicateInitializationOfFinalLocal( (LocalVariableBinding) variable, @@ -145,8 +149,8 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // check only immutable null checks on innermost looping context for (int i = 0; i < this.nullCount; i++) { - VariableBinding local = this.nullVariables[i]; - Expression expression = this.nullReferences[i]; + LocalVariableBinding local = this.nullLocals[i]; + ASTNode location = this.nullReferences[i]; // final local variable switch (this.nullCheckTypes[i]) { case CAN_ONLY_NON_NULL | IN_COMPARISON_NULL: @@ -155,11 +159,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn this.nullReferences[i] = null; if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(local, expression); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } } continue; @@ -171,11 +175,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn this.nullReferences[i] = null; if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(local, expression); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } } continue; @@ -184,11 +188,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn this.nullReferences[i] = null; if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNull(local, location); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, expression); + scope.problemReporter().localVariableNullComparedToNonNull(local, location); } } continue; @@ -198,32 +202,33 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: + Expression expression = (Expression)location; if (flowInfo.isDefinitelyNull(local)) { this.nullReferences[i] = null; switch(this.nullCheckTypes[i] & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); } continue; case FlowContext.IN_COMPARISON_NON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, expression); + scope.problemReporter().localVariableNullComparedToNonNull(local, expression); } continue; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(local, expression); + scope.problemReporter().localVariableRedundantNullAssignment(local, expression); continue; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(local, expression); + scope.problemReporter().localVariableNullInstanceof(local, expression); continue; } } else if (flowInfo.isPotentiallyNull(local)) { @@ -231,14 +236,14 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case FlowContext.IN_COMPARISON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; case FlowContext.IN_COMPARISON_NON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; @@ -248,26 +253,41 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case MAY_NULL: if (flowInfo.isDefinitelyNull(local)) { this.nullReferences[i] = null; - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, location); continue; } break; case ASSIGN_TO_NONNULL: - this.parent.recordNullityMismatch(scope, expression, flowInfo.nullStatus(local), this.expectedTypes[i]); + this.parent.recordNullityMismatch(scope, (Expression)location, flowInfo.nullStatus(local), this.expectedTypes[i]); + break; + case EXIT_RESOURCE: + FakedTrackingVariable trackingVar = local.closeTracker; + if (trackingVar != null) { + if (trackingVar.hasDefinitelyNoResource(flowInfo)) { + continue; // no resource - no warning. + } + if (trackingVar.isClosedInFinallyOfEnclosing(scope)) { + continue; + } + if (this.parent.recordExitAgainstResource(scope, flowInfo, trackingVar, location)) { + this.nullReferences[i] = null; + continue; + } + } break; default: // never happens } - this.parent.recordUsingNullReference(scope, local, expression, + this.parent.recordUsingNullReference(scope, local, location, this.nullCheckTypes[i], flowInfo); } } else { // check inconsistent null checks on outermost looping context for (int i = 0; i < this.nullCount; i++) { - Expression expression = this.nullReferences[i]; + ASTNode location = this.nullReferences[i]; // final local variable - VariableBinding local = this.nullVariables[i]; + LocalVariableBinding local = this.nullLocals[i]; switch (this.nullCheckTypes[i]) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: @@ -275,11 +295,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn this.nullReferences[i] = null; if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, location); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(local, expression); + scope.problemReporter().localVariableNonNullComparedToNull(local, location); } } continue; @@ -289,32 +309,33 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: + Expression expression = (Expression) location; if (flowInfo.isDefinitelyNull(local)) { this.nullReferences[i] = null; switch(this.nullCheckTypes[i] & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, expression); + scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); } continue; case FlowContext.IN_COMPARISON_NON_NULL: if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, expression); continue; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, expression); + scope.problemReporter().localVariableNullComparedToNonNull(local, expression); } continue; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(local, expression); + scope.problemReporter().localVariableRedundantNullAssignment(local, expression); continue; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(local, expression); + scope.problemReporter().localVariableNullInstanceof(local, expression); continue; } } else if (flowInfo.isPotentiallyNull(local)) { @@ -322,14 +343,14 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case FlowContext.IN_COMPARISON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; case FlowContext.IN_COMPARISON_NON_NULL: this.nullReferences[i] = null; if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, expression); + scope.problemReporter().localVariablePotentialNullReference(local, expression); continue; } break; @@ -339,12 +360,12 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn case MAY_NULL: if (flowInfo.isDefinitelyNull(local)) { this.nullReferences[i] = null; - scope.problemReporter().variableNullReference(local, expression); + scope.problemReporter().localVariableNullReference(local, location); continue; } if (flowInfo.isPotentiallyNull(local)) { this.nullReferences[i] = null; - scope.problemReporter().variablePotentialNullReference(local, expression); + scope.problemReporter().localVariablePotentialNullReference(local, location); continue; } break; @@ -352,7 +373,26 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn int nullStatus = flowInfo.nullStatus(local); if (nullStatus != FlowInfo.NON_NULL) { char[][] annotationName = scope.environment().getNonNullAnnotationName(); - scope.problemReporter().nullityMismatch(expression, this.expectedTypes[i], nullStatus, annotationName); + scope.problemReporter().nullityMismatch((Expression) location, this.expectedTypes[i], nullStatus, annotationName); + } + break; + case EXIT_RESOURCE: + nullStatus = flowInfo.nullStatus(local); + if (nullStatus != FlowInfo.NON_NULL) { + FakedTrackingVariable closeTracker = local.closeTracker; + if (closeTracker != null) { + if (closeTracker.hasDefinitelyNoResource(flowInfo)) { + continue; // no resource - no warning. + } + if (closeTracker.isClosedInFinallyOfEnclosing(scope)) { + continue; + } + nullStatus = closeTracker.findMostSpecificStatus(flowInfo, scope, null); + closeTracker.recordErrorLocation(this.nullReferences[i], nullStatus); + closeTracker.reportRecordedErrors(scope, nullStatus); + this.nullReferences[i] = null; + continue; + } } break; default: @@ -476,28 +516,46 @@ public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) return true; } -protected void recordNullReference(VariableBinding local, - Expression expression, int status) { +protected void recordNullReference(LocalVariableBinding local, + ASTNode expression, int status) { if (this.nullCount == 0) { - this.nullVariables = new VariableBinding[5]; - this.nullReferences = new Expression[5]; + this.nullLocals = new LocalVariableBinding[5]; + this.nullReferences = new ASTNode[5]; this.nullCheckTypes = new int[5]; } - else if (this.nullCount == this.nullVariables.length) { - System.arraycopy(this.nullVariables, 0, - this.nullVariables = new VariableBinding[this.nullCount * 2], 0, this.nullCount); + else if (this.nullCount == this.nullLocals.length) { + System.arraycopy(this.nullLocals, 0, + this.nullLocals = new LocalVariableBinding[this.nullCount * 2], 0, this.nullCount); System.arraycopy(this.nullReferences, 0, - this.nullReferences = new Expression[this.nullCount * 2], 0, this.nullCount); + this.nullReferences = new ASTNode[this.nullCount * 2], 0, this.nullCount); System.arraycopy(this.nullCheckTypes, 0, this.nullCheckTypes = new int[this.nullCount * 2], 0, this.nullCount); } - this.nullVariables[this.nullCount] = local; + this.nullLocals[this.nullCount] = local; this.nullReferences[this.nullCount] = expression; this.nullCheckTypes[this.nullCount++] = status; } -public void recordUsingNullReference(Scope scope, VariableBinding local, - Expression reference, int checkType, FlowInfo flowInfo) { +/** Record the fact that we see an early exit (in 'reference') while 'trackingVar' is in scope and may be unclosed. */ +public boolean recordExitAgainstResource(BlockScope scope, FlowInfo flowInfo, FakedTrackingVariable trackingVar, ASTNode reference) { + LocalVariableBinding local = trackingVar.binding; + if (flowInfo.isDefinitelyNonNull(local)) { + return false; + } + if (flowInfo.isDefinitelyNull(local)) { + scope.problemReporter().unclosedCloseable(trackingVar, reference); + return true; // handled + } + if (flowInfo.isPotentiallyNull(local)) { + scope.problemReporter().potentiallyUnclosedCloseable(trackingVar, reference); + return true; // handled + } + recordNullReference(trackingVar.binding, reference, EXIT_RESOURCE); + return true; // handled +} + +public void recordUsingNullReference(Scope scope, LocalVariableBinding local, + ASTNode location, int checkType, FlowInfo flowInfo) { if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || flowInfo.isDefinitelyUnknown(local)) { return; @@ -505,17 +563,18 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, switch (checkType) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: + Expression reference = (Expression)location; if (flowInfo.isDefinitelyNonNull(local)) { if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNonNull(local, reference); + scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNonNullComparedToNull(local, reference); + scope.problemReporter().localVariableNonNullComparedToNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); @@ -524,14 +583,14 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, } else if (flowInfo.isDefinitelyNull(local)) { if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, reference); + scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } } else { if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, reference); + scope.problemReporter().localVariableNullComparedToNonNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); @@ -564,6 +623,7 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: + reference = (Expression)location; if (flowInfo.isPotentiallyNonNull(local) || flowInfo.isPotentiallyUnknown(local) || flowInfo.isProtectedNonNull(local)) { @@ -575,11 +635,11 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableRedundantCheckOnNull(local, reference); + scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); @@ -587,34 +647,34 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, return; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, reference); return; } if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { - scope.problemReporter().variableNullComparedToNonNull(local, reference); + scope.problemReporter().localVariableNullComparedToNonNull(local, reference); } if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) { flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); } return; case FlowContext.IN_ASSIGNMENT: - scope.problemReporter().variableRedundantNullAssignment(local, reference); + scope.problemReporter().localVariableRedundantNullAssignment(local, reference); return; case FlowContext.IN_INSTANCEOF: - scope.problemReporter().variableNullInstanceof(local, reference); + scope.problemReporter().localVariableNullInstanceof(local, reference); return; } } else if (flowInfo.isPotentiallyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; case FlowContext.IN_COMPARISON_NON_NULL: if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, reference); return; } break; @@ -633,14 +693,14 @@ public void recordUsingNullReference(Scope scope, VariableBinding local, return; } if (flowInfo.isDefinitelyNull(local)) { - scope.problemReporter().variableNullReference(local, reference); + scope.problemReporter().localVariableNullReference(local, location); return; } if (flowInfo.isPotentiallyNull(local)) { - scope.problemReporter().variablePotentialNullReference(local, reference); + scope.problemReporter().localVariablePotentialNullReference(local, location); return; } - recordNullReference(local, reference, checkType); + recordNullReference(local, location, checkType); return; default: // never happens diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java index 99dd2feaa..a2abb6bc4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 IBM Corporation and others. + * Copyright (c) 2006, 2011 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,8 +11,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; /** * A degenerate form of UnconditionalFlowInfo explicitly meant to capture @@ -41,8 +40,6 @@ public class NullInfoRegistry extends UnconditionalFlowInfo { */ public NullInfoRegistry(UnconditionalFlowInfo upstream) { this.maxFieldCount = upstream.maxFieldCount; - this.constantFieldsMask = upstream.constantFieldsMask; - this.extraConstantFieldMask = upstream.extraConstantFieldMask; if ((upstream.tagBits & NULL_FLAG_MASK) != 0) { long u1, u2, u3, u4, nu2, nu3, nu4; this.nullBit2 = (u1 = upstream.nullBit1) @@ -90,8 +87,6 @@ public NullInfoRegistry add(NullInfoRegistry other) { this.nullBit2 |= other.nullBit2; this.nullBit3 |= other.nullBit3; this.nullBit4 |= other.nullBit4; - this.maxFieldCount = other.maxFieldCount; - this.addConstantFieldsMask(other); if (other.extra != null) { if (this.extra == null) { this.extra = new long[extraLength][]; @@ -121,21 +116,13 @@ public NullInfoRegistry add(NullInfoRegistry other) { return this; } -public void markAsComparedEqualToNonNull(VariableBinding local) { +public void markAsComparedEqualToNonNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; int position; - if (local instanceof FieldBinding && ((local.modifiers & AccConstant) == AccConstant)) { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields. - this.markAsDefinitelyUnknown(local); - return; - } else { - position = local.getAnalysisId(this.maxFieldCount); - } // position is zero-based - if (position < BitCacheSize) { // use bits + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // set protected non null this.nullBit1 |= (1L << position); if (COVERAGE_TEST_FLAG) { @@ -174,20 +161,13 @@ public void markAsComparedEqualToNonNull(VariableBinding local) { } } -public void markAsDefinitelyNonNull(VariableBinding local) { +public void markAsDefinitelyNonNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; int position; - if (local instanceof FieldBinding && ((local.modifiers & AccConstant) == AccConstant)) { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields. - this.markAsDefinitelyUnknown(local); - return; - } else { - position = local.getAnalysisId(this.maxFieldCount); - } - if (position < BitCacheSize) { // use bits + // position is zero-based + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // set assigned non null this.nullBit3 |= (1L << position); if (COVERAGE_TEST_FLAG) { @@ -227,21 +207,13 @@ public void markAsDefinitelyNonNull(VariableBinding local) { } // PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either // PREMATURE project protected non null onto something else -public void markAsDefinitelyNull(VariableBinding local) { +public void markAsDefinitelyNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; int position; - if (local instanceof FieldBinding && ((local.modifiers & AccConstant) == AccConstant)) { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as potential null. - this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL); - return; - } else { - position = local.getAnalysisId(this.maxFieldCount); - } // position is zero-based - if (position < BitCacheSize) { // use bits + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // set assigned null this.nullBit2 |= (1L << position); if (COVERAGE_TEST_FLAG) { @@ -280,13 +252,13 @@ public void markAsDefinitelyNull(VariableBinding local) { } } -public void markAsDefinitelyUnknown(VariableBinding local) { +public void markAsDefinitelyUnknown(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; - int position = local.getAnalysisId(this.maxFieldCount); + int position; // position is zero-based - if (position < BitCacheSize) { // use bits + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // set assigned unknown this.nullBit4 |= (1L << position); if (COVERAGE_TEST_FLAG) { @@ -435,13 +407,13 @@ public String toString(){ * Mark a local as potentially having been assigned to an unknown value. * @param local the local to mark */ -public void markPotentiallyUnknownBit(VariableBinding local) { +public void markPotentiallyUnknownBit(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = local.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ @@ -482,12 +454,12 @@ public void markPotentiallyUnknownBit(VariableBinding local) { } } -public void markPotentiallyNullBit(VariableBinding local) { +public void markPotentiallyNullBit(LocalVariableBinding local) { if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; - long mask; - int position = local.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ @@ -528,12 +500,12 @@ public void markPotentiallyNullBit(VariableBinding local) { } } -public void markPotentiallyNonNullBit(VariableBinding local) { +public void markPotentiallyNonNullBit(LocalVariableBinding local) { if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = local.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ 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 5532e4482..30b2bcf7b 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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,13 +20,11 @@ package org.eclipse.jdt.internal.compiler.flow; import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallTrackingVariable; /** @@ -92,20 +90,17 @@ public class UnconditionalFlowInfo extends FlowInfo { // extra segments public static final int extraLength = 6; - // extra bit fields for larger numbers of fields/variables - // extra[0] holds definiteInits values, extra[1] potentialInits, etc. - // lifecycle is extra == null or else all extra[]'s are allocated - // arrays which have the same size public long extra[][]; - + // extra bit fields for larger numbers of fields/variables + // extra[0] holds definiteInits values, extra[1] potentialInits, etc. + // lifecycle is extra == null or else all extra[]'s are allocated + // arrays which have the same size + public int maxFieldCount; // limit between fields and locals // Constants public static final int BitCacheSize = 64; // 64 bits in a long. public int[] nullStatusChangedInAssert; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448 - public long constantFieldsMask; // record positions of constant fields so that they don't get reset in resetNullInfoForFields() - public long extraConstantFieldMask[]; // extra mask for larger number of fields - protected static final int AccConstant = ClassFileConstants.AccStatic|ClassFileConstants.AccFinal; public FlowInfo addInitializationsFrom(FlowInfo inits) { return addInfoFrom(inits, true); @@ -535,13 +530,13 @@ public UnconditionalFlowInfo addPotentialNullInfoFrom( return this; } -final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding var) { +final public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return ( (~this.nullBit1 @@ -566,13 +561,13 @@ final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean cannotBeNull(VariableBinding var) { +final public boolean cannotBeNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return (this.nullBit1 & this.nullBit3 & ((this.nullBit2 & this.nullBit4) | ~this.nullBit2) @@ -593,13 +588,13 @@ final public boolean cannotBeNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean canOnlyBeNull(VariableBinding var) { +final public boolean canOnlyBeNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return (this.nullBit1 & this.nullBit2 & (~this.nullBit3 | ~this.nullBit4) @@ -637,8 +632,6 @@ public FlowInfo copy() { } copy.tagBits = this.tagBits; copy.maxFieldCount = this.maxFieldCount; - copy.constantFieldsMask = this.constantFieldsMask; - copy.extraConstantFieldMask = this.extraConstantFieldMask; if (this.extra != null) { int length; copy.extra = new long[extraLength][]; @@ -756,47 +749,32 @@ final public boolean isDefinitelyAssigned(FieldBinding field) { if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0) { return true; } - //{ObjectTeams: if it is copied don't require definite assignment again - if (field.copyInheritanceSrc != null) - return true; - // SH} - return isDefinitelyAssigned(field.getAnalysisId(this.maxFieldCount)); +//{ObjectTeams: if it is copied don't require definite assignment again + if (field.copyInheritanceSrc != null) + return true; +// SH} + return isDefinitelyAssigned(field.id); } -final public boolean isDefinitelyAssigned(LocalVariableBinding var) { +final public boolean isDefinitelyAssigned(LocalVariableBinding local) { // do not want to complain in unreachable code if local declared in reachable code - if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0 && (var.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) { + if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0 && (local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) { return true; } - return isDefinitelyAssigned(var.id + this.maxFieldCount); -} - -final public boolean isDefinitelyAssigned(VariableBinding var) { - if (var instanceof FieldBinding) { - return this.isDefinitelyAssigned((FieldBinding)var); - } else { - return this.isDefinitelyAssigned((LocalVariableBinding)var); - } + return isDefinitelyAssigned(local.id + this.maxFieldCount); } -final public boolean isDefinitelyNonNull(VariableBinding var) { - boolean isField = var instanceof FieldBinding; - if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) { - // no local yet in scope. Came here because of a field being queried for non null - // will only happen for final fields, since they are assigned in a constructor or static block - // and we may currently be in some other method - this.tagBits |= NULL_FLAG_MASK; - } +final public boolean isDefinitelyNonNull(LocalVariableBinding local) { // do not want to complain in unreachable code if ((this.tagBits & UNREACHABLE) != 0 || (this.tagBits & NULL_FLAG_MASK) == 0) { return false; } - if ((var.type.tagBits & TagBits.IsBaseType) != 0 || - var.constant() != Constant.NotAConstant) { // String instances + if ((local.type.tagBits & TagBits.IsBaseType) != 0 || + local.constant() != Constant.NotAConstant) { // String instances return true; } - int position = var.getAnalysisId(this.maxFieldCount); + int position = local.id + this.maxFieldCount; if (position < BitCacheSize) { // use bits return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4)) & (1L << position)) != 0; @@ -815,21 +793,14 @@ final public boolean isDefinitelyNonNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean isDefinitelyNull(VariableBinding var) { - boolean isField = var instanceof FieldBinding; - if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) { - // no local yet in scope. Came here because of a field being queried for non null - // will only happen for final fields, since they are assigned in a constructor or static block - // and we may currently be in some other method - this.tagBits |= NULL_FLAG_MASK; - } +final public boolean isDefinitelyNull(LocalVariableBinding local) { // do not want to complain in unreachable code if ((this.tagBits & UNREACHABLE) != 0 || (this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); + int position = local.id + this.maxFieldCount; if (position < BitCacheSize) { // use bits return ((this.nullBit1 & this.nullBit2 & (~this.nullBit3 | ~this.nullBit4)) @@ -849,13 +820,13 @@ final public boolean isDefinitelyNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean isDefinitelyUnknown(VariableBinding var) { +final public boolean isDefinitelyUnknown(LocalVariableBinding local) { // do not want to complain in unreachable code if ((this.tagBits & UNREACHABLE) != 0 || (this.tagBits & NULL_FLAG_MASK) == 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); + int position = local.id + this.maxFieldCount; if (position < BitCacheSize) { // use bits return ((this.nullBit1 & this.nullBit4 & ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0; @@ -904,7 +875,7 @@ final private boolean isPotentiallyAssigned(int position) { } final public boolean isPotentiallyAssigned(FieldBinding field) { - return isPotentiallyAssigned(field.getAnalysisId(this.maxFieldCount)); + return isPotentiallyAssigned(field.id); } final public boolean isPotentiallyAssigned(LocalVariableBinding local) { @@ -915,22 +886,14 @@ final public boolean isPotentiallyAssigned(LocalVariableBinding local) { return isPotentiallyAssigned(local.id + this.maxFieldCount); } -final public boolean isPotentiallyAssigned(VariableBinding var) { - if (var instanceof FieldBinding) { - return this.isPotentiallyAssigned((FieldBinding)var); - } else { - return this.isPotentiallyAssigned((LocalVariableBinding)var); - } -} - // TODO (Ayush) Check why this method does not return true for protected non null (1111) -final public boolean isPotentiallyNonNull(VariableBinding var) { +final public boolean isPotentiallyNonNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { // use bits + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2)) & (1L << position)) != 0; @@ -950,13 +913,13 @@ final public boolean isPotentiallyNonNull(VariableBinding var) { } // TODO (Ayush) Check why this method does not return true for protected null -final public boolean isPotentiallyNull(VariableBinding var) { +final public boolean isPotentiallyNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3)) & (1L << position)) != 0; @@ -975,13 +938,13 @@ final public boolean isPotentiallyNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean isPotentiallyUnknown(VariableBinding var) { +final public boolean isPotentiallyUnknown(LocalVariableBinding local) { // do not want to complain in unreachable code if ((this.tagBits & UNREACHABLE) != 0 || (this.tagBits & NULL_FLAG_MASK) == 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); + int position = local.id + this.maxFieldCount; if (position < BitCacheSize) { // use bits return (this.nullBit4 & (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3) @@ -1002,13 +965,14 @@ final public boolean isPotentiallyUnknown(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean isProtectedNonNull(VariableBinding var) { +final public boolean isProtectedNonNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { // use bits + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0; } // use extra vector @@ -1026,13 +990,13 @@ final public boolean isProtectedNonNull(VariableBinding var) { & (1L << (position % BitCacheSize))) != 0; } -final public boolean isProtectedNull(VariableBinding var) { +final public boolean isProtectedNull(LocalVariableBinding local) { if ((this.tagBits & NULL_FLAG_MASK) == 0 || - (var.type.tagBits & TagBits.IsBaseType) != 0) { + (local.type.tagBits & TagBits.IsBaseType) != 0) { return false; } - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits return (this.nullBit1 & this.nullBit2 & (this.nullBit3 ^ this.nullBit4) @@ -1065,27 +1029,15 @@ protected static boolean isTrue(boolean expression, String message) { throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$ return expression; } -public void markAsComparedEqualToNonNull(VariableBinding var) { +public void markAsComparedEqualToNonNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; int position; - if (var instanceof FieldBinding) { - if ((var.modifiers & AccConstant) == AccConstant) { - position = var.getAnalysisId(this.maxFieldCount); - } else { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields - this.markAsDefinitelyUnknown(var); - return; - } - } else { - position = var.id + this.maxFieldCount; - } long mask; long a1, a2, a3, a4, na2; // position is zero-based - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits if (((mask = 1L << position) & (a1 = this.nullBit1) @@ -1174,26 +1126,14 @@ public void markAsComparedEqualToNonNull(VariableBinding var) { } } -public void markAsComparedEqualToNull(VariableBinding var) { +public void markAsComparedEqualToNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; int position; long mask; // position is zero-based - if (var instanceof FieldBinding) { - if ((var.modifiers & AccConstant) == AccConstant) { - position = var.getAnalysisId(this.maxFieldCount); - } else { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as potential null. - this.markNullStatus(var, FlowInfo.POTENTIALLY_NULL); - return; - } - } else { - position = var.id + this.maxFieldCount; - } - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits if (((mask = 1L << position) & this.nullBit1) != 0) { if ((mask @@ -1314,31 +1254,24 @@ final private void markAsDefinitelyAssigned(int position) { } } -public void markAsDefinitelyAssigned(VariableBinding var) { +public void markAsDefinitelyAssigned(FieldBinding field) { if (this != DEAD_END) - markAsDefinitelyAssigned(var.getAnalysisId(this.maxFieldCount)); + markAsDefinitelyAssigned(field.id); } -public void markAsDefinitelyNonNull(VariableBinding var) { +public void markAsDefinitelyAssigned(LocalVariableBinding local) { + if (this != DEAD_END) + markAsDefinitelyAssigned(local.id + this.maxFieldCount); +} + +public void markAsDefinitelyNonNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; long mask; int position; // position is zero-based - if (var instanceof FieldBinding) { - if ((var.modifiers & AccConstant) == AccConstant) { - position = var.getAnalysisId(this.maxFieldCount); - } else { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields. - this.markAsDefinitelyUnknown(var); - return; - } - } else { - position = var.id + this.maxFieldCount; - } - if (position < BitCacheSize) { // use bits + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // set assigned non null this.nullBit1 |= (mask = 1L << position); this.nullBit3 |= mask; @@ -1385,26 +1318,14 @@ public void markAsDefinitelyNonNull(VariableBinding var) { } } -public void markAsDefinitelyNull(VariableBinding var) { +public void markAsDefinitelyNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; long mask; int position; // position is zero-based - if (var instanceof FieldBinding) { - if ((var.modifiers & AccConstant) == AccConstant) { - position = var.getAnalysisId(this.maxFieldCount); - } else { - // non-final fields may be modified in separate threads and we cannot be sure about their - // definite nullness. Hence, marking as potential null. - this.markNullStatus(var, FlowInfo.POTENTIALLY_NULL); - return; - } - } else { - position = var.id + this.maxFieldCount; - } - if (position < BitCacheSize) { // use bits + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // mark assigned null this.nullBit1 |= (mask = 1L << position); this.nullBit2 |= mask; @@ -1453,17 +1374,18 @@ public void markAsDefinitelyNull(VariableBinding var) { /** * Mark a local as having been assigned to an unknown value. - * @param var the local to mark + * @param local the local to mark */ // PREMATURE may try to get closer to markAsDefinitelyAssigned, but not // obvious -public void markAsDefinitelyUnknown(VariableBinding var) { +public void markAsDefinitelyUnknown(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; long mask; - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + int position; + // position is zero-based + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits // mark assigned null this.nullBit1 |= (mask = 1L << position); @@ -1511,12 +1433,12 @@ public void markAsDefinitelyUnknown(VariableBinding var) { } } -public void resetNullInfo(VariableBinding var) { +public void resetNullInfo(LocalVariableBinding local) { if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits this.nullBit1 &= (mask = ~(1L << position)); this.nullBit2 &= mask; @@ -1539,132 +1461,17 @@ public void resetNullInfo(VariableBinding var) { } } -public void resetNullInfoForFields() { - if (this != DEAD_END) { - long mask = this.maxFieldCount < BitCacheSize ? (-1L << this.maxFieldCount) : 0L; - mask |= this.constantFieldsMask; - // first reset normal bits: - this.nullBit1 |= ~mask; - this.nullBit2 &= mask; - this.nullBit3 &= mask; - this.nullBit4 |= ~mask; - if (this.maxFieldCount >= BitCacheSize && this.extra != null) { - // use extra vector - int localsStartIndex = this.maxFieldCount/BitCacheSize - 1; - int localsStartOffset = this.maxFieldCount % BitCacheSize; - int len = Math.min(localsStartIndex+1, this.extra[2].length); - if (this.extraConstantFieldMask != null){ - for (int vectorIndex = 0; vectorIndex < len; vectorIndex++) { - if (vectorIndex >= this.extraConstantFieldMask.length) { - // no constant fields after this, just mask all fields - if (vectorIndex == localsStartIndex) { - // some locals, some fields at this vectorIndex - mask = -1L << localsStartOffset; - } else { - // all fields here - mask = 0L; - } - } else { - if (vectorIndex == localsStartIndex) { - // some locals, some fields at this vectorIndex - mask = ((-1 << localsStartOffset) | this.extraConstantFieldMask[vectorIndex]); - } else { - // all fields here - mask = 0L | this.extraConstantFieldMask[vectorIndex]; - } - - } - this.extra[2][vectorIndex] - |= ~mask; - this.extra[3][vectorIndex] &= mask; - this.extra[4][vectorIndex] &= mask; - this.extra[5][vectorIndex] |= ~mask; - } - } else { - // no constant fields - for (int vectorIndex = 0; vectorIndex < len; vectorIndex++) { - if (vectorIndex == localsStartIndex) { - // some locals, some fields at this vectorIndex - mask = -1L << localsStartOffset; - } else { - // all fields here - mask = 0L; - } - this.extra[2][vectorIndex] - |= ~mask; - this.extra[3][vectorIndex] &= mask; - this.extra[4][vectorIndex] &= mask; - this.extra[5][vectorIndex] |= ~mask; - } - } - } - } -} - -public void updateConstantFieldsMask(FieldBinding field) { - int position = field.getAnalysisId(this.maxFieldCount); - long mask = 1L << (position % BitCacheSize); - if (position < BitCacheSize) { - this.constantFieldsMask |= 1L << position; // exclude this field from being reset - } else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extraConstantFieldMask == null) { - // extra array not created. Create constant field mask bit streams. - int length = vectorIndex + 1; - this.extraConstantFieldMask = new long[length]; - } - else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extraConstantFieldMask.length)) { - System.arraycopy(this.extraConstantFieldMask, 0, (this.extraConstantFieldMask = new long[vectorIndex + 1]), 0, oldLength); - } - } - this.extraConstantFieldMask[vectorIndex] |= mask; // exclude this field from resetNullInfoForFields - } -} - -/** - * All the infos originate in TypeDeclaration.analyseCode(). So making sure that this method is called for every info that is sent into - * methods/constructors should be sufficient - */ -public void addConstantFieldsMask(UnconditionalFlowInfo other) { - this.constantFieldsMask |= other.constantFieldsMask; - if (other.extraConstantFieldMask != null) { - int oldLength = 0; - int otherLen = other.extraConstantFieldMask.length; - if (this.extraConstantFieldMask != null) { - oldLength = this.extraConstantFieldMask.length; - if (otherLen > (oldLength = this.extraConstantFieldMask.length)) { - System.arraycopy(this.extraConstantFieldMask, 0, (this.extraConstantFieldMask = new long[otherLen]), 0, oldLength); - for (int i = 0; i < oldLength; i++) { - this.extraConstantFieldMask[i] |= other.extraConstantFieldMask[i]; - } - } else { - for (int i = 0; i < otherLen; i++) { - this.extraConstantFieldMask[i] |= other.extraConstantFieldMask[i]; - } - } - } else { - this.extraConstantFieldMask = new long[otherLen]; - } - for (int i = oldLength; i < otherLen; i++) { - this.extraConstantFieldMask[i] = other.extraConstantFieldMask[i]; - } - } -} - /** * Mark a local as potentially having been assigned to an unknown value. - * @param var the local to mark + * @param local the local to mark */ -public void markPotentiallyUnknownBit(VariableBinding var) { +public void markPotentiallyUnknownBit(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ @@ -1706,12 +1513,12 @@ public void markPotentiallyUnknownBit(VariableBinding var) { } } -public void markPotentiallyNullBit(VariableBinding var) { +public void markPotentiallyNullBit(LocalVariableBinding local) { if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ @@ -1753,12 +1560,12 @@ public void markPotentiallyNullBit(VariableBinding var) { } } -public void markPotentiallyNonNullBit(VariableBinding var) { +public void markPotentiallyNonNullBit(LocalVariableBinding local) { if (this != DEAD_END) { this.tagBits |= NULL_FLAG_MASK; + int position; long mask; - int position = var.getAnalysisId(this.maxFieldCount); - if (position < BitCacheSize) { + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits mask = 1L << position; isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ @@ -2115,8 +1922,6 @@ public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() { copy.tagBits = this.tagBits & ~NULL_FLAG_MASK; copy.maxFieldCount = this.maxFieldCount; copy.nullStatusChangedInAssert = this.nullStatusChangedInAssert; - copy.constantFieldsMask = this.constantFieldsMask; - copy.extraConstantFieldMask = this.extraConstantFieldMask; if (this.extra != null) { int length; copy.extra = new long[extraLength][]; @@ -2239,8 +2044,6 @@ public UnconditionalFlowInfo unconditionalFieldLessCopy() { UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); copy.tagBits = this.tagBits; copy.maxFieldCount = this.maxFieldCount; - copy.constantFieldsMask = this.constantFieldsMask; - copy.extraConstantFieldMask = this.extraConstantFieldMask; int limit = this.maxFieldCount; if (limit < BitCacheSize) { long mask; @@ -2295,8 +2098,8 @@ public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() { return this; } -public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) { - int position = binding.getAnalysisId(this.maxFieldCount); +public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) { + int position = local.id + this.maxFieldCount; int oldLength; if (this.nullStatusChangedInAssert == null) { this.nullStatusChangedInAssert = new int[position + 1]; @@ -2309,8 +2112,8 @@ public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) { this.nullStatusChangedInAssert[position] = 1; } -public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding) { - int position = binding.getAnalysisId(this.maxFieldCount); +public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) { + int position = local.id + this.maxFieldCount; if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) { return false; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index 3d3e18c79..72ca121f2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -15,6 +15,8 @@ * bug 295551 - Add option to automatically promote all warnings to errors * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking + * bug 370639 - [compiler][resource] restore the default for resource leak warnings + * bug 366063 - Compiler should not add synthetic @NonNull annotations *******************************************************************************/ package org.eclipse.jdt.internal.compiler.impl; @@ -147,7 +149,6 @@ public class CompilerOptions { public static final String OPTION_ReportTasks = "org.eclipse.jdt.core.compiler.problem.tasks"; //$NON-NLS-1$ public static final String OPTION_ReportUnusedObjectAllocation = "org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation"; //$NON-NLS-1$ public static final String OPTION_IncludeNullInfoFromAsserts = "org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts"; //$NON-NLS-1$ - public static final String OPTION_IncludeFieldsInNullAnalysis = "org.eclipse.jdt.core.compiler.problem.includeFieldsInNullAnalysis"; //$NON-NLS-1$ public static final String OPTION_ReportMethodCanBeStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic"; //$NON-NLS-1$ public static final String OPTION_ReportMethodCanBePotentiallyStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ public static final String OPTION_ReportRedundantSpecificationOfTypeArguments = "org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments"; //$NON-NLS-1$ @@ -490,8 +491,6 @@ public class CompilerOptions { public boolean ignoreMethodBodies; /** Raise null related warnings for variables tainted inside an assert statement (java 1.4 and above)*/ public boolean includeNullInfoFromAsserts; - /** Specify if fields are to be included in null analysis */ - public boolean includeFieldsInNullAnalysis; /** Controls whether forced generic type problems get reported */ public boolean reportUnavoidableGenericTypeProblems; @@ -514,7 +513,9 @@ public class CompilerOptions { /** Fully qualified name of annotation to use as marker for default nonnull. */ public char[][] nonNullByDefaultAnnotationName; /** TagBits-encoded default for non-annotated types. */ - public long defaultNonNullness; // 0 or TagBits#AnnotationNonNull + public long intendedDefaultNonNullness; // 0 or TagBits#AnnotationNonNull + /** Should resources (objects of type Closeable) be analysed for matching calls to close()? */ + public boolean analyseResourceLeaks; // keep in sync with warningTokenToIrritant and warningTokenFromIrritant public final static String[] warningTokens = { @@ -1364,7 +1365,6 @@ public class CompilerOptions { optionsMap.put(OPTION_ReportTasks, getSeverityString(Tasks)); optionsMap.put(OPTION_ReportUnusedObjectAllocation, getSeverityString(UnusedObjectAllocation)); optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED); - optionsMap.put(OPTION_IncludeFieldsInNullAnalysis, this.includeFieldsInNullAnalysis ? ENABLED : DISABLED); optionsMap.put(OPTION_ReportMethodCanBeStatic, getSeverityString(MethodCanBeStatic)); optionsMap.put(OPTION_ReportMethodCanBePotentiallyStatic, getSeverityString(MethodCanBePotentiallyStatic)); optionsMap.put(OPTION_ReportRedundantSpecificationOfTypeArguments, getSeverityString(RedundantSpecificationOfTypeArguments)); @@ -1411,7 +1411,7 @@ public class CompilerOptions { optionsMap.put(OPTION_NullableAnnotationName, String.valueOf(CharOperation.concatWith(this.nullableAnnotationName, '.'))); optionsMap.put(OPTION_NonNullAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullAnnotationName, '.'))); optionsMap.put(OPTION_NonNullByDefaultAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullByDefaultAnnotationName, '.'))); - if (this.defaultNonNullness == TagBits.AnnotationNonNull) + if (this.intendedDefaultNonNullness == TagBits.AnnotationNonNull) optionsMap.put(OPTION_NonNullIsDefault, CompilerOptions.ENABLED); else optionsMap.put(OPTION_NonNullIsDefault, CompilerOptions.DISABLED); @@ -1566,14 +1566,13 @@ public class CompilerOptions { // allow null info from asserts to be considered downstream by default this.includeNullInfoFromAsserts = false; - // null analysis for fields - this.includeFieldsInNullAnalysis = false; - this.isAnnotationBasedNullAnalysisEnabled = false; this.nullableAnnotationName = DEFAULT_NULLABLE_ANNOTATION_NAME; this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME; this.nonNullByDefaultAnnotationName = DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME; - this.defaultNonNullness = 0; + this.intendedDefaultNonNullness = 0; + + this.analyseResourceLeaks = true; } public void set(Map optionsMap) { @@ -1794,13 +1793,6 @@ public class CompilerOptions { this.includeNullInfoFromAsserts = false; } } - if ((optionValue = optionsMap.get(OPTION_IncludeFieldsInNullAnalysis)) != null) { - if (ENABLED.equals(optionValue)) { - this.includeFieldsInNullAnalysis = true; - } else if (DISABLED.equals(optionValue)) { - this.includeFieldsInNullAnalysis = false; - } - } if ((optionValue = optionsMap.get(OPTION_ReportMethodWithConstructorName)) != null) updateSeverity(MethodWithConstructorName, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportOverridingPackageDefaultMethod)) != null) updateSeverity(OverriddenPackageDefaultMethod, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportDeprecation)) != null) updateSeverity(UsingDeprecatedAPI, optionValue); @@ -1864,6 +1856,13 @@ public class CompilerOptions { if ((optionValue = optionsMap.get(OPTION_ReportUnclosedCloseable)) != null) updateSeverity(UnclosedCloseable, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportPotentiallyUnclosedCloseable)) != null) updateSeverity(PotentiallyUnclosedCloseable, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportExplicitlyClosedAutoCloseable)) != null) updateSeverity(ExplicitlyClosedAutoCloseable, optionValue); + if (getSeverity(UnclosedCloseable) == ProblemSeverities.Ignore + && getSeverity(PotentiallyUnclosedCloseable) == ProblemSeverities.Ignore + && getSeverity(ExplicitlyClosedAutoCloseable) == ProblemSeverities.Ignore) { + this.analyseResourceLeaks = false; + } else { + this.analyseResourceLeaks = true; + } //{ObjectTeams: if ((optionValue = optionsMap.get(OPTION_ReportNotExactlyOneBasecall)) != null) updateSeverity(NotExactlyOneBasecall, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportBaseclassCycle)) != null) updateSeverity(BaseclassCycle, optionValue); @@ -1939,9 +1938,9 @@ public class CompilerOptions { } if ((optionValue = optionsMap.get(OPTION_NonNullIsDefault)) != null) { if (CompilerOptions.ENABLED.equals(optionValue)) - this.defaultNonNullness = TagBits.AnnotationNonNull; + this.intendedDefaultNonNullness = TagBits.AnnotationNonNull; else if (CompilerOptions.DISABLED.equals(optionValue)) - this.defaultNonNullness = 0; + this.intendedDefaultNonNullness = 0; } } @@ -2138,7 +2137,6 @@ public class CompilerOptions { buf.append("\n\t- missing @Deprecated annotation: ").append(getSeverityString(MissingDeprecatedAnnotation)); //$NON-NLS-1$ buf.append("\n\t- incomplete enum switch: ").append(getSeverityString(IncompleteEnumSwitch)); //$NON-NLS-1$ buf.append("\n\t- raise null related warnings for variables tainted in assert statements: ").append(this.includeNullInfoFromAsserts ? ENABLED : DISABLED); //$NON-NLS-1$ - buf.append("\n\t- include fields in null analysis: ").append(this.includeFieldsInNullAnalysis ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- suppress warnings: ").append(this.suppressWarnings ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- suppress optional errors: ").append(this.suppressOptionalErrors ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- unhandled warning token: ").append(getSeverityString(UnhandledWarningToken)); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java index ef5f4a242..aa76152ec 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ * Stephan Herrmann - Contributions for * bug 349326 - [1.7] new warning for missing try-with-resources * bug 186342 - [compiler][null] Using annotations for null checking + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.impl; @@ -180,6 +181,7 @@ public class IrritantSet { .set( CompilerOptions.DeadCode |CompilerOptions.Tasks + |CompilerOptions.UnclosedCloseable |CompilerOptions.NullSpecInsufficientInfo |CompilerOptions.RedundantNullAnnotation); // default errors IF AnnotationBasedNullAnalysis is enabled: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index 1648cff86..4af69a35d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -15,6 +15,7 @@ * bug 364890 - BinaryTypeBinding should use char constants from Util * bug 365387 - [compiler][null] bug 186342: Issues to follow up post review and verification. * bug 358903 - Filter practically unimportant resource leak warnings + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -552,6 +553,11 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { } } + // need type annotations before processing methods (for @NonNullByDefault) + if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { + scanTypeForNullDefaultAnnotation(binaryType); + } + if (needFieldsAndMethods) { createFields(binaryType.getFields(), sourceLevel, missingTypeNames); createMethods(binaryType.getMethods(), sourceLevel, missingTypeNames); @@ -581,14 +587,6 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { // SH} if (this.environment.globalOptions.storeAnnotations) setAnnotations(createAnnotations(binaryType.getAnnotations(), this.environment, missingTypeNames)); - - if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled - && CharOperation.equals(TypeConstants.PACKAGE_INFO_NAME, binaryType.getSourceName())) - { - // only for package-info.java can type-level null-annotations (i.e., @NonNullByDefault) - // on a binary type influence the compilation - scanPackageInfoForNullDefaultAnnotation(binaryType); - } } finally { // protect against incorrect use of the needFieldsAndMethods flag, see 48459 if (this.fields == null) @@ -1586,65 +1584,93 @@ void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding methodBindi return; char[][] nullableAnnotationName = this.environment.getNullableAnnotationName(); char[][] nonNullAnnotationName = this.environment.getNonNullAnnotationName(); - if (nullableAnnotationName == null || nonNullAnnotationName == null) + char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName(); + if (nullableAnnotationName == null || nonNullAnnotationName == null || nonNullByDefaultAnnotationName == null) return; // not well-configured to use null annotations + int currentDefault = NO_NULL_DEFAULT; + if ((this.tagBits & TagBits.AnnotationNonNullByDefault) != 0) { + currentDefault = NONNULL_BY_DEFAULT; + } else if ((this.tagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) { + currentDefault = NULL_UNSPECIFIED_BY_DEFAULT; + } + // return: IBinaryAnnotation[] annotations = method.getAnnotations(); + boolean explicitNullness = false; if (annotations != null) { for (int i = 0; i < annotations.length; i++) { char[] annotationTypeName = annotations[i].getTypeName(); if (annotationTypeName[0] != Util.C_RESOLVED) continue; char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' - if (CharOperation.equals(typeName, nonNullAnnotationName)) { + if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) { + methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault; + currentDefault = NONNULL_BY_DEFAULT; + } + if (!explicitNullness && CharOperation.equals(typeName, nonNullAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNonNull; - break; + explicitNullness = true; } - if (CharOperation.equals(typeName, nullableAnnotationName)) { + if (!explicitNullness && CharOperation.equals(typeName, nullableAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNullable; - break; + explicitNullness = true; } } } + if (!explicitNullness && currentDefault == NONNULL_BY_DEFAULT) { + methodBinding.tagBits |= TagBits.AnnotationNonNull; + } // parameters: TypeBinding[] parameters = methodBinding.parameters; int numVisibleParams = parameters.length; int numParamAnnotations = method.getAnnotatedParametersCount(); - if (numParamAnnotations > 0) { - int startIndex = numParamAnnotations - numVisibleParams; + if (numParamAnnotations > 0 || currentDefault == NONNULL_BY_DEFAULT) { for (int j = 0; j < numVisibleParams; j++) { - IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex); - if (paramAnnotations != null) { - for (int i = 0; i < paramAnnotations.length; i++) { - char[] annotationTypeName = paramAnnotations[i].getTypeName(); - if (annotationTypeName[0] != Util.C_RESOLVED) - continue; - char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' - if (CharOperation.equals(typeName, nonNullAnnotationName)) { - if (methodBinding.parameterNonNullness == null) - methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; - methodBinding.parameterNonNullness[j] = Boolean.TRUE; - break; - } else if (CharOperation.equals(typeName, nullableAnnotationName)) { - if (methodBinding.parameterNonNullness == null) - methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; - methodBinding.parameterNonNullness[j] = Boolean.FALSE; - break; + explicitNullness = false; + if (numParamAnnotations > 0) { + int startIndex = numParamAnnotations - numVisibleParams; + IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex); + if (paramAnnotations != null) { + for (int i = 0; i < paramAnnotations.length; i++) { + char[] annotationTypeName = paramAnnotations[i].getTypeName(); + if (annotationTypeName[0] != Util.C_RESOLVED) + continue; + char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' + if (CharOperation.equals(typeName, nonNullAnnotationName)) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.TRUE; + explicitNullness = true; + break; + } else if (CharOperation.equals(typeName, nullableAnnotationName)) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.FALSE; + explicitNullness = true; + break; + } } } } + if (!explicitNullness && currentDefault == NONNULL_BY_DEFAULT) { + if (methodBinding.parameterNonNullness == null) + methodBinding.parameterNonNullness = new Boolean[numVisibleParams]; + methodBinding.parameterNonNullness[j] = Boolean.TRUE; + } } } } -void scanPackageInfoForNullDefaultAnnotation(IBinaryType binaryType) { +void scanTypeForNullDefaultAnnotation(IBinaryType binaryType) { char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName(); if (nonNullByDefaultAnnotationName == null) return; // not well-configured to use null annotations IBinaryAnnotation[] annotations = binaryType.getAnnotations(); if (annotations != null) { + long annotationBit = 0L; + int nullness = NO_NULL_DEFAULT; int length = annotations.length; for (int i = 0; i < length; i++) { char[] annotationTypeName = annotations[i].getTypeName(); @@ -1659,13 +1685,28 @@ void scanPackageInfoForNullDefaultAnnotation(IBinaryType binaryType) { && !((BooleanConstant)value).booleanValue()) { // parameter is 'false': this means we cancel defaults from outer scopes: - this.getPackage().nullnessDefaultAnnotation = ReferenceBinding.NULL_UNSPECIFIED; - return; + annotationBit = TagBits.AnnotationNullUnspecifiedByDefault; + nullness = NULL_UNSPECIFIED_BY_DEFAULT; + break; } } - this.getPackage().nullnessDefaultAnnotation = - this.environment.getNullAnnotationBinding(TagBits.AnnotationNonNull, false/*resolve*/); - return; + annotationBit = TagBits.AnnotationNonNullByDefault; + nullness = NONNULL_BY_DEFAULT; + break; + } + } + if (annotationBit != 0L) { + this.tagBits |= annotationBit; + if (CharOperation.equals(this.sourceName(), TypeConstants.PACKAGE_INFO_NAME)) + this.getPackage().defaultNullness = nullness; + } else { + switch (this.getPackage().defaultNullness) { + case NONNULL_BY_DEFAULT : + this.tagBits |= TagBits.AnnotationNonNullByDefault; + break; + case NULL_UNSPECIFIED_BY_DEFAULT : + this.tagBits |= TagBits.AnnotationNullUnspecifiedByDefault; + break; } } } 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 ea41433e6..f4c04c2ff 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 @@ -10,6 +10,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 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -68,6 +70,11 @@ public abstract class Binding { public static final MethodBinding[] UNINITIALIZED_METHODS = new MethodBinding[0]; public static final ReferenceBinding[] UNINITIALIZED_REFERENCE_TYPES = new ReferenceBinding[0]; + // Nullness defaults: + public static final int NO_NULL_DEFAULT = 0; + public static final int NULL_UNSPECIFIED_BY_DEFAULT = 1; + public static final int NONNULL_BY_DEFAULT = 2; + /* * Answer the receiver's binding type from Binding.BindingID. */ 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 ba128f166..5df6a31d1 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 @@ -14,6 +14,8 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * bug 358903 - Filter practically unimportant resource leak warnings + * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK + * bug 370639 - [compiler][resource] restore the default for resource leak warnings *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -28,6 +30,7 @@ import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.WrapperKind; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; @@ -1156,11 +1159,12 @@ public void pruneWrapperTrackingVar(FakedTrackingVariable trackingVariable) { * At the end of a block check the closing-status of all tracked closeables that are declared in this block. * Also invoked when entering unreachable code. */ -public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location, BlockScope locationScope) { +public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, ASTNode location, BlockScope locationScope) { + if (!compilerOptions().analyseResourceLeaks) return; if (this.trackingVariables == null) { // at a method return we also consider enclosing scopes if (location != null && this.parent instanceof BlockScope) - ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, location, locationScope); + ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, flowContext, location, locationScope); return; } if (location != null && flowInfo.reachMode() != 0) return; @@ -1177,9 +1181,14 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location, BlockSc continue; } - if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding)) - continue; // reporting against a specific location, resource is null at this flow, don't complain - + if (location != null && trackingVar.hasDefinitelyNoResource(flowInfo)) { + continue; // reporting against a specific location, there is no resource at this flow, don't complain + } + + if (location != null && flowContext != null && flowContext.recordExitAgainstResource(this, flowInfo, trackingVar, location)) { + continue; // handled by the flow context + } + // compute the most specific null status for this resource, int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope); 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 b82025b21..f8ec700ab 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 @@ -139,6 +139,7 @@ public class ClassScope extends Scope { public TypeDeclaration referenceContext; public TypeReference superTypeReference; java.util.ArrayList deferredBoundChecks; + public ClassScope(Scope parent, TypeDeclaration context) { super(Scope.CLASS_SCOPE, parent); this.referenceContext = context; @@ -179,7 +180,6 @@ public class ClassScope extends Scope { } } } - this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex; connectMemberTypes(); buildFieldsAndMethods(); //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies): @@ -271,7 +271,6 @@ public class ClassScope extends Scope { // remove duplicate fields if (count != fieldBindings.length) System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); - sourceType.cumulativeFieldCount += count; sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type sourceType.setFields(fieldBindings); } @@ -412,7 +411,6 @@ public class ClassScope extends Scope { checkParameterizedTypeBounds(); checkParameterizedSuperTypeCollisions(); } - this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex; buildFieldsAndMethods(); //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies). if (this.referenceContext.isRole()) { @@ -842,8 +840,6 @@ public class ClassScope extends Scope { fieldDeclaration, null, fieldDeclaration.modifiers|ExtraCompilerModifiers.AccUnresolved, sourceType); sourceType.addField(fieldBinding); - sourceType.cumulativeFieldCount++; - this.referenceContext.updateMaxFieldCount(); checkAndSetModifiersForField(fieldBinding, fieldDeclaration); // FIXME(SH): does this improve robustness? diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java index 5d20c1d42..28818d76a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -351,13 +351,6 @@ public long getAnnotationTagBits() { return originalField.tagBits; } -public int getAnalysisId(int maxFieldCount) { - TypeBinding original = this.declaringClass.original(); - if (original instanceof SourceTypeBinding) - return ((SourceTypeBinding)original).fieldAnalysisOffset + this.id; - return this.id; -} - public final boolean isDefault() { return !isPublic() && !isProtected() && !isPrivate(); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index 8951528e0..8e8fa9446 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -12,6 +12,7 @@ * Stephan Herrmann - contributions for * bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment * bug 186342 - [compiler][null] Using annotations for null checking + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -1301,59 +1302,6 @@ public char[][] getNonNullByDefaultAnnotationName() { return this.globalOptions.nonNullByDefaultAnnotationName; } -/** - * Answer the type binding representing the null-annotation identified by the given tag bits. - * @param annotationTagBit tag bits potentially denoting a null-annotation - * @param resolve should the resulting type binding be resolved? - * @return the corresponding annotation type binding - * or <code>null</code> if no annotation bits are contained in the given tag bits. - */ -public TypeBinding getNullAnnotationBinding(long annotationTagBit, boolean resolve) { - char[][] name = null; - if (annotationTagBit == TagBits.AnnotationNonNull) - name = getNonNullAnnotationName(); - else if (annotationTagBit == TagBits.AnnotationNullable) - name = getNullableAnnotationName(); - else - return null; - if (resolve) - return getType(name); - else - return getTypeFromCompoundName(name, false, false); -} - -/** - * Inspect the given tag bits and answer a corresponding null annotation type binding - * @param defaultTagBit tag bits representing the default applicable at the current code location - * @param resolve should the resulting type binding be resolved? - * @return the corresponding concrete annotation type binding (<code>@NonNull</code> or <code>@Nullable</code>) - * or <code>null</code> if no bits of a default-annotation are contained in the given tag bits. - */ -public TypeBinding getNullAnnotationBindingFromDefault(long defaultTagBit, boolean resolve) { - if ((defaultTagBit & TagBits.AnnotationNullUnspecifiedByDefault) != 0) - return ReferenceBinding.NULL_UNSPECIFIED; - if ((defaultTagBit & TagBits.AnnotationNonNullByDefault) != 0) - return getNullAnnotationBinding(TagBits.AnnotationNonNull, resolve); - return null; -} - -TypeBinding getNullAnnotationResolved(TypeBinding nullAnnotation, Scope scope) { - // avoid unspecific error "The type in.valid cannot be resolved. It is indirectly referenced from required .class files" - boolean tolerateMissing = this.mayTolerateMissingType; - this.mayTolerateMissingType = true; - try { - nullAnnotation = BinaryTypeBinding.resolveType(nullAnnotation, this, false); - } finally { - this.mayTolerateMissingType = tolerateMissing; - } - if (nullAnnotation instanceof MissingTypeBinding) { - // convert error into a specific one: - scope.problemReporter().missingNullAnnotationType(((MissingTypeBinding)nullAnnotation).compoundName); - return null; - } - return nullAnnotation; -} - /* Answer the top level package named name if it exists in the cache. * Answer theNotFoundPackage if it could not be resolved the first time * it was looked up, otherwise answer null. diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java index d49b3039e..da2f17577 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java @@ -14,6 +14,7 @@ * bug 367203 - [compiler][null] detect assigning null to nonnull argument * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -854,10 +855,9 @@ public final char[] constantPoolName() { } /** - * After method verifier has finished, fill in missing nullness values from the applicable default. - * @param annotationBinding the null annotation specified to be the default at the current code location. + * After method verifier has finished, fill in missing @NonNull specification from the applicable default. */ -protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { +protected void fillInDefaultNonNullness() { if (this.parameterNonNullness == null) this.parameterNonNullness = new Boolean[this.parameters.length]; AbstractMethodDeclaration sourceMethod = sourceMethod(); @@ -870,9 +870,7 @@ protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { added = true; this.parameterNonNullness[i] = Boolean.TRUE; if (sourceMethod != null) { - Argument argument = sourceMethod.arguments[i]; - sourceMethod.addParameterNonNullAnnotation(argument, (ReferenceBinding)annotationBinding); - argument.binding.tagBits |= TagBits.AnnotationNonNull; + sourceMethod.arguments[i].binding.tagBits |= TagBits.AnnotationNonNull; } } else if (this.parameterNonNullness[i].booleanValue()) { sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, i); @@ -885,8 +883,6 @@ protected void fillInDefaultNonNullness(TypeBinding annotationBinding) { && (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) { this.tagBits |= TagBits.AnnotationNonNull; - if (sourceMethod != null) - sourceMethod.addNonNullAnnotation((ReferenceBinding)annotationBinding); } else if ((this.tagBits & TagBits.AnnotationNonNull) != 0) { sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, -1/*signifies method return*/); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java index a7cc75a7b..0c6cd255e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -13,6 +13,7 @@ * Stephan Herrmann - Contributions for * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -35,8 +36,9 @@ public class PackageBinding extends Binding implements TypeConstants { HashtableOfType knownTypes; HashtableOfPackage knownPackages; - // annotation type binding representing the default that has been defined for this package (using @NonNullByDefault) - protected TypeBinding nullnessDefaultAnnotation; + // code representing the default that has been defined for this package (using @NonNullByDefault) + // one of Binding.{NO_NULL_DEFAULT,NULL_UNSPECIFIED_BY_DEFAULT,NONNULL_BY_DEFAULT} + protected int defaultNullness = NO_NULL_DEFAULT; protected PackageBinding() { // for creating problem package @@ -297,12 +299,6 @@ void checkIfNullAnnotationType(ReferenceBinding type) { } } -public TypeBinding getNullnessDefaultAnnotation(Scope scope) { - if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding) - return this.nullnessDefaultAnnotation = this.environment.getNullAnnotationResolved(this.nullnessDefaultAnnotation, scope); - return this.nullnessDefaultAnnotation; -} - public char[] readableName() /*java.lang*/ { return CharOperation.concatWith(this.compoundName, '.'); } 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 22e8ec920..fe876d5c6 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 @@ -14,6 +14,7 @@ * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 358903 - Filter practically unimportant resource leak warnings + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -101,14 +102,6 @@ abstract public class ReferenceBinding extends AbstractOTReferenceBinding { public boolean hasTypeBit(int bit) { return false; } }; - /** - * This faked annotation type binding marks types with unspecified nullness. - * For use in {@link PackageBinding#nullnessDefaultAnnotation} and SourceTypeBinding#nullnessDefaultAnnotation - */ - final static ReferenceBinding NULL_UNSPECIFIED = new ReferenceBinding() { /* faked type binding */ - public boolean hasTypeBit(int bit) { return false; } - }; - private static final Comparator FIELD_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { char[] n1 = ((FieldBinding) o1).name; 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 07d1434a1..dc57ce771 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 @@ -16,6 +16,8 @@ * bug 365836 - [compiler][null] Incomplete propagation of null defaults. * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults + * bug 366063 - Compiler should not add synthetic @NonNull annotations *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -107,8 +109,6 @@ public class SourceTypeBinding extends ReferenceBinding { // SH} public ClassScope scope; - public int fieldAnalysisOffset; // an offset for ids of fields of this class (id to be used for flow analysis) - public int cumulativeFieldCount; // cumulative field count from all enclosing types, used to build unique field id's for member types. // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and bridge methods // if a new category is added, also increment MAX_SYNTHETICS @@ -139,7 +139,7 @@ public class SourceTypeBinding extends ReferenceBinding { private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder - private TypeBinding nullnessDefaultAnnotation; + private int defaultNullness; private int nullnessDefaultInitialized = 0; // 0: nothing; 1: type; 2: package public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { @@ -158,7 +158,6 @@ public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassSc // SH} this.sourceName = scope.referenceContext.name; this.scope = scope; - this.cumulativeFieldCount = 0; //{ObjectTeams: ROFI create a package binding for our role files (if any): maybeSetTeamPackage(compoundName, fPackage, scope.environment()); // SH} @@ -2376,9 +2375,9 @@ private void createArgumentBindings(MethodBinding method) { if (methodDecl != null) { if (method.parameters != Binding.NO_PARAMETERS) methodDecl.createArgumentBindings(); - TypeBinding annotationBinding = findDefaultNullness(methodDecl.scope, methodDecl.scope.environment()); - if (annotationBinding != null && annotationBinding.id == TypeIds.T_ConfiguredAnnotationNonNull) - method.fillInDefaultNonNullness(annotationBinding); + if ((findNonNullDefault(methodDecl.scope, methodDecl.scope.environment()) == NONNULL_BY_DEFAULT)) { + method.fillInDefaultNonNullness(); + } } } private void evaluateNullAnnotations(long annotationTagBits) { @@ -2386,18 +2385,16 @@ private void evaluateNullAnnotations(long annotationTagBits) { return; this.nullnessDefaultInitialized = 1; // transfer nullness info from tagBits to this.nullnessDefaultAnnotation - TypeBinding defaultAnnotation = getPackage().environment - .getNullAnnotationBindingFromDefault(annotationTagBits, false/*resolve*/); - if (defaultAnnotation != null) { + int newDefaultNullness = NO_NULL_DEFAULT; + if ((annotationTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) + newDefaultNullness = NULL_UNSPECIFIED_BY_DEFAULT; + else if ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) + newDefaultNullness = NONNULL_BY_DEFAULT; + if (newDefaultNullness != NO_NULL_DEFAULT) { if (CharOperation.equals(this.sourceName, TypeConstants.PACKAGE_INFO_NAME)) { - getPackage().nullnessDefaultAnnotation = defaultAnnotation; - long globalDefault = this.scope.compilerOptions().defaultNonNullness; - if (globalDefault == TagBits.AnnotationNonNull && (annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) { - TypeDeclaration typeDecl = this.scope.referenceContext; - this.scope.problemReporter().nullDefaultAnnotationIsRedundant(typeDecl, typeDecl.annotations, null); - } + getPackage().defaultNullness = newDefaultNullness; } else { - this.nullnessDefaultAnnotation = defaultAnnotation; + this.defaultNullness = newDefaultNullness; TypeDeclaration typeDecl = this.scope.referenceContext; long nullDefaultBits = annotationTagBits & (TagBits.AnnotationNullUnspecifiedByDefault|TagBits.AnnotationNonNullByDefault); checkRedundantNullnessDefaultRecurse(typeDecl, typeDecl.annotations, nullDefaultBits); @@ -2406,25 +2403,20 @@ private void evaluateNullAnnotations(long annotationTagBits) { } protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) { - if (this.fPackage.nullnessDefaultAnnotation != null) { - if ((this.fPackage.nullnessDefaultAnnotation.id == TypeIds.T_ConfiguredAnnotationNonNull + if (this.fPackage.defaultNullness != NO_NULL_DEFAULT) { + if ((this.fPackage.defaultNullness == NONNULL_BY_DEFAULT && ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0))) { this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, this.fPackage); } return; } - long globalDefault = this.scope.compilerOptions().defaultNonNullness; - if (globalDefault == TagBits.AnnotationNonNull && annotationTagBits == TagBits.AnnotationNonNullByDefault) { - this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, null); - } } // return: should caller continue searching? protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[] annotations, long annotationTagBits) { - TypeBinding thisDefault = this.nullnessDefaultAnnotation; - if (thisDefault != null) { - if (thisDefault.id == TypeIds.T_ConfiguredAnnotationNonNull - && ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0)) { + int thisDefault = this.defaultNullness; + if (thisDefault == NONNULL_BY_DEFAULT) { + if ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) { this.scope.problemReporter().nullDefaultAnnotationIsRedundant(location, annotations, this); } return false; // different default means inner default is not redundant -> we're done @@ -2432,42 +2424,35 @@ protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[ return true; } -private TypeBinding getNullnessDefaultAnnotation() { - if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding) - this.nullnessDefaultAnnotation = this.scope.environment().getNullAnnotationResolved(this.nullnessDefaultAnnotation, this.scope); - return this.nullnessDefaultAnnotation; -} /** * Answer the nullness default applicable at the given method binding. - * Possible values:<ul> - * <li>the type binding for @NonNulByDefault</li> - * <li>the synthetic type {@link ReferenceBinding#NULL_UNSPECIFIED} if a default from outer scope has been canceled</li> - * <li>null if no default has been defined</li> - * </ul> + * Possible values: {@link Binding#NO_NULL_DEFAULT}, {@link Binding#NULL_UNSPECIFIED_BY_DEFAULT}, {@link Binding#NONNULL_BY_DEFAULT}. * @param currentScope where to start search for lexically enclosing default - * @param environment gateway to options and configured annotation types + * @param environment gateway to options */ -private TypeBinding findDefaultNullness(Scope currentScope, LookupEnvironment environment) { +private int findNonNullDefault(Scope currentScope, LookupEnvironment environment) { // find the applicable default inside->out: SourceTypeBinding currentType = null; - TypeBinding annotationBinding; while (currentScope != null) { switch (currentScope.kind) { case Scope.METHOD_SCOPE: AbstractMethodDeclaration referenceMethod = ((MethodScope)currentScope).referenceMethod(); if (referenceMethod != null && referenceMethod.binding != null) { - annotationBinding = environment.getNullAnnotationBindingFromDefault(referenceMethod.binding.tagBits, true/*resolve*/); - if (annotationBinding != null) - return annotationBinding; + long methodTagBits = referenceMethod.binding.tagBits; + if ((methodTagBits & TagBits.AnnotationNonNullByDefault) != 0) + return NONNULL_BY_DEFAULT; + if ((methodTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) + return NULL_UNSPECIFIED_BY_DEFAULT; } break; case Scope.CLASS_SCOPE: currentType = ((ClassScope)currentScope).referenceContext.binding; if (currentType != null) { - annotationBinding = currentType.getNullnessDefaultAnnotation(); - if (annotationBinding != null) - return annotationBinding; + int foundDefaultNullness = currentType.defaultNullness; + if (foundDefaultNullness != NO_NULL_DEFAULT) { + return foundDefaultNullness; + } } break; } @@ -2476,28 +2461,13 @@ private TypeBinding findDefaultNullness(Scope currentScope, LookupEnvironment en // package if (currentType != null) { - annotationBinding = currentType.getPackage().getNullnessDefaultAnnotation(this.scope); - if (annotationBinding != null) - return annotationBinding; - } - - // global - long defaultNullness = environment.globalOptions.defaultNonNullness; - if (defaultNullness != 0) { - // we have a default, so we need an annotation type to record this during compile and in the byte code - annotationBinding = environment.getNullAnnotationBinding(defaultNullness, true/*resolve*/); - if (annotationBinding != null) - return annotationBinding; - - // on this branch default was not defined using an annotation, thus annotation type can still be missing - if (defaultNullness == TagBits.AnnotationNonNull) - this.scope.problemReporter().missingNullAnnotationType(environment.getNonNullAnnotationName()); - else - this.scope.problemReporter().abortDueToInternalError("Illegal default nullness value: "+defaultNullness); //$NON-NLS-1$ - // reset default to avoid duplicate errors: - environment.globalOptions.defaultNonNullness = 0; + int foundDefaultNullness = currentType.getPackage().defaultNullness; + if (foundDefaultNullness != NO_NULL_DEFAULT) { + return foundDefaultNullness; + } } - return null; + + return NO_NULL_DEFAULT; } //{ObjectTeams: helper to find args allowing baseclass decapsulation: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java index ae9a80904..d11f88d6c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java @@ -60,10 +60,6 @@ public abstract class VariableBinding return this.constant; } - public int getAnalysisId(int maxFieldCount) { - return this.id + maxFieldCount; - } - public abstract AnnotationBinding[] getAnnotations(); public final boolean isBlankFinal(){ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java index 7276e84c2..a542af5ab 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -921,6 +921,7 @@ public JavadocParser javadocParser; // used for recovery protected int lastJavadocEnd; public org.eclipse.jdt.internal.compiler.ReadManager readManager; +private boolean shouldDeferRecovery = false; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=291040 //{ObjectTeams: context info while parsing separate role files: @@ -3042,6 +3043,7 @@ protected void consumeClassBodyopt() { // ClassBodyopt ::= $empty pushOnAstStack(null); this.endPosition = this.rParenPos; + this.shouldDeferRecovery = false; } protected void consumeClassDeclaration() { // ClassDeclaration ::= ClassHeader ClassBody @@ -3998,6 +4000,7 @@ protected void consumeEnhancedForStatementHeaderInit(boolean hasModifiers) { iteratorForStatement.sourceEnd = localDeclaration.declarationSourceEnd; } protected void consumeEnterAnonymousClassBody(boolean qualified) { + this.shouldDeferRecovery = false; // EnterAnonymousClassBody ::= $empty TypeReference typeReference = getTypeReference(0); @@ -7013,7 +7016,6 @@ protected void consumeRightParen() { // PushRPAREN ::= ')' pushOnIntStack(this.rParenPos); } -//CLOVER OFF // This method is part of an automatic generation : do NOT edit-modify protected void consumeRule(int act) { switch ( act ) { @@ -8027,7 +8029,7 @@ protected void consumeRule(int act) { consumeClassInstanceCreationExpressionWithTypeArguments(); break; - case 486 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new ClassType LPAREN"); } //$NON-NLS-1$ + case 486 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new ClassType..."); } //$NON-NLS-1$ consumeClassInstanceCreationExpression(); break; @@ -8047,1110 +8049,1115 @@ protected void consumeRule(int act) { consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() ; break; - case 491 : if (DEBUG) { System.out.println("ClassInstanceCreationExpressionName ::= Name DOT"); } //$NON-NLS-1$ + case 491 : if (DEBUG) { System.out.println("EnterInstanceCreationArgumentList ::="); } //$NON-NLS-1$ + consumeEnterInstanceCreationArgumentList(); + break; + + case 492 : if (DEBUG) { System.out.println("ClassInstanceCreationExpressionName ::= Name DOT"); } //$NON-NLS-1$ consumeClassInstanceCreationExpressionName() ; break; - case 492 : if (DEBUG) { System.out.println("UnqualifiedClassBodyopt ::="); } //$NON-NLS-1$ + case 493 : if (DEBUG) { System.out.println("UnqualifiedClassBodyopt ::="); } //$NON-NLS-1$ consumeClassBodyopt(); break; - case 494 : if (DEBUG) { System.out.println("UnqualifiedEnterAnonymousClassBody ::="); } //$NON-NLS-1$ + case 495 : if (DEBUG) { System.out.println("UnqualifiedEnterAnonymousClassBody ::="); } //$NON-NLS-1$ consumeEnterAnonymousClassBody(false); break; - case 495 : if (DEBUG) { System.out.println("QualifiedClassBodyopt ::="); } //$NON-NLS-1$ + case 496 : if (DEBUG) { System.out.println("QualifiedClassBodyopt ::="); } //$NON-NLS-1$ consumeClassBodyopt(); break; - case 497 : if (DEBUG) { System.out.println("QualifiedEnterAnonymousClassBody ::="); } //$NON-NLS-1$ + case 498 : if (DEBUG) { System.out.println("QualifiedEnterAnonymousClassBody ::="); } //$NON-NLS-1$ consumeEnterAnonymousClassBody(true); break; - case 499 : if (DEBUG) { System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); } //$NON-NLS-1$ + case 500 : if (DEBUG) { System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); } //$NON-NLS-1$ consumeArgumentList(); break; - case 500 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new PrimitiveType..."); } //$NON-NLS-1$ + case 501 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new PrimitiveType..."); } //$NON-NLS-1$ consumeArrayCreationHeader(); break; - case 501 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new ClassOrInterfaceType..."); } //$NON-NLS-1$ + case 502 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new ClassOrInterfaceType..."); } //$NON-NLS-1$ consumeArrayCreationHeader(); break; - case 502 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); } //$NON-NLS-1$ + case 503 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); } //$NON-NLS-1$ consumeArrayCreationExpressionWithoutInitializer(); break; - case 503 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new PrimitiveType"); } //$NON-NLS-1$ + case 504 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new PrimitiveType"); } //$NON-NLS-1$ consumeArrayCreationExpressionWithInitializer(); break; - case 504 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); } //$NON-NLS-1$ + case 505 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); } //$NON-NLS-1$ consumeArrayCreationExpressionWithoutInitializer(); break; - case 505 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new..."); } //$NON-NLS-1$ + case 506 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new..."); } //$NON-NLS-1$ consumeArrayCreationExpressionWithInitializer(); break; - case 507 : if (DEBUG) { System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs..."); } //$NON-NLS-1$ + case 508 : if (DEBUG) { System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs..."); } //$NON-NLS-1$ consumeDimWithOrWithOutExprs(); break; - case 509 : if (DEBUG) { System.out.println("DimWithOrWithOutExpr ::= LBRACKET RBRACKET"); } //$NON-NLS-1$ + case 510 : if (DEBUG) { System.out.println("DimWithOrWithOutExpr ::= LBRACKET RBRACKET"); } //$NON-NLS-1$ consumeDimWithOrWithOutExpr(); break; - case 510 : if (DEBUG) { System.out.println("Dims ::= DimsLoop"); } //$NON-NLS-1$ + case 511 : if (DEBUG) { System.out.println("Dims ::= DimsLoop"); } //$NON-NLS-1$ consumeDims(); break; - case 513 : if (DEBUG) { System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); } //$NON-NLS-1$ + case 514 : if (DEBUG) { System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); } //$NON-NLS-1$ consumeOneDimLoop(); break; - case 514 : if (DEBUG) { System.out.println("FieldAccess ::= Primary DOT Identifier"); } //$NON-NLS-1$ + case 515 : if (DEBUG) { System.out.println("FieldAccess ::= Primary DOT Identifier"); } //$NON-NLS-1$ consumeFieldAccess(false); break; - case 515 : if (DEBUG) { System.out.println("FieldAccess ::= super DOT Identifier"); } //$NON-NLS-1$ + case 516 : if (DEBUG) { System.out.println("FieldAccess ::= super DOT Identifier"); } //$NON-NLS-1$ consumeFieldAccess(true); break; - case 516 : if (DEBUG) { System.out.println("MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN"); } //$NON-NLS-1$ + case 517 : if (DEBUG) { System.out.println("MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN"); } //$NON-NLS-1$ consumeMethodInvocationName(); break; - case 517 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT OnlyTypeArguments..."); } //$NON-NLS-1$ + case 518 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT OnlyTypeArguments..."); } //$NON-NLS-1$ consumeMethodInvocationNameWithTypeArguments(); break; - case 518 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT OnlyTypeArguments..."); } //$NON-NLS-1$ + case 519 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT OnlyTypeArguments..."); } //$NON-NLS-1$ consumeMethodInvocationPrimaryWithTypeArguments(); break; - case 519 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT Identifier LPAREN..."); } //$NON-NLS-1$ + case 520 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT Identifier LPAREN..."); } //$NON-NLS-1$ consumeMethodInvocationPrimary(); break; - case 520 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT OnlyTypeArguments..."); } //$NON-NLS-1$ + case 521 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT OnlyTypeArguments..."); } //$NON-NLS-1$ consumeMethodInvocationSuperWithTypeArguments(); break; - case 521 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT Identifier LPAREN..."); } //$NON-NLS-1$ + case 522 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT Identifier LPAREN..."); } //$NON-NLS-1$ consumeMethodInvocationSuper(); break; - case 522 : if (DEBUG) { System.out.println("MethodInvocation ::= tsuper DOT Identifier LPAREN..."); } //$NON-NLS-1$ + case 523 : if (DEBUG) { System.out.println("MethodInvocation ::= tsuper DOT Identifier LPAREN..."); } //$NON-NLS-1$ consumeMethodInvocationTSuper(UNQUALIFIED); break; - case 523 : if (DEBUG) { System.out.println("MethodInvocation ::= tsuper DOT OnlyTypeArguments..."); } //$NON-NLS-1$ + case 524 : if (DEBUG) { System.out.println("MethodInvocation ::= tsuper DOT OnlyTypeArguments..."); } //$NON-NLS-1$ consumeMethodInvocationTSuperWithTypeArguments(0); break; - case 524 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT tsuper DOT Identifier..."); } //$NON-NLS-1$ + case 525 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT tsuper DOT Identifier..."); } //$NON-NLS-1$ consumeMethodInvocationTSuper(QUALIFIED); break; - case 525 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT tsuper DOT..."); } //$NON-NLS-1$ + case 526 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT tsuper DOT..."); } //$NON-NLS-1$ consumeMethodInvocationTSuperWithTypeArguments(2); break; - case 526 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT Identifier LPAREN..."); } //$NON-NLS-1$ + case 527 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT Identifier LPAREN..."); } //$NON-NLS-1$ consumeMethodInvocationBase(false); break; - case 527 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT OnlyTypeArguments..."); } //$NON-NLS-1$ + case 528 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT OnlyTypeArguments..."); } //$NON-NLS-1$ consumeMethodInvocationBaseWithTypeArguments(false); break; - case 528 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT super DOT Identifier..."); } //$NON-NLS-1$ + case 529 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT super DOT Identifier..."); } //$NON-NLS-1$ consumeMethodInvocationBase(true); break; - case 529 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT super DOT..."); } //$NON-NLS-1$ + case 530 : if (DEBUG) { System.out.println("MethodInvocation ::= base DOT super DOT..."); } //$NON-NLS-1$ consumeMethodInvocationBaseWithTypeArguments(true); break; - case 530 : if (DEBUG) { System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); } //$NON-NLS-1$ + case 531 : if (DEBUG) { System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); } //$NON-NLS-1$ consumeArrayAccess(true); break; - case 531 : if (DEBUG) { System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression..."); } //$NON-NLS-1$ + case 532 : if (DEBUG) { System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression..."); } //$NON-NLS-1$ consumeArrayAccess(false); break; - case 532 : if (DEBUG) { System.out.println("ArrayAccess ::= ArrayCreationWithArrayInitializer..."); } //$NON-NLS-1$ + case 533 : if (DEBUG) { System.out.println("ArrayAccess ::= ArrayCreationWithArrayInitializer..."); } //$NON-NLS-1$ consumeArrayAccess(false); break; - case 534 : if (DEBUG) { System.out.println("PostfixExpression ::= Name"); } //$NON-NLS-1$ + case 535 : if (DEBUG) { System.out.println("PostfixExpression ::= Name"); } //$NON-NLS-1$ consumePostfixExpression(); break; - case 537 : if (DEBUG) { System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); } //$NON-NLS-1$ + case 538 : if (DEBUG) { System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.PLUS,true); break; - case 538 : if (DEBUG) { System.out.println("PostDecrementExpression ::= PostfixExpression..."); } //$NON-NLS-1$ + case 539 : if (DEBUG) { System.out.println("PostDecrementExpression ::= PostfixExpression..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.MINUS,true); break; - case 539 : if (DEBUG) { System.out.println("PushPosition ::="); } //$NON-NLS-1$ + case 540 : if (DEBUG) { System.out.println("PushPosition ::="); } //$NON-NLS-1$ consumePushPosition(); break; - case 542 : if (DEBUG) { System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); } //$NON-NLS-1$ + case 543 : if (DEBUG) { System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.PLUS); break; - case 543 : if (DEBUG) { System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); } //$NON-NLS-1$ + case 544 : if (DEBUG) { System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.MINUS); break; - case 545 : if (DEBUG) { System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition..."); } //$NON-NLS-1$ + case 546 : if (DEBUG) { System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.PLUS,false); break; - case 546 : if (DEBUG) { System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition..."); } //$NON-NLS-1$ + case 547 : if (DEBUG) { System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.MINUS,false); break; - case 548 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition..."); } //$NON-NLS-1$ + case 549 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.TWIDDLE); break; - case 549 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition..."); } //$NON-NLS-1$ + case 550 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.NOT); break; - case 551 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt..."); } //$NON-NLS-1$ + case 552 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt..."); } //$NON-NLS-1$ consumeCastExpressionWithPrimitiveType(); break; - case 552 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); } //$NON-NLS-1$ + case 553 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); } //$NON-NLS-1$ consumeCastExpressionWithGenericsArray(); break; - case 553 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); } //$NON-NLS-1$ + case 554 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); } //$NON-NLS-1$ consumeCastExpressionWithQualifiedGenericsArray(); break; - case 554 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name PushRPAREN..."); } //$NON-NLS-1$ + case 555 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name PushRPAREN..."); } //$NON-NLS-1$ consumeCastExpressionLL1(); break; - case 555 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name Dims PushRPAREN..."); } //$NON-NLS-1$ + case 556 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name Dims PushRPAREN..."); } //$NON-NLS-1$ consumeCastExpressionWithNameArray(); break; - case 556 : if (DEBUG) { System.out.println("OnlyTypeArgumentsForCastExpression ::= OnlyTypeArguments"); } //$NON-NLS-1$ + case 557 : if (DEBUG) { System.out.println("OnlyTypeArgumentsForCastExpression ::= OnlyTypeArguments"); } //$NON-NLS-1$ consumeOnlyTypeArgumentsForCastExpression(); break; - case 557 : if (DEBUG) { System.out.println("InsideCastExpression ::="); } //$NON-NLS-1$ + case 558 : if (DEBUG) { System.out.println("InsideCastExpression ::="); } //$NON-NLS-1$ consumeInsideCastExpression(); break; - case 558 : if (DEBUG) { System.out.println("InsideCastExpressionLL1 ::="); } //$NON-NLS-1$ + case 559 : if (DEBUG) { System.out.println("InsideCastExpressionLL1 ::="); } //$NON-NLS-1$ consumeInsideCastExpressionLL1(); break; - case 559 : if (DEBUG) { System.out.println("InsideCastExpressionWithQualifiedGenerics ::="); } //$NON-NLS-1$ + case 560 : if (DEBUG) { System.out.println("InsideCastExpressionWithQualifiedGenerics ::="); } //$NON-NLS-1$ consumeInsideCastExpressionWithQualifiedGenerics(); break; - case 561 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ + case 562 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.MULTIPLY); break; - case 562 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ + case 563 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.DIVIDE); break; - case 563 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ + case 564 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.REMAINDER); break; - case 565 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression PLUS..."); } //$NON-NLS-1$ + case 566 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression PLUS..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.PLUS); break; - case 566 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression MINUS..."); } //$NON-NLS-1$ + case 567 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression MINUS..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.MINUS); break; - case 568 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT..."); } //$NON-NLS-1$ + case 569 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LEFT_SHIFT); break; - case 569 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT..."); } //$NON-NLS-1$ + case 570 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.RIGHT_SHIFT); break; - case 570 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ + case 571 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.UNSIGNED_RIGHT_SHIFT); break; - case 572 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS..."); } //$NON-NLS-1$ + case 573 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LESS); break; - case 573 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression GREATER..."); } //$NON-NLS-1$ + case 574 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression GREATER..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.GREATER); break; - case 574 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL"); } //$NON-NLS-1$ + case 575 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL"); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LESS_EQUAL); break; - case 575 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression..."); } //$NON-NLS-1$ + case 576 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.GREATER_EQUAL); break; - case 577 : if (DEBUG) { System.out.println("InstanceofExpression ::= InstanceofExpression instanceof"); } //$NON-NLS-1$ + case 578 : if (DEBUG) { System.out.println("InstanceofExpression ::= InstanceofExpression instanceof"); } //$NON-NLS-1$ consumeInstanceOfExpression(); break; - case 579 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL..."); } //$NON-NLS-1$ + case 580 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL..."); } //$NON-NLS-1$ consumeEqualityExpression(OperatorIds.EQUAL_EQUAL); break; - case 580 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL..."); } //$NON-NLS-1$ + case 581 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL..."); } //$NON-NLS-1$ consumeEqualityExpression(OperatorIds.NOT_EQUAL); break; - case 582 : if (DEBUG) { System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); } //$NON-NLS-1$ + case 583 : if (DEBUG) { System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.AND); break; - case 584 : if (DEBUG) { System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR..."); } //$NON-NLS-1$ + case 585 : if (DEBUG) { System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.XOR); break; - case 586 : if (DEBUG) { System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR..."); } //$NON-NLS-1$ + case 587 : if (DEBUG) { System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.OR); break; - case 588 : if (DEBUG) { System.out.println("ConditionalAndExpression ::= ConditionalAndExpression..."); } //$NON-NLS-1$ + case 589 : if (DEBUG) { System.out.println("ConditionalAndExpression ::= ConditionalAndExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.AND_AND); break; - case 590 : if (DEBUG) { System.out.println("ConditionalOrExpression ::= ConditionalOrExpression..."); } //$NON-NLS-1$ + case 591 : if (DEBUG) { System.out.println("ConditionalOrExpression ::= ConditionalOrExpression..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.OR_OR); break; - case 592 : if (DEBUG) { System.out.println("ConditionalExpression ::= ConditionalOrExpression..."); } //$NON-NLS-1$ + case 593 : if (DEBUG) { System.out.println("ConditionalExpression ::= ConditionalOrExpression..."); } //$NON-NLS-1$ consumeConditionalExpression(OperatorIds.QUESTIONCOLON) ; break; - case 595 : if (DEBUG) { System.out.println("Assignment ::= PostfixExpression AssignmentOperator..."); } //$NON-NLS-1$ + case 596 : if (DEBUG) { System.out.println("Assignment ::= PostfixExpression AssignmentOperator..."); } //$NON-NLS-1$ consumeAssignment(); break; - case 597 : if (DEBUG) { System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); } //$NON-NLS-1$ + case 598 : if (DEBUG) { System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); } //$NON-NLS-1$ ignoreExpressionAssignment(); break; - case 598 : if (DEBUG) { System.out.println("AssignmentOperator ::= EQUAL"); } //$NON-NLS-1$ + case 599 : if (DEBUG) { System.out.println("AssignmentOperator ::= EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(EQUAL); break; - case 599 : if (DEBUG) { System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); } //$NON-NLS-1$ + case 600 : if (DEBUG) { System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(MULTIPLY); break; - case 600 : if (DEBUG) { System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); } //$NON-NLS-1$ + case 601 : if (DEBUG) { System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(DIVIDE); break; - case 601 : if (DEBUG) { System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); } //$NON-NLS-1$ + case 602 : if (DEBUG) { System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(REMAINDER); break; - case 602 : if (DEBUG) { System.out.println("AssignmentOperator ::= PLUS_EQUAL"); } //$NON-NLS-1$ + case 603 : if (DEBUG) { System.out.println("AssignmentOperator ::= PLUS_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(PLUS); break; - case 603 : if (DEBUG) { System.out.println("AssignmentOperator ::= MINUS_EQUAL"); } //$NON-NLS-1$ + case 604 : if (DEBUG) { System.out.println("AssignmentOperator ::= MINUS_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(MINUS); break; - case 604 : if (DEBUG) { System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); } //$NON-NLS-1$ + case 605 : if (DEBUG) { System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(LEFT_SHIFT); break; - case 605 : if (DEBUG) { System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); } //$NON-NLS-1$ + case 606 : if (DEBUG) { System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(RIGHT_SHIFT); break; - case 606 : if (DEBUG) { System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); } //$NON-NLS-1$ + case 607 : if (DEBUG) { System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT); break; - case 607 : if (DEBUG) { System.out.println("AssignmentOperator ::= AND_EQUAL"); } //$NON-NLS-1$ + case 608 : if (DEBUG) { System.out.println("AssignmentOperator ::= AND_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(AND); break; - case 608 : if (DEBUG) { System.out.println("AssignmentOperator ::= XOR_EQUAL"); } //$NON-NLS-1$ + case 609 : if (DEBUG) { System.out.println("AssignmentOperator ::= XOR_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(XOR); break; - case 609 : if (DEBUG) { System.out.println("AssignmentOperator ::= OR_EQUAL"); } //$NON-NLS-1$ + case 610 : if (DEBUG) { System.out.println("AssignmentOperator ::= OR_EQUAL"); } //$NON-NLS-1$ consumeAssignmentOperator(OR); break; - case 613 : if (DEBUG) { System.out.println("Expressionopt ::="); } //$NON-NLS-1$ + case 614 : if (DEBUG) { System.out.println("Expressionopt ::="); } //$NON-NLS-1$ consumeEmptyExpression(); break; - case 618 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::="); } //$NON-NLS-1$ + case 619 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::="); } //$NON-NLS-1$ consumeEmptyClassBodyDeclarationsopt(); break; - case 619 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ + case 620 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ consumeClassBodyDeclarationsopt(); break; - case 620 : if (DEBUG) { System.out.println("Modifiersopt ::="); } //$NON-NLS-1$ + case 621 : if (DEBUG) { System.out.println("Modifiersopt ::="); } //$NON-NLS-1$ consumeDefaultModifiers(); break; - case 621 : if (DEBUG) { System.out.println("Modifiersopt ::= Modifiers"); } //$NON-NLS-1$ + case 622 : if (DEBUG) { System.out.println("Modifiersopt ::= Modifiers"); } //$NON-NLS-1$ consumeModifiers(); break; - case 622 : if (DEBUG) { System.out.println("BlockStatementsopt ::="); } //$NON-NLS-1$ + case 623 : if (DEBUG) { System.out.println("BlockStatementsopt ::="); } //$NON-NLS-1$ consumeEmptyBlockStatementsopt(); break; - case 624 : if (DEBUG) { System.out.println("Dimsopt ::="); } //$NON-NLS-1$ + case 625 : if (DEBUG) { System.out.println("Dimsopt ::="); } //$NON-NLS-1$ consumeEmptyDimsopt(); break; - case 626 : if (DEBUG) { System.out.println("ArgumentListopt ::="); } //$NON-NLS-1$ + case 627 : if (DEBUG) { System.out.println("ArgumentListopt ::="); } //$NON-NLS-1$ consumeEmptyArgumentListopt(); break; - case 630 : if (DEBUG) { System.out.println("FormalParameterListopt ::="); } //$NON-NLS-1$ + case 631 : if (DEBUG) { System.out.println("FormalParameterListopt ::="); } //$NON-NLS-1$ consumeFormalParameterListopt(); break; - case 634 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::="); } //$NON-NLS-1$ + case 635 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::="); } //$NON-NLS-1$ consumeEmptyInterfaceMemberDeclarationsopt(); break; - case 635 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ + case 636 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ consumeInterfaceMemberDeclarationsopt(); break; - case 636 : if (DEBUG) { System.out.println("NestedType ::="); } //$NON-NLS-1$ + case 637 : if (DEBUG) { System.out.println("NestedType ::="); } //$NON-NLS-1$ consumeNestedType(); break; - case 637 : if (DEBUG) { System.out.println("ForInitopt ::="); } //$NON-NLS-1$ + case 638 : if (DEBUG) { System.out.println("ForInitopt ::="); } //$NON-NLS-1$ consumeEmptyForInitopt(); break; - case 639 : if (DEBUG) { System.out.println("ForUpdateopt ::="); } //$NON-NLS-1$ + case 640 : if (DEBUG) { System.out.println("ForUpdateopt ::="); } //$NON-NLS-1$ consumeEmptyForUpdateopt(); break; - case 643 : if (DEBUG) { System.out.println("Catchesopt ::="); } //$NON-NLS-1$ + case 644 : if (DEBUG) { System.out.println("Catchesopt ::="); } //$NON-NLS-1$ consumeEmptyCatchesopt(); break; - case 645 : if (DEBUG) { System.out.println("EnumDeclaration ::= EnumHeader EnumBody"); } //$NON-NLS-1$ + case 646 : if (DEBUG) { System.out.println("EnumDeclaration ::= EnumHeader EnumBody"); } //$NON-NLS-1$ consumeEnumDeclaration(); break; - case 646 : if (DEBUG) { System.out.println("EnumHeader ::= EnumHeaderName ClassHeaderImplementsopt"); } //$NON-NLS-1$ + case 647 : if (DEBUG) { System.out.println("EnumHeader ::= EnumHeaderName ClassHeaderImplementsopt"); } //$NON-NLS-1$ consumeEnumHeader(); break; - case 647 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum Identifier"); } //$NON-NLS-1$ + case 648 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum Identifier"); } //$NON-NLS-1$ consumeEnumHeaderName(); break; - case 648 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum Identifier..."); } //$NON-NLS-1$ + case 649 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum Identifier..."); } //$NON-NLS-1$ consumeEnumHeaderNameWithTypeParameters(); break; - case 649 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumBodyDeclarationsopt RBRACE"); } //$NON-NLS-1$ + case 650 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumBodyDeclarationsopt RBRACE"); } //$NON-NLS-1$ consumeEnumBodyNoConstants(); break; - case 650 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE COMMA EnumBodyDeclarationsopt..."); } //$NON-NLS-1$ + case 651 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE COMMA EnumBodyDeclarationsopt..."); } //$NON-NLS-1$ consumeEnumBodyNoConstants(); break; - case 651 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants COMMA..."); } //$NON-NLS-1$ + case 652 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants COMMA..."); } //$NON-NLS-1$ consumeEnumBodyWithConstants(); break; - case 652 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants..."); } //$NON-NLS-1$ + case 653 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants..."); } //$NON-NLS-1$ consumeEnumBodyWithConstants(); break; - case 654 : if (DEBUG) { System.out.println("EnumConstants ::= EnumConstants COMMA EnumConstant"); } //$NON-NLS-1$ + case 655 : if (DEBUG) { System.out.println("EnumConstants ::= EnumConstants COMMA EnumConstant"); } //$NON-NLS-1$ consumeEnumConstants(); break; - case 655 : if (DEBUG) { System.out.println("EnumConstantHeaderName ::= Modifiersopt Identifier"); } //$NON-NLS-1$ + case 656 : if (DEBUG) { System.out.println("EnumConstantHeaderName ::= Modifiersopt Identifier"); } //$NON-NLS-1$ consumeEnumConstantHeaderName(); break; - case 656 : if (DEBUG) { System.out.println("EnumConstantHeader ::= EnumConstantHeaderName..."); } //$NON-NLS-1$ + case 657 : if (DEBUG) { System.out.println("EnumConstantHeader ::= EnumConstantHeaderName..."); } //$NON-NLS-1$ consumeEnumConstantHeader(); break; - case 657 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader ForceNoDiet..."); } //$NON-NLS-1$ + case 658 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader ForceNoDiet..."); } //$NON-NLS-1$ consumeEnumConstantWithClassBody(); break; - case 658 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader"); } //$NON-NLS-1$ + case 659 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader"); } //$NON-NLS-1$ consumeEnumConstantNoClassBody(); break; - case 659 : if (DEBUG) { System.out.println("Arguments ::= LPAREN ArgumentListopt RPAREN"); } //$NON-NLS-1$ + case 660 : if (DEBUG) { System.out.println("Arguments ::= LPAREN ArgumentListopt RPAREN"); } //$NON-NLS-1$ consumeArguments(); break; - case 660 : if (DEBUG) { System.out.println("Argumentsopt ::="); } //$NON-NLS-1$ + case 661 : if (DEBUG) { System.out.println("Argumentsopt ::="); } //$NON-NLS-1$ consumeEmptyArguments(); break; - case 662 : if (DEBUG) { System.out.println("EnumDeclarations ::= SEMICOLON ClassBodyDeclarationsopt"); } //$NON-NLS-1$ + case 663 : if (DEBUG) { System.out.println("EnumDeclarations ::= SEMICOLON ClassBodyDeclarationsopt"); } //$NON-NLS-1$ consumeEnumDeclarations(); break; - case 663 : if (DEBUG) { System.out.println("EnumBodyDeclarationsopt ::="); } //$NON-NLS-1$ + case 664 : if (DEBUG) { System.out.println("EnumBodyDeclarationsopt ::="); } //$NON-NLS-1$ consumeEmptyEnumDeclarations(); break; - case 665 : if (DEBUG) { System.out.println("EnhancedForStatement ::= EnhancedForStatementHeader..."); } //$NON-NLS-1$ + case 666 : if (DEBUG) { System.out.println("EnhancedForStatement ::= EnhancedForStatementHeader..."); } //$NON-NLS-1$ consumeEnhancedForStatement(); break; - case 666 : if (DEBUG) { System.out.println("EnhancedForStatementNoShortIf ::=..."); } //$NON-NLS-1$ + case 667 : if (DEBUG) { System.out.println("EnhancedForStatementNoShortIf ::=..."); } //$NON-NLS-1$ consumeEnhancedForStatement(); break; - case 667 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Type..."); } //$NON-NLS-1$ + case 668 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Type..."); } //$NON-NLS-1$ consumeEnhancedForStatementHeaderInit(false); break; - case 668 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Modifiers"); } //$NON-NLS-1$ + case 669 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Modifiers"); } //$NON-NLS-1$ consumeEnhancedForStatementHeaderInit(true); break; - case 669 : if (DEBUG) { System.out.println("EnhancedForStatementHeader ::=..."); } //$NON-NLS-1$ + case 670 : if (DEBUG) { System.out.println("EnhancedForStatementHeader ::=..."); } //$NON-NLS-1$ consumeEnhancedForStatementHeader(); break; - case 670 : if (DEBUG) { System.out.println("SingleBaseImportDeclaration ::=..."); } //$NON-NLS-1$ + case 671 : if (DEBUG) { System.out.println("SingleBaseImportDeclaration ::=..."); } //$NON-NLS-1$ consumeImportDeclaration(); break; - case 671 : if (DEBUG) { System.out.println("SingleBaseImportDeclarationName ::= import base Name"); } //$NON-NLS-1$ + case 672 : if (DEBUG) { System.out.println("SingleBaseImportDeclarationName ::= import base Name"); } //$NON-NLS-1$ consumeSingleBaseImportDeclarationName(); break; - case 672 : if (DEBUG) { System.out.println("SingleStaticImportDeclaration ::=..."); } //$NON-NLS-1$ + case 673 : if (DEBUG) { System.out.println("SingleStaticImportDeclaration ::=..."); } //$NON-NLS-1$ consumeImportDeclaration(); break; - case 673 : if (DEBUG) { System.out.println("SingleStaticImportDeclarationName ::= import static Name"); } //$NON-NLS-1$ + case 674 : if (DEBUG) { System.out.println("SingleStaticImportDeclarationName ::= import static Name"); } //$NON-NLS-1$ consumeSingleStaticImportDeclarationName(); break; - case 674 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclaration ::=..."); } //$NON-NLS-1$ + case 675 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclaration ::=..."); } //$NON-NLS-1$ consumeImportDeclaration(); break; - case 675 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclarationName ::= import static..."); } //$NON-NLS-1$ + case 676 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclarationName ::= import static..."); } //$NON-NLS-1$ consumeStaticImportOnDemandDeclarationName(); break; - case 676 : if (DEBUG) { System.out.println("TypeArguments ::= LESS TypeArgumentList1"); } //$NON-NLS-1$ + case 677 : if (DEBUG) { System.out.println("TypeArguments ::= LESS TypeArgumentList1"); } //$NON-NLS-1$ consumeTypeArguments(); break; - case 677 : if (DEBUG) { System.out.println("OnlyTypeArguments ::= LESS TypeArgumentList1"); } //$NON-NLS-1$ + case 678 : if (DEBUG) { System.out.println("OnlyTypeArguments ::= LESS TypeArgumentList1"); } //$NON-NLS-1$ consumeOnlyTypeArguments(); break; - case 679 : if (DEBUG) { System.out.println("TypeArgumentList1 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ + case 680 : if (DEBUG) { System.out.println("TypeArgumentList1 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ consumeTypeArgumentList1(); break; - case 681 : if (DEBUG) { System.out.println("TypeArgumentList ::= TypeArgumentList COMMA TypeArgument"); } //$NON-NLS-1$ + case 682 : if (DEBUG) { System.out.println("TypeArgumentList ::= TypeArgumentList COMMA TypeArgument"); } //$NON-NLS-1$ consumeTypeArgumentList(); break; - case 682 : if (DEBUG) { System.out.println("TypeArgument ::= ReferenceType"); } //$NON-NLS-1$ + case 683 : if (DEBUG) { System.out.println("TypeArgument ::= ReferenceType"); } //$NON-NLS-1$ consumeTypeArgument(); break; - case 687 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name"); } //$NON-NLS-1$ + case 688 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name"); } //$NON-NLS-1$ consumeTypeAnchor(false); break; - case 688 : if (DEBUG) { System.out.println("TypeAnchor ::= AT base"); } //$NON-NLS-1$ + case 689 : if (DEBUG) { System.out.println("TypeAnchor ::= AT base"); } //$NON-NLS-1$ consumeTypeAnchor(true); break; - case 689 : if (DEBUG) { System.out.println("TypeAnchor ::= AT this"); } //$NON-NLS-1$ + case 690 : if (DEBUG) { System.out.println("TypeAnchor ::= AT this"); } //$NON-NLS-1$ skipThisAnchor(); break; - case 690 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name DOT base"); } //$NON-NLS-1$ + case 691 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name DOT base"); } //$NON-NLS-1$ consumeQualifiedBaseTypeAnchor(); break; - case 693 : if (DEBUG) { System.out.println("ReferenceType1 ::= ReferenceType GREATER"); } //$NON-NLS-1$ + case 694 : if (DEBUG) { System.out.println("ReferenceType1 ::= ReferenceType GREATER"); } //$NON-NLS-1$ consumeReferenceType1(); break; - case 694 : if (DEBUG) { System.out.println("ReferenceType1 ::= ClassOrInterface LESS..."); } //$NON-NLS-1$ + case 695 : if (DEBUG) { System.out.println("ReferenceType1 ::= ClassOrInterface LESS..."); } //$NON-NLS-1$ consumeTypeArgumentReferenceType1(); break; - case 696 : if (DEBUG) { System.out.println("TypeArgumentList2 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ + case 697 : if (DEBUG) { System.out.println("TypeArgumentList2 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ consumeTypeArgumentList2(); break; - case 699 : if (DEBUG) { System.out.println("ReferenceType2 ::= ReferenceType RIGHT_SHIFT"); } //$NON-NLS-1$ + case 700 : if (DEBUG) { System.out.println("ReferenceType2 ::= ReferenceType RIGHT_SHIFT"); } //$NON-NLS-1$ consumeReferenceType2(); break; - case 700 : if (DEBUG) { System.out.println("ReferenceType2 ::= ClassOrInterface LESS..."); } //$NON-NLS-1$ + case 701 : if (DEBUG) { System.out.println("ReferenceType2 ::= ClassOrInterface LESS..."); } //$NON-NLS-1$ consumeTypeArgumentReferenceType2(); break; - case 702 : if (DEBUG) { System.out.println("TypeArgumentList3 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ + case 703 : if (DEBUG) { System.out.println("TypeArgumentList3 ::= TypeArgumentList COMMA..."); } //$NON-NLS-1$ consumeTypeArgumentList3(); break; - case 705 : if (DEBUG) { System.out.println("ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ + case 706 : if (DEBUG) { System.out.println("ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ consumeReferenceType3(); break; - case 706 : if (DEBUG) { System.out.println("Wildcard ::= QUESTION"); } //$NON-NLS-1$ + case 707 : if (DEBUG) { System.out.println("Wildcard ::= QUESTION"); } //$NON-NLS-1$ consumeWildcard(); break; - case 707 : if (DEBUG) { System.out.println("Wildcard ::= QUESTION WildcardBounds"); } //$NON-NLS-1$ + case 708 : if (DEBUG) { System.out.println("Wildcard ::= QUESTION WildcardBounds"); } //$NON-NLS-1$ consumeWildcardWithBounds(); break; - case 708 : if (DEBUG) { System.out.println("WildcardBounds ::= extends ReferenceType"); } //$NON-NLS-1$ + case 709 : if (DEBUG) { System.out.println("WildcardBounds ::= extends ReferenceType"); } //$NON-NLS-1$ consumeWildcardBoundsExtends(); break; - case 709 : if (DEBUG) { System.out.println("WildcardBounds ::= super ReferenceType"); } //$NON-NLS-1$ + case 710 : if (DEBUG) { System.out.println("WildcardBounds ::= super ReferenceType"); } //$NON-NLS-1$ consumeWildcardBoundsSuper(); break; - case 710 : if (DEBUG) { System.out.println("Wildcard1 ::= QUESTION GREATER"); } //$NON-NLS-1$ + case 711 : if (DEBUG) { System.out.println("Wildcard1 ::= QUESTION GREATER"); } //$NON-NLS-1$ consumeWildcard1(); break; - case 711 : if (DEBUG) { System.out.println("Wildcard1 ::= QUESTION WildcardBounds1"); } //$NON-NLS-1$ + case 712 : if (DEBUG) { System.out.println("Wildcard1 ::= QUESTION WildcardBounds1"); } //$NON-NLS-1$ consumeWildcard1WithBounds(); break; - case 712 : if (DEBUG) { System.out.println("WildcardBounds1 ::= extends ReferenceType1"); } //$NON-NLS-1$ + case 713 : if (DEBUG) { System.out.println("WildcardBounds1 ::= extends ReferenceType1"); } //$NON-NLS-1$ consumeWildcardBounds1Extends(); break; - case 713 : if (DEBUG) { System.out.println("WildcardBounds1 ::= super ReferenceType1"); } //$NON-NLS-1$ + case 714 : if (DEBUG) { System.out.println("WildcardBounds1 ::= super ReferenceType1"); } //$NON-NLS-1$ consumeWildcardBounds1Super(); break; - case 714 : if (DEBUG) { System.out.println("Wildcard2 ::= QUESTION RIGHT_SHIFT"); } //$NON-NLS-1$ + case 715 : if (DEBUG) { System.out.println("Wildcard2 ::= QUESTION RIGHT_SHIFT"); } //$NON-NLS-1$ consumeWildcard2(); break; - case 715 : if (DEBUG) { System.out.println("Wildcard2 ::= QUESTION WildcardBounds2"); } //$NON-NLS-1$ + case 716 : if (DEBUG) { System.out.println("Wildcard2 ::= QUESTION WildcardBounds2"); } //$NON-NLS-1$ consumeWildcard2WithBounds(); break; - case 716 : if (DEBUG) { System.out.println("WildcardBounds2 ::= extends ReferenceType2"); } //$NON-NLS-1$ + case 717 : if (DEBUG) { System.out.println("WildcardBounds2 ::= extends ReferenceType2"); } //$NON-NLS-1$ consumeWildcardBounds2Extends(); break; - case 717 : if (DEBUG) { System.out.println("WildcardBounds2 ::= super ReferenceType2"); } //$NON-NLS-1$ + case 718 : if (DEBUG) { System.out.println("WildcardBounds2 ::= super ReferenceType2"); } //$NON-NLS-1$ consumeWildcardBounds2Super(); break; - case 718 : if (DEBUG) { System.out.println("Wildcard3 ::= QUESTION UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ + case 719 : if (DEBUG) { System.out.println("Wildcard3 ::= QUESTION UNSIGNED_RIGHT_SHIFT"); } //$NON-NLS-1$ consumeWildcard3(); break; - case 719 : if (DEBUG) { System.out.println("Wildcard3 ::= QUESTION WildcardBounds3"); } //$NON-NLS-1$ + case 720 : if (DEBUG) { System.out.println("Wildcard3 ::= QUESTION WildcardBounds3"); } //$NON-NLS-1$ consumeWildcard3WithBounds(); break; - case 720 : if (DEBUG) { System.out.println("WildcardBounds3 ::= extends ReferenceType3"); } //$NON-NLS-1$ + case 721 : if (DEBUG) { System.out.println("WildcardBounds3 ::= extends ReferenceType3"); } //$NON-NLS-1$ consumeWildcardBounds3Extends(); break; - case 721 : if (DEBUG) { System.out.println("WildcardBounds3 ::= super ReferenceType3"); } //$NON-NLS-1$ + case 722 : if (DEBUG) { System.out.println("WildcardBounds3 ::= super ReferenceType3"); } //$NON-NLS-1$ consumeWildcardBounds3Super(); break; - case 722 : if (DEBUG) { System.out.println("TypeParameterHeader ::= Identifier"); } //$NON-NLS-1$ + case 723 : if (DEBUG) { System.out.println("TypeParameterHeader ::= Identifier"); } //$NON-NLS-1$ consumeTypeParameterHeader(); break; - case 723 : if (DEBUG) { System.out.println("TypeParameters ::= LESS TypeParameterList1"); } //$NON-NLS-1$ + case 724 : if (DEBUG) { System.out.println("TypeParameters ::= LESS TypeParameterList1"); } //$NON-NLS-1$ consumeTypeParameters(); break; - case 725 : if (DEBUG) { System.out.println("TypeParameterList ::= TypeParameterList COMMA..."); } //$NON-NLS-1$ + case 726 : if (DEBUG) { System.out.println("TypeParameterList ::= TypeParameterList COMMA..."); } //$NON-NLS-1$ consumeTypeParameterList(); break; - case 727 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ + case 728 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ consumeTypeParameterWithExtends(); break; - case 728 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ + case 729 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ consumeTypeParameterWithExtendsAndBounds(); break; - case 729 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader base ReferenceType"); } //$NON-NLS-1$ + case 730 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader base ReferenceType"); } //$NON-NLS-1$ consumeTypeParameterWithBase(); break; - case 733 : if (DEBUG) { System.out.println("TypeValueParameter ::= TypeParameterHeader Identifier"); } //$NON-NLS-1$ + case 734 : if (DEBUG) { System.out.println("TypeValueParameter ::= TypeParameterHeader Identifier"); } //$NON-NLS-1$ consumeTypeValueParameter(); break; - case 738 : if (DEBUG) { System.out.println("TypeBoundOpt ::= extends ReferenceType"); } //$NON-NLS-1$ + case 739 : if (DEBUG) { System.out.println("TypeBoundOpt ::= extends ReferenceType"); } //$NON-NLS-1$ consumeBoundsOfAnchoredTypeParameter(); break; - case 740 : if (DEBUG) { System.out.println("TypeBoundOpt1 ::= extends ReferenceType1"); } //$NON-NLS-1$ + case 741 : if (DEBUG) { System.out.println("TypeBoundOpt1 ::= extends ReferenceType1"); } //$NON-NLS-1$ consumeBoundsOfAnchoredTypeParameter(); break; - case 741 : if (DEBUG) { System.out.println("AnchoredTypeParameterHeader0 ::= TypeParameterHeader..."); } //$NON-NLS-1$ + case 742 : if (DEBUG) { System.out.println("AnchoredTypeParameterHeader0 ::= TypeParameterHeader..."); } //$NON-NLS-1$ consumeAnchoredTypeParameter(); break; - case 743 : if (DEBUG) { System.out.println("AdditionalBoundList ::= AdditionalBoundList..."); } //$NON-NLS-1$ + case 744 : if (DEBUG) { System.out.println("AdditionalBoundList ::= AdditionalBoundList..."); } //$NON-NLS-1$ consumeAdditionalBoundList(); break; - case 744 : if (DEBUG) { System.out.println("AdditionalBound ::= AND ReferenceType"); } //$NON-NLS-1$ + case 745 : if (DEBUG) { System.out.println("AdditionalBound ::= AND ReferenceType"); } //$NON-NLS-1$ consumeAdditionalBound(); break; - case 746 : if (DEBUG) { System.out.println("TypeParameterList1 ::= TypeParameterList COMMA..."); } //$NON-NLS-1$ + case 747 : if (DEBUG) { System.out.println("TypeParameterList1 ::= TypeParameterList COMMA..."); } //$NON-NLS-1$ consumeTypeParameterList1(); break; - case 747 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader GREATER"); } //$NON-NLS-1$ + case 748 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader GREATER"); } //$NON-NLS-1$ consumeTypeParameter1(); break; - case 748 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ + case 749 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ consumeTypeParameter1WithExtends(); break; - case 749 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader base..."); } //$NON-NLS-1$ + case 750 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader base..."); } //$NON-NLS-1$ consumeTypeParameter1WithBase(); break; - case 750 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ + case 751 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); } //$NON-NLS-1$ consumeTypeParameter1WithExtendsAndBounds(); break; - case 752 : if (DEBUG) { System.out.println("AdditionalBoundList1 ::= AdditionalBoundList..."); } //$NON-NLS-1$ + case 753 : if (DEBUG) { System.out.println("AdditionalBoundList1 ::= AdditionalBoundList..."); } //$NON-NLS-1$ consumeAdditionalBoundList1(); break; - case 753 : if (DEBUG) { System.out.println("AdditionalBound1 ::= AND ReferenceType1"); } //$NON-NLS-1$ + case 754 : if (DEBUG) { System.out.println("AdditionalBound1 ::= AND ReferenceType1"); } //$NON-NLS-1$ consumeAdditionalBound1(); break; - case 759 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= PLUS PushPosition..."); } //$NON-NLS-1$ + case 760 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= PLUS PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.PLUS); break; - case 760 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= MINUS PushPosition..."); } //$NON-NLS-1$ + case 761 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= MINUS PushPosition..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.MINUS); break; - case 763 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= TWIDDLE..."); } //$NON-NLS-1$ + case 764 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= TWIDDLE..."); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.TWIDDLE); break; - case 764 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= NOT PushPosition"); } //$NON-NLS-1$ + case 765 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= NOT PushPosition"); } //$NON-NLS-1$ consumeUnaryExpression(OperatorIds.NOT); break; - case 767 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ + case 768 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.MULTIPLY); break; - case 768 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name MULTIPLY..."); } //$NON-NLS-1$ + case 769 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name MULTIPLY..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.MULTIPLY); break; - case 769 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ + case 770 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.DIVIDE); break; - case 770 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name DIVIDE..."); } //$NON-NLS-1$ + case 771 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name DIVIDE..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.DIVIDE); break; - case 771 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ + case 772 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.REMAINDER); break; - case 772 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name REMAINDER..."); } //$NON-NLS-1$ + case 773 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= Name REMAINDER..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.REMAINDER); break; - case 774 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); } //$NON-NLS-1$ + case 775 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.PLUS); break; - case 775 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= Name PLUS..."); } //$NON-NLS-1$ + case 776 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= Name PLUS..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.PLUS); break; - case 776 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); } //$NON-NLS-1$ + case 777 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.MINUS); break; - case 777 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= Name MINUS..."); } //$NON-NLS-1$ + case 778 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= Name MINUS..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.MINUS); break; - case 779 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ + case 780 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LEFT_SHIFT); break; - case 780 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name LEFT_SHIFT..."); } //$NON-NLS-1$ + case 781 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name LEFT_SHIFT..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.LEFT_SHIFT); break; - case 781 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ + case 782 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.RIGHT_SHIFT); break; - case 782 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name RIGHT_SHIFT..."); } //$NON-NLS-1$ + case 783 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name RIGHT_SHIFT..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.RIGHT_SHIFT); break; - case 783 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ + case 784 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.UNSIGNED_RIGHT_SHIFT); break; - case 784 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name UNSIGNED_RIGHT_SHIFT..."); } //$NON-NLS-1$ + case 785 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= Name UNSIGNED_RIGHT_SHIFT..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.UNSIGNED_RIGHT_SHIFT); break; - case 786 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); } //$NON-NLS-1$ + case 787 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LESS); break; - case 787 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS..."); } //$NON-NLS-1$ + case 788 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.LESS); break; - case 788 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); } //$NON-NLS-1$ + case 789 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.GREATER); break; - case 789 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name GREATER..."); } //$NON-NLS-1$ + case 790 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name GREATER..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.GREATER); break; - case 790 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); } //$NON-NLS-1$ + case 791 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.LESS_EQUAL); break; - case 791 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS_EQUAL..."); } //$NON-NLS-1$ + case 792 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS_EQUAL..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.LESS_EQUAL); break; - case 792 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); } //$NON-NLS-1$ + case 793 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.GREATER_EQUAL); break; - case 793 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name GREATER_EQUAL..."); } //$NON-NLS-1$ + case 794 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name GREATER_EQUAL..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.GREATER_EQUAL); break; - case 795 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::= Name instanceof..."); } //$NON-NLS-1$ + case 796 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::= Name instanceof..."); } //$NON-NLS-1$ consumeInstanceOfExpressionWithName(); break; - case 796 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::=..."); } //$NON-NLS-1$ + case 797 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::=..."); } //$NON-NLS-1$ consumeInstanceOfExpression(); break; - case 798 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); } //$NON-NLS-1$ + case 799 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); } //$NON-NLS-1$ consumeEqualityExpression(OperatorIds.EQUAL_EQUAL); break; - case 799 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= Name EQUAL_EQUAL..."); } //$NON-NLS-1$ + case 800 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= Name EQUAL_EQUAL..."); } //$NON-NLS-1$ consumeEqualityExpressionWithName(OperatorIds.EQUAL_EQUAL); break; - case 800 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); } //$NON-NLS-1$ + case 801 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); } //$NON-NLS-1$ consumeEqualityExpression(OperatorIds.NOT_EQUAL); break; - case 801 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= Name NOT_EQUAL..."); } //$NON-NLS-1$ + case 802 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= Name NOT_EQUAL..."); } //$NON-NLS-1$ consumeEqualityExpressionWithName(OperatorIds.NOT_EQUAL); break; - case 803 : if (DEBUG) { System.out.println("AndExpression_NotName ::= AndExpression_NotName AND..."); } //$NON-NLS-1$ + case 804 : if (DEBUG) { System.out.println("AndExpression_NotName ::= AndExpression_NotName AND..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.AND); break; - case 804 : if (DEBUG) { System.out.println("AndExpression_NotName ::= Name AND EqualityExpression"); } //$NON-NLS-1$ + case 805 : if (DEBUG) { System.out.println("AndExpression_NotName ::= Name AND EqualityExpression"); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.AND); break; - case 806 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::=..."); } //$NON-NLS-1$ + case 807 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.XOR); break; - case 807 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::= Name XOR AndExpression"); } //$NON-NLS-1$ + case 808 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::= Name XOR AndExpression"); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.XOR); break; - case 809 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::=..."); } //$NON-NLS-1$ + case 810 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.OR); break; - case 810 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::= Name OR..."); } //$NON-NLS-1$ + case 811 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::= Name OR..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.OR); break; - case 812 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::=..."); } //$NON-NLS-1$ + case 813 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.AND_AND); break; - case 813 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::= Name AND_AND..."); } //$NON-NLS-1$ + case 814 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::= Name AND_AND..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.AND_AND); break; - case 815 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::=..."); } //$NON-NLS-1$ + case 816 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::=..."); } //$NON-NLS-1$ consumeBinaryExpression(OperatorIds.OR_OR); break; - case 816 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::= Name OR_OR..."); } //$NON-NLS-1$ + case 817 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::= Name OR_OR..."); } //$NON-NLS-1$ consumeBinaryExpressionWithName(OperatorIds.OR_OR); break; - case 818 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::=..."); } //$NON-NLS-1$ + case 819 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::=..."); } //$NON-NLS-1$ consumeConditionalExpression(OperatorIds.QUESTIONCOLON) ; break; - case 819 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::= Name QUESTION..."); } //$NON-NLS-1$ + case 820 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::= Name QUESTION..."); } //$NON-NLS-1$ consumeConditionalExpressionWithName(OperatorIds.QUESTIONCOLON) ; break; - case 823 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); } //$NON-NLS-1$ + case 824 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclarationHeaderName() ; break; - case 824 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); } //$NON-NLS-1$ + case 825 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters() ; break; - case 825 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); } //$NON-NLS-1$ + case 826 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters() ; break; - case 826 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); } //$NON-NLS-1$ + case 827 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclarationHeaderName() ; break; - case 827 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeader ::=..."); } //$NON-NLS-1$ + case 828 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeader ::=..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclarationHeader() ; break; - case 828 : if (DEBUG) { System.out.println("AnnotationTypeDeclaration ::=..."); } //$NON-NLS-1$ + case 829 : if (DEBUG) { System.out.println("AnnotationTypeDeclaration ::=..."); } //$NON-NLS-1$ consumeAnnotationTypeDeclaration() ; break; - case 830 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::="); } //$NON-NLS-1$ + case 831 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::="); } //$NON-NLS-1$ consumeEmptyAnnotationTypeMemberDeclarationsopt() ; break; - case 831 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ + case 832 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::= NestedType..."); } //$NON-NLS-1$ consumeAnnotationTypeMemberDeclarationsopt() ; break; - case 833 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarations ::=..."); } //$NON-NLS-1$ + case 834 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarations ::=..."); } //$NON-NLS-1$ consumeAnnotationTypeMemberDeclarations() ; break; - case 834 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt..."); } //$NON-NLS-1$ + case 835 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt..."); } //$NON-NLS-1$ consumeMethodHeaderNameWithTypeParameters(true); break; - case 835 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt Type..."); } //$NON-NLS-1$ + case 836 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt Type..."); } //$NON-NLS-1$ consumeMethodHeaderName(true); break; - case 836 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::="); } //$NON-NLS-1$ + case 837 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::="); } //$NON-NLS-1$ consumeEmptyMethodHeaderDefaultValue() ; break; - case 837 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::= DefaultValue"); } //$NON-NLS-1$ + case 838 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::= DefaultValue"); } //$NON-NLS-1$ consumeMethodHeaderDefaultValue(); break; - case 838 : if (DEBUG) { System.out.println("AnnotationMethodHeader ::= AnnotationMethodHeaderName..."); } //$NON-NLS-1$ + case 839 : if (DEBUG) { System.out.println("AnnotationMethodHeader ::= AnnotationMethodHeaderName..."); } //$NON-NLS-1$ consumeMethodHeader(); break; - case 839 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclaration ::=..."); } //$NON-NLS-1$ + case 840 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclaration ::=..."); } //$NON-NLS-1$ consumeAnnotationTypeMemberDeclaration() ; break; - case 847 : if (DEBUG) { System.out.println("AnnotationName ::= AT Name"); } //$NON-NLS-1$ + case 848 : if (DEBUG) { System.out.println("AnnotationName ::= AT Name"); } //$NON-NLS-1$ consumeAnnotationName() ; break; - case 848 : if (DEBUG) { System.out.println("NormalAnnotation ::= AnnotationName LPAREN..."); } //$NON-NLS-1$ + case 849 : if (DEBUG) { System.out.println("NormalAnnotation ::= AnnotationName LPAREN..."); } //$NON-NLS-1$ consumeNormalAnnotation() ; break; - case 849 : if (DEBUG) { System.out.println("MemberValuePairsopt ::="); } //$NON-NLS-1$ + case 850 : if (DEBUG) { System.out.println("MemberValuePairsopt ::="); } //$NON-NLS-1$ consumeEmptyMemberValuePairsopt() ; break; - case 852 : if (DEBUG) { System.out.println("MemberValuePairs ::= MemberValuePairs COMMA..."); } //$NON-NLS-1$ + case 853 : if (DEBUG) { System.out.println("MemberValuePairs ::= MemberValuePairs COMMA..."); } //$NON-NLS-1$ consumeMemberValuePairs() ; break; - case 853 : if (DEBUG) { System.out.println("MemberValuePair ::= SimpleName EQUAL EnterMemberValue..."); } //$NON-NLS-1$ + case 854 : if (DEBUG) { System.out.println("MemberValuePair ::= SimpleName EQUAL EnterMemberValue..."); } //$NON-NLS-1$ consumeMemberValuePair() ; break; - case 854 : if (DEBUG) { System.out.println("EnterMemberValue ::="); } //$NON-NLS-1$ + case 855 : if (DEBUG) { System.out.println("EnterMemberValue ::="); } //$NON-NLS-1$ consumeEnterMemberValue() ; break; - case 855 : if (DEBUG) { System.out.println("ExitMemberValue ::="); } //$NON-NLS-1$ + case 856 : if (DEBUG) { System.out.println("ExitMemberValue ::="); } //$NON-NLS-1$ consumeExitMemberValue() ; break; - case 857 : if (DEBUG) { System.out.println("MemberValue ::= Name"); } //$NON-NLS-1$ + case 858 : if (DEBUG) { System.out.println("MemberValue ::= Name"); } //$NON-NLS-1$ consumeMemberValueAsName() ; break; - case 860 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ + case 861 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ consumeMemberValueArrayInitializer() ; break; - case 861 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ + case 862 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ consumeMemberValueArrayInitializer() ; break; - case 862 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ + case 863 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ consumeEmptyMemberValueArrayInitializer() ; break; - case 863 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ + case 864 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); } //$NON-NLS-1$ consumeEmptyMemberValueArrayInitializer() ; break; - case 864 : if (DEBUG) { System.out.println("EnterMemberValueArrayInitializer ::="); } //$NON-NLS-1$ + case 865 : if (DEBUG) { System.out.println("EnterMemberValueArrayInitializer ::="); } //$NON-NLS-1$ consumeEnterMemberValueArrayInitializer() ; break; - case 866 : if (DEBUG) { System.out.println("MemberValues ::= MemberValues COMMA MemberValue"); } //$NON-NLS-1$ + case 867 : if (DEBUG) { System.out.println("MemberValues ::= MemberValues COMMA MemberValue"); } //$NON-NLS-1$ consumeMemberValues() ; break; - case 867 : if (DEBUG) { System.out.println("MarkerAnnotation ::= AnnotationName"); } //$NON-NLS-1$ + case 868 : if (DEBUG) { System.out.println("MarkerAnnotation ::= AnnotationName"); } //$NON-NLS-1$ consumeMarkerAnnotation() ; break; - case 868 : if (DEBUG) { System.out.println("SingleMemberAnnotationMemberValue ::= MemberValue"); } //$NON-NLS-1$ + case 869 : if (DEBUG) { System.out.println("SingleMemberAnnotationMemberValue ::= MemberValue"); } //$NON-NLS-1$ consumeSingleMemberAnnotationMemberValue() ; break; - case 869 : if (DEBUG) { System.out.println("SingleMemberAnnotation ::= AnnotationName LPAREN..."); } //$NON-NLS-1$ + case 870 : if (DEBUG) { System.out.println("SingleMemberAnnotation ::= AnnotationName LPAREN..."); } //$NON-NLS-1$ consumeSingleMemberAnnotation() ; break; - case 870 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt TypeParameters"); } //$NON-NLS-1$ + case 871 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt TypeParameters"); } //$NON-NLS-1$ consumeRecoveryMethodHeaderNameWithTypeParameters(); break; - case 871 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt Type..."); } //$NON-NLS-1$ + case 872 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt Type..."); } //$NON-NLS-1$ consumeRecoveryMethodHeaderName(); break; - case 872 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ + case 873 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ consumeMethodHeader(); break; - case 873 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ + case 874 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ consumeMethodHeader(); break; - case 876 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= RecoveryCallinBindingLeftLong"); } //$NON-NLS-1$ + case 877 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= RecoveryCallinBindingLeftLong"); } //$NON-NLS-1$ consumeCallinHeader(); break; - case 877 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt CallinLabel..."); } //$NON-NLS-1$ + case 878 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt CallinLabel..."); } //$NON-NLS-1$ consumeCallinHeader(); break; - case 878 : if (DEBUG) { System.out.println("RecoveryCallinBindingLeftLong ::= RecoveryMethodSpecLong"); } //$NON-NLS-1$ + case 879 : if (DEBUG) { System.out.println("RecoveryCallinBindingLeftLong ::= RecoveryMethodSpecLong"); } //$NON-NLS-1$ consumeCallinBindingLeft(true); break; - case 879 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt..."); } //$NON-NLS-1$ + case 880 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt..."); } //$NON-NLS-1$ consumeCallinHeader(); break; - case 880 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt CallinLabel..."); } //$NON-NLS-1$ + case 881 : if (DEBUG) { System.out.println("RecoveryCallinHeader ::= Modifiersopt CallinLabel..."); } //$NON-NLS-1$ consumeCallinHeader(); break; - case 881 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= RecoveryCalloutBindingLeftLong"); } //$NON-NLS-1$ + case 882 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= RecoveryCalloutBindingLeftLong"); } //$NON-NLS-1$ consumeCalloutHeader(); break; - case 882 : if (DEBUG) { System.out.println("RecoveryCalloutBindingLeftLong ::=..."); } //$NON-NLS-1$ + case 883 : if (DEBUG) { System.out.println("RecoveryCalloutBindingLeftLong ::=..."); } //$NON-NLS-1$ consumeCalloutBindingLeft(true); break; - case 883 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= RecoveryCalloutBindingLeftLong"); } //$NON-NLS-1$ + case 884 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= RecoveryCalloutBindingLeftLong"); } //$NON-NLS-1$ consumeCalloutHeader(); break; - case 884 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= Modifiersopt..."); } //$NON-NLS-1$ + case 885 : if (DEBUG) { System.out.println("RecoveryCalloutHeader ::= Modifiersopt..."); } //$NON-NLS-1$ consumeCalloutHeader(); break; - case 885 : if (DEBUG) { System.out.println("RecoveryMethodSpecLong ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ + case 886 : if (DEBUG) { System.out.println("RecoveryMethodSpecLong ::= RecoveryMethodHeaderName..."); } //$NON-NLS-1$ consumeMethodSpecLong(false); break; } } -//CLOVER ON - +protected void consumeEnterInstanceCreationArgumentList() { + this.shouldDeferRecovery = true; +} protected void consumeSimpleAssertStatement() { // AssertStatement ::= 'assert' Expression ';' this.expressionLengthPtr--; @@ -12085,8 +12092,8 @@ protected void parse() { this.stack[this.stateStackTop] = act; act = tAction(act, this.currentToken); - if (act == ERROR_ACTION || this.restartRecovery) { - + if (act == ERROR_ACTION || (this.restartRecovery && !this.shouldDeferRecovery)) { + this.shouldDeferRecovery = false; if (DEBUG_AUTOMATON) { if (this.restartRecovery) { System.out.println("Restart - "); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java index 38624439c..6d1e45543 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java @@ -17,20 +17,20 @@ public interface ParserBasicInformation { ERROR_SYMBOL = 129, MAX_NAME_LENGTH = 41, - NUM_STATES = 1260, + NUM_STATES = 1266, NT_OFFSET = 129, SCOPE_UBOUND = 195, SCOPE_SIZE = 196, - LA_STATE_OFFSET = 14929, + LA_STATE_OFFSET = 14988, MAX_LA = 1, - NUM_RULES = 885, + NUM_RULES = 886, NUM_TERMINALS = 129, - NUM_NON_TERMINALS = 393, - NUM_SYMBOLS = 522, - START_STATE = 1374, + NUM_NON_TERMINALS = 394, + NUM_SYMBOLS = 523, + START_STATE = 1043, EOFT_SYMBOL = 73, EOLT_SYMBOL = 73, - ACCEPT_ACTION = 14928, - ERROR_ACTION = 14929; + ACCEPT_ACTION = 14987, + ERROR_ACTION = 14988; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java index dcabee07b..d81e2d64d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -120,6 +120,15 @@ public RecoveredElement add(Statement statement, int bracketBalanceValue) { /* default behavior is to delegate recording to parent if any */ resetPendingModifiers(); if (this.parent == null) return this; // ignore + if (this instanceof RecoveredType) { + TypeDeclaration typeDeclaration = ((RecoveredType) this).typeDeclaration; + if (typeDeclaration != null && (typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=291040, new X(<SelectOnMessageSend:zoo()>) { ??? + if (statement.sourceStart > typeDeclaration.sourceStart && statement.sourceEnd < typeDeclaration.sourceEnd) { + return this; + } + } + } this.updateSourceEndIfNecessary(previousAvailableLineEnd(statement.sourceStart - 1)); return this.parent.add(statement, bracketBalanceValue); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc Binary files differindex da3eb6b59..4e454509b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc Binary files differindex 6b4873738..12cb2fb54 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc Binary files differindex 383317c05..7945cf379 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc Binary files differindex af303e131..f8170121e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc Binary files differindex 5e881e4de..d46f8d727 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc Binary files differindex 4f0e77631..2eb1023f4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc Binary files differindex 963847eb7..fdb5c0b67 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc Binary files differindex 40303cab6..d4336044e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc Binary files differindex d38f08095..c36d2da5b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc Binary files differindex 627ba055f..eab2c90ed 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc index 3e8bc6e4c..f87b95095 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc @@ -1 +1 @@ - n uu s A LLLJJs n888x" Lo8 rA8JQJ
^^J"mmJmOnKzAnmJiMMPK""N"8i"x"""-"-"
\ No newline at end of file + n uu s A LLLJJs n888x" Lo8 rA8JQJ
^^J"mmJmOnKzAnmJiMMPK""N"8i"x"""-"-"
\ No newline at end of file diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc Binary files differindex 31386b4ea..1cd9bf0e5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc Binary files differindex 3833c700b..eadb7d274 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc Binary files differindex f645786af..7e2dda74d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc Binary files differindex e98e6140b..8a021578c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc Binary files differindex dffe4103e..da4cf4423 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc Binary files differindex 26160a974..b6d844e63 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc Binary files differindex ae96cd5fc..dc471b6e7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc Binary files differindex a7338d6ca..9fbed24cf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc Binary files differindex 49ede772f..8a682b47c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc Binary files differindex eea7898dd..5178a981c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc Binary files differindex bcd45f8f2..d2f1bc10b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.properties index ede708a07..a7cb94713 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.properties @@ -1,5 +1,5 @@ ,opt=, -\;opt=; +;opt=; AbstractMethodDeclaration=MethodDeclaration AdditionalBound1=AdditionalBound1 AdditionalBound=AdditionalBound @@ -134,6 +134,7 @@ EnhancedForStatementHeader=EnhancedForStatementHeader EnhancedForStatementHeaderInit=EnhancedForStatementHeaderInit EnhancedForStatementNoShortIf=EnhancedForStatementNoShortIf EnterCompilationUnit=EnterCompilationUnit +EnterInstanceCreationArgumentList=EnterInstanceCreationArgumentList EnterMemberValue=EnterMemberValue EnterMemberValueArrayInitializer=EnterMemberValueArrayInitializer EnterVariable=EnterVariable 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 ec4613745..b8c31f074 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 @@ -18,6 +18,7 @@ * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults *******************************************************************************/ package org.eclipse.jdt.internal.compiler.problem; @@ -351,26 +352,18 @@ public static int getIrritant(int problemID) { return CompilerOptions.VarargsArgumentNeedCast; case IProblem.NullLocalVariableReference: - case IProblem.NullFieldReference: return CompilerOptions.NullReference; case IProblem.PotentialNullLocalVariableReference: case IProblem.PotentialNullMessageSendReference: - case IProblem.PotentialNullFieldReference: return CompilerOptions.PotentialNullReference; case IProblem.RedundantLocalVariableNullAssignment: - case IProblem.RedundantFieldNullAssignment: case IProblem.RedundantNullCheckOnNonNullLocalVariable: case IProblem.RedundantNullCheckOnNullLocalVariable: case IProblem.NonNullLocalVariableComparisonYieldsFalse: case IProblem.NullLocalVariableComparisonYieldsFalse: case IProblem.NullLocalVariableInstanceofYieldsFalse: - case IProblem.NullFieldInstanceofYieldsFalse: - case IProblem.RedundantNullCheckOnNonNullField: - case IProblem.RedundantNullCheckOnNullField: - case IProblem.NonNullFieldComparisonYieldsFalse: - case IProblem.NullFieldComparisonYieldsFalse: case IProblem.RedundantNullCheckOnNonNullMessageSend: return CompilerOptions.RedundantNullCheck; @@ -782,7 +775,6 @@ public static int getProblemCategory(int severity, int problemID) { switch (problemID) { case IProblem.IsClassPathCorrect : case IProblem.CorruptedSignature : - case IProblem.MissingNullAnnotationType : return CategorizedProblem.CAT_BUILDPATH; //{ObjectTeams: case IProblem.BaseImportFromSplitPackage : @@ -5676,101 +5668,71 @@ public void localVariableHiding(LocalDeclaration local, Binding hiddenVariable, } } -public void variableNonNullComparedToNull(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.NonNullFieldComparisonYieldsFalse; - } else { - problem = IProblem.NonNullLocalVariableComparisonYieldsFalse; - } - int severity = computeSeverity(problem); +public void localVariableNonNullComparedToNull(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.NonNullLocalVariableComparisonYieldsFalse); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.NonNullLocalVariableComparisonYieldsFalse, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableNullComparedToNonNull(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.NullFieldComparisonYieldsFalse; - } else { - problem = IProblem.NullLocalVariableComparisonYieldsFalse; - } - int severity = computeSeverity(problem); +public void localVariableNullComparedToNonNull(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.NullLocalVariableComparisonYieldsFalse); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.NullLocalVariableComparisonYieldsFalse, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableNullInstanceof(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.NullFieldInstanceofYieldsFalse; - } else { - problem = IProblem.NullLocalVariableInstanceofYieldsFalse; - } - int severity = computeSeverity(problem); +public void localVariableNullInstanceof(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.NullLocalVariableInstanceofYieldsFalse); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.NullLocalVariableInstanceofYieldsFalse, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableNullReference(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.NullFieldReference; - } else { - problem = IProblem.NullLocalVariableReference; - } - int severity = computeSeverity(problem); +public void localVariableNullReference(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.NullLocalVariableReference); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; -//{ObjectTeams: synthetic local variabel (in within statement)? - if (location instanceof WithinStatement.SubstitutedReference) { - WithinStatement.SubstitutedReference nameRef = (WithinStatement.SubstitutedReference) location; - location = nameRef.getExpression(); - if (location instanceof SingleNameReference) // should be, since it resolved to a local variable - arguments = new String[] { new String(((SingleNameReference)location).token) }; - } -// SH} + String[] arguments = new String[] {new String(local.name) }; + //{ObjectTeams: synthetic local variable (in within statement)? + if (location instanceof WithinStatement.SubstitutedReference) { + WithinStatement.SubstitutedReference nameRef = (WithinStatement.SubstitutedReference) location; + location = nameRef.getExpression(); + if (location instanceof SingleNameReference) // should be, since it resolved to a local variable + arguments = new String[] { new String(((SingleNameReference)location).token) }; + } + // SH} this.handle( - problem, + IProblem.NullLocalVariableReference, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variablePotentialNullReference(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.PotentialNullFieldReference; - } else { - problem = IProblem.PotentialNullLocalVariableReference; - } - int severity = computeSeverity(problem); +public void localVariablePotentialNullReference(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.PotentialNullLocalVariableReference); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name)}; -//{ObjectTeams: synthetic local variabel (in within statement)? + String[] arguments = new String[] {new String(local.name)}; +//{ObjectTeams: synthetic local variable (in within statement)? if (location instanceof WithinStatement.SubstitutedReference) { WithinStatement.SubstitutedReference nameRef = (WithinStatement.SubstitutedReference) location; location = nameRef.getExpression(); @@ -5779,71 +5741,53 @@ public void variablePotentialNullReference(VariableBinding variable, ASTNode loc } // SH} this.handle( - problem, + IProblem.PotentialNullLocalVariableReference, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableRedundantCheckOnNonNull(VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.RedundantNullCheckOnNonNullField; - } else { - problem = IProblem.RedundantNullCheckOnNonNullLocalVariable; - } - int severity = computeSeverity(problem); +public void localVariableRedundantCheckOnNonNull(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.RedundantNullCheckOnNonNullLocalVariable); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.RedundantNullCheckOnNonNullLocalVariable, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableRedundantCheckOnNull (VariableBinding variable, ASTNode location) { - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.RedundantNullCheckOnNullField; - } else { - problem = IProblem.RedundantNullCheckOnNullLocalVariable; - } - int severity = computeSeverity(problem); +public void localVariableRedundantCheckOnNull(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.RedundantNullCheckOnNullLocalVariable); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.RedundantNullCheckOnNullLocalVariable, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } -public void variableRedundantNullAssignment (VariableBinding variable, ASTNode location) { +public void localVariableRedundantNullAssignment(LocalVariableBinding local, ASTNode location) { if ((location.bits & ASTNode.FirstAssignmentToLocal) != 0) // https://bugs.eclipse.org/338303 - Warning about Redundant assignment conflicts with definite assignment return; - int problem; - if (variable instanceof FieldBinding) { - problem = IProblem.RedundantFieldNullAssignment; - } else { - problem = IProblem.RedundantLocalVariableNullAssignment; - } - int severity = computeSeverity(problem); + int severity = computeSeverity(IProblem.RedundantLocalVariableNullAssignment); if (severity == ProblemSeverities.Ignore) return; - String[] arguments = new String[] {new String(variable.name) }; + String[] arguments = new String[] {new String(local.name) }; this.handle( - problem, + IProblem.RedundantLocalVariableNullAssignment, arguments, arguments, severity, - nodeSourceStart(variable, location), - nodeSourceEnd(variable, location)); + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); } public void methodMustOverride(AbstractMethodDeclaration method, long complianceLevel) { @@ -12586,11 +12530,6 @@ public void messageSendRedundantCheckOnNonNull(MethodBinding method, ASTNode loc location.sourceEnd); } -public void missingNullAnnotationType(char[][] nullAnnotationName) { - String[] args = { new String(CharOperation.concatWith(nullAnnotationName, '.')) }; - this.handle(IProblem.MissingNullAnnotationType, args, args, 0, 0); -} - public void cannotImplementIncompatibleNullness(MethodBinding currentMethod, MethodBinding inheritedMethod) { int sourceStart = 0, sourceEnd = 0; if (this.referenceContext instanceof TypeDeclaration) { 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 1a6a5876e..21e370c65 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 @@ -15,6 +15,7 @@ # bug 349326 - [1.7] new warning for missing try-with-resources # bug 186342 - [compiler][null] Using annotations for null checking # bug 365662 - [compiler][null] warn on contradictory and redundant null annotations +# bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults ############################################################################### 0 = {0} 1 = super cannot be used in java.lang.Object @@ -584,16 +585,6 @@ ### MORE GENERICS 660 = Unused type arguments for the non generic constructor {0}({1}) of type {2}; it should not be parameterized with arguments <{3}> -### NULL ANALYSIS FOR FIELDS -670 = Null pointer access: The field {0} can only be null at this location -671 = Potential null pointer access: The field {0} may be null at this location -672 = Redundant null check: The field {0} can only be null at this location -673 = Null comparison always yields false: The field {0} can only be null at this location -674 = Redundant null check: The field {0} cannot be null at this location -675 = Null comparison always yields false: The field {0} cannot be null at this location -676 = Redundant assignment: The field {0} can only be null at this location -677 = instanceof always yields false: The field {0} can only be null at this location - ### CORRUPTED BINARIES 700 = The class file {0} contains a signature ''{1}'' ill-formed at position {2} @@ -673,7 +664,7 @@ 910 = Type mismatch: required ''@{0} {1}'' but the provided value is null 911 = Type mismatch: required ''@{0} {1}'' but the provided value can be null 912 = Potential type mismatch: required ''@{0} {1}'' but nullness of the provided value is unknown -913 = Buildpath problem: the type {0}, which is configured as a null annotation type, cannot be resolved +#913 removed 914 = The return type is incompatible with the @{1} return from {0} 915 = Illegal redefinition of parameter {0}, inherited method from {1} declares this parameter as @{2} 916 = Illegal redefinition of parameter {0}, inherited method from {1} does not constrain this parameter diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeValueParameter.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeValueParameter.java index 8950b3f8c..f4a622cc4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeValueParameter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeValueParameter.java @@ -145,14 +145,12 @@ public class TypeValueParameter extends TypeParameter { } /** Count all TypeValuaParameters of declaration into the number of its fields. */ - public static int count(TypeDeclaration declaration) { + public static void updateMaxFieldCount(TypeDeclaration declaration) { TypeParameter[] typeParameters = declaration.typeParameters; - int count = 0; for (int i = 0; i < typeParameters.length; i++) { - if (typeParameters[i] instanceof TypeValueParameter) { - count++; - } + if (typeParameters[i] instanceof TypeValueParameter) + declaration.maxFieldCount++; } - return count; + } } diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java index a5faa36ba..54f3fd567 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -107,6 +107,7 @@ public final class AST { /** * Constant for indicating the AST API that handles JLS2. + * <p> * This API is capable of handling all constructs * in the Java language as described in the Java Language * Specification, Second Edition (JLS2). @@ -114,6 +115,7 @@ public final class AST { * Java language, and the JLS2 API can be used to manipulate * programs written in all versions of the Java language * up to and including J2SE 1.4. + * </p> * * @since 3.0 * @deprecated Clients should use the {@link #JLS4} AST API instead. @@ -129,6 +131,7 @@ public final class AST { /** * Constant for indicating the AST API that handles JLS3. + * <p> * This API is capable of handling all constructs in the * Java language as described in the Java Language * Specification, Third Edition (JLS3). @@ -136,21 +139,23 @@ public final class AST { * Java language, and the JLS3 API can be used to manipulate * programs written in all versions of the Java language * up to and including J2SE 5 (aka JDK 1.5). + * </p> * * @since 3.1 */ public static final int JLS3 = 3; /** - * Constant for indicating the AST API that handles JLS4. + * Constant for indicating the AST API that handles JLS4 (aka JLS7). + * <p> * This API is capable of handling all constructs in the * Java language as described in the Java Language - * Specification, Third Edition (JLS3) plus all the new language - * features described in the JSR334. + * Specification, Java SE 7 Edition (JLS7) as specified by JSR336. * JLS4 is a superset of all earlier versions of the * Java language, and the JLS4 API can be used to manipulate * programs written in all versions of the Java language - * up to and including J2SE 7 (aka JDK 1.7). + * up to and including Java SE 7 (aka JDK 1.7). + * </p> * * @since 3.7.1 */ @@ -168,7 +173,7 @@ public final class AST { * into a compilation unit. This method is not intended to be called by clients. * </p> * - * @param level the API level; one of the LEVEL constants + * @param level the API level; one of the <code>JLS*</code> level constants * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration * @param source the string of the Java compilation unit * @param options compiler options @@ -199,7 +204,7 @@ public final class AST { * into a compilation unit. This method is not intended to be called by clients. * </p> * - * @param level the API level; one of the LEVEL constants + * @param level the API level; one of the <code>JLS*</code> level constants * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration * @param options compiler options * @param workingCopy the working copy that the AST is created from @@ -250,11 +255,11 @@ public final class AST { * AST level in all cases, even when dealing with source of earlier JDK versions like 1.3 or 1.4. * </p> * - * @param level the API level; one of the LEVEL constants + * @param level the API level; one of the <code>JLS*</code> level constants * @return new AST instance following the specified set of API rules. * @exception IllegalArgumentException if: * <ul> - * <li>the API level is not one of the LEVEL constants</li> + * <li>the API level is not one of the <code>JLS*</code> level constants</li> * </ul> * @since 3.0 */ @@ -637,7 +642,7 @@ public final class AST { * Creates a new Java abstract syntax tree * (AST) following the specified set of API rules. * - * @param level the API level; one of the JLS* level constants + * @param level the API level; one of the <code>JLS*</code> level constants * @since 3.0 */ private AST(int level) { @@ -732,7 +737,7 @@ public final class AST { /** * Return the API level supported by this AST. * - * @return level the API level; one of the <code>JLS*</code>LEVEL + * @return level the API level; one of the <code>JLS*</code> level constants * declared on <code>AST</code>; assume this set is open-ended * @since 3.0 */ diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java index c2aa0cd84..3383674bf 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java @@ -4768,7 +4768,6 @@ class ASTConverter { int indexInAnnotations = 0; while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { IExtendedModifier modifier = null; - switchToken: switch(token) { case TerminalTokens.TokenNameabstract: modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); @@ -4814,13 +4813,7 @@ class ASTConverter { case TerminalTokens.TokenNameAT : // we have an annotation if (annotations != null && indexInAnnotations < annotations.length) { - // method may have synthetic annotations, skip them: - org.eclipse.jdt.internal.compiler.ast.Annotation annotation; - do { - if (indexInAnnotations == annotations.length) - break switchToken; - annotation = annotations[indexInAnnotations++]; - } while ((annotation.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsSynthetic) != 0); + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; modifier = convert(annotation); this.scanner.resetTo(annotation.declarationSourceEnd + 1, modifiersEnd); } @@ -4934,7 +4927,6 @@ class ASTConverter { int token; while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { IExtendedModifier modifier = null; - switchToken: switch(token) { case TerminalTokens.TokenNameabstract: modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); @@ -4972,13 +4964,7 @@ class ASTConverter { case TerminalTokens.TokenNameAT : // we have an annotation if (annotations != null && indexInAnnotations < annotations.length) { - // argument may have synthetic annotations, skip them: - org.eclipse.jdt.internal.compiler.ast.Annotation annotation; - do { - if (indexInAnnotations == annotations.length) - break switchToken; - annotation = annotations[indexInAnnotations++]; - } while ((annotation.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsSynthetic) != 0); + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; modifier = convert(annotation); this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength); } @@ -5052,7 +5038,6 @@ class ASTConverter { break; case TerminalTokens.TokenNameAT : // we have an annotation - // (local variable has no synthetic annotations, no need to skip them) if (annotations != null && indexInAnnotations < annotations.length) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; modifier = convert(annotation); @@ -5155,7 +5140,6 @@ class ASTConverter { break; case TerminalTokens.TokenNameAT : // we have an annotation - // (local variable has no synthetic annotations, no need to skip them) if (annotations != null && indexInAnnotations < annotations.length) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; modifier = convert(annotation); @@ -5237,7 +5221,6 @@ class ASTConverter { break; case TerminalTokens.TokenNameAT : // we have an annotation - // (local variable has no synthetic annotations, no need to skip them) if (annotations != null && indexInAnnotations < annotations.length) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; modifier = convert(annotation); diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java index 37343ada8..fc3fe76fb 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2012 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 @@ -121,8 +121,8 @@ public class ASTParser { * Creates a new object for creating a Java abstract syntax tree * (AST) following the specified set of API rules. * - * @param level the API level; one of the LEVEL constants - * declared on <code>AST</code> + * @param level the API level; one of the <code>.JLS*</code> level constants + * declared on {@link AST} * @return new ASTParser instance */ public static ASTParser newParser(int level) { @@ -217,8 +217,8 @@ public class ASTParser { * N.B. This constructor is package-private. * </p> * - * @param level the API level; one of the LEVEL constants - * declared on <code>AST</code> + * @param level the API level; one of the <code>JLS*</code> level constants + * declared on {@link AST} */ ASTParser(int level) { switch(level) { diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java index 01b3d3dce..446681928 100644 --- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java +++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2010 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 @@ -126,7 +126,6 @@ public CodeSnippetClassFile( } // retrieve the enclosing one guaranteed to be the one matching the propagated flow info // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) - // see also https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564#c65 this.codeStream.maxFieldCount = aType.scope.outerMostClassScope().referenceType().maxFieldCount; } /** diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core/grammar/java.g index 702448ff0..f520041de 100644 --- a/org.eclipse.jdt.core/grammar/java.g +++ b/org.eclipse.jdt.core/grammar/java.g @@ -1701,28 +1701,32 @@ AllocationHeader ::= 'new' ClassType '(' ArgumentListopt ')' /.$putCase consumeAllocationHeader(); $break ./ /:$readableName AllocationHeader:/ -ClassInstanceCreationExpression ::= 'new' OnlyTypeArguments ClassType '(' ArgumentListopt ')' UnqualifiedClassBodyopt +ClassInstanceCreationExpression ::= 'new' OnlyTypeArguments ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' UnqualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpressionWithTypeArguments(); $break ./ -ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' UnqualifiedClassBodyopt +ClassInstanceCreationExpression ::= 'new' ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' UnqualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpression(); $break ./ --1.1 feature -ClassInstanceCreationExpression ::= Primary '.' 'new' OnlyTypeArguments ClassType '(' ArgumentListopt ')' QualifiedClassBodyopt +ClassInstanceCreationExpression ::= Primary '.' 'new' OnlyTypeArguments ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' QualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() ; $break ./ -ClassInstanceCreationExpression ::= Primary '.' 'new' ClassType '(' ArgumentListopt ')' QualifiedClassBodyopt +ClassInstanceCreationExpression ::= Primary '.' 'new' ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' QualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./ --1.1 feature -ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' ClassType '(' ArgumentListopt ')' QualifiedClassBodyopt +ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' QualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./ /:$readableName ClassInstanceCreationExpression:/ -ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' OnlyTypeArguments ClassType '(' ArgumentListopt ')' QualifiedClassBodyopt +ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' OnlyTypeArguments ClassType EnterInstanceCreationArgumentList '(' ArgumentListopt ')' QualifiedClassBodyopt /.$putCase consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() ; $break ./ /:$readableName ClassInstanceCreationExpression:/ +EnterInstanceCreationArgumentList ::= $empty +/.$putCase consumeEnterInstanceCreationArgumentList(); $break ./ +/:$readableName EnterInstanceCreationArgumentList:/ + ClassInstanceCreationExpressionName ::= Name '.' /.$putCase consumeClassInstanceCreationExpressionName() ; $break ./ /:$readableName ClassInstanceCreationExpressionName:/ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index 7cd1b9297..623b7b468 100644 --- a/org.ecl |