added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ArrayReference.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.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18
19 public class ArrayReference extends Reference {
20         
21         public Expression receiver;
22         public Expression position;
23
24         public ArrayReference(Expression rec, Expression pos) {
25                 this.receiver = rec;
26                 this.position = pos;
27                 sourceStart = rec.sourceStart;
28         }
29
30         public FlowInfo analyseAssignment(
31                 BlockScope currentScope,
32                 FlowContext flowContext,
33                 FlowInfo flowInfo,
34                 Assignment assignment,
35                 boolean compoundAssignment) {
36
37                 if (assignment.expression == null) {
38                         return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
39                 }
40                 return assignment
41                         .expression
42                         .analyseCode(
43                                 currentScope,
44                                 flowContext,
45                                 analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
46                         .unconditionalInits();
47         }
48
49         public FlowInfo analyseCode(
50                 BlockScope currentScope,
51                 FlowContext flowContext,
52                 FlowInfo flowInfo) {
53
54                 flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo);
55                 receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
56                 return position.analyseCode(currentScope, flowContext, flowInfo);
57         }
58
59         public void generateAssignment(
60                 BlockScope currentScope,
61                 CodeStream codeStream,
62                 Assignment assignment,
63                 boolean valueRequired) {
64
65                 receiver.generateCode(currentScope, codeStream, true);
66                 if (receiver instanceof CastExpression  // ((type[])null)[0]
67                                 && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){
68                         codeStream.checkcast(receiver.resolvedType); 
69                 }       
70                 position.generateCode(currentScope, codeStream, true);
71                 assignment.expression.generateCode(currentScope, codeStream, true);
72                 codeStream.arrayAtPut(this.resolvedType.id, valueRequired);
73                 if (valueRequired) {
74                         codeStream.generateImplicitConversion(assignment.implicitConversion);
75                 }
76         }
77
78         /**
79          * Code generation for a array reference
80          */
81         public void generateCode(
82                 BlockScope currentScope,
83                 CodeStream codeStream,
84                 boolean valueRequired) {
85
86                 int pc = codeStream.position;
87                 receiver.generateCode(currentScope, codeStream, true);
88                 if (receiver instanceof CastExpression  // ((type[])null)[0]
89                                 && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){
90                         codeStream.checkcast(receiver.resolvedType); 
91                 }                       
92                 position.generateCode(currentScope, codeStream, true);
93                 codeStream.arrayAt(this.resolvedType.id);
94                 // Generating code for the potential runtime type checking
95                 if (valueRequired) {
96                         codeStream.generateImplicitConversion(implicitConversion);
97                 } else {
98                         if (this.resolvedType == LongBinding
99                                 || this.resolvedType == DoubleBinding) {
100                                 codeStream.pop2();
101                         } else {
102                                 codeStream.pop();
103                         }
104                 }
105                 codeStream.recordPositionsFrom(pc, this.sourceStart);
106         }
107
108         public void generateCompoundAssignment(
109                 BlockScope currentScope,
110                 CodeStream codeStream,
111                 Expression expression,
112                 int operator,
113                 int assignmentImplicitConversion,
114                 boolean valueRequired) {
115
116                 receiver.generateCode(currentScope, codeStream, true);
117                 if (receiver instanceof CastExpression  // ((type[])null)[0]
118                                 && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){
119                         codeStream.checkcast(receiver.resolvedType); 
120                 }       
121                 position.generateCode(currentScope, codeStream, true);
122                 codeStream.dup2();
123                 codeStream.arrayAt(this.resolvedType.id);
124                 int operationTypeID;
125                 switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
126                         case T_JavaLangString :
127                         case T_JavaLangObject :
128                         case T_undefined :
129                                 codeStream.generateStringConcatenationAppend(currentScope, null, expression);
130                                 break;
131                         default :
132                                 // promote the array reference to the suitable operation type
133                                 codeStream.generateImplicitConversion(implicitConversion);
134                                 // generate the increment value (will by itself  be promoted to the operation value)
135                                 if (expression == IntLiteral.One) { // prefix operation
136                                         codeStream.generateConstant(expression.constant, implicitConversion);
137                                 } else {
138                                         expression.generateCode(currentScope, codeStream, true);
139                                 }
140                                 // perform the operation
141                                 codeStream.sendOperator(operator, operationTypeID);
142                                 // cast the value back to the array reference type
143                                 codeStream.generateImplicitConversion(assignmentImplicitConversion);
144                 }
145                 codeStream.arrayAtPut(this.resolvedType.id, valueRequired);
146         }
147
148         public void generatePostIncrement(
149                 BlockScope currentScope,
150                 CodeStream codeStream,
151                 CompoundAssignment postIncrement,
152                 boolean valueRequired) {
153
154                 receiver.generateCode(currentScope, codeStream, true);
155                 if (receiver instanceof CastExpression  // ((type[])null)[0]
156                                 && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){
157                         codeStream.checkcast(receiver.resolvedType); 
158                 }       
159                 position.generateCode(currentScope, codeStream, true);
160                 codeStream.dup2();
161                 codeStream.arrayAt(this.resolvedType.id);
162                 if (valueRequired) {
163                         if ((this.resolvedType == LongBinding)
164                                 || (this.resolvedType == DoubleBinding)) {
165                                 codeStream.dup2_x2();
166                         } else {
167                                 codeStream.dup_x2();
168                         }
169                 }
170                 codeStream.generateImplicitConversion(implicitConversion);              
171                 codeStream.generateConstant(
172                         postIncrement.expression.constant,
173                         implicitConversion);
174                 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
175                 codeStream.generateImplicitConversion(
176                         postIncrement.assignmentImplicitConversion);
177                 codeStream.arrayAtPut(this.resolvedType.id, false);
178         }
179
180         public StringBuffer printExpression(int indent, StringBuffer output) {
181
182                 receiver.printExpression(0, output).append('[');
183                 return position.printExpression(0, output).append(']');
184         } 
185
186         public TypeBinding resolveType(BlockScope scope) {
187
188                 constant = Constant.NotAConstant;
189                 if (receiver instanceof CastExpression  // no cast check for ((type[])null)[0]
190                                 && ((CastExpression)receiver).innermostCastedExpression() instanceof NullLiteral) {
191                         this.receiver.bits |= IgnoreNeedForCastCheckMASK; // will check later on
192                 }               
193                 TypeBinding arrayType = receiver.resolveType(scope);
194                 if (arrayType != null) {
195                         receiver.computeConversion(scope, arrayType, arrayType);
196                         if (arrayType.isArrayType()) {
197                                 this.resolvedType = ((ArrayBinding) arrayType).elementsType();
198                         } else {
199                                 scope.problemReporter().referenceMustBeArrayTypeAt(arrayType, this);
200                         }
201                 }
202                 TypeBinding positionType = position.resolveTypeExpecting(scope, IntBinding);
203                 if (positionType != null) {
204                         position.computeConversion(scope, IntBinding, positionType);
205                 }
206                 return this.resolvedType;
207         }
208
209         public void traverse(ASTVisitor visitor, BlockScope scope) {
210                 
211                 if (visitor.visit(this, scope)) {
212                         receiver.traverse(visitor, scope);
213                         position.traverse(visitor, scope);
214                 }
215                 visitor.endVisit(this, scope);
216         }
217 }