1 /******************************************************************************* 2 * Copyright (c) 2000, 2004 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 14 import org.eclipse.jdt.internal.compiler.codegen.*; 15 import org.eclipse.jdt.internal.compiler.flow.*; 16 import org.eclipse.jdt.internal.compiler.impl.Constant; 17 import org.eclipse.jdt.internal.compiler.lookup.*; 18 import org.eclipse.jdt.internal.compiler.ASTVisitor; 19 20 public class AssertStatement extends Statement { 21 22 public Expression assertExpression, exceptionArgument; 23 24 // for local variable attribute 25 int preAssertInitStateIndex = -1; 26 private FieldBinding assertionSyntheticFieldBinding; 27 AssertStatement( Expression exceptionArgument, Expression assertExpression, int startPosition)28 public AssertStatement( 29 Expression exceptionArgument, 30 Expression assertExpression, 31 int startPosition) { 32 33 this.assertExpression = assertExpression; 34 this.exceptionArgument = exceptionArgument; 35 sourceStart = startPosition; 36 sourceEnd = exceptionArgument.sourceEnd; 37 } 38 AssertStatement(Expression assertExpression, int startPosition)39 public AssertStatement(Expression assertExpression, int startPosition) { 40 41 this.assertExpression = assertExpression; 42 sourceStart = startPosition; 43 sourceEnd = assertExpression.sourceEnd; 44 } 45 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)46 public FlowInfo analyseCode( 47 BlockScope currentScope, 48 FlowContext flowContext, 49 FlowInfo flowInfo) { 50 51 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); 52 53 Constant cst = this.assertExpression.optimizedBooleanConstant(); 54 boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true; 55 boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false; 56 57 FlowInfo assertInfo = flowInfo.copy(); 58 if (isOptimizedTrueAssertion) { 59 assertInfo.setReachMode(FlowInfo.UNREACHABLE); 60 } 61 assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits(); 62 63 if (exceptionArgument != null) { 64 // only gets evaluated when escaping - results are not taken into account 65 FlowInfo exceptionInfo = exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); 66 67 if (!isOptimizedTrueAssertion){ 68 flowContext.checkExceptionHandlers( 69 currentScope.getJavaLangAssertionError(), 70 this, 71 exceptionInfo, 72 currentScope); 73 } 74 } 75 76 if (!isOptimizedTrueAssertion){ 77 // add the assert support in the clinit 78 manageSyntheticAccessIfNecessary(currentScope, flowInfo); 79 } 80 if (isOptimizedFalseAssertion) { 81 return flowInfo; // if assertions are enabled, the following code will be unreachable 82 } else { 83 return flowInfo.mergedWith(assertInfo.unconditionalInits()); 84 } 85 } 86 generateCode(BlockScope currentScope, CodeStream codeStream)87 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 88 89 if ((bits & IsReachableMASK) == 0) { 90 return; 91 } 92 int pc = codeStream.position; 93 94 if (this.assertionSyntheticFieldBinding != null) { 95 Label assertionActivationLabel = new Label(codeStream); 96 codeStream.getstatic(this.assertionSyntheticFieldBinding); 97 codeStream.ifne(assertionActivationLabel); 98 99 Label falseLabel = new Label(codeStream); 100 this.assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new Label(codeStream)), null , true); 101 codeStream.newJavaLangAssertionError(); 102 codeStream.dup(); 103 if (exceptionArgument != null) { 104 exceptionArgument.generateCode(currentScope, codeStream, true); 105 codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF); 106 } else { 107 codeStream.invokeJavaLangAssertionErrorDefaultConstructor(); 108 } 109 codeStream.athrow(); 110 falseLabel.place(); 111 assertionActivationLabel.place(); 112 } 113 114 // May loose some local variable initializations : affecting the local variable attributes 115 if (preAssertInitStateIndex != -1) { 116 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preAssertInitStateIndex); 117 } 118 codeStream.recordPositionsFrom(pc, this.sourceStart); 119 } 120 resolve(BlockScope scope)121 public void resolve(BlockScope scope) { 122 123 assertExpression.resolveTypeExpecting(scope, BooleanBinding); 124 if (exceptionArgument != null) { 125 TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope); 126 if (exceptionArgumentType != null){ 127 int id = exceptionArgumentType.id; 128 switch(id) { 129 case T_void : 130 scope.problemReporter().illegalVoidExpression(exceptionArgument); 131 default: 132 id = T_Object; 133 case T_boolean : 134 case T_byte : 135 case T_char : 136 case T_short : 137 case T_double : 138 case T_float : 139 case T_int : 140 case T_long : 141 case T_String : 142 exceptionArgument.implicitConversion = (id << 4) + id; 143 } 144 } 145 } 146 } 147 traverse(ASTVisitor visitor, BlockScope scope)148 public void traverse(ASTVisitor visitor, BlockScope scope) { 149 150 if (visitor.visit(this, scope)) { 151 assertExpression.traverse(visitor, scope); 152 if (exceptionArgument != null) { 153 exceptionArgument.traverse(visitor, scope); 154 } 155 } 156 visitor.endVisit(this, scope); 157 } 158 manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo)159 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { 160 161 if (!flowInfo.isReachable()) return; 162 163 // need assertion flag: $assertionsDisabled on outer most source clas 164 // (in case of static member of interface, will use the outermost static member - bug 22334) 165 SourceTypeBinding outerMostClass = currentScope.enclosingSourceType(); 166 while (outerMostClass.isLocalType()){ 167 ReferenceBinding enclosing = outerMostClass.enclosingType(); 168 if (enclosing == null || enclosing.isInterface()) break; 169 outerMostClass = (SourceTypeBinding) enclosing; 170 } 171 172 this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticField(this, currentScope); 173 174 // find <clinit> and enable assertion support 175 TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType(); 176 AbstractMethodDeclaration[] methods = typeDeclaration.methods; 177 for (int i = 0, max = methods.length; i < max; i++) { 178 AbstractMethodDeclaration method = methods[i]; 179 if (method.isClinit()) { 180 ((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding, currentScope.environment().options.sourceLevel < ClassFileConstants.JDK1_5); 181 break; 182 } 183 } 184 } 185 printStatement(int tab, StringBuffer output)186 public StringBuffer printStatement(int tab, StringBuffer output) { 187 188 printIndent(tab, output); 189 output.append("assert "); //$NON-NLS-1$ 190 this.assertExpression.printExpression(0, output); 191 if (this.exceptionArgument != null) { 192 output.append(": "); //$NON-NLS-1$ 193 this.exceptionArgument.printExpression(0, output); 194 } 195 return output.append(';'); 196 } 197 198 } 199