package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
public class TryStatement extends SubRoutineStatement {
static final char[] SECRET_RETURN_ADDRESS_NAME = " returnAddress".toCharArray();
static final char[] SECRET_ANY_HANDLER_NAME = " anyExceptionHandler".toCharArray();
static final char[] SECRET_PRIMARY_EXCEPTION_VARIABLE_NAME = " primaryException".toCharArray();
static final char[] SECRET_CAUGHT_THROWABLE_VARIABLE_NAME = " caughtThrowable".toCharArray();
static final char[] SECRET_RETURN_VALUE_NAME = " returnValue".toCharArray();
public Statement[] resources = new Statement[0];
public Block tryBlock;
public Block[] catchBlocks;
public Argument[] catchArguments;
public Block finallyBlock;
BlockScope scope;
public UnconditionalFlowInfo subRoutineInits;
ReferenceBinding[] caughtExceptionTypes;
boolean[] catchExits;
BranchLabel subRoutineStartLabel;
public LocalVariableBinding anyExceptionVariable,
returnAddressVariable,
secretReturnValue;
ExceptionLabel[] declaredExceptionLabels;
private Object[] reusableJSRTargets;
private BranchLabel[] reusableJSRSequenceStartLabels;
private int[] reusableJSRStateIndexes;
private int reusableJSRTargetsCount = 0;
private static final int NO_FINALLY = 0;
private static final int FINALLY_SUBROUTINE = 1;
private static final int FINALLY_DOES_NOT_COMPLETE = 2;
private static final int FINALLY_INLINE = 3;
int mergedInitStateIndex = -1;
int preTryInitStateIndex = -1;
int postTryInitStateIndex = -1;
int[] postResourcesInitStateIndexes;
int naturalExitMergeInitStateIndex = -1;
int[] catchExitInitStateIndexes;
private LocalVariableBinding primaryExceptionVariable;
private LocalVariableBinding caughtThrowableVariable;
private ExceptionLabel[] resourceExceptionLabels;
private int[] caughtExceptionsCatchBlocks;
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
this.preTryInitStateIndex =
currentScope.methodScope().recordInitializationStates(flowInfo);
if (this.anyExceptionVariable != null) {
this.anyExceptionVariable.useFlag = LocalVariableBinding.USED;
}
if (this.primaryExceptionVariable != null) {
this.primaryExceptionVariable.useFlag = LocalVariableBinding.USED;
}
if (this.caughtThrowableVariable != null) {
this.caughtThrowableVariable.useFlag = LocalVariableBinding.USED;
}
if (this.returnAddressVariable != null) {
this.returnAddressVariable.useFlag = LocalVariableBinding.USED;
}
int resourcesLength = this.resources.length;
if (resourcesLength > 0) {
this.postResourcesInitStateIndexes = new int[resourcesLength];
}
if (this.subRoutineStartLabel == null) {
if (flowContext instanceof FinallyFlowContext) {
FinallyFlowContext finallyContext = (FinallyFlowContext) flowContext;
finallyContext.outerTryContext = finallyContext.tryContext;
}
ExceptionHandlingFlowContext handlingContext =
new ExceptionHandlingFlowContext(
flowContext,
this,
this.caughtExceptionTypes,
this.caughtExceptionsCatchBlocks,
null,
this.scope,
flowInfo);
handlingContext.conditionalLevel = 0;
FlowInfo tryInfo = flowInfo.copy();
for (int i = 0; i < resourcesLength; i++) {
final Statement resource = this.resources[i];
tryInfo = resource.analyseCode(currentScope, handlingContext, tryInfo);
this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(tryInfo);
TypeBinding resolvedType = null;
LocalVariableBinding localVariableBinding = null;
if (resource instanceof LocalDeclaration) {
localVariableBinding = ((LocalDeclaration) resource).binding;
resolvedType = localVariableBinding.type;
} else {
if (resource instanceof NameReference && ((NameReference) resource).binding instanceof LocalVariableBinding) {
localVariableBinding = (LocalVariableBinding) ((NameReference) resource).binding;
}
resolvedType = ((Expression) resource).resolvedType;
}
if (localVariableBinding != null) {
localVariableBinding.useFlag = LocalVariableBinding.USED;
if (localVariableBinding.closeTracker != null) {
localVariableBinding.closeTracker.withdraw();
localVariableBinding.closeTracker = null;
}
}
MethodBinding closeMethod = findCloseMethod(resource, resolvedType);
if (closeMethod != null && closeMethod.isValidBinding() && closeMethod.returnType.id == TypeIds.T_void) {
ReferenceBinding[] thrownExceptions = closeMethod.thrownExceptions;
for (int j = 0, length = thrownExceptions.length; j < length; j++) {
handlingContext.checkExceptionHandlers(thrownExceptions[j], this.resources[i], tryInfo, currentScope, true);
}
}
}
if (!this.tryBlock.isEmptyBlock()) {
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, tryInfo);
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
this.bits |= ASTNode.IsTryBlockExiting;
}
if (resourcesLength > 0) {
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo);
for (int i = 0; i < resourcesLength; i++) {
if (this.resources[i] instanceof LocalDeclaration)
tryInfo.resetAssignmentInfo(((LocalDeclaration) this.resources[i]).binding);
}
}
handlingContext.complainIfUnusedExceptionHandlers(this.scope, this);
if (this.catchArguments != null) {
int catchCount;
this.catchExits = new boolean[catchCount = this.catchBlocks.length];
this.catchExitInitStateIndexes = new int[catchCount];
for (int i = 0; i < catchCount; i++) {
FlowInfo catchInfo = prepareCatchInfo(flowInfo, handlingContext, tryInfo, i);
flowContext.conditionalLevel++;
catchInfo =
this.catchBlocks[i].analyseCode(
currentScope,
flowContext,
catchInfo);
flowContext.conditionalLevel--;
this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
this.catchExits[i] =
(catchInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0;
tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
}
}
this.mergedInitStateIndex =
currentScope.methodScope().recordInitializationStates(tryInfo);
flowContext.mergeFinallyNullInfo(handlingContext.initsOnFinally);
return tryInfo;
} else {
InsideSubRoutineFlowContext insideSubContext;
FinallyFlowContext finallyContext;
UnconditionalFlowInfo subInfo;
insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
if (flowContext instanceof FinallyFlowContext) {
insideSubContext.outerTryContext = ((FinallyFlowContext)flowContext).tryContext;
}
ExceptionHandlingFlowContext handlingContext =
new ExceptionHandlingFlowContext(
insideSubContext,
this,
this.caughtExceptionTypes,
this.caughtExceptionsCatchBlocks,
null,
this.scope,
flowInfo);
insideSubContext.initsOnFinally = handlingContext.initsOnFinally;
subInfo =
this.finallyBlock
.analyseCode(
currentScope,
finallyContext = new FinallyFlowContext(flowContext, this.finallyBlock, handlingContext),
flowInfo.nullInfoLessUnconditionalCopy())
.unconditionalInits();
handlingContext.conditionalLevel = 0;
if (subInfo == FlowInfo.DEAD_END) {
this.bits |= ASTNode.IsSubRoutineEscaping;
this.scope.problemReporter().finallyMustCompleteNormally(this.finallyBlock);
} else {
FlowInfo finallyInfo = subInfo.copy();
this.tryBlock.scope.finallyInfo = finallyInfo;
if (this.catchBlocks != null) {
for (int i = 0; i < this.catchBlocks.length; i++)
this.catchBlocks[i].scope.finallyInfo = finallyInfo;
}
}
this.subRoutineInits = subInfo;
FlowInfo tryInfo = flowInfo.copy();
for (int i = 0; i < resourcesLength; i++) {
final Statement resource = this.resources[i];
tryInfo = resource.analyseCode(currentScope, handlingContext, tryInfo);
this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(tryInfo);
TypeBinding resolvedType = null;
LocalVariableBinding localVariableBinding = null;
if (resource instanceof LocalDeclaration) {
localVariableBinding = ((LocalDeclaration) this.resources[i]).binding;
resolvedType = localVariableBinding.type;
} else {
if (resource instanceof NameReference && ((NameReference) resource).binding instanceof LocalVariableBinding) {
localVariableBinding = (LocalVariableBinding)((NameReference) resource).binding;
}
resolvedType = ((Expression) resource).resolvedType;
}
if (localVariableBinding != null) {
localVariableBinding.useFlag = LocalVariableBinding.USED;
if (localVariableBinding.closeTracker != null) {
localVariableBinding.closeTracker.withdraw();
}
}
MethodBinding closeMethod = findCloseMethod(resource, resolvedType);
if (closeMethod != null && closeMethod.isValidBinding() && closeMethod.returnType.id == TypeIds.T_void) {
ReferenceBinding[] thrownExceptions = closeMethod.thrownExceptions;
for (int j = 0, length = thrownExceptions.length; j < length; j++) {
handlingContext.checkExceptionHandlers(thrownExceptions[j], this.resources[i], tryInfo, currentScope, true);
}
}
}
if (!this.tryBlock.isEmptyBlock()) {
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, tryInfo);
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
this.bits |= ASTNode.IsTryBlockExiting;
}
if (resourcesLength > 0) {
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo);
for (int i = 0; i < resourcesLength; i++) {
if (this.resources[i] instanceof LocalDeclaration)
tryInfo.resetAssignmentInfo(((LocalDeclaration)this.resources[i]).binding);
}
}
handlingContext.complainIfUnusedExceptionHandlers(this.scope, this);
if (this.catchArguments != null) {
int catchCount;
this.catchExits = new boolean[catchCount = this.catchBlocks.length];
this.catchExitInitStateIndexes = new int[catchCount];
for (int i = 0; i < catchCount; i++) {
FlowInfo catchInfo = prepareCatchInfo(flowInfo, handlingContext, tryInfo, i);
insideSubContext.conditionalLevel = 1;
catchInfo =
this.catchBlocks[i].analyseCode(
currentScope,
insideSubContext,
catchInfo);
this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
this.catchExits[i] =
(catchInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0;
tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
}
}
finallyContext.complainOnDeferredChecks(
((tryInfo.tagBits & FlowInfo.UNREACHABLE) == 0 ?
flowInfo.unconditionalCopy().
addPotentialInitializationsFrom(tryInfo).
addPotentialInitializationsFrom(insideSubContext.initsOnReturn) :
insideSubContext.initsOnReturn).
addNullInfoFrom(
handlingContext.initsOnFinally),
currentScope);
flowContext.mergeFinallyNullInfo(handlingContext.initsOnFinally);
this.naturalExitMergeInitStateIndex =
currentScope.methodScope().recordInitializationStates(tryInfo);
if (subInfo == FlowInfo.DEAD_END) {
this.mergedInitStateIndex =
currentScope.methodScope().recordInitializationStates(subInfo);
return subInfo;
} else {
FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo);
this.mergedInitStateIndex =
currentScope.methodScope().recordInitializationStates(mergedInfo);
return mergedInfo;
}
}
}
private MethodBinding findCloseMethod(final ASTNode resource, TypeBinding type) {
MethodBinding closeMethod = null;
if (type != null && type.isValidBinding() && type instanceof ReferenceBinding) {
ReferenceBinding binding = (ReferenceBinding) type;
closeMethod = binding.getExactMethod(ConstantPool.Close, new TypeBinding [0], this.scope.compilationUnitScope());
if(closeMethod == null) {
InvocationSite site = new InvocationSite.EmptyWithAstNode(resource);
closeMethod = this.scope.compilationUnitScope().findMethod(binding, ConstantPool.Close, new TypeBinding[0], site, false);
}
}
return closeMethod;
}
private FlowInfo prepareCatchInfo(FlowInfo flowInfo, ExceptionHandlingFlowContext handlingContext, FlowInfo tryInfo, int i) {
FlowInfo catchInfo;
if (isUncheckedCatchBlock(i)) {
catchInfo =
flowInfo.unconditionalCopy().
addPotentialInitializationsFrom(
handlingContext.initsOnException(i)).
addPotentialInitializationsFrom(tryInfo).
addPotentialInitializationsFrom(
handlingContext.initsOnReturn).
addNullInfoFrom(handlingContext.initsOnFinally);
} else {
FlowInfo initsOnException = handlingContext.initsOnException(i);
catchInfo =
flowInfo.nullInfoLessUnconditionalCopy()
.addPotentialInitializationsFrom(initsOnException)
.addNullInfoFrom(initsOnException)
.addPotentialInitializationsFrom(
tryInfo.nullInfoLessUnconditionalCopy())
.addPotentialInitializationsFrom(
handlingContext.initsOnReturn.nullInfoLessUnconditionalCopy());
}
LocalVariableBinding catchArg = this.catchArguments[i].binding;
catchInfo.markAsDefinitelyAssigned(catchArg);
catchInfo.markAsDefinitelyNonNull(catchArg);
if (this.tryBlock.statements == null && this.resources == null) {
catchInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
return catchInfo;
}
private boolean isUncheckedCatchBlock(int catchBlock) {
if (this.caughtExceptionsCatchBlocks == null) {
return this.caughtExceptionTypes[catchBlock].isUncheckedException(true);
}
for (int i = 0, length = this.caughtExceptionsCatchBlocks.length; i < length; i++) {
if (this.caughtExceptionsCatchBlocks[i] == catchBlock) {
if (this.caughtExceptionTypes[i].isUncheckedException(true)) {
return true;
}
}
}
return false;
}
@Override
public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) {
if (this.subRoutineStartLabel == null)
return null;
return super.enterAnyExceptionHandler(codeStream);
}
@Override
public void enterDeclaredExceptionHandlers(CodeStream codeStream) {
for (int i = 0, length = this.declaredExceptionLabels == null ? 0 : this.declaredExceptionLabels.length; i < length; i++) {
this.declaredExceptionLabels[i].placeStart();
}
int resourceCount = this.resources.length;
if (resourceCount > 0 && this.resourceExceptionLabels != null) {
for (int i = resourceCount; i >= 0; --i) {
this.resourceExceptionLabels[i].placeStart();
}
}
}
@Override
public void exitAnyExceptionHandler() {
if (this.subRoutineStartLabel == null)
return;
super.exitAnyExceptionHandler();
}
@Override
public void exitDeclaredExceptionHandlers(CodeStream codeStream) {
for (int i = 0, length = this.declaredExceptionLabels == null ? 0 : this.declaredExceptionLabels.length; i < length; i++) {
this.declaredExceptionLabels[i].placeEnd();
}
}
private int finallyMode() {
if (this.subRoutineStartLabel == null) {
return NO_FINALLY;
} else if (isSubRoutineEscaping()) {
return FINALLY_DOES_NOT_COMPLETE;
} else if (this.scope.compilerOptions().inlineJsrBytecode) {
return FINALLY_INLINE;
} else {
return FINALLY_SUBROUTINE;
}
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((this.bits & ASTNode.IsReachable) == 0) {
return;
}
boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream;
this.anyExceptionLabel = null;
this.reusableJSRTargets = null;
this.reusableJSRSequenceStartLabels = null;
this.reusableJSRTargetsCount = 0;
int pc = codeStream.position;
int finallyMode = finallyMode();
boolean requiresNaturalExit = false;
int maxCatches = this.catchArguments == null ? 0 : this.catchArguments.length;
ExceptionLabel[] exceptionLabels;
if (maxCatches > 0) {
exceptionLabels = new ExceptionLabel[maxCatches];
for (int i = 0; i < maxCatches; i++) {
Argument argument = this.catchArguments[i];
ExceptionLabel exceptionLabel = null;
if ((argument.binding.tagBits & TagBits.MultiCatchParameter) != 0) {
MultiCatchExceptionLabel multiCatchExceptionLabel = new MultiCatchExceptionLabel(codeStream, argument.binding.type);
multiCatchExceptionLabel.initialize((UnionTypeReference) argument.type, argument.annotations);
exceptionLabel = multiCatchExceptionLabel;
} else {
exceptionLabel = new ExceptionLabel(codeStream, argument.binding.type, argument.type, argument.annotations);
}
exceptionLabel.placeStart();
exceptionLabels[i] = exceptionLabel;
}
} else {
exceptionLabels = null;
}
if (this.subRoutineStartLabel != null) {
this.subRoutineStartLabel.initialize(codeStream);
enterAnyExceptionHandler(codeStream);
}
try {
this.declaredExceptionLabels = exceptionLabels;
int resourceCount = this.resources.length;
if (resourceCount > 0) {
this.resourceExceptionLabels = new ExceptionLabel[resourceCount + 1];
codeStream.aconst_null();
codeStream.store(this.primaryExceptionVariable, false );
codeStream.addVariable(this.primaryExceptionVariable);
codeStream.aconst_null();
codeStream.store(this.caughtThrowableVariable, false );
codeStream.addVariable(this.caughtThrowableVariable);
for (int i = 0; i <= resourceCount; i++) {
this.resourceExceptionLabels[i] = new ExceptionLabel(codeStream, null);
this.resourceExceptionLabels[i].placeStart();
if (i < resourceCount) {
Statement stmt = this.resources[i];
if (stmt instanceof NameReference) {
NameReference ref = (NameReference) stmt;
ref.bits |= ASTNode.IsCapturedOuterLocal;
VariableBinding binding = (VariableBinding) ref.binding;
ref.checkEffectiveFinality(binding, this.scope);
} else if (stmt instanceof FieldReference) {
FieldReference fieldReference = (FieldReference) stmt;
if (!fieldReference.binding.isFinal())
this.scope.problemReporter().cannotReferToNonFinalField(fieldReference.binding, fieldReference);
}
stmt.generateCode(this.scope, codeStream);
}
}
}
this.tryBlock.generateCode(this.scope, codeStream);
if (resourceCount > 0) {
for (int i = resourceCount; i >= 0; i--) {
BranchLabel exitLabel = new BranchLabel(codeStream);
this.resourceExceptionLabels[i].placeEnd();
Statement stmt = i > 0 ? this.resources[i - 1] : null;
if ((this.bits & ASTNode.IsTryBlockExiting) == 0) {
if (i > 0) {
int invokeCloseStartPc = codeStream.position;
if (this.postTryInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex);
}
generateCodeSnippet(stmt, codeStream, exitLabel, false );
codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd);
}
codeStream.goto_(exitLabel);
}
if (i > 0) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postResourcesInitStateIndexes[i - 1]);
codeStream.addDefinitelyAssignedVariables(currentScope, this.postResourcesInitStateIndexes[i - 1]);
} else {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
}
codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable());
this.resourceExceptionLabels[i].place();
if (i == resourceCount) {
codeStream.store(this.primaryExceptionVariable, false);
} else {
BranchLabel elseLabel = new BranchLabel(codeStream), postElseLabel = new BranchLabel(codeStream);
codeStream.store(this.caughtThrowableVariable, false);
codeStream.load(this.primaryExceptionVariable);
codeStream.ifnonnull(elseLabel);
codeStream.load(this.caughtThrowableVariable);
codeStream.store(this.primaryExceptionVariable, false);
codeStream.goto_(postElseLabel);
elseLabel.place();
codeStream.load(this.primaryExceptionVariable);
codeStream.load(this.caughtThrowableVariable);
codeStream.if_acmpeq(postElseLabel);
codeStream.load(this.primaryExceptionVariable);
codeStream.load(this.caughtThrowableVariable);
codeStream.invokeThrowableAddSuppressed();
postElseLabel.place();
}
if (i > 0) {
BranchLabel postCloseLabel = new BranchLabel(codeStream);
generateCodeSnippet(stmt, codeStream, postCloseLabel, true , i, codeStream.position);
postCloseLabel.place();
}
codeStream.load(this.primaryExceptionVariable);
codeStream.athrow();
exitLabel.place();
}
codeStream.removeVariable(this.primaryExceptionVariable);
codeStream.removeVariable(this.caughtThrowableVariable);
}
} finally {
this.declaredExceptionLabels = null;
this.resourceExceptionLabels = null;
}
boolean tryBlockHasSomeCode = codeStream.position != pc;
if (tryBlockHasSomeCode) {
BranchLabel naturalExitLabel = new BranchLabel(codeStream);
BranchLabel postCatchesFinallyLabel = null;
for (int i = 0; i < maxCatches; i++) {
exceptionLabels[i].placeEnd();
}
if ((this.bits & ASTNode.IsTryBlockExiting) == 0) {
int position = codeStream.position;
switch(finallyMode) {
case FINALLY_SUBROUTINE :
case FINALLY_INLINE :
requiresNaturalExit = true;
if (this.naturalExitMergeInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
}
codeStream.goto_(naturalExitLabel);
break;
case NO_FINALLY :
if (this.naturalExitMergeInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
}
codeStream.goto_(naturalExitLabel);
break;
case FINALLY_DOES_NOT_COMPLETE :
codeStream.goto_(this.subRoutineStartLabel);
break;
}
codeStream.recordPositionsFrom(position, this.tryBlock.sourceEnd);
}
exitAnyExceptionHandler();
if (this.catchArguments != null) {
postCatchesFinallyLabel = new BranchLabel(codeStream);
for (int i = 0; i < maxCatches; i++) {
if (exceptionLabels[i].getCount() == 0) continue;
enterAnyExceptionHandler(codeStream);
if (this.preTryInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
}
codeStream.pushExceptionOnStack(exceptionLabels[i].exceptionType);
exceptionLabels[i].place();
LocalVariableBinding catchVar;
int varPC = codeStream.position;
if ((catchVar = this.catchArguments[i].binding).resolvedPosition != -1) {
codeStream.store(catchVar, false);
catchVar.recordInitializationStartPC(codeStream.position);
codeStream.addVisibleLocalVariable(catchVar);
} else {
codeStream.pop();
}
codeStream.recordPositionsFrom(varPC, this.catchArguments[i].sourceStart);
this.catchBlocks[i].generateCode(this.scope, codeStream);
exitAnyExceptionHandler();
if (!this.catchExits[i]) {
switch(finallyMode) {
case FINALLY_INLINE :
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex);
}
if (this.catchExitInitStateIndexes[i] != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]);
codeStream.addDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]);
}
this.finallyBlock.generateCode(this.scope, codeStream);
codeStream.goto_(postCatchesFinallyLabel);
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).popStateIndex();
}
break;
case FINALLY_SUBROUTINE :
requiresNaturalExit = true;
case NO_FINALLY :
if (this.naturalExitMergeInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
}
codeStream.goto_(naturalExitLabel);
break;
case FINALLY_DOES_NOT_COMPLETE :
codeStream.goto_(this.subRoutineStartLabel);
break;
}
}
}
}
ExceptionLabel naturalExitExceptionHandler = requiresNaturalExit && (finallyMode == FINALLY_SUBROUTINE)
? new ExceptionLabel(codeStream, null)
: null;
int finallySequenceStartPC = codeStream.position;
if (this.subRoutineStartLabel != null && this.anyExceptionLabel.getCount() != 0) {
codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable());
if (this.preTryInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
}
placeAllAnyExceptionHandler();
if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place();
switch(finallyMode) {
case FINALLY_SUBROUTINE :
codeStream.store(this.anyExceptionVariable, false);
codeStream.jsr(this.subRoutineStartLabel);
codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart);
int position = codeStream.position;
codeStream.throwAnyException(this.anyExceptionVariable);
codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd);
this.subRoutineStartLabel.place();
codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable());
position = codeStream.position;
codeStream.store(this.returnAddressVariable, false);
codeStream.recordPositionsFrom(position, this.finallyBlock.sourceStart);
this.finallyBlock.generateCode(this.scope, codeStream);
position = codeStream.position;
codeStream.ret(this.returnAddressVariable.resolvedPosition);
codeStream.recordPositionsFrom(
position,
this.finallyBlock.sourceEnd);
break;
case FINALLY_INLINE :
codeStream.store(this.anyExceptionVariable, false);
codeStream.addVariable(this.anyExceptionVariable);
codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart);
this.finallyBlock.generateCode(currentScope, codeStream);
position = codeStream.position;
codeStream.throwAnyException(this.anyExceptionVariable);
codeStream.removeVariable(this.anyExceptionVariable);
if (this.preTryInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex);
}
this.subRoutineStartLabel.place();
codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd);
break;
case FINALLY_DOES_NOT_COMPLETE :
codeStream.pop();
this.subRoutineStartLabel.place();
codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart);
this.finallyBlock.generateCode(this.scope, codeStream);
break;
}
if (requiresNaturalExit) {
switch(finallyMode) {
case FINALLY_SUBROUTINE :
naturalExitLabel.place();
int position = codeStream.position;
naturalExitExceptionHandler.placeStart();
codeStream.jsr(this.subRoutineStartLabel);
naturalExitExceptionHandler.placeEnd();
codeStream.recordPositionsFrom(
position,
this.finallyBlock.sourceEnd);
break;
case FINALLY_INLINE :
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex);
}
if (this.naturalExitMergeInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex);
}
naturalExitLabel.place();
this.finallyBlock.generateCode(this.scope, codeStream);
if (postCatchesFinallyLabel != null) {
position = codeStream.position;
codeStream.goto_(postCatchesFinallyLabel);
codeStream.recordPositionsFrom(
position,
this.finallyBlock.sourceEnd);
}
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).popStateIndex();
}
break;
case FINALLY_DOES_NOT_COMPLETE :
break;
default :
naturalExitLabel.place();
break;
}
}
if (postCatchesFinallyLabel != null) {
postCatchesFinallyLabel.place();
}
} else {
naturalExitLabel.place();
}
} else {
if (this.subRoutineStartLabel != null) {
this.finallyBlock.generateCode(this.scope, codeStream);
}
}
if (this.mergedInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
private void generateCodeSnippet(Statement statement, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int... values) {
int i = -1;
int invokeCloseStartPc = -1;
if (record) {
i = values[0];
invokeCloseStartPc = values[1];
}
if (statement instanceof LocalDeclaration)
generateCodeSnippet((LocalDeclaration)statement, codeStream, postCloseLabel, record, i, invokeCloseStartPc);
else if (statement instanceof Reference)
generateCodeSnippet((Reference)statement, codeStream, postCloseLabel, record, i, invokeCloseStartPc);
}
private void generateCodeSnippet(Reference reference, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int i, int invokeCloseStartPc) {
reference.generateCode(this.scope, codeStream, true);
codeStream.ifnull(postCloseLabel);
reference.generateCode(this.scope, codeStream, true);
codeStream.invokeAutoCloseableClose(reference.resolvedType);
if (!record) return;
codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd);
isDuplicateResourceReference(i);
}
private void generateCodeSnippet(LocalDeclaration localDeclaration, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int i, int invokeCloseStartPc) {
LocalVariableBinding variableBinding = localDeclaration.binding;
codeStream.load(variableBinding);
codeStream.ifnull(postCloseLabel);
codeStream.load(variableBinding);
codeStream.invokeAutoCloseableClose(variableBinding.type);
if (!record) return;
codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd);
if (!isDuplicateResourceReference(i))
codeStream.removeVariable(variableBinding);
}
private boolean isDuplicateResourceReference(int index) {
int len = this.resources.length;
if (index < len && this.resources[index] instanceof Reference) {
Reference ref = (Reference) this.resources[index];
Binding refBinding = ref instanceof NameReference ? ((NameReference) ref).binding :
ref instanceof FieldReference ? ((FieldReference) ref).binding : null;
if (refBinding == null) return false;
for (int i = 0; i < index; i++) {
Statement stmt = this.resources[i];
Binding b = stmt instanceof LocalDeclaration ? ((LocalDeclaration) stmt).binding :
stmt instanceof NameReference ? ((NameReference) stmt).binding :
stmt instanceof FieldReference ? ((FieldReference) stmt).binding : null;
if (b == refBinding) {
this.scope.problemReporter().duplicateResourceReference(ref);
return true;
}
}
}
return false;
}
@Override
public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) {
int resourceCount = this.resources.length;
if (resourceCount > 0 && this.resourceExceptionLabels != null) {
for (int i = resourceCount; i > 0; --i) {
this.resourceExceptionLabels[i].placeEnd();
BranchLabel exitLabel = new BranchLabel(codeStream);
int invokeCloseStartPc = codeStream.position;
generateCodeSnippet(this.resources[i - 1], codeStream, exitLabel, false);
codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd);
exitLabel.place();
}
this.resourceExceptionLabels[0].placeEnd();
}
boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream;
int finallyMode = finallyMode();
switch(finallyMode) {
case FINALLY_DOES_NOT_COMPLETE :
codeStream.goto_(this.subRoutineStartLabel);
return true;
case NO_FINALLY :
exitDeclaredExceptionHandlers(codeStream);
return false;
}
CompilerOptions options = this.scope.compilerOptions();
if (options.shareCommonFinallyBlocks && targetLocation != null) {
boolean reuseTargetLocation = true;
if (this.reusableJSRTargetsCount > 0) {
nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) {
Object reusableJSRTarget = this.reusableJSRTargets[i];
differentTarget: {
if (targetLocation == reusableJSRTarget)
break differentTarget;
if (targetLocation instanceof Constant
&& reusableJSRTarget instanceof Constant
&& ((Constant)targetLocation).hasSameValue((Constant) reusableJSRTarget)) {
break differentTarget;
}
continue nextReusableTarget;
}
if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE) {
reuseTargetLocation = false;
break nextReusableTarget;
} else {
codeStream.goto_(this.reusableJSRSequenceStartLabels[i]);
return true;
}
}
} else {
this.reusableJSRTargets = new Object[3];
this.reusableJSRSequenceStartLabels = new BranchLabel[3];
this.reusableJSRStateIndexes = new int[3];
}
if (reuseTargetLocation) {
if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) {
System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount);
System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount);
System.arraycopy(this.reusableJSRStateIndexes, 0, this.reusableJSRStateIndexes = new int[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount);
}
this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation;
BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream);
reusableJSRSequenceStartLabel.place();
this.reusableJSRStateIndexes[this.reusableJSRTargetsCount] = stateIndex;
this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel;
}
}
if (finallyMode == FINALLY_INLINE) {
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex);
}
exitAnyExceptionHandler();
exitDeclaredExceptionHandlers(codeStream);
this.finallyBlock.generateCode(currentScope, codeStream);
if (isStackMapFrameCodeStream) {
((StackMapFrameCodeStream) codeStream).popStateIndex();
}
} else {
codeStream.jsr(this.subRoutineStartLabel);
exitAnyExceptionHandler();
exitDeclaredExceptionHandlers(codeStream);
}
return false;
}
@Override
public boolean isSubRoutineEscaping() {
return (this.bits & ASTNode.IsSubRoutineEscaping) != 0;
}
@Override
public StringBuffer printStatement(int indent, StringBuffer output) {
int length = this.resources.length;
printIndent(indent, output).append("try" + (length == 0 ? "\n" : " ("));
for (int i = 0; i < length; i++) {
Statement stmt = this.resources[i];
if (stmt instanceof LocalDeclaration) {
((LocalDeclaration) stmt).printAsExpression(0, output);
} else if (stmt instanceof Reference) {
((Reference) stmt).printExpression(0, output);
} else continue;
if (i != length - 1) {
output.append(";\n");
printIndent(indent + 2, output);
}
}
if (length > 0) {
output.append(")\n");
}
this.tryBlock.printStatement(indent + 1, output);
if (this.catchBlocks != null)
for (int i = 0; i < this.catchBlocks.length; i++) {
output.append('\n');
printIndent(indent, output).append("catch (");
this.catchArguments[i].print(0, output).append(")\n");
this.catchBlocks[i].printStatement(indent + 1, output);
}
if (this.finallyBlock != null) {
output.append('\n');
printIndent(indent, output).append("finally\n");
this.finallyBlock.printStatement(indent + 1, output);
}
return output;
}
@Override
public void resolve(BlockScope upperScope) {
this.scope = new BlockScope(upperScope);
BlockScope finallyScope = null;
BlockScope resourceManagementScope = null;
int resourceCount = this.resources.length;
if (resourceCount > 0) {
resourceManagementScope = new BlockScope(this.scope);
this.primaryExceptionVariable =
new LocalVariableBinding(TryStatement.SECRET_PRIMARY_EXCEPTION_VARIABLE_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false);
resourceManagementScope.addLocalVariable(this.primaryExceptionVariable);
this.primaryExceptionVariable.setConstant(Constant.NotAConstant);
this.caughtThrowableVariable =
new LocalVariableBinding(TryStatement.SECRET_CAUGHT_THROWABLE_VARIABLE_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false);
resourceManagementScope.addLocalVariable(this.caughtThrowableVariable);
this.caughtThrowableVariable.setConstant(Constant.NotAConstant);
}
for (int i = 0; i < resourceCount; i++) {
this.resources[i].resolve(resourceManagementScope);
if (this.resources[i] instanceof LocalDeclaration) {
LocalDeclaration node = (LocalDeclaration)this.resources[i];
LocalVariableBinding localVariableBinding = node.binding;
if (localVariableBinding != null && localVariableBinding.isValidBinding()) {
localVariableBinding.modifiers |= ClassFileConstants.AccFinal;
localVariableBinding.tagBits |= TagBits.IsResource;
TypeBinding resourceType = localVariableBinding.type;
if (resourceType instanceof ReferenceBinding) {
if (resourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangAutoCloseable, false ) == null && resourceType.isValidBinding()) {
upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node.type);
localVariableBinding.type = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource);
}
} else if (resourceType != null) {
upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node.type);
localVariableBinding.type = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource);
}
}
} else {
Expression node = (Expression) this.resources[i];
TypeBinding resourceType = node.resolvedType;
if (resourceType instanceof ReferenceBinding) {
if (resourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangAutoCloseable, false ) == null && resourceType.isValidBinding()) {
upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node);
((Expression) this.resources[i]).resolvedType = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource);
}
} else if (resourceType != null) {
upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node);
((Expression) this.resources[i]).resolvedType = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource);
}
}
}
BlockScope tryScope = new BlockScope(resourceManagementScope != null ? resourceManagementScope : this.scope);
if (this.finallyBlock != null) {
if (this.finallyBlock.isEmptyBlock()) {
if ((this.finallyBlock.bits & ASTNode.UndocumentedEmptyBlock) != 0) {
this.scope.problemReporter().undocumentedEmptyBlock(this.finallyBlock.sourceStart, this.finallyBlock.sourceEnd);
}
} else {
finallyScope = new BlockScope(this.scope, false);
MethodScope methodScope = this.scope.methodScope();
if (!upperScope.compilerOptions().inlineJsrBytecode) {
this.returnAddressVariable =
new LocalVariableBinding(TryStatement.SECRET_RETURN_ADDRESS_NAME, upperScope.getJavaLangObject(), ClassFileConstants.AccDefault, false);
finallyScope.addLocalVariable(this.returnAddressVariable);
this.returnAddressVariable.setConstant(Constant.NotAConstant);
}
this.subRoutineStartLabel = new BranchLabel();
this.anyExceptionVariable =
new LocalVariableBinding(TryStatement.SECRET_ANY_HANDLER_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false);
finallyScope.addLocalVariable(this.anyExceptionVariable);
this.anyExceptionVariable.setConstant(Constant.NotAConstant);
if (!methodScope.isInsideInitializer()) {
MethodBinding methodBinding = methodScope.referenceContext instanceof AbstractMethodDeclaration ?
((AbstractMethodDeclaration) methodScope.referenceContext).binding : (methodScope.referenceContext instanceof LambdaExpression ?
((LambdaExpression)methodScope.referenceContext).binding : null);
if (methodBinding != null) {
TypeBinding methodReturnType = methodBinding.returnType;
if (methodReturnType.id != TypeIds.T_void) {
this.secretReturnValue =
new LocalVariableBinding(
TryStatement.SECRET_RETURN_VALUE_NAME,
methodReturnType,
ClassFileConstants.AccDefault,
false);
finallyScope.addLocalVariable(this.secretReturnValue);
this.secretReturnValue.setConstant(Constant.NotAConstant);
}
}
}
this.finallyBlock.resolveUsing(finallyScope);
int shiftScopesLength = this.catchArguments == null ? 1 : this.catchArguments.length + 1;
finallyScope.shiftScopes = new BlockScope[shiftScopesLength];
finallyScope.shiftScopes[0] = tryScope;
}
}
this.tryBlock.resolveUsing(tryScope);
if (this.catchBlocks != null) {
int length = this.catchArguments.length;
TypeBinding[] argumentTypes = new TypeBinding[length];
boolean containsUnionTypes = false;
boolean catchHasError = false;
for (int i = 0; i < length; i++) {
BlockScope catchScope = new BlockScope(this.scope);
if (finallyScope != null){
finallyScope.shiftScopes[i+1] = catchScope;
}
Argument catchArgument = this.catchArguments[i];
containsUnionTypes |= (catchArgument.type.bits & ASTNode.IsUnionType) != 0;
if ((argumentTypes[i] = catchArgument.resolveForCatch(catchScope)) == null) {
catchHasError = true;
}
this.catchBlocks[i].resolveUsing(catchScope);
}
if (catchHasError) {
return;
}
verifyDuplicationAndOrder(length, argumentTypes, containsUnionTypes);
} else {
this.caughtExceptionTypes = new ReferenceBinding[0];
}
if (finallyScope != null){
this.scope.addSubscope(finallyScope);
}
}
@Override
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
Statement[] statements = this.resources;
for (int i = 0, max = statements.length; i < max; i++) {
statements[i].traverse(visitor, this.scope);
}
this.tryBlock.traverse(visitor, this.scope);
if (this.catchArguments != null) {
for (int i = 0, max = this.catchBlocks.length; i < max; i++) {
this.catchArguments[i].traverse(visitor, this.scope);
this.catchBlocks[i].traverse(visitor, this.scope);
}
}
if (this.finallyBlock != null)
this.finallyBlock.traverse(visitor, this.scope);
}
visitor.endVisit(this, blockScope);
}
protected void verifyDuplicationAndOrder(int length, TypeBinding[] argumentTypes, boolean containsUnionTypes) {
if (containsUnionTypes) {
int totalCount = 0;
ReferenceBinding[][] allExceptionTypes = new ReferenceBinding[length][];
for (int i = 0; i < length; i++) {
if (argumentTypes[i] instanceof ArrayBinding)
continue;
ReferenceBinding currentExceptionType = (ReferenceBinding) argumentTypes[i];
TypeReference catchArgumentType = this.catchArguments[i].type;
if ((catchArgumentType.bits & ASTNode.IsUnionType) != 0) {
TypeReference[] typeReferences = ((UnionTypeReference) catchArgumentType).typeReferences;
int typeReferencesLength = typeReferences.length;
ReferenceBinding[] unionExceptionTypes = new ReferenceBinding[typeReferencesLength];
for (int j = 0; j < typeReferencesLength; j++) {
unionExceptionTypes[j] = (ReferenceBinding) typeReferences[j].resolvedType;
}
totalCount += typeReferencesLength;
allExceptionTypes[i] = unionExceptionTypes;
} else {
allExceptionTypes[i] = new ReferenceBinding[] { currentExceptionType };
totalCount++;
}
}
this.caughtExceptionTypes = new ReferenceBinding[totalCount];
this.caughtExceptionsCatchBlocks = new int[totalCount];
for (int i = 0, l = 0; i < length; i++) {
ReferenceBinding[] currentExceptions = allExceptionTypes[i];
if (currentExceptions == null) continue;
loop: for (int j = 0, max = currentExceptions.length; j < max; j++) {
ReferenceBinding exception = currentExceptions[j];
this.caughtExceptionTypes[l] = exception;
this.caughtExceptionsCatchBlocks[l++] = i;
for (int k = 0; k < i; k++) {
ReferenceBinding[] exceptions = allExceptionTypes[k];
if (exceptions == null) continue;
for (int n = 0, max2 = exceptions.length; n < max2; n++) {
ReferenceBinding currentException = exceptions[n];
if (exception.isCompatibleWith(currentException)) {
TypeReference catchArgumentType = this.catchArguments[i].type;
if ((catchArgumentType.bits & ASTNode.IsUnionType) != 0) {
catchArgumentType = ((UnionTypeReference) catchArgumentType).typeReferences[j];
}
this.scope.problemReporter().wrongSequenceOfExceptionTypesError(
catchArgumentType,
exception,
currentException);
break loop;
}
}
}
}
}
} else {
this.caughtExceptionTypes = new ReferenceBinding[length];
for (int i = 0; i < length; i++) {
if (argumentTypes[i] instanceof ArrayBinding)
continue;
this.caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
for (int j = 0; j < i; j++) {
if (this.caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) {
this.scope.problemReporter().wrongSequenceOfExceptionTypesError(
this.catchArguments[i].type,
this.caughtExceptionTypes[i],
argumentTypes[j]);
}
}
}
}
}
@Override
public boolean doesNotCompleteNormally() {
if (!this.tryBlock.doesNotCompleteNormally()) {
return (this.finallyBlock != null) ? this.finallyBlock.doesNotCompleteNormally() : false;
}
if (this.catchBlocks != null) {
for (int i = 0; i < this.catchBlocks.length; i++) {
if (!this.catchBlocks[i].doesNotCompleteNormally()) {
return (this.finallyBlock != null) ? this.finallyBlock.doesNotCompleteNormally() : false;
}
}
}
return true;
}
@Override
public boolean completesByContinue() {
if (this.tryBlock.completesByContinue()) {
return (this.finallyBlock == null) ? true :
!this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue();
}
if (this.catchBlocks != null) {
for (int i = 0; i < this.catchBlocks.length; i++) {
if (this.catchBlocks[i].completesByContinue()) {
return (this.finallyBlock == null) ? true :
!this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue();
}
}
}
return this.finallyBlock != null && this.finallyBlock.completesByContinue();
}
}