|
Removed
Link Here
|
| 1 |
/******************************************************************************* |
| 2 |
* Copyright (c) 2011 IBM Corporation and others. |
| 3 |
* All rights reserved. This program and the accompanying materials |
| 4 |
* are made available under the terms of the Eclipse Public License v1.0 |
| 5 |
* which accompanies this distribution, and is available at |
| 6 |
* http://www.eclipse.org/legal/epl-v10.html |
| 7 |
* |
| 8 |
* This is an implementation of an early-draft specification developed under the Java |
| 9 |
* Community Process (JCP) and is made available for testing and evaluation purposes |
| 10 |
* only. The code is not compatible with any specification of the JCP. |
| 11 |
* |
| 12 |
* Contributors: |
| 13 |
* IBM Corporation - initial API and implementation |
| 14 |
*******************************************************************************/ |
| 15 |
package org.eclipse.jdt.internal.compiler.ast; |
| 16 |
|
| 17 |
import org.eclipse.jdt.internal.compiler.ASTVisitor; |
| 18 |
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| 19 |
import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; |
| 20 |
import org.eclipse.jdt.internal.compiler.impl.Constant; |
| 21 |
import org.eclipse.jdt.internal.compiler.lookup.BlockScope; |
| 22 |
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; |
| 23 |
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; |
| 24 |
import org.eclipse.jdt.internal.compiler.lookup.MethodScope; |
| 25 |
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
| 26 |
import org.eclipse.jdt.internal.compiler.lookup.TagBits; |
| 27 |
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| 28 |
import org.eclipse.jdt.internal.compiler.lookup.TypeIds; |
| 29 |
|
| 30 |
public class TryStatementWithResources extends TryStatement { |
| 31 |
|
| 32 |
private static LocalDeclaration [] NO_RESOURCES = new LocalDeclaration[0]; |
| 33 |
public LocalDeclaration[] resources = NO_RESOURCES; |
| 34 |
|
| 35 |
public StringBuffer printStatement(int indent, StringBuffer output) { |
| 36 |
printIndent(indent, output).append("try ("); //$NON-NLS-1$ |
| 37 |
int length = this.resources.length; |
| 38 |
for (int i = 0; i < length; i++) { |
| 39 |
this.resources[i].printAsExpression(0, output); |
| 40 |
if (i != length - 1) { |
| 41 |
output.append(";\n"); //$NON-NLS-1$ |
| 42 |
printIndent(indent + 2, output); |
| 43 |
} |
| 44 |
} |
| 45 |
output.append(")\n"); //$NON-NLS-1$ |
| 46 |
this.tryBlock.printStatement(indent + 1, output); |
| 47 |
|
| 48 |
// catches |
| 49 |
if (this.catchBlocks != null) |
| 50 |
for (int i = 0; i < this.catchBlocks.length; i++) { |
| 51 |
output.append('\n'); |
| 52 |
printIndent(indent, output).append("catch ("); //$NON-NLS-1$ |
| 53 |
this.catchArguments[i].print(0, output).append(")\n"); //$NON-NLS-1$ |
| 54 |
this.catchBlocks[i].printStatement(indent + 1, output); |
| 55 |
} |
| 56 |
// finally |
| 57 |
if (this.finallyBlock != null) { |
| 58 |
output.append('\n'); |
| 59 |
printIndent(indent, output).append("finally\n"); //$NON-NLS-1$ |
| 60 |
this.finallyBlock.printStatement(indent + 1, output); |
| 61 |
} |
| 62 |
return output; |
| 63 |
} |
| 64 |
|
| 65 |
public void resolve(BlockScope upperScope) { |
| 66 |
// special scope for secret locals optimization. |
| 67 |
this.scope = new BlockScope(upperScope); |
| 68 |
|
| 69 |
BlockScope finallyScope = null; |
| 70 |
|
| 71 |
// resolve all resources and inject them into separate scopes |
| 72 |
BlockScope localScope = new BlockScope(this.scope); |
| 73 |
for (int i = 0, max = this.resources.length; i < max; i++) { |
| 74 |
this.resources[i].resolve(localScope); |
| 75 |
LocalVariableBinding localVariableBinding = this.resources[i].binding; |
| 76 |
if (localVariableBinding != null && localVariableBinding.isValidBinding()) { |
| 77 |
localVariableBinding.modifiers |= ClassFileConstants.AccFinal; |
| 78 |
localVariableBinding.tagBits |= TagBits.IsResource; |
| 79 |
TypeBinding resourceType = localVariableBinding.type; |
| 80 |
if (resourceType.isClass() || resourceType.isInterface()) { |
| 81 |
if (resourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangAutoCloseable, false /*AutoCloseable is not a class*/) == null && resourceType.isValidBinding()) { |
| 82 |
upperScope.problemReporter().resourceHasToBeAutoCloseable(resourceType, this.resources[i].type); |
| 83 |
} |
| 84 |
} else { |
| 85 |
upperScope.problemReporter().resourceHasToBeAutoCloseable(resourceType, this.resources[i].type); |
| 86 |
} |
| 87 |
} |
| 88 |
localScope = new BlockScope(localScope, 1); |
| 89 |
} |
| 90 |
|
| 91 |
BlockScope tryScope = new BlockScope(localScope); |
| 92 |
|
| 93 |
if (this.finallyBlock != null) { |
| 94 |
if (this.finallyBlock.isEmptyBlock()) { |
| 95 |
if ((this.finallyBlock.bits & ASTNode.UndocumentedEmptyBlock) != 0) { |
| 96 |
this.scope.problemReporter().undocumentedEmptyBlock(this.finallyBlock.sourceStart, |
| 97 |
this.finallyBlock.sourceEnd); |
| 98 |
} |
| 99 |
} else { |
| 100 |
finallyScope = new BlockScope(this.scope, false); // don't add it yet to parent scope |
| 101 |
|
| 102 |
// provision for returning and forcing the finally block to run |
| 103 |
MethodScope methodScope = this.scope.methodScope(); |
| 104 |
|
| 105 |
// the type does not matter as long as it is not a base type |
| 106 |
if (!upperScope.compilerOptions().inlineJsrBytecode) { |
| 107 |
this.returnAddressVariable = new LocalVariableBinding(TryStatement.SECRET_RETURN_ADDRESS_NAME, |
| 108 |
upperScope.getJavaLangObject(), ClassFileConstants.AccDefault, false); |
| 109 |
finallyScope.addLocalVariable(this.returnAddressVariable); |
| 110 |
this.returnAddressVariable.setConstant(Constant.NotAConstant); // not inlinable |
| 111 |
} |
| 112 |
this.subRoutineStartLabel = new BranchLabel(); |
| 113 |
|
| 114 |
this.anyExceptionVariable = new LocalVariableBinding(TryStatement.SECRET_ANY_HANDLER_NAME, |
| 115 |
this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false); |
| 116 |
finallyScope.addLocalVariable(this.anyExceptionVariable); |
| 117 |
this.anyExceptionVariable.setConstant(Constant.NotAConstant); // not inlinable |
| 118 |
|
| 119 |
if (!methodScope.isInsideInitializer()) { |
| 120 |
MethodBinding methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding; |
| 121 |
if (methodBinding != null) { |
| 122 |
TypeBinding methodReturnType = methodBinding.returnType; |
| 123 |
if (methodReturnType.id != TypeIds.T_void) { |
| 124 |
this.secretReturnValue = new LocalVariableBinding(TryStatement.SECRET_RETURN_VALUE_NAME, |
| 125 |
methodReturnType, ClassFileConstants.AccDefault, false); |
| 126 |
finallyScope.addLocalVariable(this.secretReturnValue); |
| 127 |
this.secretReturnValue.setConstant(Constant.NotAConstant); // not inlinable |
| 128 |
} |
| 129 |
} |
| 130 |
} |
| 131 |
this.finallyBlock.resolveUsing(finallyScope); |
| 132 |
// force the finally scope to have variable positions shifted after its try scope and catch ones |
| 133 |
int shiftScopesLength = this.catchArguments == null ? 1 : this.catchArguments.length + 1; |
| 134 |
shiftScopesLength += this.resources.length; |
| 135 |
finallyScope.shiftScopes = new BlockScope[shiftScopesLength]; |
| 136 |
for (int i = 0, max = this.resources.length; i < max; i++) { |
| 137 |
LocalVariableBinding localVariableBinding = this.resources[i].binding; |
| 138 |
if (localVariableBinding != null && localVariableBinding.isValidBinding()) { |
| 139 |
finallyScope.shiftScopes[i] = localVariableBinding.declaringScope; |
| 140 |
} |
| 141 |
} |
| 142 |
finallyScope.shiftScopes[this.resources.length] = tryScope; |
| 143 |
} |
| 144 |
} |
| 145 |
|
| 146 |
this.tryBlock.resolveUsing(tryScope); |
| 147 |
|
| 148 |
// arguments type are checked against JavaLangThrowable in resolveForCatch(..) |
| 149 |
if (this.catchBlocks != null) { |
| 150 |
int length = this.catchArguments.length; |
| 151 |
TypeBinding[] argumentTypes = new TypeBinding[length]; |
| 152 |
boolean containsDisjunctiveTypes = false; |
| 153 |
boolean catchHasError = false; |
| 154 |
for (int i = 0; i < length; i++) { |
| 155 |
BlockScope catchScope = new BlockScope(this.scope); |
| 156 |
if (finallyScope != null) { |
| 157 |
finallyScope.shiftScopes[i + 1] = catchScope; |
| 158 |
} |
| 159 |
// side effect on catchScope in resolveForCatch(..) |
| 160 |
Argument catchArgument = this.catchArguments[i]; |
| 161 |
containsDisjunctiveTypes |= (catchArgument.type.bits & ASTNode.IsDisjuntive) != 0; |
| 162 |
if ((argumentTypes[i] = catchArgument.resolveForCatch(catchScope)) == null) { |
| 163 |
catchHasError = true; |
| 164 |
} |
| 165 |
this.catchBlocks[i].resolveUsing(catchScope); |
| 166 |
} |
| 167 |
if (catchHasError) { |
| 168 |
return; |
| 169 |
} |
| 170 |
this.caughtExceptionTypes = new ReferenceBinding[length]; |
| 171 |
verifyDuplicationAndOrder(length, argumentTypes, containsDisjunctiveTypes); |
| 172 |
} else { |
| 173 |
this.caughtExceptionTypes = new ReferenceBinding[0]; |
| 174 |
} |
| 175 |
|
| 176 |
if (finallyScope != null) { |
| 177 |
// add finallyScope as last subscope, so it can be shifted behind try/catch subscopes. |
| 178 |
// the shifting is necessary to achieve no overlay in between the finally scope and its |
| 179 |
// sibling in term of local variable positions. |
| 180 |
this.scope.addSubscope(finallyScope); |
| 181 |
} |
| 182 |
} |
| 183 |
public void traverse(ASTVisitor visitor, BlockScope blockScope) { |
| 184 |
if (visitor.visit(this, blockScope)) { |
| 185 |
LocalDeclaration[] localDeclarations = this.resources; |
| 186 |
for (int i = 0, max = localDeclarations.length; i < max; i++) { |
| 187 |
localDeclarations[i].traverse(visitor, this.scope); |
| 188 |
} |
| 189 |
this.tryBlock.traverse(visitor, this.scope); |
| 190 |
if (this.catchArguments != null) { |
| 191 |
for (int i = 0, max = this.catchBlocks.length; i < max; i++) { |
| 192 |
this.catchArguments[i].traverse(visitor, this.scope); |
| 193 |
this.catchBlocks[i].traverse(visitor, this.scope); |
| 194 |
} |
| 195 |
} |
| 196 |
if (this.finallyBlock != null) |
| 197 |
this.finallyBlock.traverse(visitor, this.scope); |
| 198 |
} |
| 199 |
visitor.endVisit(this, blockScope); |
| 200 |
} |
| 201 |
} |