added -J option to preserve unmodified files in preexisting jarfile
[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.classfmt.ClassFileConstants;
14 import org.eclipse.jdt.internal.compiler.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.internal.compiler.impl.Constant;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18 import org.eclipse.jdt.internal.compiler.ASTVisitor;
19
20 public class AssertStatement extends Statement {
21         
22         public Expression assertExpression, exceptionArgument;
23
24         // for local variable attribute
25         int preAssertInitStateIndex = -1;
26         private FieldBinding assertionSyntheticFieldBinding;
27         
28         public AssertStatement(
29                 Expression exceptionArgument,
30                 Expression assertExpression,
31                 int startPosition) {
32                         
33                 this.assertExpression = assertExpression;
34                 this.exceptionArgument = exceptionArgument;
35                 sourceStart = startPosition;
36                 sourceEnd = exceptionArgument.sourceEnd;
37         }
38
39         public AssertStatement(Expression assertExpression, int startPosition) {
40
41                 this.assertExpression = assertExpression;
42                 sourceStart = startPosition;
43                 sourceEnd = assertExpression.sourceEnd;
44         }
45
46         public FlowInfo analyseCode(
47                 BlockScope currentScope,
48                 FlowContext flowContext,
49                 FlowInfo flowInfo) {
50                         
51                 preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
52
53                 Constant cst = this.assertExpression.optimizedBooleanConstant();                
54                 boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true;
55                 boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false;
56
57                 FlowInfo assertInfo = flowInfo.copy();
58                 if (isOptimizedTrueAssertion) {
59                         assertInfo.setReachMode(FlowInfo.UNREACHABLE);
60                 }
61                 assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
62                 
63                 if (exceptionArgument != null) {
64                         // only gets evaluated when escaping - results are not taken into account
65                         FlowInfo exceptionInfo = exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); 
66                         
67                         if (!isOptimizedTrueAssertion){
68                                 flowContext.checkExceptionHandlers(
69                                         currentScope.getJavaLangAssertionError(),
70                                         this,
71                                         exceptionInfo,
72                                         currentScope);
73                         }
74                 }
75                 
76                 if (!isOptimizedTrueAssertion){
77                         // add the assert support in the clinit
78                         manageSyntheticAccessIfNecessary(currentScope, flowInfo);
79                 }
80                 if (isOptimizedFalseAssertion) {
81                         return flowInfo; // if assertions are enabled, the following code will be unreachable
82                 } else {
83                         return flowInfo.mergedWith(assertInfo.unconditionalInits()); 
84                 }
85         }
86
87         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
88
89                 if ((bits & IsReachableMASK) == 0) {
90                         return;
91                 }
92                 int pc = codeStream.position;
93         
94                 if (this.assertionSyntheticFieldBinding != null) {
95                         Label assertionActivationLabel = new Label(codeStream);
96                         codeStream.getstatic(this.assertionSyntheticFieldBinding);
97                         codeStream.ifne(assertionActivationLabel);
98                         
99                         Label falseLabel = new Label(codeStream);
100                         this.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                             int id = exceptionArgumentType.id;
128                             switch(id) {
129                                         case T_void :
130                                                 scope.problemReporter().illegalVoidExpression(exceptionArgument);
131                                         default:
132                                             id = T_JavaLangObject;
133                                         case T_boolean :
134                                         case T_byte :
135                                         case T_char :
136                                         case T_short :
137                                         case T_double :
138                                         case T_float :
139                                         case T_int :
140                                         case T_long :
141                                         case T_JavaLangString :
142                                                 exceptionArgument.implicitConversion = (id << 4) + id;
143                                 }
144                         }
145                 }
146         }
147
148         public void traverse(ASTVisitor visitor, BlockScope scope) {
149
150                 if (visitor.visit(this, scope)) {
151                         assertExpression.traverse(visitor, scope);
152                         if (exceptionArgument != null) {
153                                 exceptionArgument.traverse(visitor, scope);
154                         }
155                 }
156                 visitor.endVisit(this, scope);
157         }       
158         
159         public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
160
161                 if (!flowInfo.isReachable()) return;
162                 
163                 // need assertion flag: $assertionsDisabled on outer most source clas
164                 // (in case of static member of interface, will use the outermost static member - bug 22334)
165                 SourceTypeBinding outerMostClass = currentScope.enclosingSourceType();
166                 while (outerMostClass.isLocalType()){
167                         ReferenceBinding enclosing = outerMostClass.enclosingType();
168                         if (enclosing == null || enclosing.isInterface()) break;
169                         outerMostClass = (SourceTypeBinding) enclosing;
170                 }
171
172                 this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticFieldForAssert(currentScope);
173
174                 // find <clinit> and enable assertion support
175                 TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType();
176                 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
177                 for (int i = 0, max = methods.length; i < max; i++) {
178                         AbstractMethodDeclaration method = methods[i];
179                         if (method.isClinit()) {
180                                 ((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding, currentScope.environment().options.sourceLevel < ClassFileConstants.JDK1_5);
181                                 break;
182                         }
183                 }
184         }
185
186         public StringBuffer printStatement(int tab, StringBuffer output) {
187
188                 printIndent(tab, output);
189                 output.append("assert "); //$NON-NLS-1$
190                 this.assertExpression.printExpression(0, output);
191                 if (this.exceptionArgument != null) {
192                         output.append(": "); //$NON-NLS-1$
193                         this.exceptionArgument.printExpression(0, output);
194                 }
195                 return output.append(';');
196         }
197         
198 }