diff options
Diffstat (limited to 'org.eclipse.jdt.core')
90 files changed, 1604 insertions, 1877 deletions
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.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -103,7 +103,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.CoreException; @@ -120,7 +119,6 @@ import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; @@ -1799,20 +1797,6 @@ public final class JavaCore extends Plugin { */ public static final String COMPILER_PB_INCLUDE_ASSERTS_IN_NULL_ANALYSIS = PLUGIN_ID + ".compiler.problem.includeNullInfoFromAsserts"; //$NON-NLS-1$ /** - * Compiler option ID: Raise null related errors or warnings on fields. - * <p>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.</p> - * <p>When disabled, the compiler will not flag null related errors or warnings on fields.</p> - * <dl> - * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.includeFieldsInNullAnalysis"</code></dd> - * <dt>Possible values:</dt><dd><code>{ "enabled", "disabled" }</code></dd> - * <dt>Default:</dt><dd><code>"disabled"</code></dd> - * </dl> - * @since 3.8 - * @category CompilerOptionID - */ - public static final String COMPILER_PB_INCLUDE_FIELDS_IN_NULL_ANALYSIS = PLUGIN_ID + ".compiler.problem.includeFieldsInNullAnalysis"; //$NON-NLS-1$ - /** * Compiler option ID: Further Determining the Effect of <code>@SuppressWarnings</code> if also * {@link #COMPILER_PB_SUPPRESS_WARNINGS} is enabled. * <p>When enabled, the <code>@SuppressWarnings</code> annotation can additionally be used to suppress @@ -3919,7 +3903,6 @@ public final class JavaCore extends Plugin { monitor.subTask(Messages.javamodel_resetting_source_attachment_properties); final IJavaProject[] projects = manager.getJavaModel().getJavaProjects(); HashSet visitedPaths = new HashSet(); - HashSet externalPaths = new HashSet(); ExternalFoldersManager externalFoldersManager = JavaModelManager.getExternalManager(); for (int i = 0, length = projects.length; i < length; i++) { JavaProject javaProject = (JavaProject) projects[i]; @@ -3943,32 +3926,19 @@ public final class JavaCore extends Plugin { if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath entryPath = entry.getPath(); if (ExternalFoldersManager.isExternalFolderPath(entryPath) && externalFoldersManager.getFolder(entryPath) == null) { - externalPaths.add(entryPath); + externalFoldersManager.addFolder(entryPath, true); } } } } } - - ISchedulingRule rule = null; try { - // Use a schedule rule to avoid a race condition (https://bugs.eclipse.org/bugs/show_bug.cgi?id=369251) - rule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(externalFoldersManager.getExternalFoldersProject()); - Job.getJobManager().beginRule(rule, monitor); - - Iterator externalPathIter = externalPaths.iterator(); - while (externalPathIter.hasNext()) { - externalFoldersManager.addFolder((IPath) externalPathIter.next(), true); - } externalFoldersManager.createPendingFolders(monitor); - - } catch (JavaModelException jme) { + } + catch(JavaModelException jme) { // Creation of external folder project failed. Log it and continue; Util.log(jme, "Error while processing external folders"); //$NON-NLS-1$ - } finally { - Job.getJobManager().endRule(rule); } - // initialize delta state if (monitor != null) monitor.subTask(Messages.javamodel_initializing_delta_state); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java index d6156980e..928b6d1c2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.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 @@ -122,7 +122,7 @@ public class ExternalFoldersManager { } while (result.exists()); if (scheduleForCreation) { if (this.pendingFolders == null) - this.pendingFolders = new HashSet(); + this.pendingFolders = Collections.synchronizedSet(new HashSet()); this.pendingFolders.add(externalFolderPath); } knownFolders.put(externalFolderPath, result); @@ -166,16 +166,22 @@ public class ExternalFoldersManager { catch(CoreException e) { throw new JavaModelException(e); } - Iterator iterator = this.pendingFolders.iterator(); - while (iterator.hasNext()) { - Object folderPath = iterator.next(); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=368152 + // To avoid race condition (from addFolder and removeFolder, load the map elements into an array and clear the map immediately. + // The createLinkFolder being in the synchronized block can cause a deadlock and hence keep it out of the synchronized block. + Object[] arrayOfFolders = null; + synchronized (this.pendingFolders) { + arrayOfFolders = this.pendingFolders.toArray(); + this.pendingFolders.clear(); + } + + for (int i=0; i < arrayOfFolders.length; i++) { try { - createLinkFolder((IPath) folderPath, false, externalFoldersProject, monitor); + createLinkFolder((IPath) arrayOfFolders[i], false, externalFoldersProject, monitor); } catch (CoreException e) { - Util.log(e, "Error while creating a link for external folder :" + folderPath); //$NON-NLS-1$ + Util.log(e, "Error while creating a link for external folder :" + arrayOfFolders[i]); //$NON-NLS-1$ } } - this.pendingFolders.clear(); } public void cleanUp(IProgressMonitor monitor) throws CoreException { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java index 38599dc0a..836959a56 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Technical University Berlin - extended API and implementation + * Terry Parker <tparker@google.com> (Google Inc.) https://bugs.eclipse.org/365499 *******************************************************************************/ package org.eclipse.jdt.internal.core; import java.util.HashMap; @@ -31,6 +32,7 @@ public class JavaModelCache { public static final int DEFAULT_OPENABLE_SIZE = 250; // average 6629 bytes per openable (includes children) -> maximum size : 662900*BASE_VALUE bytes public static final int DEFAULT_CHILDREN_SIZE = 250*20; // average 20 children per openable public static final String RATIO_PROPERTY = "org.eclipse.jdt.core.javamodelcache.ratio"; //$NON-NLS-1$ + public static final String JAR_TYPE_RATIO_PROPERTY = "org.eclipse.jdt.core.javamodelcache.jartyperatio"; //$NON-NLS-1$ public static final Object NON_EXISTING_JAR_TYPE_INFO = new Object(); @@ -75,9 +77,9 @@ public class JavaModelCache { protected LRUCache jarTypeCache; public JavaModelCache() { - // set the size of the caches in function of the maximum amount of memory available + // set the size of the caches as a function of the maximum amount of memory available double ratio = getMemoryRatio(); - // adjust the size of the openable cache in function of the RATIO_PROPERTY property + // adjust the size of the openable cache using the RATIO_PROPERTY property double openableRatio = getOpenableRatio(); this.projectCache = new HashMap(DEFAULT_PROJECT_SIZE); // NB: Don't use a LRUCache for projects as they are constantly reopened (e.g. during delta processing) if (VERBOSE) { @@ -94,13 +96,21 @@ public JavaModelCache() { } private double getOpenableRatio() { - String property = System.getProperty(RATIO_PROPERTY); + return getRatioForProperty(RATIO_PROPERTY); +} + +private double getJarTypeRatio() { + return getRatioForProperty(JAR_TYPE_RATIO_PROPERTY); +} + +private double getRatioForProperty(String propertyName) { + String property = System.getProperty(propertyName); if (property != null) { try { return Double.parseDouble(property); } catch (NumberFormatException e) { // ignore - Util.log(e, "Could not parse value for " + RATIO_PROPERTY + ": " + property); //$NON-NLS-1$ //$NON-NLS-2$ + Util.log(e, "Could not parse value for " + propertyName + ": " + property); //$NON-NLS-1$ //$NON-NLS-2$ } } return 1.0; @@ -264,7 +274,7 @@ protected void removeInfo(JavaElement element) { } } protected void resetJarTypeCache() { - this.jarTypeCache = new LRUCache((int) (DEFAULT_OPENABLE_SIZE * getMemoryRatio())); + this.jarTypeCache = new LRUCache((int) (DEFAULT_OPENABLE_SIZE * getMemoryRatio() * getJarTypeRatio())); } public String toString() { return toStringFillingRation(""); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/scripts/generateOTParser.sh b/org.eclipse.jdt.core/scripts/generateOTParser.sh index 4dc1bf4f3..4dc1bf4f3 100644..100755 --- a/org.eclipse.jdt.core/scripts/generateOTParser.sh +++ b/org.eclipse.jdt.core/scripts/generateOTParser.sh diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java index 753c785ed..f47d86553 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.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 @@ -75,9 +75,12 @@ import org.eclipse.jdt.internal.core.PackageFragmentRoot; import org.eclipse.jdt.internal.core.SearchableEnvironment; import org.eclipse.jdt.internal.core.SourceMapper; import org.eclipse.jdt.internal.core.SourceMethod; +import org.eclipse.jdt.internal.core.SourceType; import org.eclipse.jdt.internal.core.SourceTypeElementInfo; import org.eclipse.jdt.internal.core.index.Index; import org.eclipse.jdt.internal.core.search.*; +import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; +import org.eclipse.jdt.internal.core.util.ASTNodeFinder; import org.eclipse.jdt.internal.core.util.HandleFactory; import org.eclipse.jdt.internal.core.util.Util; import org.eclipse.objectteams.otdt.core.IMethodMapping; @@ -202,6 +205,8 @@ SimpleLookupTable bindings; HashSet methodHandles; private final boolean searchPackageDeclaration; +private int sourceStartOfMethodToRetain; +private int sourceEndOfMethodToRetain; public static class WorkingCopyDocument extends JavaSearchDocument { public org.eclipse.jdt.core.ICompilationUnit workingCopy; @@ -351,6 +356,22 @@ public MatchLocator( } else { this.searchPackageDeclaration = false; } + if (pattern instanceof MethodPattern) { + IType type = ((MethodPattern) pattern).declaringType; + if (type != null && !type.isBinary()) { + SourceType sourceType = (SourceType) type; + IMember local = sourceType.getOuterMostLocalContext(); + if (local instanceof IMethod) { // remember this method's range so we don't purge its statements. + try { + ISourceRange range = local.getSourceRange(); + this.sourceStartOfMethodToRetain = range.getOffset(); + this.sourceEndOfMethodToRetain = this.sourceStartOfMethodToRetain + range.getLength() - 1; // offset is 0 based. + } catch (JavaModelException e) { + // drop silently. + } + } + } + } } /** * Add an additional binary type @@ -969,10 +990,47 @@ protected TypeBinding getType(Object typeKey, char[] typeName) { // Get binding from unit scope char[][] compoundName = CharOperation.splitOn('.', typeName); TypeBinding typeBinding = this.unitScope.getType(compoundName, compoundName.length); + if (typeBinding == null || !typeBinding.isValidBinding()) { + typeBinding = this.lookupEnvironment.getType(compoundName); + } this.bindings.put(typeKey, typeBinding); - return typeBinding.isValidBinding() ? typeBinding : null; + return typeBinding != null && typeBinding.isValidBinding() ? typeBinding : null; } public MethodBinding getMethodBinding(MethodPattern methodPattern) { + MethodBinding methodBinding = getMethodBinding0(methodPattern); + if (methodBinding != null) + return methodBinding; // known to be valid. + // special handling for methods of anonymous/local types. Since these cannot be looked up in the environment the usual way ... + if (methodPattern.focus instanceof SourceMethod) { + char[] typeName = PatternLocator.qualifiedPattern(methodPattern.declaringSimpleName, methodPattern.declaringQualification); + if (CharOperation.indexOf(IIndexConstants.ONE_STAR, typeName, true) >= 0) { // See org.eclipse.jdt.core.search.SearchPattern.enclosingTypeNames(IType) + IType type = methodPattern.declaringType; + IType enclosingType = type.getDeclaringType(); + while (enclosingType != null) { + type = enclosingType; + enclosingType = type.getDeclaringType(); + } + typeName = type.getFullyQualifiedName().toCharArray(); + TypeBinding declaringTypeBinding = getType(typeName, typeName); + if (declaringTypeBinding instanceof SourceTypeBinding) { + SourceTypeBinding sourceTypeBinding = ((SourceTypeBinding) declaringTypeBinding); + ClassScope skope = sourceTypeBinding.scope; + if (skope != null) { + CompilationUnitDeclaration unit = skope.referenceCompilationUnit(); + if (unit != null) { + AbstractMethodDeclaration amd = new ASTNodeFinder(unit).findMethod((IMethod) methodPattern.focus); + if (amd != null && amd.binding != null && amd.binding.isValidBinding()) { + this.bindings.put(methodPattern, amd.binding); + return amd.binding; + } + } + } + } + } + } + return null; +} +private MethodBinding getMethodBinding0(MethodPattern methodPattern) { if (this.unitScope == null) return null; // Try to get binding from cache Binding binding = (Binding) this.bindings.get(methodPattern); @@ -1083,7 +1141,7 @@ public void initialize(JavaProject project, int possibleMatchSize) throws JavaMo this.options, new DefaultProblemFactory()); this.lookupEnvironment = new LookupEnvironment(this, this.options, problemReporter, this.nameEnvironment); - + this.lookupEnvironment.mayTolerateMissingType = true; this.parser = MatchLocatorParser.createParser(problemReporter, this); // basic parser needs also to be reset as project options may have changed @@ -1856,14 +1914,19 @@ protected void purgeMethodStatements(TypeDeclaration type, boolean checkEachMeth for (int j = 0, length = methods.length; j < length; j++) { AbstractMethodDeclaration method = methods[j]; if (!this.currentPossibleMatch.nodeSet.hasPossibleNodes(method.declarationSourceStart, method.declarationSourceEnd)) { - method.statements = null; - method.javadoc = null; + if (this.sourceStartOfMethodToRetain != method.declarationSourceStart || this.sourceEndOfMethodToRetain != method.declarationSourceEnd) { // approximate, but no big deal + method.statements = null; + method.javadoc = null; + } } } } else { for (int j = 0, length = methods.length; j < length; j++) { - methods[j].statements = null; - methods[j].javadoc = null; + AbstractMethodDeclaration method = methods[j]; + if (this.sourceStartOfMethodToRetain != method.declarationSourceStart || this.sourceEndOfMethodToRetain != method.declarationSourceEnd) { // approximate, but no big deal + method.statements = null; + method.javadoc = null; + } } } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java index 1e437fa52..c05d929a1 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.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 @@ -83,6 +83,7 @@ protected boolean isDeclarationOfReferencedMethodsPattern; //extra reference info public char[][][] allSuperDeclaringTypeNames; +private MatchLocator matchLocator; //method declarations which parameters verification fail private HashMap methodDeclarationsWithInvalidParam = new HashMap(); @@ -134,6 +135,7 @@ public void initializePolymorphicSearch(MatchLocator locator) { locator, this.pattern.declaringType, locator.progressMonitor).collect(); + this.matchLocator = locator; } catch (JavaModelException e) { // inaccurate matches will be found } @@ -359,7 +361,7 @@ protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) { // return inaccurate match for ambiguous call (bug 80890) return INACCURATE_MATCH; } - + boolean foundTypeVariable = false; // verify each parameter for (int i = 0; i < parameterCount; i++) { //{ObjectTeams: callin method? @@ -385,6 +387,9 @@ protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) { // Do not consider match as impossible while finding declarations and source level >= 1.5 // (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763) newLevel = level; + } else if (argType.isTypeVariable()) { + newLevel = level; + foundTypeVariable = true; } else { return IMPOSSIBLE_MATCH; } @@ -392,10 +397,23 @@ protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) { level = newLevel; // can only be downgraded } } + if (foundTypeVariable) { + if (!method.isStatic() && !method.isPrivate()) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types. + MethodBinding focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern); + if (focusMethodBinding != null) { + if (matchOverriddenMethod(focusMethodBinding.declaringClass, focusMethodBinding, method)) { + return ACCURATE_MATCH; + } + } + } + return IMPOSSIBLE_MATCH; + } } return level; } +// This works for only methods of parameterized types. private boolean matchOverriddenMethod(ReferenceBinding type, MethodBinding method, MethodBinding matchMethod) { if (type == null || this.pattern.selector == null) return false; |