KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > eval > CodeSnippetFieldReference


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.eval;
12  
13 import org.eclipse.jdt.internal.compiler.ast.Assignment;
14 import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
15 import org.eclipse.jdt.internal.compiler.ast.Expression;
16 import org.eclipse.jdt.internal.compiler.ast.FieldReference;
17 import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
18 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
19 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
20 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
21 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22 import org.eclipse.jdt.internal.compiler.impl.Constant;
23 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
24 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
25 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedFieldBinding;
26 import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
27 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
28 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
29 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
30 import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
31
32 public class CodeSnippetFieldReference extends FieldReference implements ProblemReasons, EvaluationConstants {
33
34     EvaluationContext evaluationContext;
35     FieldBinding delegateThis;
36 /**
37  * CodeSnippetFieldReference constructor comment.
38  * @param source char[]
39  * @param pos long
40  */

41 public CodeSnippetFieldReference(char[] source, long pos, EvaluationContext evaluationContext) {
42     super(source, pos);
43     this.evaluationContext = evaluationContext;
44 }
45 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
46
47     if (this.codegenBinding.canBeSeenBy(this.receiverType, this, currentScope)) {
48         this.receiver.generateCode(currentScope, codeStream, !this.codegenBinding.isStatic());
49         assignment.expression.generateCode(currentScope, codeStream, true);
50         fieldStore(codeStream, this.codegenBinding, null, valueRequired);
51     } else {
52         codeStream.generateEmulationForField(this.codegenBinding);
53         this.receiver.generateCode(currentScope, codeStream, !this.codegenBinding.isStatic());
54         if (this.codegenBinding.isStatic()) { // need a receiver?
55
codeStream.aconst_null();
56         }
57         assignment.expression.generateCode(currentScope, codeStream, true);
58         if (valueRequired) {
59             if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
60                 codeStream.dup2_x2();
61             } else {
62                 codeStream.dup_x2();
63             }
64         }
65         codeStream.generateEmulatedWriteAccessForField(this.codegenBinding);
66     }
67     if (valueRequired){
68         codeStream.generateImplicitConversion(assignment.implicitConversion);
69     }
70 }
71 /**
72  * Field reference code generation
73  *
74  * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
75  * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
76  * @param valueRequired boolean
77  */

78 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
79
80     int pc = codeStream.position;
81     if (this.constant != Constant.NotAConstant) {
82         if (valueRequired) {
83             codeStream.generateConstant(this.constant, this.implicitConversion);
84         }
85     } else {
86         boolean isStatic = this.codegenBinding.isStatic();
87         this.receiver.generateCode(currentScope, codeStream, !isStatic);
88         if (valueRequired) {
89             Constant fieldConstant = this.codegenBinding.constant();
90             if (fieldConstant == Constant.NotAConstant) {
91                 if (this.codegenBinding.declaringClass == null) { // array length
92
codeStream.arraylength();
93                 } else {
94                     if (this.codegenBinding.canBeSeenBy(this.receiverType, this, currentScope)) {
95                         if (isStatic) {
96                             codeStream.getstatic(this.codegenBinding);
97                         } else {
98                             codeStream.getfield(this.codegenBinding);
99                         }
100                     } else {
101                         if (isStatic) {
102                             // we need a null on the stack to use the reflect emulation
103
codeStream.aconst_null();
104                         }
105                         codeStream.generateEmulatedReadAccessForField(this.codegenBinding);
106                     }
107                 }
108                 codeStream.generateImplicitConversion(this.implicitConversion);
109             } else {
110                 if (!isStatic) {
111                     codeStream.invokeObjectGetClass(); // perform null check
112
codeStream.pop();
113                 }
114                 codeStream.generateConstant(fieldConstant, this.implicitConversion);
115             }
116         } else {
117             if (!isStatic){
118                 codeStream.invokeObjectGetClass(); // perform null check
119
codeStream.pop();
120             }
121         }
122     }
123     codeStream.recordPositionsFrom(pc, this.sourceStart);
124 }
125
126 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
127     
128     boolean isStatic;
129     if (this.codegenBinding.canBeSeenBy(this.receiverType, this, currentScope)) {
130         this.receiver.generateCode(currentScope, codeStream, !(isStatic = this.codegenBinding.isStatic()));
131         if (isStatic) {
132             codeStream.getstatic(this.codegenBinding);
133         } else {
134             codeStream.dup();
135             codeStream.getfield(this.codegenBinding);
136         }
137         int operationTypeID;
138         switch(operationTypeID = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
139             case T_JavaLangString :
140             case T_JavaLangObject :
141             case T_undefined :
142                 codeStream.generateStringConcatenationAppend(currentScope, null, expression);
143                 break;
144             default :
145                 // promote the array reference to the suitable operation type
146
codeStream.generateImplicitConversion(this.implicitConversion);
147                 // generate the increment value (will by itself be promoted to the operation value)
148
if (expression == IntLiteral.One){ // prefix operation
149
codeStream.generateConstant(expression.constant, this.implicitConversion);
150                 } else {
151                     expression.generateCode(currentScope, codeStream, true);
152                 }
153                 // perform the operation
154
codeStream.sendOperator(operator, operationTypeID);
155                 // cast the value back to the array reference type
156
codeStream.generateImplicitConversion(assignmentImplicitConversion);
157         }
158         fieldStore(codeStream, this.codegenBinding, null, valueRequired);
159     } else {
160         this.receiver.generateCode(currentScope, codeStream, !(isStatic = this.codegenBinding.isStatic()));
161         if (isStatic) {
162             // used to store the value
163
codeStream.generateEmulationForField(this.codegenBinding);
164             codeStream.aconst_null();
165
166             // used to retrieve the actual value
167
codeStream.aconst_null();
168             codeStream.generateEmulatedReadAccessForField(this.codegenBinding);
169         } else {
170             // used to store the value
171
codeStream.generateEmulationForField(this.binding);
172             this.receiver.generateCode(currentScope, codeStream, !isStatic);
173
174             // used to retrieve the actual value
175
codeStream.dup();
176             codeStream.generateEmulatedReadAccessForField(this.codegenBinding);
177         }
178         int operationTypeID;
179         if ((operationTypeID = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_JavaLangString) {
180             codeStream.generateStringConcatenationAppend(currentScope, null, expression);
181         } else {
182             // promote the array reference to the suitable operation type
183
codeStream.generateImplicitConversion(this.implicitConversion);
184             // generate the increment value (will by itself be promoted to the operation value)
185
if (expression == IntLiteral.One){ // prefix operation
186
codeStream.generateConstant(expression.constant, this.implicitConversion);
187             } else {
188                 expression.generateCode(currentScope, codeStream, true);
189             }
190             // perform the operation
191
codeStream.sendOperator(operator, operationTypeID);
192             // cast the value back to the array reference type
193
codeStream.generateImplicitConversion(assignmentImplicitConversion);
194         }
195         // current stack is:
196
// field receiver value
197
if (valueRequired) {
198             if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
199                 codeStream.dup2_x2();
200             } else {
201                 codeStream.dup_x2();
202             }
203         }
204         // current stack is:
205
// value field receiver value
206
codeStream.generateEmulatedWriteAccessForField(this.codegenBinding);
207     }
208 }
209 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
210     boolean isStatic;
211     if (this.codegenBinding.canBeSeenBy(this.receiverType, this, currentScope)) {
212         this.receiver.generateCode(currentScope, codeStream, !(isStatic = this.codegenBinding.isStatic()));
213         if (isStatic) {
214             codeStream.getstatic(this.codegenBinding);
215         } else {
216             codeStream.dup();
217             codeStream.getfield(this.codegenBinding);
218         }
219         if (valueRequired) {
220             if (isStatic) {
221                 if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
222                     codeStream.dup2();
223                 } else {
224                     codeStream.dup();
225                 }
226             } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
227
if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
228                     codeStream.dup2_x1();
229                 } else {
230                     codeStream.dup_x1();
231                 }
232             }
233         }
234         codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
235         codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
236         codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
237         fieldStore(codeStream, this.codegenBinding, null, false);
238     } else {
239         this.receiver.generateCode(currentScope, codeStream, !(isStatic = this.codegenBinding.isStatic()));
240         if (isStatic) {
241             codeStream.aconst_null();
242         }
243         // the actual stack is: receiver
244
codeStream.dup();
245         // the actual stack is: receiver receiver
246
codeStream.generateEmulatedReadAccessForField(this.codegenBinding);
247         // the actual stack is: receiver value
248
// receiver value
249
// value receiver value dup_x1 or dup2_x1 if value required
250
// value value receiver value dup_x1 or dup2_x1
251
// value value receiver pop or pop2
252
// value value receiver field generateEmulationForField
253
// value value field receiver swap
254
// value field receiver value field receiver dup2_x1 or dup2_x2
255
// value field receiver value pop2
256
// value field receiver newvalue generate constant + op
257
// value store
258
if (valueRequired) {
259             if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
260                 codeStream.dup2_x1();
261             } else {
262                 codeStream.dup_x1();
263             }
264         }
265         if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
266             codeStream.dup2_x1();
267             codeStream.pop2();
268         } else {
269             codeStream.dup_x1();
270             codeStream.pop();
271         }
272         codeStream.generateEmulationForField(this.codegenBinding);
273         codeStream.swap();
274         
275         if ((this.codegenBinding.type == TypeBinding.LONG) || (this.codegenBinding.type == TypeBinding.DOUBLE)) {
276             codeStream.dup2_x2();
277         } else {
278             codeStream.dup2_x1();
279         }
280         codeStream.pop2();
281
282         codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
283         codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
284         codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
285         codeStream.generateEmulatedWriteAccessForField(this.codegenBinding);
286     }
287 }
288 /*
289  * No need to emulate access to protected fields since not implicitly accessed
290  */

291 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess){
292     // The private access will be managed through the code generation
293

294     if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
295     
296     // if field from parameterized type got found, use the original field at codegen time
297
if (this.binding instanceof ParameterizedFieldBinding) {
298         ParameterizedFieldBinding parameterizedField = (ParameterizedFieldBinding) this.binding;
299         this.codegenBinding = parameterizedField.originalField;
300         // extra cast needed if field type was type variable
301
if (this.codegenBinding.type.isTypeVariable()) {
302             TypeVariableBinding variableReturnType = (TypeVariableBinding) this.codegenBinding.type;
303             if (variableReturnType.firstBound != parameterizedField.type) { // no need for extra cast if same as first bound anyway
304
this.genericCast = parameterizedField.type.erasure();
305             }
306         }
307     } else {
308         this.codegenBinding = this.binding;
309     }
310         
311     // if the binding declaring class is not visible, need special action
312
// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
313
// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
314
TypeBinding someReceiverType = this.delegateThis != null ? this.delegateThis.type : this.receiverType;
315     if (this.binding.declaringClass != someReceiverType
316             && !someReceiverType.isArrayType()
317             && this.binding.declaringClass != null // array.length
318
&& this.binding.constant() == Constant.NotAConstant) {
319     
320         CompilerOptions options = currentScope.compilerOptions();
321         if ((options.targetJDK >= ClassFileConstants.JDK1_2
322                 && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !receiver.isImplicitThis() || !this.codegenBinding.isStatic())
323                 && this.binding.declaringClass.id != T_JavaLangObject) // no change for Object fields
324
|| !this.binding.declaringClass.canBeSeenBy(currentScope)) {
325
326             this.codegenBinding =
327                 currentScope.enclosingSourceType().getUpdatedFieldBinding(
328                     this.codegenBinding,
329                     (ReferenceBinding) someReceiverType.erasure());
330         }
331     }
332 }
333 public TypeBinding resolveType(BlockScope scope) {
334     // Answer the signature type of the field.
335
// constants are propaged when the field is final
336
// and initialized with a (compile time) constant
337

338     // regular receiver reference
339
this.receiverType = this.receiver.resolveType(scope);
340     if (this.receiverType == null){
341         this.constant = Constant.NotAConstant;
342         return null;
343     }
344     // the case receiverType.isArrayType and token = 'length' is handled by the scope API
345
this.codegenBinding = this.binding = scope.getField(this.receiverType, this.token, this);
346     FieldBinding firstAttempt = this.binding;
347     boolean isNotVisible = false;
348     if (!this.binding.isValidBinding()) {
349         if (this.binding instanceof ProblemFieldBinding
350             && ((ProblemFieldBinding) this.binding).problemId() == NotVisible) {
351                 isNotVisible = true;
352                 if (this.evaluationContext.declaringTypeName != null) {
353                     this.delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
354                     if (this.delegateThis == null){ // if not found then internal error, field should have been found
355
this.constant = Constant.NotAConstant;
356                         scope.problemReporter().invalidField(this, this.receiverType);
357                         return null;
358                     }
359                 } else {
360                     this.constant = Constant.NotAConstant;
361                     scope.problemReporter().invalidField(this, this.receiverType);
362                     return null;
363                 }
364             CodeSnippetScope localScope = new CodeSnippetScope(scope);
365             this.codegenBinding = this.binding = localScope.getFieldForCodeSnippet(this.delegateThis.type, this.token, this);
366         }
367     }
368
369     if (!this.binding.isValidBinding()) {
370         this.constant = Constant.NotAConstant;
371         if (isNotVisible) {
372             this.codegenBinding = this.binding = firstAttempt;
373         }
374         scope.problemReporter().invalidField(this, this.receiverType);
375         return null;
376     }
377
378     if (isFieldUseDeprecated(this.binding, scope, (this.bits & IsStrictlyAssigned) !=0)) {
379         scope.problemReporter().deprecatedField(this.binding, this);
380     }
381     // check for this.x in static is done in the resolution of the receiver
382
this.constant = this.receiver.isImplicitThis() ? this.binding.constant() : Constant.NotAConstant;
383     if (!this.receiver.isThis()) { // TODO need to check if shouldn't be isImplicitThis check (and then removed)
384
this.constant = Constant.NotAConstant;
385     }
386     return this.resolvedType = this.binding.type;
387 }
388 }
389
Popular Tags