/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; import net.sourceforge.phpdt.internal.compiler.ASTVisitor; import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.impl.Constant; import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; public class AssertStatement extends Statement { public Expression assertExpression, exceptionArgument; // for local variable attribute int preAssertInitStateIndex = -1; private FieldBinding assertionSyntheticFieldBinding; public AssertStatement(Expression exceptionArgument, Expression assertExpression, int startPosition) { this.assertExpression = assertExpression; this.exceptionArgument = exceptionArgument; sourceStart = startPosition; sourceEnd = exceptionArgument.sourceEnd; } public AssertStatement(Expression assertExpression, int startPosition) { this.assertExpression = assertExpression; sourceStart = startPosition; sourceEnd = assertExpression.sourceEnd; } public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { preAssertInitStateIndex = currentScope.methodScope() .recordInitializationStates(flowInfo); Constant cst = this.assertExpression.optimizedBooleanConstant(); boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true; boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false; FlowInfo assertInfo = flowInfo.copy(); if (isOptimizedTrueAssertion) { assertInfo.setReachMode(FlowInfo.UNREACHABLE); } assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits(); if (exceptionArgument != null) { // only gets evaluated when escaping - results are not taken into // account FlowInfo exceptionInfo = exceptionArgument.analyseCode( currentScope, flowContext, assertInfo.copy()); if (!isOptimizedTrueAssertion) { flowContext.checkExceptionHandlers(currentScope .getJavaLangAssertionError(), this, exceptionInfo, currentScope); } } // add the assert support in the clinit manageSyntheticAccessIfNecessary(currentScope); if (isOptimizedFalseAssertion) { return flowInfo; // if assertions are enabled, the following code // will be unreachable } else { return flowInfo.mergedWith(assertInfo.unconditionalInits()); } } // public void generateCode(BlockScope currentScope, CodeStream codeStream) // { // // if ((bits & IsReachableMASK) == 0) { // return; // } // int pc = codeStream.position; // // if (this.assertionSyntheticFieldBinding != null) { // Label assertionActivationLabel = new Label(codeStream); // codeStream.getstatic(this.assertionSyntheticFieldBinding); // codeStream.ifne(assertionActivationLabel); // Label falseLabel = new Label(codeStream); // assertExpression.generateOptimizedBoolean(currentScope, codeStream, // (falseLabel = new Label(codeStream)), null , true); // codeStream.newJavaLangAssertionError(); // codeStream.dup(); // if (exceptionArgument != null) { // exceptionArgument.generateCode(currentScope, codeStream, true); // codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion // & 0xF); // } else { // codeStream.invokeJavaLangAssertionErrorDefaultConstructor(); // } // codeStream.athrow(); // falseLabel.place(); // assertionActivationLabel.place(); // } // // // May loose some local variable initializations : affecting the local // variable attributes // if (preAssertInitStateIndex != -1) { // codeStream.removeNotDefinitelyAssignedVariables(currentScope, // preAssertInitStateIndex); // } // codeStream.recordPositionsFrom(pc, this.sourceStart); // } public StringBuffer printStatement(int tab, StringBuffer output) { printIndent(tab, output); output.append("assert "); //$NON-NLS-1$ this.assertExpression.printExpression(0, output); if (this.exceptionArgument != null) { output.append(": "); //$NON-NLS-1$ this.exceptionArgument.printExpression(0, output); } return output.append(';'); } public void resolve(BlockScope scope) { assertExpression.resolveTypeExpecting(scope, BooleanBinding); if (exceptionArgument != null) { TypeBinding exceptionArgumentType = exceptionArgument .resolveType(scope); if (exceptionArgumentType != null) { if (exceptionArgumentType.id == T_void) { scope.problemReporter().illegalVoidExpression( exceptionArgument); } exceptionArgument.implicitConversion = (exceptionArgumentType.id << 4) + exceptionArgumentType.id; } } } public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { assertExpression.traverse(visitor, scope); if (exceptionArgument != null) { exceptionArgument.traverse(visitor, scope); } } visitor.endVisit(this, scope); } public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { // need assertion flag: $assertionsDisabled on outer most source clas // (in case of static member of interface, will use the outermost static // member - bug 22334) SourceTypeBinding outerMostClass = currentScope.enclosingSourceType(); while (outerMostClass.isLocalType()) { ReferenceBinding enclosing = outerMostClass.enclosingType(); if (enclosing == null || enclosing.isInterface()) break; outerMostClass = (SourceTypeBinding) enclosing; } this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticField( this, currentScope); // find and enable assertion support TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType(); AbstractMethodDeclaration[] methods = typeDeclaration.methods; for (int i = 0, max = methods.length; i < max; i++) { AbstractMethodDeclaration method = methods[i]; if (method.isClinit()) { ((Clinit) method) .addSupportForAssertion(assertionSyntheticFieldBinding); break; } } } public String toString(int tab) { StringBuffer buffer = new StringBuffer(tabString(tab)); buffer.append("assert "); //$NON-NLS-1$ buffer.append(this.assertExpression); if (this.exceptionArgument != null) { buffer.append(":"); //$NON-NLS-1$ buffer.append(this.exceptionArgument); buffer.append(";"); //$NON-NLS-1$ } return buffer.toString(); } }