A variable description (like PHPFunctionDeclaration)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AssertStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.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.impl.*;
14 import net.sourceforge.phpdt.internal.compiler.codegen.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
17 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
18
19 public class AssertStatement extends Statement {
20         
21         public Expression assertExpression, exceptionArgument;
22
23         // for local variable attribute
24         int preAssertInitStateIndex = -1;
25         private FieldBinding assertionSyntheticFieldBinding;
26         
27         public AssertStatement(
28                 Expression exceptionArgument,
29                 Expression assertExpression,
30                 int startPosition) {
31                         
32                 this.assertExpression = assertExpression;
33                 this.exceptionArgument = exceptionArgument;
34                 sourceStart = startPosition;
35                 sourceEnd = exceptionArgument.sourceEnd;
36         }
37
38         public AssertStatement(Expression assertExpression, int startPosition) {
39
40                 this.assertExpression = assertExpression;
41                 sourceStart = startPosition;
42                 sourceEnd = assertExpression.sourceEnd;
43         }
44
45         public FlowInfo analyseCode(
46                 BlockScope currentScope,
47                 FlowContext flowContext,
48                 FlowInfo flowInfo) {
49                         
50                 Constant constant = assertExpression.constant;
51                 if (constant != NotAConstant && constant.booleanValue() == true) {
52                         return flowInfo;
53                 }
54
55                 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
56                 FlowInfo assertInfo = flowInfo.copy();
57                         
58                 if (exceptionArgument != null) {
59                         assertInfo = exceptionArgument.analyseCode(
60                                                 currentScope,
61                                                 flowContext,
62                                                 assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits())
63                                         .unconditionalInits();
64                 } else {
65                         assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
66                 }
67                 
68                 // assertion might throw AssertionError (unchecked), which can have consequences in term of
69                 // definitely assigned variables (depending on caught exception in the context)
70                 // DISABLED - AssertionError is unchecked, try statements are already protected against these.
71                 //flowContext.checkExceptionHandlers(currentScope.getJavaLangAssertionError(), this, assertInfo, currentScope);
72
73                 // only retain potential initializations
74                 flowInfo.addPotentialInitializationsFrom(assertInfo.unconditionalInits());
75
76                 // add the assert support in the clinit
77                 manageSyntheticAccessIfNecessary(currentScope);
78                                         
79                 return flowInfo;
80         }
81
82         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
83
84                 if ((bits & IsReachableMASK) == 0) {
85                         return;
86                 }
87                 int pc = codeStream.position;
88         
89                 if (this.assertionSyntheticFieldBinding != null) {
90                         Label assertionActivationLabel = new Label(codeStream);
91                         codeStream.getstatic(this.assertionSyntheticFieldBinding);
92                         codeStream.ifne(assertionActivationLabel);
93                         Label falseLabel = new Label(codeStream);
94                         assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new Label(codeStream)), null , true);
95                         codeStream.newJavaLangAssertionError();
96                         codeStream.dup();
97                         if (exceptionArgument != null) {
98                                 exceptionArgument.generateCode(currentScope, codeStream, true);
99                                 codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF);
100                         } else {
101                                 codeStream.invokeJavaLangAssertionErrorDefaultConstructor();
102                         }
103                         codeStream.athrow();
104                         falseLabel.place();
105                         assertionActivationLabel.place();
106                 }
107                 
108                 // May loose some local variable initializations : affecting the local variable attributes
109                 if (preAssertInitStateIndex != -1) {
110                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, preAssertInitStateIndex);
111                 }       
112                 codeStream.recordPositionsFrom(pc, this.sourceStart);
113         }
114
115         public void resolve(BlockScope scope) {
116
117                 assertExpression.resolveTypeExpecting(scope, BooleanBinding);
118                 if (exceptionArgument != null) {
119                         TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope);
120                         if (exceptionArgumentType != null){
121                                 if (exceptionArgumentType.id == T_void){
122                                         scope.problemReporter().illegalVoidExpression(exceptionArgument);
123                                 }
124                                 exceptionArgument.implicitConversion = (exceptionArgumentType.id << 4) + exceptionArgumentType.id;
125                         }
126                 }
127         }
128         
129         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
130
131                 if (visitor.visit(this, scope)) {
132                         assertExpression.traverse(visitor, scope);
133                         if (exceptionArgument != null) {
134                                 exceptionArgument.traverse(visitor, scope);
135                         }
136                 }
137                 visitor.endVisit(this, scope);
138         }       
139         
140         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
141
142                 // need assertion flag: $assertionsDisabled on outer most source type
143                 ClassScope outerMostClassScope = currentScope.outerMostClassScope();
144                 SourceTypeBinding sourceTypeBinding = outerMostClassScope.enclosingSourceType();
145                 this.assertionSyntheticFieldBinding = sourceTypeBinding.addSyntheticField(this, currentScope);
146
147                 // find <clinit> and enable assertion support
148                 TypeDeclaration typeDeclaration = outerMostClassScope.referenceType();
149                 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
150                 for (int i = 0, max = methods.length; i < max; i++) {
151                         AbstractMethodDeclaration method = methods[i];
152                         if (method.isClinit()) {
153                                 ((Clinit) method).addSupportForAssertion(assertionSyntheticFieldBinding);
154                                 break;
155                         }
156                 }
157         }
158
159         public String toString(int tab) {
160
161                 StringBuffer buffer = new StringBuffer(tabString(tab));
162                 buffer.append("assert"); //$NON-NLS-1$
163                 buffer.append(this.assertExpression);
164                 if (this.exceptionArgument != null) {
165                         buffer.append(":"); //$NON-NLS-1$
166                         buffer.append(this.exceptionArgument);
167                         buffer.append(";"); //$NON-NLS-1$
168                 }
169                 return buffer.toString();
170         }
171         
172 }