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