f67d14f4e3bb6cdb7ff6bbfadd0dfb95aeee29e9
[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.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
24
25 public class AssertStatement extends Statement {
26         
27         public Expression assertExpression, exceptionArgument;
28
29         // for local variable attribute
30         int preAssertInitStateIndex = -1;
31         private FieldBinding assertionSyntheticFieldBinding;
32         
33         public AssertStatement(
34                 Expression exceptionArgument,
35                 Expression assertExpression,
36                 int startPosition) {
37                         
38                 this.assertExpression = assertExpression;
39                 this.exceptionArgument = exceptionArgument;
40                 sourceStart = startPosition;
41                 sourceEnd = exceptionArgument.sourceEnd;
42         }
43
44         public AssertStatement(Expression assertExpression, int startPosition) {
45
46                 this.assertExpression = assertExpression;
47                 sourceStart = startPosition;
48                 sourceEnd = assertExpression.sourceEnd;
49         }
50
51         public FlowInfo analyseCode(
52                 BlockScope currentScope,
53                 FlowContext flowContext,
54                 FlowInfo flowInfo) {
55                         
56                 Constant constant = assertExpression.constant;
57                 if (constant != NotAConstant && constant.booleanValue() == true) {
58                         return flowInfo;
59                 }
60
61                 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
62                 FlowInfo assertInfo = flowInfo.copy();
63                         
64                 if (exceptionArgument != null) {
65                         assertInfo = exceptionArgument.analyseCode(
66                                                 currentScope,
67                                                 flowContext,
68                                                 assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits())
69                                         .unconditionalInits();
70                 } else {
71                         assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
72                 }
73                 
74                 // assertion might throw AssertionError (unchecked), which can have consequences in term of
75                 // definitely assigned variables (depending on caught exception in the context)
76                 // DISABLED - AssertionError is unchecked, try statements are already protected against these.
77                 //flowContext.checkExceptionHandlers(currentScope.getJavaLangAssertionError(), this, assertInfo, currentScope);
78
79                 // only retain potential initializations
80                 flowInfo.addPotentialInitializationsFrom(assertInfo.unconditionalInits());
81
82                 // add the assert support in the clinit
83                 manageSyntheticAccessIfNecessary(currentScope);
84                                         
85                 return flowInfo;
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
121         public void resolve(BlockScope scope) {
122
123                 assertExpression.resolveTypeExpecting(scope, BooleanBinding);
124                 if (exceptionArgument != null) {
125                         TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope);
126                         if (exceptionArgumentType != null){
127                                 if (exceptionArgumentType.id == T_void){
128                                         scope.problemReporter().illegalVoidExpression(exceptionArgument);
129                                 }
130                                 exceptionArgument.implicitConversion = (exceptionArgumentType.id << 4) + exceptionArgumentType.id;
131                         }
132                 }
133         }
134         
135         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
136
137                 if (visitor.visit(this, scope)) {
138                         assertExpression.traverse(visitor, scope);
139                         if (exceptionArgument != null) {
140                                 exceptionArgument.traverse(visitor, scope);
141                         }
142                 }
143                 visitor.endVisit(this, scope);
144         }       
145         
146         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
147
148                 // need assertion flag: $assertionsDisabled on outer most source type
149                 ClassScope outerMostClassScope = currentScope.outerMostClassScope();
150                 SourceTypeBinding sourceTypeBinding = outerMostClassScope.enclosingSourceType();
151                 this.assertionSyntheticFieldBinding = sourceTypeBinding.addSyntheticField(this, currentScope);
152
153                 // find <clinit> and enable assertion support
154                 TypeDeclaration typeDeclaration = outerMostClassScope.referenceType();
155                 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
156                 for (int i = 0, max = methods.length; i < max; i++) {
157                         AbstractMethodDeclaration method = methods[i];
158                         if (method.isClinit()) {
159                                 ((Clinit) method).addSupportForAssertion(assertionSyntheticFieldBinding);
160                                 break;
161                         }
162                 }
163         }
164
165         public String toString(int tab) {
166
167                 StringBuffer buffer = new StringBuffer(tabString(tab));
168                 buffer.append("assert"); //$NON-NLS-1$
169                 buffer.append(this.assertExpression);
170                 if (this.exceptionArgument != null) {
171                         buffer.append(":"); //$NON-NLS-1$
172                         buffer.append(this.exceptionArgument);
173                         buffer.append(";"); //$NON-NLS-1$
174                 }
175                 return buffer.toString();
176         }
177         
178 }