### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v retrieving revision 1.225.2.22 diff -u -r1.225.2.22 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 21 Jun 2011 15:48:53 -0000 1.225.2.22 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 23 Jun 2011 21:24:35 -0000 @@ -1392,6 +1392,15 @@ int SwitchOnStringsNotBelow17 = TypeRelated + 881; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=348492 /** @since 3.7 */ int UnhandledExceptionOnAutoClose = TypeRelated + 882; + /** @since 3.7 */ + int PotentiallyUnclosedCloseable = Internal + 883; + /** @since 3.7 */ + int PotentiallyUnclosedCloseableAtExit = Internal + 884; + /** @since 3.7 */ + int UnclosedCloseable = Internal + 885; + /** @since 3.7 */ + int UnclosedCloseableAtExit = Internal + 886; + /** * External problems -- These are problems defined by other plugins */ Index: compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java =================================================================== RCS file: compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java diff -N compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2011 GK Software AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * GK Software AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; + +/** + * A faked local variable declaration used for keeping track of data flows of a + * special variable. Certain events will be recorded by changing the null info + * for this variable. + * + * @author Stephan Herrmann + */ +public class FakedTrackingVariable extends LocalDeclaration { + + public FakedTrackingVariable(BlockScope currentScope, LocalDeclaration localDeclaration) { + super(localDeclaration.name, localDeclaration.sourceStart, localDeclaration.sourceEnd); + this.type = new SingleTypeReference( + TypeConstants.OBJECT, + ((long)this.sourceStart <<32)+this.sourceEnd); + currentScope.addTrackingVariable(this); + resolve(currentScope); + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream) + { /* NOP - this variable is completely dummy, ie. for analysis only. */ } + + public void resolve (BlockScope scope) { + // only need the binding, which is used as reference in FlowInfo methods. + this.binding = new LocalVariableBinding( + this.name, + scope.getJavaLangObject(), // dummy, just needs to be a reference type + 0, + false); + this.binding.setConstant(Constant.NotAConstant); + this.binding.useFlag = LocalVariableBinding.USED; + // use a free slot without assigning it: + this.binding.id = scope.outerMostMethodScope().analysisIndex+1; // FIXME(SH): avoid conflicting index for several tracking vars within 1 method + } + + public static boolean isAutoCloseable(TypeBinding typeBinding) { + return typeBinding instanceof ReferenceBinding + && (((ReferenceBinding)typeBinding).typeBits & TypeIds.BitAutoCloseable) != 0; + } + + public static FakedTrackingVariable getTrackingVariable(Expression expression) { + if (expression instanceof SingleNameReference) { + SingleNameReference returnName = (SingleNameReference) expression; + if (returnName.binding instanceof LocalVariableBinding) + return ((LocalVariableBinding)returnName.binding).closeTracker; + } + return null; + } +} Index: compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java,v retrieving revision 1.77.2.3 diff -u -r1.77.2.3 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 8 Mar 2011 17:20:09 -0000 1.77.2.3 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 23 Jun 2011 21:24:37 -0000 @@ -71,6 +71,10 @@ if ((this.initialization.implicitConversion & TypeIds.UNBOXING) != 0) { this.initialization.checkNPE(currentScope, flowContext, flowInfo); } + if (FakedTrackingVariable.isAutoCloseable(this.initialization.resolvedType)) { + this.binding.closeTracker = new FakedTrackingVariable(currentScope, this); + flowInfo.markAsDefinitelyNull(this.binding.closeTracker.binding); + } flowInfo = this.initialization Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v retrieving revision 1.151.2.7 diff -u -r1.151.2.7 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 7 Jun 2011 16:14:10 -0000 1.151.2.7 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 23 Jun 2011 21:24:39 -0000 @@ -42,6 +42,7 @@ import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; 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.problem.ProblemSeverities; @@ -64,6 +65,10 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { boolean nonStatic = !this.binding.isStatic(); flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); + FakedTrackingVariable trackingVariable = FakedTrackingVariable.getTrackingVariable(this.receiver); + if ( trackingVariable != null + && CharOperation.equals(TypeConstants.CLOSE, this.selector)) + flowInfo.markAsDefinitelyNonNull(trackingVariable.binding); if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 Index: compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java,v retrieving revision 1.79.2.1 diff -u -r1.79.2.1 MethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 5 Mar 2011 18:12:56 -0000 1.79.2.1 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 23 Jun 2011 21:24:39 -0000 @@ -134,6 +134,7 @@ } } + this.scope.checkUnclosedCloseables(flowInfo, null); } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java,v retrieving revision 1.70.2.1 diff -u -r1.70.2.1 ReturnStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 27 Apr 2011 16:33:51 -0000 1.70.2.1 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 23 Jun 2011 21:24:39 -0000 @@ -40,6 +40,9 @@ if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } + FakedTrackingVariable trackingVariable = FakedTrackingVariable.getTrackingVariable(this.expression); + if (trackingVariable != null) + flowInfo.markAsDefinitelyNonNull(trackingVariable.binding); } this.initStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); @@ -104,6 +107,7 @@ this.expression.bits |= ASTNode.IsReturnedValue; } } + currentScope.checkUnclosedCloseables(flowInfo, this); return FlowInfo.DEAD_END; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java,v retrieving revision 1.116.2.25 diff -u -r1.116.2.25 TryStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 21 Jun 2011 15:48:53 -0000 1.116.2.25 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 23 Jun 2011 21:24:42 -0000 @@ -120,8 +120,11 @@ for (int i = 0, max = this.resources.length; i < max; i++) { flowInfo = this.resources[i].analyseCode(currentScope, handlingContext, flowInfo.copy()); - this.resources[i].binding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. - TypeBinding type = this.resources[i].binding.type; + LocalVariableBinding resourceBinding = this.resources[i].binding; + resourceBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. + if (resourceBinding.closeTracker != null) + flowInfo.markAsDefinitelyNonNull(resourceBinding.closeTracker.binding); + TypeBinding type = resourceBinding.type; if (type != null && type.isValidBinding()) { ReferenceBinding binding = (ReferenceBinding) type; MethodBinding closeMethod = binding.getExactMethod(ConstantPool.Close, new TypeBinding [0], this.scope.compilationUnitScope()); // scope needs to be tighter Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java,v retrieving revision 1.136 diff -u -r1.136 BinaryTypeBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 17 Jan 2011 13:00:56 -0000 1.136 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 23 Jun 2011 21:24:44 -0000 @@ -1141,6 +1141,7 @@ this.tagBits &= ~TagBits.HasUnresolvedSuperclass; if (this.superclass.problemId() == ProblemReasons.NotFound) this.tagBits |= TagBits.HierarchyHasProblems; // propagate type inconsistency + this.typeBits |= (this.superclass.id & TypeIds.BitAutoCloseable); return this.superclass; } // NOTE: superInterfaces of binary types are resolved when needed @@ -1152,6 +1153,9 @@ this.superInterfaces[i] = (ReferenceBinding) resolveType(this.superInterfaces[i], this.environment, true /* raw conversion */); if (this.superInterfaces[i].problemId() == ProblemReasons.NotFound) this.tagBits |= TagBits.HierarchyHasProblems; // propagate type inconsistency + if ( this.superInterfaces[i].id == TypeIds.T_JavaLangAutoCloseable + || (this.superInterfaces[i].typeBits & TypeIds.BitAutoCloseable) != 0) + this.typeBits |= TypeIds.BitAutoCloseable; } this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces; return this.superInterfaces; Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java,v retrieving revision 1.123.2.3 diff -u -r1.123.2.3 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 5 May 2011 14:31:10 -0000 1.123.2.3 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 23 Jun 2011 21:24:46 -0000 @@ -10,10 +10,14 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; @@ -957,4 +961,24 @@ } } } + +// TODO: List or array? +// TODO: move these to FlowInfo? (beware of flowInfo copying!) +private List trackingVariables; +public void addTrackingVariable(FakedTrackingVariable fakedTrackingVariable) { + if (this.trackingVariables == null) + this.trackingVariables = new ArrayList(); + this.trackingVariables.add(fakedTrackingVariable); +} + +public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location) { + if (this.trackingVariables == null) return; + for (int i=0; i