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