Avoid NPE in update OccurrenceAnnotation
[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         private FieldBinding assertionSyntheticFieldBinding;
30         
31         public AssertStatement(
32                 Expression exceptionArgument,
33                 Expression assertExpression,
34                 int startPosition) {
35                         
36                 this.assertExpression = assertExpression;
37                 this.exceptionArgument = exceptionArgument;
38                 sourceStart = startPosition;
39                 sourceEnd = exceptionArgument.sourceEnd;
40         }
41
42         public AssertStatement(Expression assertExpression, int startPosition) {
43
44                 this.assertExpression = assertExpression;
45                 sourceStart = startPosition;
46                 sourceEnd = assertExpression.sourceEnd;
47         }
48
49         public FlowInfo analyseCode(
50                 BlockScope currentScope,
51                 FlowContext flowContext,
52                 FlowInfo flowInfo) {
53                         
54                 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
55
56                 Constant cst = this.assertExpression.optimizedBooleanConstant();                
57                 boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true;
58                 boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false;
59
60                 FlowInfo assertInfo = flowInfo.copy();
61                 if (isOptimizedTrueAssertion) {
62                         assertInfo.setReachMode(FlowInfo.UNREACHABLE);
63                 }
64                 assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
65                 
66                 if (exceptionArgument != null) {
67                         // only gets evaluated when escaping - results are not taken into account
68                         FlowInfo exceptionInfo = exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); 
69                         
70                         if (!isOptimizedTrueAssertion){
71                                 flowContext.checkExceptionHandlers(
72                                         currentScope.getJavaLangAssertionError(),
73                                         this,
74                                         exceptionInfo,
75                                         currentScope);
76                         }
77                 }
78                 
79                 // add the assert support in the clinit
80                 manageSyntheticAccessIfNecessary(currentScope);
81                 if (isOptimizedFalseAssertion) {
82                         return flowInfo; // if assertions are enabled, the following code will be unreachable
83                 } else {
84                         return flowInfo.mergedWith(assertInfo.unconditionalInits()); 
85                 }
86         }
87
88 //      public void generateCode(BlockScope currentScope, CodeStream codeStream) {
89 //
90 //              if ((bits & IsReachableMASK) == 0) {
91 //                      return;
92 //              }
93 //              int pc = codeStream.position;
94 //      
95 //              if (this.assertionSyntheticFieldBinding != null) {
96 //                      Label assertionActivationLabel = new Label(codeStream);
97 //                      codeStream.getstatic(this.assertionSyntheticFieldBinding);
98 //                      codeStream.ifne(assertionActivationLabel);
99 //                      Label falseLabel = new Label(codeStream);
100 //                      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         public StringBuffer printStatement(int tab, StringBuffer output) {
121
122                 printIndent(tab, output);
123                 output.append("assert "); //$NON-NLS-1$
124                 this.assertExpression.printExpression(0, output);
125                 if (this.exceptionArgument != null) {
126                         output.append(": "); //$NON-NLS-1$
127                         this.exceptionArgument.printExpression(0, output);
128                 }
129                 return output.append(';');
130         }
131         public void resolve(BlockScope scope) {
132
133                 assertExpression.resolveTypeExpecting(scope, BooleanBinding);
134                 if (exceptionArgument != null) {
135                         TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope);
136                         if (exceptionArgumentType != null){
137                                 if (exceptionArgumentType.id == T_void){
138                                         scope.problemReporter().illegalVoidExpression(exceptionArgument);
139                                 }
140                                 exceptionArgument.implicitConversion = (exceptionArgumentType.id << 4) + exceptionArgumentType.id;
141                         }
142                 }
143         }
144         
145         public void traverse(ASTVisitor visitor, BlockScope scope) {
146
147                 if (visitor.visit(this, scope)) {
148                         assertExpression.traverse(visitor, scope);
149                         if (exceptionArgument != null) {
150                                 exceptionArgument.traverse(visitor, scope);
151                         }
152                 }
153                 visitor.endVisit(this, scope);
154         }       
155         
156         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
157
158                 // need assertion flag: $assertionsDisabled on outer most source clas
159                 // (in case of static member of interface, will use the outermost static member - bug 22334)
160                 SourceTypeBinding outerMostClass = currentScope.enclosingSourceType();
161                 while (outerMostClass.isLocalType()){
162                         ReferenceBinding enclosing = outerMostClass.enclosingType();
163                         if (enclosing == null || enclosing.isInterface()) break;
164                         outerMostClass = (SourceTypeBinding) enclosing;
165                 }
166
167                 this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticField(this, currentScope);
168
169                 // find <clinit> and enable assertion support
170                 TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType();
171                 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
172                 for (int i = 0, max = methods.length; i < max; i++) {
173                         AbstractMethodDeclaration method = methods[i];
174                         if (method.isClinit()) {
175                                 ((Clinit) method).addSupportForAssertion(assertionSyntheticFieldBinding);
176                                 break;
177                         }
178                 }
179         }
180
181         public String toString(int tab) {
182
183                 StringBuffer buffer = new StringBuffer(tabString(tab));
184                 buffer.append("assert "); //$NON-NLS-1$
185                 buffer.append(this.assertExpression);
186                 if (this.exceptionArgument != null) {
187                         buffer.append(":"); //$NON-NLS-1$
188                         buffer.append(this.exceptionArgument);
189                         buffer.append(";"); //$NON-NLS-1$
190                 }
191                 return buffer.toString();
192         }
193         
194 }