### 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 6 Jul 2011 16:03:43 -0000 @@ -1392,6 +1392,17 @@ 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; + /** @since 3.7 */ + int ExplicitlyClosedAutoCloseable = Internal + 887; + /** * External problems -- These are problems defined by other plugins */ Index: compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java,v retrieving revision 1.94.2.3 diff -u -r1.94.2.3 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 16 Mar 2011 10:04:29 -0000 1.94.2.3 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 6 Jul 2011 16:03:43 -0000 @@ -48,6 +48,25 @@ if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } + if (local != null) { + LocalVariableBinding trackerBinding = null; + if (local.closeTracker != null) { + // Assigning to a variable already holding an AutoCloseable, has it been closed before? + trackerBinding = local.closeTracker.binding; + if (flowInfo.isDefinitelyNull(trackerBinding)) + currentScope.problemReporter().unclosedCloseable(local.closeTracker, this); + else if (flowInfo.isPotentiallyNull(trackerBinding)) + currentScope.problemReporter().potentiallyUnclosedCloseable(local.closeTracker, this); + } + if (FakedTrackingVariable.isAutoCloseable(this.expression.resolvedType)) { + // new value is AutoCloseable start tracking, possibly re-using existing tracker var: + if (trackerBinding == null) { + local.closeTracker = new FakedTrackingVariable(currentScope, this, local.name); + trackerBinding = local.closeTracker.binding; + } + flowInfo.markAsDefinitelyNull(trackerBinding); + } + } flowInfo = ((Reference) this.lhs) .analyseAssignment(currentScope, flowContext, flowInfo, this, false) .unconditionalInits(); 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,70 @@ +/******************************************************************************* + * 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 boolean isInsideTWR = false; + + public FakedTrackingVariable(BlockScope currentScope, Statement location, char[] name) { + super(name, location.sourceStart, location.sourceEnd); + this.type = new SingleTypeReference( + TypeConstants.OBJECT, + ((long)this.sourceStart <<32)+this.sourceEnd); + 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().registerTrackingVariable(this); + } + + public static boolean isAutoCloseable(TypeBinding typeBinding) { + return typeBinding instanceof ReferenceBinding + && ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable); + } + + 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 6 Jul 2011 16:03:44 -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, this.name); + 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.8 diff -u -r1.151.2.8 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 28 Jun 2011 14:49:04 -0000 1.151.2.8 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 6 Jul 2011 16:03:45 -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 6 Jul 2011 16:03:45 -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 6 Jul 2011 16:03:45 -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.26 diff -u -r1.116.2.26 TryStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 4 Jul 2011 08:57:17 -0000 1.116.2.26 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 6 Jul 2011 16:03:45 -0000 @@ -120,8 +120,13 @@ 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) { + resourceBinding.closeTracker.isInsideTWR = true; + 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/impl/CompilerOptions.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java,v retrieving revision 1.241.2.3 diff -u -r1.241.2.3 CompilerOptions.java --- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 14 Feb 2011 14:08:01 -0000 1.241.2.3 +++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 6 Jul 2011 16:03:47 -0000 @@ -136,6 +136,9 @@ public static final String OPTION_IncludeNullInfoFromAsserts = "org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts"; //$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_ReportUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.reportUnclosedCloseable"; //$NON-NLS-1$ + public static final String OPTION_ReportPotentiallyUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"; //$NON-NLS-1$ + public static final String OPTION_ReportExplicitlyClosedAutoCloseable = "org.eclipse.jdt.core.compiler.problem.reportExplicitlyClosedAutoCloseable"; //$NON-NLS-1$ /** * Possible values for configurable options */ @@ -238,6 +241,9 @@ public static final int UnusedObjectAllocation = IrritantSet.GROUP2 | ASTNode.Bit4; public static final int MethodCanBeStatic = IrritantSet.GROUP2 | ASTNode.Bit5; public static final int MethodCanBePotentiallyStatic = IrritantSet.GROUP2 | ASTNode.Bit6; + public static final int UnclosedCloseable = IrritantSet.GROUP2 | ASTNode.Bit7; + public static final int PotentiallyUnclosedCloseable = IrritantSet.GROUP2 | ASTNode.Bit8; + public static final int ExplicitlyClosedAutoCloseable = IrritantSet.GROUP2 | ASTNode.Bit9; // Severity level for handlers /** @@ -547,6 +553,12 @@ return OPTION_ReportMethodCanBeStatic; case MethodCanBePotentiallyStatic : return OPTION_ReportMethodCanBePotentiallyStatic; + case UnclosedCloseable : + return OPTION_ReportUnclosedCloseable; + case PotentiallyUnclosedCloseable : + return OPTION_ReportPotentiallyUnclosedCloseable; + case ExplicitlyClosedAutoCloseable : + return OPTION_ReportExplicitlyClosedAutoCloseable; } return null; } @@ -709,6 +721,9 @@ OPTION_ReportUnusedTypeArgumentsForMethodInvocation, OPTION_ReportUnusedWarningToken, OPTION_ReportVarargsArgumentNeedCast, + OPTION_ReportUnclosedCloseable, + OPTION_ReportPotentiallyUnclosedCloseable, + OPTION_ReportExplicitlyClosedAutoCloseable, }; return result; } @@ -973,6 +988,9 @@ optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED); optionsMap.put(OPTION_ReportMethodCanBeStatic, getSeverityString(MethodCanBeStatic)); optionsMap.put(OPTION_ReportMethodCanBePotentiallyStatic, getSeverityString(MethodCanBePotentiallyStatic)); + optionsMap.put(OPTION_ReportUnclosedCloseable, getSeverityString(UnclosedCloseable)); + optionsMap.put(OPTION_ReportPotentiallyUnclosedCloseable, getSeverityString(PotentiallyUnclosedCloseable)); + optionsMap.put(OPTION_ReportExplicitlyClosedAutoCloseable, getSeverityString(ExplicitlyClosedAutoCloseable)); return optionsMap; } @@ -1402,6 +1420,9 @@ if ((optionValue = optionsMap.get(OPTION_ReportUnusedObjectAllocation)) != null) updateSeverity(UnusedObjectAllocation, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBeStatic)) != null) updateSeverity(MethodCanBeStatic, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBePotentiallyStatic)) != null) updateSeverity(MethodCanBePotentiallyStatic, optionValue); + 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); // Javadoc options if ((optionValue = optionsMap.get(OPTION_DocCommentSupport)) != null) { Index: compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java,v retrieving revision 1.13.2.1 diff -u -r1.13.2.1 IrritantSet.java --- compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 11 Feb 2011 15:17:16 -0000 1.13.2.1 +++ compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 6 Jul 2011 16:03:47 -0000 @@ -99,7 +99,8 @@ // group-2 warnings enabled by default .set( CompilerOptions.DeadCode - |CompilerOptions.Tasks); + |CompilerOptions.Tasks + |CompilerOptions.UnclosedCloseable); ALL.setAll(); HIDING 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 6 Jul 2011 16:03:48 -0000 @@ -971,6 +971,12 @@ variable.resolve(); return variable; } +public boolean hasTypeBit(int bit) { + // ensure hierarchy is resolved + superclass(); + superInterfaces(); + return (this.typeBits & bit) != 0; +} private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBinding[] existingVariables, SignatureWrapper wrapper, char[][][] missingTypeNames) { // ParameterSignature = Identifier ':' TypeSignature // or Identifier ':' TypeSignature(optional) InterfaceBound(s) @@ -1141,6 +1147,11 @@ this.tagBits &= ~TagBits.HasUnresolvedSuperclass; if (this.superclass.problemId() == ProblemReasons.NotFound) this.tagBits |= TagBits.HierarchyHasProblems; // propagate type inconsistency + else { + this.superclass.superclass(); + this.superclass.superInterfaces(); + } + this.typeBits |= this.superclass.typeBits; return this.superclass; } // NOTE: superInterfaces of binary types are resolved when needed @@ -1152,6 +1163,14 @@ 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 + else + // TODO(SH): check if this actually speeds up anything: + if ((this.superInterfaces[i].tagBits & (TagBits.HasUnresolvedSuperclass|TagBits.HasUnresolvedSuperinterfaces)) != 0) + { + this.superInterfaces[i].superclass(); + this.superInterfaces[i].superInterfaces(); + } + this.typeBits |= this.superInterfaces[i].typeBits; } 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 6 Jul 2011 16:03:48 -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,27 @@ } } } + +// TODO: List or array? +// TODO: move these to FlowInfo? (beware of flowInfo copying!) +private List trackingVariables; +public int addTrackingVariable(FakedTrackingVariable fakedTrackingVariable) { + if (this.trackingVariables == null) + this.trackingVariables = new ArrayList(); + this.trackingVariables.add(fakedTrackingVariable); + return this.trackingVariables.size(); +} + +public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location) { + if (this.trackingVariables == null) return; + for (int i=0; i= ClassFileConstants.JDK1_7 && !trackingVar.isInsideTWR) + problemReporter().explicitlyClosedAutoCloseable(trackingVar); + } +} } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java,v retrieving revision 1.183.2.1 diff -u -r1.183.2.1 ClassScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 20 Apr 2011 20:40:00 -0000 1.183.2.1 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 6 Jul 2011 16:03:49 -0000 @@ -907,6 +907,7 @@ } else { // only want to reach here when no errors are reported sourceType.superclass = superclass; + sourceType.typeBits |= superclass.typeBits; return true; } } @@ -1017,6 +1018,7 @@ noProblems &= superInterfaceRef.resolvedType.isValidBinding(); } // only want to reach here when no errors are reported + sourceType.typeBits |= superInterface.typeBits; interfaceBindings[count++] = superInterface; } // hold onto all correctly resolved superinterfaces Index: compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java,v retrieving revision 1.49.2.2 diff -u -r1.49.2.2 LocalVariableBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java 27 Apr 2011 16:33:51 -0000 1.49.2.2 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java 6 Jul 2011 16:03:49 -0000 @@ -19,6 +19,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.impl.Constant; @@ -39,6 +40,8 @@ public int[] initializationPCs; public int initializationCount = 0; + public FakedTrackingVariable closeTracker; + // for synthetic local variables // if declaration slot is not positionned, the variable will not be listed in attribute // note that the name of a variable should be chosen so as not to conflict with user ones (usually starting with a space char is all needed) Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java,v retrieving revision 1.78.2.1 diff -u -r1.78.2.1 MethodScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java 8 Mar 2011 17:20:09 -0000 1.78.2.1 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java 6 Jul 2011 16:03:50 -0000 @@ -479,4 +479,10 @@ public TypeDeclaration referenceType() { return ((ClassScope) this.parent).referenceContext; } + +public int registerTrackingVariable(FakedTrackingVariable fakedTrackingVariable) { + int offset = addTrackingVariable(fakedTrackingVariable); + return this.analysisIndex + offset; + +} } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java,v retrieving revision 1.120.2.2 diff -u -r1.120.2.2 ParameterizedTypeBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java 9 May 2011 14:30:21 -0000 1.120.2.2 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java 6 Jul 2011 16:03:50 -0000 @@ -629,6 +629,13 @@ return this.type.hasMemberTypes(); } + public boolean hasTypeBit(int bit) { + TypeBinding erasure = erasure(); + if (erasure instanceof ReferenceBinding) + return ((ReferenceBinding) erasure).hasTypeBit(bit); + return false; + } + /** * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#implementsMethod(MethodBinding) */ Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java,v retrieving revision 1.140.2.6 diff -u -r1.140.2.6 ReferenceBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java 28 Jun 2011 15:35:07 -0000 1.140.2.6 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java 6 Jul 2011 16:03:51 -0000 @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.Comparator; +import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; @@ -45,6 +46,8 @@ private SimpleLookupTable compatibleCache; + public int typeBits; + public static final ReferenceBinding LUB_GENERIC = new ReferenceBinding() { /* used for lub computation */}; private static final Comparator FIELD_COMPARATOR = new Comparator() { @@ -428,8 +431,10 @@ case 'A' : switch(typeName.length) { case 13 : - if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_AUTOCLOSEABLE[2])) + if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_AUTOCLOSEABLE[2])) { this.id = TypeIds.T_JavaLangAutoCloseable; + this.typeBits |= TypeIds.BitAutoCloseable; + } return; case 14: if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ASSERTIONERROR[2])) @@ -928,6 +933,12 @@ return (this.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0; } +public boolean hasTypeBit(int bit) { + if (!isLocalType()) + Assert.isTrue((this.tagBits & TagBits.EndHierarchyCheck) != 0, "Hierarchy should be connected"); //$NON-NLS-1$ + return (this.typeBits & bit) != 0; +} + /** Answer true if the receiver implements anInterface or is identical to anInterface. * If searchHierarchy is true, then also search the receiver's superclasses. * Index: compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java,v retrieving revision 1.51.2.6 diff -u -r1.51.2.6 TypeConstants.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java 28 Jun 2011 15:35:07 -0000 1.51.2.6 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java 6 Jul 2011 16:03:51 -0000 @@ -154,6 +154,7 @@ "MethodHandle$PolymorphicSignature".toCharArray() //$NON-NLS-1$ }; char[][] JAVA_LANG_AUTOCLOSEABLE = {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$ + char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$ // Constraints for generic type argument inference int CONSTRAINT_EQUAL = 0; // Actual = Formal Index: compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java,v retrieving revision 1.36.2.5 diff -u -r1.36.2.5 TypeIds.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java 28 Jun 2011 15:35:07 -0000 1.36.2.5 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java 6 Jul 2011 16:03:51 -0000 @@ -173,4 +173,6 @@ final int Object2Object = T_JavaLangObject + (T_JavaLangObject << 4); final int BOXING = 0x200; final int UNBOXING = 0x400; + + final int BitAutoCloseable = 1; } Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.430.2.33 diff -u -r1.430.2.33 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 24 Jun 2011 17:14:37 -0000 1.430.2.33 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 6 Jul 2011 16:03:56 -0000 @@ -55,6 +55,7 @@ import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.ImportReference; @@ -430,6 +431,15 @@ case IProblem.MethodCanBePotentiallyStatic: return CompilerOptions.MethodCanBePotentiallyStatic; + + case IProblem.UnclosedCloseable: + case IProblem.UnclosedCloseableAtExit: + return CompilerOptions.UnclosedCloseable; + case IProblem.PotentiallyUnclosedCloseable: + case IProblem.PotentiallyUnclosedCloseableAtExit: + return CompilerOptions.PotentiallyUnclosedCloseable; + case IProblem.ExplicitlyClosedAutoCloseable: + return CompilerOptions.ExplicitlyClosedAutoCloseable; } return 0; } @@ -7862,4 +7872,49 @@ type.sourceStart, type.sourceEnd); } +public void potentiallyUnclosedCloseable(FakedTrackingVariable trackVar, ASTNode location) { + if (location == null) { + this.handle( + IProblem.PotentiallyUnclosedCloseable, + NoArgument, + NoArgument, + trackVar.sourceStart, + trackVar.sourceEnd); + } else { + String[] args = { String.valueOf(trackVar.name) }; + this.handle( + IProblem.PotentiallyUnclosedCloseableAtExit, + args, + args, + location.sourceStart, + location.sourceEnd); + } +} +public void unclosedCloseable(FakedTrackingVariable trackVar, ASTNode location) { + if (location == null) { + this.handle( + IProblem.UnclosedCloseable, + NoArgument, + NoArgument, + trackVar.sourceStart, + trackVar.sourceEnd); + } else { + String[] args = { String.valueOf(trackVar.name) }; + this.handle( + IProblem.UnclosedCloseableAtExit, + args, + args, + location.sourceStart, + location.sourceEnd); + } +} +public void explicitlyClosedAutoCloseable(FakedTrackingVariable trackVar) { + String[] args = { String.valueOf(trackVar.name) }; + this.handle( + IProblem.ExplicitlyClosedAutoCloseable, + args, + args, + trackVar.sourceStart, + trackVar.sourceEnd); +} } \ No newline at end of file Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v retrieving revision 1.262.2.30 diff -u -r1.262.2.30 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 5 Jul 2011 11:02:25 -0000 1.262.2.30 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 6 Jul 2011 16:03:56 -0000 @@ -645,6 +645,11 @@ 880 = '<>' cannot be used with anonymous classes 881 = Cannot switch on a value of type String for source level below 1.7. Only convertible int values or enum constants are permitted 882 = Unhandled exception type {0} thrown by automatic close() invocation on {1} +883 = Value of type AutoCloseable is not closed on all paths. +884 = Instance '{0}' of type AutoCloseable may be unclosed at this point. +885 = Value of type AutoCloseable is not closed neither explicitly nor using a try-with-resources. +886 = Instance '{0}' of type AutoCloseable is not closed at this point. +887 = Instance '{0}' should be managed by try-with-resource. ### ELABORATIONS ## Access restrictions Index: model/org/eclipse/jdt/core/JavaCore.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v retrieving revision 1.659.2.2 diff -u -r1.659.2.2 JavaCore.java --- model/org/eclipse/jdt/core/JavaCore.java 19 Apr 2011 16:41:17 -0000 1.659.2.2 +++ model/org/eclipse/jdt/core/JavaCore.java 6 Jul 2011 16:04:01 -0000 @@ -1357,6 +1357,52 @@ */ public static final String COMPILER_PB_POTENTIALLY_MISSING_STATIC_ON_METHOD = PLUGIN_ID + ".compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ /** + * Compiler option ID: Reporting a resource that is not closed properly. + *

When enabled, that compiler will issue an error or a warning if a local variable + * holds a value of type AutoCloseable (or Closeable if compliance is < 1.7) + * and if flow analysis shows that the method close() is not invoked locally on that value. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.reportUnclosedCloseable"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"warning"
+ *
+ * @since 3.7 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.reportUnclosedCloseable"; //$NON-NLS-1$ + /** + * Compiler option ID: Reporting a resource that may not be closed properly. + *

When enabled, that compiler will issue an error or a warning if a local variable + * holds a value of type AutoCloseable (or Closeable if compliance is < 1.7) + * and if flow analysis shows that the method close() is not invoked locally + * on that value for all execution paths. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"ignore"
+ *
+ * @since 3.7 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.reportPotentiallyUnclosedCloseable"; //$NON-NLS-1$ + /** + * Compiler option ID: Reporting a resource that is not managed by try-with-resources. + *

When enabled, that compiler will issue an error or a warning if a local variable + * holds a value of type AutoCloseable, and if the method close() is + * explicitly invoked on that resource, but the resource is not managed by a + * try-with-resources block. + *

Note that this option is not surfaced in the UI, as it is intended only for internal + * use for computing quick assists / cleanups. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"ignore"
+ *
+ * @since 3.7 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE = PLUGIN_ID + ".compiler.problem.reportExplicitlyClosedAutoCloseable"; //$NON-NLS-1$ + /** * Compiler option ID: Setting Source Compatibility Mode. *

Specify whether which source level compatibility is used. From 1.4 on, 'assert' is a keyword * reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Attic/TryWithResourcesStatementTest.java,v retrieving revision 1.1.2.27 diff -u -r1.1.2.27 TryWithResourcesStatementTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java 21 Jun 2011 06:09:22 -0000 1.1.2.27 +++ src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java 6 Jul 2011 16:04:04 -0000 @@ -16,13 +16,14 @@ import java.util.Map; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import junit.framework.Test; public class TryWithResourcesStatementTest extends AbstractRegressionTest { static { -// TESTS_NAMES = new String[] { "test053" }; + TESTS_NAMES = new String[] { "test055" }; // TESTS_NUMBERS = new int[] { 50 }; // TESTS_RANGE = new int[] { 11, -1 }; } @@ -3341,6 +3342,276 @@ "Object.Integer cannot be resolved to a type\n" + "----------\n"); } +// Bug 349326 - [1.7] new warning for missing try-with-resources +// a method uses an AutoCloseable without ever closing it. +public void test055() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader = new FileReader(file);\n" + +// not invoking any methods on FileReader, try to avoid necessary call to superclass() +// " char[] in = new char[50];\n" + +// " fileReader.read(in);\n" + + " }\n" + + " public static void main(String[] args) throws IOException {\n" + + " new X().foo();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 7)\n" + + " FileReader fileReader = new FileReader(file);\n" + + " ^^^^^^^^^^\n" + + "Value of type AutoCloseable is not closed neither explicitly nor using a try-with-resources.\n" + + "----------\n", + null, + true, + options); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// a method uses an AutoCloseable and closes it properly. +public void test055a() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + this.runConformTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader = new FileReader(file);\n" + + " char[] in = new char[50];\n" + + " fileReader.read(in);\n" + + " fileReader.close();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " try {\n" + + " new X().foo();\n" + + " } catch (IOException ioex) {\n" + + " System.out.println(\"caught\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "caught", /*output*/ + null/*classLibs*/, + true/*shouldFlush*/, + null/*vmargs*/, + options, + null/*requestor*/); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// a method uses an AutoCloseable properly within try-with-resources. +public void test055b() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + this.runConformTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " try (FileReader fileReader = new FileReader(file)) {\n" + + " char[] in = new char[50];\n" + + " fileReader.read(in);\n" + + " }\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " try {\n" + + " new X().foo();\n" + + " } catch (IOException ioex) {\n" + + " System.out.println(\"caught\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "caught", /*output*/ + null/*classLibs*/, + true/*shouldFlush*/, + null/*vmargs*/, + options, + null/*requestor*/); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// a method uses two AutoCloseables (testing independent analysis) +// - one closeable may be unclosed at a conditional return +// - the other is only conditionally closed +public void test055c() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo(boolean flag1, boolean flag2) throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " char[] in = new char[50];\n" + + " FileReader fileReader1 = new FileReader(file);\n" + + " fileReader1.read(in);\n" + + " FileReader fileReader2 = new FileReader(file);\n" + + " fileReader2.read(in);\n" + + " if (flag1) {\n" + + " fileReader2.close();\n" + + " return;\n" + + " } else if (flag2) {\n" + + " fileReader2.close();\n" + + " }\n" + + " fileReader1.close();\n" + + " }\n" + + " public static void main(String[] args) throws IOException {\n" + + " new X().foo(false, true);\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 10)\n" + + " FileReader fileReader2 = new FileReader(file);\n" + + " ^^^^^^^^^^^\n" + + "Value of type AutoCloseable is not closed on all paths.\n" + + "----------\n" + + "2. ERROR in X.java (at line 14)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Instance \'fileReader1\' of type AutoCloseable is not closed at this point.\n" + + "----------\n", + null, + true, + options); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// one method returns an AutoCleasble, a second method uses this object without ever closing it. +public void test055d() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " FileReader getReader(String filename) throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader = new FileReader(file);\n" + + " return fileReader;\n" + // don't complain here, pass responsibility to caller + " }\n" + + " void foo() throws IOException {\n" + + " FileReader reader = getReader(\"somefile\");\n" + + " char[] in = new char[50];\n" + + " reader.read(in);\n" + + " }\n" + + " public static void main(String[] args) throws IOException {\n" + + " new X().foo();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 11)\n" + + " FileReader reader = getReader(\"somefile\");\n" + + " ^^^^^^\n" + + "Value of type AutoCloseable is not closed neither explicitly nor using a try-with-resources.\n" + + "----------\n", + null, + true, + options); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// a method explicitly closes its AutoCloseable rather than using t-w-r +public void test055e() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportExplicitlyClosedAutoCloseable, CompilerOptions.ERROR); + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader;\n" + + " fileReader = new FileReader(file);\n" + + " char[] in = new char[50];\n" + + " fileReader.read(in);\n" + + " fileReader.close();\n" + + " }\n" + + " public static void main(String[] args) throws IOException {\n" + + " new X().foo();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 8)\n" + + " fileReader = new FileReader(file);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Instance \'fileReader\' should be managed by try-with-resource.\n" + + "----------\n", + null, + true, + options); +} +// Bug 349326 - [1.7] new warning for missing try-with-resources +// an AutoCloseable local is re-assigned +public void test055f() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR); + options.put(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE, CompilerOptions.WARNING); + options.put(JavaCore.COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "import java.io.File;\n" + + "import java.io.FileReader;\n" + + "import java.io.IOException;\n" + + "public class X {\n" + + " void foo() throws IOException {\n" + + " File file = new File(\"somefile\");\n" + + " FileReader fileReader = new FileReader(file);\n" + + " char[] in = new char[50];\n" + + " fileReader.read(in);\n" + + " fileReader = new FileReader(file);\n" + + " fileReader.read(in);\n" + + " fileReader.close();\n" + + " }\n" + + " public static void main(String[] args) throws IOException {\n" + + " new X().foo();\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " fileReader = new FileReader(file);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Instance \'fileReader\' of type AutoCloseable is not closed at this point.\n" + + "----------\n", + null, + true, + options); +} public static Class testClass() { return TryWithResourcesStatementTest.class; }