001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
013: import org.eclipse.jdt.internal.compiler.codegen.*;
014: import org.eclipse.jdt.internal.compiler.flow.*;
015: import org.eclipse.jdt.internal.compiler.impl.Constant;
016: import org.eclipse.jdt.internal.compiler.lookup.*;
017: import org.eclipse.jdt.internal.compiler.ASTVisitor;
018:
019: public class AssertStatement extends Statement {
020:
021: public Expression assertExpression, exceptionArgument;
022:
023: // for local variable attribute
024: int preAssertInitStateIndex = -1;
025: private FieldBinding assertionSyntheticFieldBinding;
026:
027: public AssertStatement(Expression exceptionArgument,
028: Expression assertExpression, int startPosition) {
029:
030: this .assertExpression = assertExpression;
031: this .exceptionArgument = exceptionArgument;
032: sourceStart = startPosition;
033: sourceEnd = exceptionArgument.sourceEnd;
034: }
035:
036: public AssertStatement(Expression assertExpression,
037: int startPosition) {
038:
039: this .assertExpression = assertExpression;
040: sourceStart = startPosition;
041: sourceEnd = assertExpression.sourceEnd;
042: }
043:
044: public FlowInfo analyseCode(BlockScope currentScope,
045: FlowContext flowContext, FlowInfo flowInfo) {
046:
047: preAssertInitStateIndex = currentScope.methodScope()
048: .recordInitializationStates(flowInfo);
049:
050: Constant cst = this .assertExpression.optimizedBooleanConstant();
051: boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant
052: && cst.booleanValue() == true;
053: boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant
054: && cst.booleanValue() == false;
055:
056: FlowInfo assertRawInfo = assertExpression.analyseCode(
057: currentScope, flowContext, flowInfo.copy());
058: UnconditionalFlowInfo assertWhenTrueInfo = assertRawInfo
059: .initsWhenTrue().unconditionalInits();
060: UnconditionalFlowInfo assertInfo = assertRawInfo
061: .unconditionalCopy();
062: if (isOptimizedTrueAssertion) {
063: assertInfo.setReachMode(FlowInfo.UNREACHABLE);
064: }
065:
066: if (exceptionArgument != null) {
067: // only gets evaluated when escaping - results are not taken into account
068: FlowInfo exceptionInfo = exceptionArgument.analyseCode(
069: currentScope, flowContext, assertInfo.copy());
070:
071: if (!isOptimizedTrueAssertion) {
072: flowContext.checkExceptionHandlers(currentScope
073: .getJavaLangAssertionError(), this ,
074: exceptionInfo, currentScope);
075: }
076: }
077:
078: if (!isOptimizedTrueAssertion) {
079: // add the assert support in the clinit
080: manageSyntheticAccessIfNecessary(currentScope, flowInfo);
081: }
082: if (isOptimizedFalseAssertion) {
083: return flowInfo; // if assertions are enabled, the following code will be unreachable
084: // change this if we need to carry null analysis results of the assert
085: // expression downstream
086: } else {
087: return flowInfo.mergedWith(
088: assertInfo.nullInfoLessUnconditionalCopy())
089: .addInitializationsFrom(
090: assertWhenTrueInfo
091: .discardInitializationInfo());
092: // keep the merge from the initial code for the definite assignment
093: // analysis, tweak the null part to influence nulls downstream
094: }
095: }
096:
097: public void generateCode(BlockScope currentScope,
098: CodeStream codeStream) {
099:
100: if ((bits & IsReachable) == 0) {
101: return;
102: }
103: int pc = codeStream.position;
104:
105: if (this .assertionSyntheticFieldBinding != null) {
106: BranchLabel assertionActivationLabel = new BranchLabel(
107: codeStream);
108: codeStream.getstatic(this .assertionSyntheticFieldBinding);
109: codeStream.ifne(assertionActivationLabel);
110:
111: BranchLabel falseLabel;
112: this .assertExpression.generateOptimizedBoolean(
113: currentScope, codeStream,
114: (falseLabel = new BranchLabel(codeStream)), null,
115: true);
116: codeStream.newJavaLangAssertionError();
117: codeStream.dup();
118: if (exceptionArgument != null) {
119: exceptionArgument.generateCode(currentScope,
120: codeStream, true);
121: codeStream
122: .invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF);
123: } else {
124: codeStream
125: .invokeJavaLangAssertionErrorDefaultConstructor();
126: }
127: codeStream.athrow();
128:
129: // May loose some local variable initializations : affecting the local variable attributes
130: if (preAssertInitStateIndex != -1) {
131: codeStream.removeNotDefinitelyAssignedVariables(
132: currentScope, preAssertInitStateIndex);
133: }
134: falseLabel.place();
135: assertionActivationLabel.place();
136: } else {
137: // May loose some local variable initializations : affecting the local variable attributes
138: if (preAssertInitStateIndex != -1) {
139: codeStream.removeNotDefinitelyAssignedVariables(
140: currentScope, preAssertInitStateIndex);
141: }
142: }
143: codeStream.recordPositionsFrom(pc, this .sourceStart);
144: }
145:
146: public void resolve(BlockScope scope) {
147:
148: assertExpression.resolveTypeExpecting(scope,
149: TypeBinding.BOOLEAN);
150: if (exceptionArgument != null) {
151: TypeBinding exceptionArgumentType = exceptionArgument
152: .resolveType(scope);
153: if (exceptionArgumentType != null) {
154: int id = exceptionArgumentType.id;
155: switch (id) {
156: case T_void:
157: scope.problemReporter().illegalVoidExpression(
158: exceptionArgument);
159: default:
160: id = T_JavaLangObject;
161: case T_boolean:
162: case T_byte:
163: case T_char:
164: case T_short:
165: case T_double:
166: case T_float:
167: case T_int:
168: case T_long:
169: case T_JavaLangString:
170: exceptionArgument.implicitConversion = (id << 4)
171: + id;
172: }
173: }
174: }
175: }
176:
177: public void traverse(ASTVisitor visitor, BlockScope scope) {
178:
179: if (visitor.visit(this , scope)) {
180: assertExpression.traverse(visitor, scope);
181: if (exceptionArgument != null) {
182: exceptionArgument.traverse(visitor, scope);
183: }
184: }
185: visitor.endVisit(this , scope);
186: }
187:
188: public void manageSyntheticAccessIfNecessary(
189: BlockScope currentScope, FlowInfo flowInfo) {
190:
191: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
192:
193: // need assertion flag: $assertionsDisabled on outer most source clas
194: // (in case of static member of interface, will use the outermost static member - bug 22334)
195: SourceTypeBinding outerMostClass = currentScope
196: .enclosingSourceType();
197: while (outerMostClass.isLocalType()) {
198: ReferenceBinding enclosing = outerMostClass
199: .enclosingType();
200: if (enclosing == null || enclosing.isInterface())
201: break;
202: outerMostClass = (SourceTypeBinding) enclosing;
203: }
204:
205: this .assertionSyntheticFieldBinding = outerMostClass
206: .addSyntheticFieldForAssert(currentScope);
207:
208: // find <clinit> and enable assertion support
209: TypeDeclaration typeDeclaration = outerMostClass.scope
210: .referenceType();
211: AbstractMethodDeclaration[] methods = typeDeclaration.methods;
212: for (int i = 0, max = methods.length; i < max; i++) {
213: AbstractMethodDeclaration method = methods[i];
214: if (method.isClinit()) {
215: ((Clinit) method)
216: .setAssertionSupport(
217: assertionSyntheticFieldBinding,
218: currentScope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5);
219: break;
220: }
221: }
222: }
223: }
224:
225: public StringBuffer printStatement(int tab, StringBuffer output) {
226:
227: printIndent(tab, output);
228: output.append("assert "); //$NON-NLS-1$
229: this .assertExpression.printExpression(0, output);
230: if (this .exceptionArgument != null) {
231: output.append(": "); //$NON-NLS-1$
232: this .exceptionArgument.printExpression(0, output);
233: }
234: return output.append(';');
235: }
236:
237: }
|