removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / AssertStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.codegen.*;
14 import org.eclipse.jdt.internal.compiler.flow.*;
15 import org.eclipse.jdt.internal.compiler.impl.Constant;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17 import org.eclipse.jdt.internal.compiler.ASTVisitor;
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                 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
51
52                 Constant cst = this.assertExpression.optimizedBooleanConstant();                
53                 boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true;
54                 boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false;
55
56                 FlowInfo assertInfo = flowInfo.copy();
57                 if (isOptimizedTrueAssertion) {
58                         assertInfo.setReachMode(FlowInfo.UNREACHABLE);
59                 }
60                 assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
61                 
62                 if (exceptionArgument != null) {
63                         // only gets evaluated when escaping - results are not taken into account
64                         FlowInfo exceptionInfo = exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); 
65                         
66                         if (!isOptimizedTrueAssertion){
67                                 flowContext.checkExceptionHandlers(
68                                         currentScope.getJavaLangAssertionError(),
69                                         this,
70                                         exceptionInfo,
71                                         currentScope);
72                         }
73                 }
74                 
75                 if (!isOptimizedTrueAssertion){
76                         // add the assert support in the clinit
77                         manageSyntheticAccessIfNecessary(currentScope, flowInfo);
78                 }
79                 if (isOptimizedFalseAssertion) {
80                         return flowInfo; // if assertions are enabled, the following code will be unreachable
81                 } else {
82                         return flowInfo.mergedWith(assertInfo.unconditionalInits()); 
83                 }
84         }
85
86         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
87
88                 if ((bits & IsReachableMASK) == 0) {
89                         return;
90                 }
91                 int pc = codeStream.position;
92         
93                 if (this.assertionSyntheticFieldBinding != null) {
94                         Label assertionActivationLabel = new Label(codeStream);
95                         codeStream.getstatic(this.assertionSyntheticFieldBinding);
96                         codeStream.ifne(assertionActivationLabel);
97                         
98                         Label falseLabel = new Label(codeStream);
99                         this.assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new Label(codeStream)), null , true);
100                         codeStream.newJavaLangAssertionError();
101                         codeStream.dup();
102                         if (exceptionArgument != null) {
103                                 exceptionArgument.generateCode(currentScope, codeStream, true);
104                                 codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF);
105                         } else {
106                                 codeStream.invokeJavaLangAssertionErrorDefaultConstructor();
107                         }
108                         codeStream.athrow();
109                         falseLabel.place();
110                         assertionActivationLabel.place();
111                 }
112                 
113                 // May loose some local variable initializations : affecting the local variable attributes
114                 if (preAssertInitStateIndex != -1) {
115                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, preAssertInitStateIndex);
116                 }       
117                 codeStream.recordPositionsFrom(pc, this.sourceStart);
118         }
119
120         public void resolve(BlockScope scope) {
121
122                 assertExpression.resolveTypeExpecting(scope, BooleanBinding);
123                 if (exceptionArgument != null) {
124                         TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope);
125                         if (exceptionArgumentType != null){
126                             int id = exceptionArgumentType.id;
127                             switch(id) {
128                                         case T_void :
129                                                 scope.problemReporter().illegalVoidExpression(exceptionArgument);
130                                         default:
131                                             id = T_Object;
132                                         case T_boolean :
133                                         case T_byte :
134                                         case T_char :
135                                         case T_short :
136                                         case T_double :
137                                         case T_float :
138                                         case T_int :
139                                         case T_long :
140                                         case T_String :
141                                                 exceptionArgument.implicitConversion = (id << 4) + id;
142                                 }
143                         }
144                 }
145         }
146
147         public void traverse(ASTVisitor visitor, BlockScope scope) {
148
149                 if (visitor.visit(this, scope)) {
150                         assertExpression.traverse(visitor, scope);
151                         if (exceptionArgument != null) {
152                                 exceptionArgument.traverse(visitor, scope);
153                         }
154                 }
155                 visitor.endVisit(this, scope);
156         }       
157         
158         public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
159
160                 if (!flowInfo.isReachable()) return;
161                 
162                 // need assertion flag: $assertionsDisabled on outer most source clas
163                 // (in case of static member of interface, will use the outermost static member - bug 22334)
164                 SourceTypeBinding outerMostClass = currentScope.enclosingSourceType();
165                 while (outerMostClass.isLocalType()){
166                         ReferenceBinding enclosing = outerMostClass.enclosingType();
167                         if (enclosing == null || enclosing.isInterface()) break;
168                         outerMostClass = (SourceTypeBinding) enclosing;
169                 }
170
171                 this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticField(this, currentScope);
172
173                 // find <clinit> and enable assertion support
174                 TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType();
175                 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
176                 for (int i = 0, max = methods.length; i < max; i++) {
177                         AbstractMethodDeclaration method = methods[i];
178                         if (method.isClinit()) {
179                                 ((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding);
180                                 break;
181                         }
182                 }
183         }
184
185         public StringBuffer printStatement(int tab, StringBuffer output) {
186
187                 printIndent(tab, output);
188                 output.append("assert "); //$NON-NLS-1$
189                 this.assertExpression.printExpression(0, output);
190                 if (this.exceptionArgument != null) {
191                         output.append(": "); //$NON-NLS-1$
192                         this.exceptionArgument.printExpression(0, output);
193                 }
194                 return output.append(';');
195         }
196         
197 }