View | Details | Raw Unified | Return to bug 151787 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java (+111 lines)
Lines 150-155 Link Here
150
		},
150
		},
151
		"12");
151
		"12");
152
}
152
}
153
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=151787
154
public void test004() {
155
	this.runNegativeTest(
156
		new String[] {
157
			"X.java",
158
			"public class X {\n" + 
159
			"    // correctly passes compilation\n" + 
160
			"    static class Test1 {\n" + 
161
			"        private final Object o;\n" + 
162
			"        \n" + 
163
			"        Test1() {\n" + 
164
			"            o = new Object();\n" + 
165
			"        }\n" + 
166
			"    }\n" + 
167
			"    \n" + 
168
			"    // correctly passes compilation\n" + 
169
			"    static class Test2 {\n" + 
170
			"        private final Object o;\n" + 
171
			"        \n" + 
172
			"        Test2() {\n" + 
173
			"            this.o = new Object();\n" + 
174
			"        }\n" + 
175
			"    }\n" + 
176
			"    \n" + 
177
			"    // correctly fails compilation\n" + 
178
			"    static class Test3 {\n" + 
179
			"        private final Object o;\n" + 
180
			"        \n" + 
181
			"        Test3() {\n" + 
182
			"            System.out.println(o); // illegal; o is not definitely assigned\n" + 
183
			"            o = new Object();\n" + 
184
			"        }\n" + 
185
			"    }\n" + 
186
			"    \n" + 
187
			"    // correctly passes compilation\n" + 
188
			"    static class Test4 {\n" + 
189
			"        private final Object o;\n" + 
190
			"        \n" + 
191
			"        Test4() {\n" + 
192
			"            System.out.println(this.o); // legal\n" + 
193
			"            o = new Object();\n" + 
194
			"        }\n" + 
195
			"    }\n" + 
196
			"    \n" + 
197
			"    // incorrectly passes compilation\n" + 
198
			"    static class Test5 {\n" + 
199
			"        private final Object o;\n" + 
200
			"        \n" + 
201
			"        Test5() {\n" + 
202
			"            Test5 other = this;\n" + 
203
			"            other.o = new Object(); // illegal!  other.o is not assignable\n" + 
204
			"        } // error: this.o is not definitely assigned\n" + 
205
			"    }\n" + 
206
			"    \n" + 
207
			"    // flags wrong statement as error\n" + 
208
			"    static class Test6 {\n" + 
209
			"        private final Object o;\n" + 
210
			"        static Test6 initing;\n" + 
211
			"        \n" + 
212
			"       Test6() {\n" + 
213
			"           initing = this;\n" + 
214
			"           System.out.println(\"greetings\");\n" + 
215
			"           Test6 other = initing;\n" + 
216
			"           other.o = new Object(); // illegal!  other.o is not assignable\n" + 
217
			"           o = new Object(); // legal\n" + 
218
			"       }\n" + 
219
			"    }\n" + 
220
			"}\n", // =================
221
		},
222
		"----------\n" + 
223
		"1. WARNING in X.java (at line 4)\n" + 
224
		"	private final Object o;\n" + 
225
		"	                     ^\n" + 
226
		"The field X.Test1.o is never read locally\n" + 
227
		"----------\n" + 
228
		"2. WARNING in X.java (at line 13)\n" + 
229
		"	private final Object o;\n" + 
230
		"	                     ^\n" + 
231
		"The field X.Test2.o is never read locally\n" + 
232
		"----------\n" + 
233
		"3. ERROR in X.java (at line 25)\n" + 
234
		"	System.out.println(o); // illegal; o is not definitely assigned\n" + 
235
		"	                   ^\n" + 
236
		"The blank final field o may not have been initialized\n" + 
237
		"----------\n" + 
238
		"4. WARNING in X.java (at line 42)\n" + 
239
		"	private final Object o;\n" + 
240
		"	                     ^\n" + 
241
		"The field X.Test5.o is never read locally\n" + 
242
		"----------\n" + 
243
		"5. ERROR in X.java (at line 44)\n" + 
244
		"	Test5() {\n" + 
245
		"	^^^^^^^\n" + 
246
		"The blank final field o may not have been initialized\n" + 
247
		"----------\n" + 
248
		"6. ERROR in X.java (at line 46)\n" + 
249
		"	other.o = new Object(); // illegal!  other.o is not assignable\n" + 
250
		"	      ^\n" + 
251
		"The final field X.Test5.o cannot be assigned\n" + 
252
		"----------\n" + 
253
		"7. WARNING in X.java (at line 52)\n" + 
254
		"	private final Object o;\n" + 
255
		"	                     ^\n" + 
256
		"The field X.Test6.o is never read locally\n" + 
257
		"----------\n" + 
258
		"8. ERROR in X.java (at line 59)\n" + 
259
		"	other.o = new Object(); // illegal!  other.o is not assignable\n" + 
260
		"	      ^\n" + 
261
		"The final field X.Test6.o cannot be assigned\n" + 
262
		"----------\n");
263
}
153
// final multiple assignment
264
// final multiple assignment
154
public void test020() {
265
public void test020() {
155
	this.runNegativeTest(
266
	this.runNegativeTest(
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java (-935 / +924 lines)
Lines 11-21 Link Here
11
package org.eclipse.jdt.internal.compiler.ast;
11
package org.eclipse.jdt.internal.compiler.ast;
12
12
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
14
import org.eclipse.jdt.internal.compiler.impl.*;
15
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
14
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16
import org.eclipse.jdt.internal.compiler.codegen.*;
15
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
17
import org.eclipse.jdt.internal.compiler.flow.*;
16
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
18
import org.eclipse.jdt.internal.compiler.lookup.*;
17
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
18
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
19
import org.eclipse.jdt.internal.compiler.impl.Constant;
20
import org.eclipse.jdt.internal.compiler.lookup.Binding;
21
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
22
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
23
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
24
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
25
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
26
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
27
import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
28
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
29
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
30
import org.eclipse.jdt.internal.compiler.lookup.Scope;
31
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
32
import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
33
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
34
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
35
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
36
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
19
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
37
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
20
38
21
public class QualifiedNameReference extends NameReference {
39
public class QualifiedNameReference extends NameReference {
Lines 30-187 Link Here
30
	public TypeBinding genericCast;
48
	public TypeBinding genericCast;
31
	public TypeBinding[] otherGenericCasts;
49
	public TypeBinding[] otherGenericCasts;
32
	
50
	
33
	public QualifiedNameReference(
51
public QualifiedNameReference(	char[][] tokens, long[] positions, int sourceStart, int sourceEnd) {
34
		char[][] sources,
52
	this.tokens = tokens;
35
		long[] positions,
53
	this.sourcePositions = positions;
36
		int sourceStart,
54
	this.sourceStart = sourceStart;
37
		int sourceEnd) {
55
	this.sourceEnd = sourceEnd;
38
		super();
56
}
39
		this.tokens = sources;
57
40
		this.sourcePositions = positions;
58
public FlowInfo analyseAssignment(BlockScope currentScope, 	FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
41
		this.sourceStart = sourceStart;
59
	// determine the rank until which we now we do not need any actual value for the field access
42
		this.sourceEnd = sourceEnd;
60
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
43
	}
61
	boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
44
	
62
	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
45
	public FlowInfo analyseAssignment(
63
	FieldBinding lastFieldBinding = null;
46
		BlockScope currentScope,
64
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
47
		FlowContext flowContext,
65
		case Binding.FIELD : // reading a field
48
		FlowInfo flowInfo,
66
			lastFieldBinding = (FieldBinding) this.binding;
49
		Assignment assignment,
67
			if (needValue || complyTo14) {
50
		boolean isCompound) {
68
				manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo);
51
69
			}
52
		// determine the rank until which we now we do not need any actual value for the field access
70
			if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
53
		int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
71
				ReferenceBinding declaringClass = lastFieldBinding.declaringClass;
54
		boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
72
				// check if accessing enum static field in initializer					
55
		boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
73
				if (declaringClass.isEnum()) {
56
		FieldBinding lastFieldBinding = null;
74
					MethodScope methodScope = currentScope.methodScope();
57
		switch (bits & RestrictiveFlagMASK) {
75
					SourceTypeBinding sourceType = methodScope.enclosingSourceType();
58
			case Binding.FIELD : // reading a field
76
					if (lastFieldBinding.isStatic()
59
				lastFieldBinding = (FieldBinding) binding;
77
							&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
60
				if (needValue || complyTo14) {
78
							&& lastFieldBinding.constant() == Constant.NotAConstant
61
					manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo);
79
							&& !methodScope.isStatic
62
				}
80
							&& methodScope.isInsideInitializerOrConstructor()) {
63
				if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
81
						currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(lastFieldBinding, this);
64
					ReferenceBinding declaringClass = lastFieldBinding.declaringClass;
82
					}
65
					// check if accessing enum static field in initializer					
66
					if (declaringClass.isEnum()) {
67
						MethodScope methodScope = currentScope.methodScope();
68
						SourceTypeBinding sourceType = methodScope.enclosingSourceType();
69
						if (lastFieldBinding.isStatic()
70
								&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
71
								&& lastFieldBinding.constant() == Constant.NotAConstant
72
								&& !methodScope.isStatic
73
								&& methodScope.isInsideInitializerOrConstructor()) {
74
							currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(lastFieldBinding, this);
75
						}
76
					}				
77
				}				
83
				}				
78
				// check if final blank field
84
			}
79
				if (lastFieldBinding.isBlankFinal()
85
			// check if final blank field
86
			if (lastFieldBinding.isBlankFinal()
80
				    && this.otherBindings != null // the last field binding is only assigned
87
				    && this.otherBindings != null // the last field binding is only assigned
81
	 				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
88
	 				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
82
					if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
89
				if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
83
						currentScope.problemReporter().uninitializedBlankFinalField(
90
					currentScope.problemReporter().uninitializedBlankFinalField(
84
							lastFieldBinding,
91
						lastFieldBinding,
85
							this);
92
						this);
86
					}
93
				}
87
				}
94
			}
88
				break;
95
			break;
89
			case Binding.LOCAL :
96
		case Binding.LOCAL :
90
				// first binding is a local variable
97
			// first binding is a local variable
91
				LocalVariableBinding localBinding;
98
			LocalVariableBinding localBinding;
92
				if (!flowInfo
99
			if (!flowInfo
93
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
100
				.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
94
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
101
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
95
				}
102
			}
96
				if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
103
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
97
					localBinding.useFlag = LocalVariableBinding.USED;
104
				localBinding.useFlag = LocalVariableBinding.USED;
98
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
105
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
99
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
106
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
100
				}
107
			}
101
				checkNPE(currentScope, flowContext, flowInfo, true);
108
			checkNPE(currentScope, flowContext, flowInfo, true);
102
		}
109
	}
103
		
110
	
104
		if (needValue) {
111
	if (needValue) {
105
			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
112
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
106
			// only for first binding
113
		// only for first binding
107
		}
114
	}
108
		// all intermediate field accesses are read accesses
115
	// all intermediate field accesses are read accesses
109
		if (otherBindings != null) {
116
	if (this.otherBindings != null) {
110
			for (int i = 0; i < otherBindingsCount-1; i++) {
117
		for (int i = 0; i < otherBindingsCount-1; i++) {
111
				lastFieldBinding = otherBindings[i];
118
			lastFieldBinding = this.otherBindings[i];
112
				needValue = !otherBindings[i+1].isStatic();
119
			needValue = !this.otherBindings[i+1].isStatic();
113
				if (needValue || complyTo14) {
120
			if (needValue || complyTo14) {
114
					manageSyntheticAccessIfNecessary(
121
				manageSyntheticAccessIfNecessary(
115
						currentScope, 
122
					currentScope, 
116
						lastFieldBinding, 
123
					lastFieldBinding, 
117
						i == 0 
124
					i == 0 
118
							? ((VariableBinding)binding).type
125
						? ((VariableBinding)this.binding).type
119
							: otherBindings[i-1].type,
126
						: this.otherBindings[i-1].type,
120
						i + 1, 
127
					i + 1, 
121
						flowInfo);
128
					flowInfo);
122
				}
123
			}
129
			}
124
			lastFieldBinding = otherBindings[otherBindingsCount-1];
125
		}
130
		}
131
		lastFieldBinding = this.otherBindings[otherBindingsCount-1];
132
	}
126
133
127
		if (isCompound) {
134
	if (isCompound) {
128
			if (otherBindingsCount == 0
135
		if (otherBindingsCount == 0
129
				&& lastFieldBinding.isBlankFinal()
136
				&& lastFieldBinding.isBlankFinal()
130
				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
137
				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
131
				&& (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
138
				&& (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
132
				currentScope.problemReporter().uninitializedBlankFinalField(
139
			currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this);
133
					lastFieldBinding,
134
					this);
135
			}
136
			TypeBinding lastReceiverType;
137
			switch (otherBindingsCount) {
138
				case 0 :
139
					lastReceiverType = this.actualReceiverType;
140
					break;
141
				case 1 :
142
					lastReceiverType = ((VariableBinding)this.binding).type;
143
					break;
144
				default:
145
					lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
146
					break;
147
			}
148
			manageSyntheticAccessIfNecessary(
149
				currentScope,
150
				lastFieldBinding,
151
				lastReceiverType,
152
				otherBindingsCount, 
153
				flowInfo);
154
		}
155
		
156
		if (assignment.expression != null) {
157
			flowInfo =
158
				assignment
159
					.expression
160
					.analyseCode(currentScope, flowContext, flowInfo)
161
					.unconditionalInits();
162
		}
163
		
164
		// the last field access is a write access
165
		if (lastFieldBinding.isFinal()) {
166
			// in a context where it can be assigned?
167
			if (lastFieldBinding.isBlankFinal()
168
					&& !isCompound
169
					&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) 
170
					&& indexOfFirstFieldBinding == 1) {
171
				if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
172
					currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
173
				} else {
174
					flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo);
175
				}
176
				flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
177
			} else {
178
				currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
179
				if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
180
					flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
181
				}
182
			}
183
		}
140
		}
184
		// equivalent to valuesRequired[maxOtherBindings]
185
		TypeBinding lastReceiverType;
141
		TypeBinding lastReceiverType;
186
		switch (otherBindingsCount) {
142
		switch (otherBindingsCount) {
187
			case 0 :
143
			case 0 :
Lines 190-320 Link Here
190
			case 1 :
146
			case 1 :
191
				lastReceiverType = ((VariableBinding)this.binding).type;
147
				lastReceiverType = ((VariableBinding)this.binding).type;
192
				break;
148
				break;
193
			default :
149
			default:
194
				lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
150
				lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
195
				break;
151
				break;
196
		}
152
		}
197
		manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo);
153
		manageSyntheticAccessIfNecessary(
198
154
			currentScope,
199
		return flowInfo;
155
			lastFieldBinding,
156
			lastReceiverType,
157
			otherBindingsCount, 
158
			flowInfo);
200
	}
159
	}
201
	
160
	
202
	public FlowInfo analyseCode(
161
	if (assignment.expression != null) {
203
		BlockScope currentScope,
162
		flowInfo =
204
		FlowContext flowContext,
163
			assignment
205
		FlowInfo flowInfo) {
164
				.expression
206
165
				.analyseCode(currentScope, flowContext, flowInfo)
207
		return analyseCode(currentScope, flowContext, flowInfo, true);
166
				.unconditionalInits();
208
	}
167
	}
209
	
168
	
210
	public FlowInfo analyseCode(
169
	// the last field access is a write access
211
		BlockScope currentScope,
170
	if (lastFieldBinding.isFinal()) {
212
		FlowContext flowContext,
171
		// in a context where it can be assigned?
213
		FlowInfo flowInfo,
172
		if (otherBindingsCount == 0
214
		boolean valueRequired) {
173
				&& this.indexOfFirstFieldBinding == 1
215
			
174
				&& lastFieldBinding.isBlankFinal()
216
		// determine the rank until which we now we do not need any actual value for the field access
175
				&& !isCompound
217
		int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
176
				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
218
177
			if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
219
		boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
178
				currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
220
		boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
179
			} else {
221
		switch (bits & RestrictiveFlagMASK) {
180
				flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo);
222
			case Binding.FIELD : // reading a field
181
			}
223
				if (needValue || complyTo14) {
182
			flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
224
					manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo);
183
		} else {
225
				}
184
			currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
226
				if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
185
			if (otherBindingsCount == 0 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
227
					FieldBinding fieldBinding = (FieldBinding) binding;
186
				flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
228
					ReferenceBinding declaringClass = fieldBinding.declaringClass;
187
			}
229
					// check if accessing enum static field in initializer					
230
					if (declaringClass.isEnum()) {
231
						MethodScope methodScope = currentScope.methodScope();
232
						SourceTypeBinding sourceType = methodScope.enclosingSourceType();
233
						if (fieldBinding.isStatic()
234
								&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
235
								&& fieldBinding.constant() == Constant.NotAConstant
236
								&& !methodScope.isStatic
237
								&& methodScope.isInsideInitializerOrConstructor()) {
238
							currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
239
						}
240
					}				
241
					// check if reading a final blank field
242
					if (fieldBinding.isBlankFinal()
243
							&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)
244
							&& !flowInfo.isDefinitelyAssigned(fieldBinding)) {
245
						currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
246
					}
247
				}
248
				break;
249
			case Binding.LOCAL : // reading a local variable
250
				LocalVariableBinding localBinding;
251
				if (!flowInfo
252
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
253
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
254
				}
255
				if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
256
					localBinding.useFlag = LocalVariableBinding.USED;
257
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
258
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
259
				}
260
				checkNPE(currentScope, flowContext, flowInfo, true);
261
		}
188
		}
262
		if (needValue) {
189
	}
263
			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
190
	// equivalent to valuesRequired[maxOtherBindings]
264
			// only for first binding (if value needed only)
191
	TypeBinding lastReceiverType;
265
		}
192
	switch (otherBindingsCount) {
266
		if (otherBindings != null) {
193
		case 0 :
267
			for (int i = 0; i < otherBindingsCount; i++) {
194
			lastReceiverType = this.actualReceiverType;
268
				needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired;
195
			break;
269
				if (needValue || complyTo14) {
196
		case 1 :
270
					TypeBinding lastReceiverType = getGenericCast(i);
197
			lastReceiverType = ((VariableBinding)this.binding).type;
271
					if (lastReceiverType == null) {
198
			break;
272
						if (i == 0) {
199
		default :
273
							 lastReceiverType = ((VariableBinding)binding).type;
200
			lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
274
						} else {
201
			break;
275
							lastReceiverType = otherBindings[i-1].type;
202
	}
276
						}
203
	manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo);
204
205
	return flowInfo;
206
}
207
208
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
209
	return analyseCode(currentScope, flowContext, flowInfo, true);
210
}
211
212
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
213
	// determine the rank until which we now we do not need any actual value for the field access
214
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
215
216
	boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
217
	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
218
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
219
		case Binding.FIELD : // reading a field
220
			if (needValue || complyTo14) {
221
				manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) this.binding, this.actualReceiverType, 0, flowInfo);
222
			}
223
			if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
224
				FieldBinding fieldBinding = (FieldBinding) this.binding;
225
				ReferenceBinding declaringClass = fieldBinding.declaringClass;
226
				// check if accessing enum static field in initializer					
227
				if (declaringClass.isEnum()) {
228
					MethodScope methodScope = currentScope.methodScope();
229
					SourceTypeBinding sourceType = methodScope.enclosingSourceType();
230
					if (fieldBinding.isStatic()
231
							&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
232
							&& fieldBinding.constant() == Constant.NotAConstant
233
							&& !methodScope.isStatic
234
							&& methodScope.isInsideInitializerOrConstructor()) {
235
						currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
236
					}
237
				}				
238
				// check if reading a final blank field
239
				if (fieldBinding.isBlankFinal()
240
						&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)
241
						&& !flowInfo.isDefinitelyAssigned(fieldBinding)) {
242
					currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
243
				}
244
			}
245
			break;
246
		case Binding.LOCAL : // reading a local variable
247
			LocalVariableBinding localBinding;
248
			if (!flowInfo
249
				.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
250
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
251
			}
252
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
253
				localBinding.useFlag = LocalVariableBinding.USED;
254
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
255
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
256
			}
257
			checkNPE(currentScope, flowContext, flowInfo, true);
258
	}
259
	if (needValue) {
260
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
261
		// only for first binding (if value needed only)
262
	}
263
	if (this.otherBindings != null) {
264
		for (int i = 0; i < otherBindingsCount; i++) {
265
			needValue = i < otherBindingsCount-1 ? !this.otherBindings[i+1].isStatic() : valueRequired;
266
			if (needValue || complyTo14) {
267
				TypeBinding lastReceiverType = getGenericCast(i);
268
				if (lastReceiverType == null) {
269
					if (i == 0) {
270
						 lastReceiverType = ((VariableBinding)this.binding).type;
271
					} else {
272
						lastReceiverType = this.otherBindings[i-1].type;
277
					}
273
					}
278
					manageSyntheticAccessIfNecessary(
279
						currentScope, 
280
						otherBindings[i], 
281
						lastReceiverType,
282
						i + 1,
283
						flowInfo);
284
				}
274
				}
275
				manageSyntheticAccessIfNecessary(
276
					currentScope, 
277
					this.otherBindings[i], 
278
					lastReceiverType,
279
					i + 1,
280
					flowInfo);
285
			}
281
			}
286
		}
282
		}
287
		return flowInfo;
288
	}
289
	/**
290
	 * Check and/or redirect the field access to the delegate receiver if any
291
	 */
292
	public TypeBinding checkFieldAccess(BlockScope scope) {
293
		FieldBinding fieldBinding = (FieldBinding) binding;
294
		MethodScope methodScope = scope.methodScope();
295
		// check for forward references
296
		if (this.indexOfFirstFieldBinding == 1
297
				&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
298
				&& methodScope.lastVisibleFieldID >= 0
299
				&& fieldBinding.id >= methodScope.lastVisibleFieldID
300
				&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
301
			scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
302
		}
303
		bits &= ~RestrictiveFlagMASK; // clear bits
304
		bits |= Binding.FIELD;
305
		return getOtherFieldBindings(scope);
306
	}
283
	}
284
	return flowInfo;
285
}
286
287
/**
288
 * Check and/or redirect the field access to the delegate receiver if any
289
 */
290
public TypeBinding checkFieldAccess(BlockScope scope) {
291
	FieldBinding fieldBinding = (FieldBinding) this.binding;
292
	MethodScope methodScope = scope.methodScope();
293
	// check for forward references
294
	if (this.indexOfFirstFieldBinding == 1
295
			&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
296
			&& methodScope.lastVisibleFieldID >= 0
297
			&& fieldBinding.id >= methodScope.lastVisibleFieldID
298
			&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
299
		scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
300
	}
301
	this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
302
	this.bits |= Binding.FIELD;
303
	return getOtherFieldBindings(scope);
304
}
307
305
308
public void checkNPE(BlockScope scope, FlowContext flowContext, 
306
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, boolean checkString) {
309
		FlowInfo flowInfo, boolean checkString) {
310
	// cannot override localVariableBinding because this would project o.m onto o when
307
	// cannot override localVariableBinding because this would project o.m onto o when
311
	// analysing assignments
308
	// analysing assignments
312
	if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
309
	if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
313
		LocalVariableBinding local = (LocalVariableBinding) this.binding;
310
		LocalVariableBinding local = (LocalVariableBinding) this.binding;
314
		if (local != null && 
311
		if (local != null && 
315
			(local.type.tagBits & TagBits.IsBaseType) == 0 &&
312
			(local.type.tagBits & TagBits.IsBaseType) == 0 &&
316
			(checkString || local.type.id != T_JavaLangString)) {
313
			(checkString || local.type.id != TypeIds.T_JavaLangString)) {
317
			if ((this.bits & IsNonNull) == 0) {
314
			if ((this.bits & ASTNode.IsNonNull) == 0) {
318
				flowContext.recordUsingNullReference(scope, local, this, 
315
				flowContext.recordUsingNullReference(scope, local, this, 
319
					FlowContext.MAY_NULL, flowInfo);
316
					FlowContext.MAY_NULL, flowInfo);
320
			}
317
			}
Lines 326-894 Link Here
326
		}
323
		}
327
	}
324
	}
328
}
325
}
329
	/**
326
330
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
327
/**
331
	 */
328
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
332
	public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
329
 */
333
		if (runtimeTimeType == null || compileTimeType == null)
330
public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
334
			return;		
331
	if (runtimeTimeType == null || compileTimeType == null)
335
		// set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
332
		return;		
336
		FieldBinding field = null;
333
	// set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
337
		int length = this.otherBindings == null ? 0 : this.otherBindings.length;
334
	FieldBinding field = null;
338
		if (length == 0) {
335
	int length = this.otherBindings == null ? 0 : this.otherBindings.length;
339
			if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
336
	if (length == 0) {
340
				field = (FieldBinding) this.binding;
337
		if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
341
			}
338
			field = (FieldBinding) this.binding;
342
		} else {
343
			field  = this.otherBindings[length-1];
344
		}
345
		if (field != null) {
346
			FieldBinding originalBinding = field.original();
347
			TypeBinding originalType = originalBinding.type;
348
		    // extra cast needed if method return type has type variable
349
			if (originalBinding != field 
350
					&& originalType != field.type
351
			    	&& runtimeTimeType.id != T_JavaLangObject
352
			    	&& (originalType.tagBits & TagBits.HasTypeVariable) != 0) {
353
		    	TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) 
354
		    		? compileTimeType  // unboxing: checkcast before conversion
355
		    		: runtimeTimeType;
356
		    	setGenericCast(length, originalType.genericCast(targetType));
357
			} 	
358
		}
359
		super.computeConversion(scope, runtimeTimeType, compileTimeType);
360
	}
361
362
	public void generateAssignment(
363
		BlockScope currentScope,
364
		CodeStream codeStream,
365
		Assignment assignment,
366
		boolean valueRequired) {
367
			
368
		int pc = codeStream.position;
369
		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
370
		codeStream.recordPositionsFrom(pc , this.sourceStart);
371
		assignment.expression.generateCode(currentScope, codeStream, true);
372
		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
373
		// equivalent to valuesRequired[maxOtherBindings]
374
		if (valueRequired) {
375
			codeStream.generateImplicitConversion(assignment.implicitConversion);
376
		}
339
		}
340
	} else {
341
		field  = this.otherBindings[length-1];
342
	}
343
	if (field != null) {
344
		FieldBinding originalBinding = field.original();
345
		TypeBinding originalType = originalBinding.type;
346
	    // extra cast needed if method return type has type variable
347
		if (originalBinding != field 
348
				&& originalType != field.type
349
		    	&& runtimeTimeType.id != TypeIds.T_JavaLangObject
350
		    	&& (originalType.tagBits & TagBits.HasTypeVariable) != 0) {
351
	    	TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) 
352
	    		? compileTimeType  // unboxing: checkcast before conversion
353
	    		: runtimeTimeType;
354
	    	setGenericCast(length, originalType.genericCast(targetType));
355
		} 	
377
	}
356
	}
357
	super.computeConversion(scope, runtimeTimeType, compileTimeType);
358
}
378
359
379
	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {		
360
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
380
		int pc = codeStream.position;
361
	int pc = codeStream.position;
381
		if (constant != Constant.NotAConstant) {
362
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
382
			if (valueRequired) {
363
	codeStream.recordPositionsFrom(pc , this.sourceStart);
383
				codeStream.generateConstant(constant, implicitConversion);
364
	assignment.expression.generateCode(currentScope, codeStream, true);
384
			}
365
	fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, valueRequired);
385
		} else {
366
	// equivalent to valuesRequired[maxOtherBindings]
386
			FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
367
	if (valueRequired) {
387
			if (lastFieldBinding != null) {
368
		codeStream.generateImplicitConversion(assignment.implicitConversion);
388
				boolean isStatic = lastFieldBinding.isStatic();
369
	}
389
				Constant fieldConstant = lastFieldBinding.constant();
370
}
390
				if (fieldConstant != Constant.NotAConstant) {
371
391
					if (!isStatic){
372
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {		
392
						codeStream.invokeObjectGetClass();
373
	int pc = codeStream.position;
393
						codeStream.pop();
374
	if (this.constant != Constant.NotAConstant) {
394
					}
375
		if (valueRequired) {
395
					if (valueRequired) { // inline the last field constant
376
			codeStream.generateConstant(this.constant, this.implicitConversion);
396
						codeStream.generateConstant(fieldConstant, implicitConversion);
377
		}
397
					}
378
	} else {
398
				} else {
379
		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
399
					boolean isFirst = lastFieldBinding == this.binding 
380
		if (lastFieldBinding != null) {
400
													&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
381
			boolean isStatic = lastFieldBinding.isStatic();
401
													&& this.otherBindings == null; // could be dup: next.next.next
382
			Constant fieldConstant = lastFieldBinding.constant();
402
					TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
383
			if (fieldConstant != Constant.NotAConstant) {
403
					if (valueRequired  
384
				if (!isStatic){
404
							|| (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
385
					codeStream.invokeObjectGetClass();
405
							|| ((implicitConversion & TypeIds.UNBOXING) != 0)
386
					codeStream.pop();
406
							|| requiredGenericCast != null) {
387
				}
407
						int lastFieldPc = codeStream.position;
388
				if (valueRequired) { // inline the last field constant
408
						if (lastFieldBinding.declaringClass == null) { // array length
389
					codeStream.generateConstant(fieldConstant, this.implicitConversion);
409
							codeStream.arraylength();
390
				}
410
							if (valueRequired) {
391
			} else {
411
								codeStream.generateImplicitConversion(implicitConversion);
392
				boolean isFirst = lastFieldBinding == this.binding 
412
							} else {
393
												&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
413
								// could occur if !valueRequired but compliance >= 1.4
394
												&& this.otherBindings == null; // could be dup: next.next.next
414
								codeStream.pop();
395
				TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
415
							}
396
				if (valueRequired  
397
						|| (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
398
						|| ((this.implicitConversion & TypeIds.UNBOXING) != 0)
399
						|| requiredGenericCast != null) {
400
					int lastFieldPc = codeStream.position;
401
					if (lastFieldBinding.declaringClass == null) { // array length
402
						codeStream.arraylength();
403
						if (valueRequired) {
404
							codeStream.generateImplicitConversion(this.implicitConversion);
416
						} else {
405
						} else {
417
							SyntheticMethodBinding accessor =
406
							// could occur if !valueRequired but compliance >= 1.4
418
								syntheticReadAccessors == null
407
							codeStream.pop();
419
									? null
408
						}
420
									: syntheticReadAccessors[syntheticReadAccessors.length - 1];
409
					} else {
421
							if (accessor == null) {
410
						SyntheticMethodBinding accessor =
422
								if (isStatic) {
411
							this.syntheticReadAccessors == null
423
									codeStream.getstatic(lastFieldBinding);
412
								? null
424
								} else {
413
								: this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
425
									codeStream.getfield(lastFieldBinding);
414
						if (accessor == null) {
426
								}
415
							if (isStatic) {
427
							} else {
416
								codeStream.getstatic(lastFieldBinding);
428
								codeStream.invokestatic(accessor);
429
							}
430
							if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
431
							if (valueRequired) {
432
								codeStream.generateImplicitConversion(implicitConversion);
433
							} else {
417
							} else {
434
								boolean isUnboxing = (implicitConversion & TypeIds.UNBOXING) != 0;
418
								codeStream.getfield(lastFieldBinding);
435
								// conversion only generated if unboxing
436
								if (isUnboxing) codeStream.generateImplicitConversion(implicitConversion);
437
								switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) {
438
									case T_long :
439
									case T_double :
440
										codeStream.pop2();
441
										break;
442
									default :
443
										codeStream.pop();
444
								}
445
							}
419
							}
420
						} else {
421
							codeStream.invokestatic(accessor);
446
						}
422
						}
447
						
423
						if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
448
						int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32);
424
						if (valueRequired) {
449
						codeStream.recordPositionsFrom(lastFieldPc, fieldPosition);
425
							codeStream.generateImplicitConversion(this.implicitConversion);
450
					} else {
426
						} else {
451
						if (!isStatic){
427
							boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
452
							codeStream.invokeObjectGetClass(); // perform null check
428
							// conversion only generated if unboxing
453
							codeStream.pop();
429
							if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion);
430
							switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) {
431
								case T_long :
432
								case T_double :
433
									codeStream.pop2();
434
									break;
435
								default :
436
									codeStream.pop();
437
							}
454
						}
438
						}
455
					}									
439
					}
456
				}
440
					
441
					int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32);
442
					codeStream.recordPositionsFrom(lastFieldPc, fieldPosition);
443
				} else {
444
					if (!isStatic){
445
						codeStream.invokeObjectGetClass(); // perform null check
446
						codeStream.pop();
447
					}
448
				}									
457
			}
449
			}
458
		}
450
		}
459
		codeStream.recordPositionsFrom(pc, this.sourceStart);
460
	}
451
	}
461
	public void generateCompoundAssignment(
452
	codeStream.recordPositionsFrom(pc, this.sourceStart);
462
		BlockScope currentScope,
453
}
463
		CodeStream codeStream,
454
464
		Expression expression,
455
public void generateCompoundAssignment(
465
		int operator,
456
	BlockScope currentScope,
466
		int assignmentImplicitConversion,
457
	CodeStream codeStream,
467
		boolean valueRequired) {
458
	Expression expression,
468
			
459
	int operator,
469
		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
460
	int assignmentImplicitConversion,
470
		SyntheticMethodBinding accessor =
461
	boolean valueRequired) {
471
			syntheticReadAccessors == null
462
		
472
				? null
463
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
473
				: syntheticReadAccessors[syntheticReadAccessors.length - 1];
464
	SyntheticMethodBinding accessor =
474
		if (lastFieldBinding.isStatic()) {
465
		this.syntheticReadAccessors == null
475
			if (accessor == null) {
466
			? null
476
				codeStream.getstatic(lastFieldBinding);
467
			: this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
477
			} else {
468
	if (lastFieldBinding.isStatic()) {
478
				codeStream.invokestatic(accessor);
469
		if (accessor == null) {
479
			}
470
			codeStream.getstatic(lastFieldBinding);
471
		} else {
472
			codeStream.invokestatic(accessor);
473
		}
474
	} else {
475
		codeStream.dup();
476
		if (accessor == null) {
477
			codeStream.getfield(lastFieldBinding);
480
		} else {
478
		} else {
481
			codeStream.dup();
479
			codeStream.invokestatic(accessor);
482
			if (accessor == null) {
480
		}
483
				codeStream.getfield(lastFieldBinding);
481
	}
482
	// the last field access is a write access
483
	// perform the actual compound operation
484
	int operationTypeID;
485
	switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
486
		case T_JavaLangString :
487
		case T_JavaLangObject :
488
		case T_undefined :
489
			codeStream.generateStringConcatenationAppend(currentScope, null, expression);
490
			break;
491
		default :
492
			TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
493
			if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);				
494
			// promote the array reference to the suitable operation type
495
			codeStream.generateImplicitConversion(this.implicitConversion);
496
			// generate the increment value (will by itself  be promoted to the operation value)
497
			if (expression == IntLiteral.One) { // prefix operation
498
				codeStream.generateConstant(expression.constant, this.implicitConversion);
484
			} else {
499
			} else {
485
				codeStream.invokestatic(accessor);
500
				expression.generateCode(currentScope, codeStream, true);
486
			}
501
			}
502
			// perform the operation
503
			codeStream.sendOperator(operator, operationTypeID);
504
			// cast the value back to the array reference type
505
			codeStream.generateImplicitConversion(assignmentImplicitConversion);
506
	}
507
	// actual assignment
508
	fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, valueRequired);
509
	// equivalent to valuesRequired[maxOtherBindings]
510
}
511
512
public void generatePostIncrement(
513
	BlockScope currentScope,
514
	CodeStream codeStream,
515
	CompoundAssignment postIncrement,
516
	boolean valueRequired) {
517
    
518
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
519
	SyntheticMethodBinding accessor =
520
		this.syntheticReadAccessors == null
521
			? null
522
			: this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
523
	if (lastFieldBinding.isStatic()) {
524
		if (accessor == null) {
525
			codeStream.getstatic(lastFieldBinding);
526
		} else {
527
			codeStream.invokestatic(accessor);
528
		}
529
	} else {
530
		codeStream.dup();
531
		if (accessor == null) {
532
			codeStream.getfield(lastFieldBinding);
533
		} else {
534
			codeStream.invokestatic(accessor);
487
		}
535
		}
488
		// the last field access is a write access
489
		// perform the actual compound operation
490
		int operationTypeID;
491
		switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
492
			case T_JavaLangString :
493
			case T_JavaLangObject :
494
			case T_undefined :
495
				codeStream.generateStringConcatenationAppend(currentScope, null, expression);
496
				break;
497
			default :
498
				TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
499
				if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);				
500
				// promote the array reference to the suitable operation type
501
				codeStream.generateImplicitConversion(implicitConversion);
502
				// generate the increment value (will by itself  be promoted to the operation value)
503
				if (expression == IntLiteral.One) { // prefix operation
504
					codeStream.generateConstant(expression.constant, implicitConversion);
505
				} else {
506
					expression.generateCode(currentScope, codeStream, true);
507
				}
508
				// perform the operation
509
				codeStream.sendOperator(operator, operationTypeID);
510
				// cast the value back to the array reference type
511
				codeStream.generateImplicitConversion(assignmentImplicitConversion);
512
		}
513
		// actual assignment
514
		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
515
		// equivalent to valuesRequired[maxOtherBindings]
516
	}
536
	}
517
	
537
	// duplicate the old field value
518
	public void generatePostIncrement(
538
	if (valueRequired) {
519
		BlockScope currentScope,
520
		CodeStream codeStream,
521
		CompoundAssignment postIncrement,
522
		boolean valueRequired) {
523
	    
524
		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
525
		SyntheticMethodBinding accessor =
526
			syntheticReadAccessors == null
527
				? null
528
				: syntheticReadAccessors[syntheticReadAccessors.length - 1];
529
		if (lastFieldBinding.isStatic()) {
539
		if (lastFieldBinding.isStatic()) {
530
			if (accessor == null) {
540
			if ((lastFieldBinding.type == TypeBinding.LONG)
531
				codeStream.getstatic(lastFieldBinding);
541
				|| (lastFieldBinding.type == TypeBinding.DOUBLE)) {
542
				codeStream.dup2();
532
			} else {
543
			} else {
533
				codeStream.invokestatic(accessor);
544
				codeStream.dup();
534
			}
545
			}
535
		} else {
546
		} else { // Stack:  [owner][old field value]  ---> [old field value][owner][old field value]
536
			codeStream.dup();
547
			if ((lastFieldBinding.type == TypeBinding.LONG)
537
			if (accessor == null) {
548
				|| (lastFieldBinding.type == TypeBinding.DOUBLE)) {
538
				codeStream.getfield(lastFieldBinding);
549
				codeStream.dup2_x1();
539
			} else {
550
			} else {
540
				codeStream.invokestatic(accessor);
551
				codeStream.dup_x1();
541
			}
552
			}
542
		}
553
		}
543
		// duplicate the old field value
554
	}
544
		if (valueRequired) {
555
	TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
545
			if (lastFieldBinding.isStatic()) {
556
	if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
546
				if ((lastFieldBinding.type == TypeBinding.LONG)
557
	
547
					|| (lastFieldBinding.type == TypeBinding.DOUBLE)) {
558
	codeStream.generateImplicitConversion(this.implicitConversion);		
548
					codeStream.dup2();
559
	codeStream.generateConstant(
560
		postIncrement.expression.constant,
561
		this.implicitConversion);
562
	codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
563
	codeStream.generateImplicitConversion(
564
		postIncrement.preAssignImplicitConversion);
565
	fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, false);
566
}	
567
568
/*
569
 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
570
 * for a read or write access.
571
 */
572
public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) {
573
	// determine the rank until which we now we do not need any actual value for the field access
574
	int otherBindingsCount = this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length;
575
	boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
576
	FieldBinding lastFieldBinding = null;
577
	TypeBinding lastGenericCast = null;
578
	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
579
580
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
581
		case Binding.FIELD :
582
			lastFieldBinding = (FieldBinding) this.codegenBinding;
583
			lastGenericCast = this.genericCast;
584
			// if first field is actually constant, we can inline it
585
			if (lastFieldBinding.constant() != Constant.NotAConstant) {
586
				break;
587
			}
588
			if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) {
589
				int pc = codeStream.position;
590
				if ((this.bits & ASTNode.DepthMASK) != 0) {
591
					ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
592
					Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
593
					codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
549
				} else {
594
				} else {
550
					codeStream.dup();
595
					generateReceiver(codeStream);
551
				}
596
				}
552
			} else { // Stack:  [owner][old field value]  ---> [old field value][owner][old field value]
597
				codeStream.recordPositionsFrom(pc, this.sourceStart);
553
				if ((lastFieldBinding.type == TypeBinding.LONG)
598
			}
554
					|| (lastFieldBinding.type == TypeBinding.DOUBLE)) {
599
			break;
555
					codeStream.dup2_x1();
600
		case Binding.LOCAL : // reading the first local variable
601
			if (!needValue) break; // no value needed
602
			LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
603
			// regular local variable read
604
			Constant localConstant = localBinding.constant();
605
			if (localConstant != Constant.NotAConstant) {
606
				codeStream.generateConstant(localConstant, 0);
607
				// no implicit conversion
608
			} else {
609
				// outer local?
610
				if ((this.bits & ASTNode.DepthMASK) != 0) {
611
					// outer local can be reached either through a synthetic arg or a synthetic field
612
					VariableBinding[] path = currentScope.getEmulationPath(localBinding);
613
					codeStream.generateOuterAccess(path, this, localBinding, currentScope);
556
				} else {
614
				} else {
557
					codeStream.dup_x1();
615
					codeStream.load(localBinding);
558
				}
616
				}
559
			}
617
			}
560
		}
618
	}
561
		TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
619
					
562
		if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
620
	// all intermediate field accesses are read accesses
563
		
621
	// only the last field binding is a write access
564
		codeStream.generateImplicitConversion(implicitConversion);		
622
	int positionsLength = this.sourcePositions.length;
565
		codeStream.generateConstant(
623
	if (this.otherCodegenBindings != null) {
566
			postIncrement.expression.constant,
624
		for (int i = 0; i < otherBindingsCount; i++) {
567
			implicitConversion);
625
			int pc = codeStream.position;
568
		codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
626
			FieldBinding nextField = this.otherCodegenBindings[i];
569
		codeStream.generateImplicitConversion(
627
			TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i];
570
			postIncrement.preAssignImplicitConversion);
628
			if (lastFieldBinding != null) {
571
		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
629
				needValue = !nextField.isStatic();
572
	}	
630
				Constant fieldConstant = lastFieldBinding.constant();
573
	
631
				if (fieldConstant != Constant.NotAConstant) {
574
	/*
632
					if (i > 0 && !lastFieldBinding.isStatic()) {
575
	 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
633
						codeStream.invokeObjectGetClass(); // perform null check
576
	 * for a read or write access.
634
						codeStream.pop();
577
	 */
578
	public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) {
579
			
580
		// determine the rank until which we now we do not need any actual value for the field access
581
		int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length;
582
		boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
583
		FieldBinding lastFieldBinding = null;
584
		TypeBinding lastGenericCast = null;
585
		boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
586
587
		switch (bits & RestrictiveFlagMASK) {
588
			case Binding.FIELD :
589
				lastFieldBinding = (FieldBinding) this.codegenBinding;
590
				lastGenericCast = this.genericCast;
591
				// if first field is actually constant, we can inline it
592
				if (lastFieldBinding.constant() != Constant.NotAConstant) {
593
					break;
594
				}
595
				if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) {
596
					int pc = codeStream.position;
597
					if ((bits & DepthMASK) != 0) {
598
						ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
599
						Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
600
						codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
601
					} else {
602
						generateReceiver(codeStream);
603
					}
635
					}
604
					codeStream.recordPositionsFrom(pc, this.sourceStart);
636
					if (needValue) {
605
				}
637
						codeStream.generateConstant(fieldConstant, 0);
606
				break;
607
			case Binding.LOCAL : // reading the first local variable
608
				if (!needValue) break; // no value needed
609
				LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
610
				// regular local variable read
611
				Constant localConstant = localBinding.constant();
612
				if (localConstant != Constant.NotAConstant) {
613
					codeStream.generateConstant(localConstant, 0);
614
					// no implicit conversion
615
				} else {
616
					// outer local?
617
					if ((bits & DepthMASK) != 0) {
618
						// outer local can be reached either through a synthetic arg or a synthetic field
619
						VariableBinding[] path = currentScope.getEmulationPath(localBinding);
620
						codeStream.generateOuterAccess(path, this, localBinding, currentScope);
621
					} else {
622
						codeStream.load(localBinding);
623
					}
638
					}
624
				}
639
				} else {
625
		}
640
					if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) {
626
						
641
						MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; 
627
		// all intermediate field accesses are read accesses
642
						if (accessor == null) {
628
		// only the last field binding is a write access
643
							if (lastFieldBinding.isStatic()) {
629
		int positionsLength = this.sourcePositions.length;
644
								codeStream.getstatic(lastFieldBinding);
630
		if (this.otherCodegenBindings != null) {
631
			for (int i = 0; i < otherBindingsCount; i++) {
632
				int pc = codeStream.position;
633
				FieldBinding nextField = this.otherCodegenBindings[i];
634
				TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i];
635
				if (lastFieldBinding != null) {
636
					needValue = !nextField.isStatic();
637
					Constant fieldConstant = lastFieldBinding.constant();
638
					if (fieldConstant != Constant.NotAConstant) {
639
						if (i > 0 && !lastFieldBinding.isStatic()) {
640
							codeStream.invokeObjectGetClass(); // perform null check
641
							codeStream.pop();
642
						}
643
						if (needValue) {
644
							codeStream.generateConstant(fieldConstant, 0);
645
						}
646
					} else {
647
						if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) {
648
							MethodBinding accessor = syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; 
649
							if (accessor == null) {
650
								if (lastFieldBinding.isStatic()) {
651
									codeStream.getstatic(lastFieldBinding);
652
								} else {
653
									codeStream.getfield(lastFieldBinding);
654
								}
655
							} else {
645
							} else {
656
								codeStream.invokestatic(accessor);
646
								codeStream.getfield(lastFieldBinding);
657
							}
647
							}
658
							if (lastGenericCast != null) codeStream.checkcast(lastGenericCast);
659
							if (!needValue) codeStream.pop();
660
						} else {
648
						} else {
661
							if (this.codegenBinding == lastFieldBinding) {
649
							codeStream.invokestatic(accessor);
662
								if (lastFieldBinding.isStatic()){
663
									// if no valueRequired, still need possible side-effects of <clinit> invocation, if field belongs to different class
664
									if (((FieldBinding)binding).original().declaringClass != this.actualReceiverType.erasure()) {
665
										MethodBinding accessor = syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; 
666
										if (accessor == null) {
667
											codeStream.getstatic(lastFieldBinding);
668
										} else {
669
											codeStream.invokestatic(accessor);
670
										}
671
										codeStream.pop();
672
									}				
673
								}
674
							} else if (!lastFieldBinding.isStatic()){
675
								codeStream.invokeObjectGetClass(); // perform null check
676
								codeStream.pop();
677
							}						
678
						}
679
						if ((positionsLength - otherBindingsCount + i - 1) >= 0) {
680
							int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32);
681
							codeStream.recordPositionsFrom(pc, fieldPosition);
682
						}
650
						}
651
						if (lastGenericCast != null) codeStream.checkcast(lastGenericCast);
652
						if (!needValue) codeStream.pop();
653
					} else {
654
						if (this.codegenBinding == lastFieldBinding) {
655
							if (lastFieldBinding.isStatic()){
656
								// if no valueRequired, still need possible side-effects of <clinit> invocation, if field belongs to different class
657
								if (((FieldBinding)this.binding).original().declaringClass != this.actualReceiverType.erasure()) {
658
									MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; 
659
									if (accessor == null) {
660
										codeStream.getstatic(lastFieldBinding);
661
									} else {
662
										codeStream.invokestatic(accessor);
663
									}
664
									codeStream.pop();
665
								}				
666
							}
667
						} else if (!lastFieldBinding.isStatic()){
668
							codeStream.invokeObjectGetClass(); // perform null check
669
							codeStream.pop();
670
						}						
671
					}
672
					if ((positionsLength - otherBindingsCount + i - 1) >= 0) {
673
						int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32);
674
						codeStream.recordPositionsFrom(pc, fieldPosition);
683
					}
675
					}
684
				}
676
				}
685
				lastFieldBinding = nextField;
686
				lastGenericCast = nextGenericCast;
687
			}
677
			}
678
			lastFieldBinding = nextField;
679
			lastGenericCast = nextGenericCast;
688
		}
680
		}
689
		return lastFieldBinding;
690
	}
681
	}
691
	public void generateReceiver(CodeStream codeStream) {
682
	return lastFieldBinding;
692
		codeStream.aload_0();
683
}
684
685
public void generateReceiver(CodeStream codeStream) {
686
	codeStream.aload_0();
687
}
688
689
/**
690
 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
691
 */
692
public TypeBinding[] genericTypeArguments() {
693
	return null;
694
}
695
696
// get the matching codegenBinding
697
protected FieldBinding getCodegenBinding(int index) {
698
  if (index == 0){
699
		return (FieldBinding)this.codegenBinding;
700
	} else {
701
		return this.otherCodegenBindings[index-1];
693
	}
702
	}
694
	/**
703
}
695
	 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
704
696
	 */
705
// get the matching generic cast
697
	public TypeBinding[] genericTypeArguments() {
706
protected TypeBinding getGenericCast(int index) {
698
		return null;
707
   if (index == 0){
708
		return this.genericCast;
709
	} else {
710
	    if (this.otherGenericCasts == null) return null;
711
		return this.otherGenericCasts[index-1];
699
	}
712
	}
713
}
700
714
701
	// get the matching codegenBinding
715
public TypeBinding getOtherFieldBindings(BlockScope scope) {
702
	protected FieldBinding getCodegenBinding(int index) {
716
	// At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
703
	  if (index == 0){
717
	int length = this.tokens.length;
704
			return (FieldBinding)this.codegenBinding;
718
	FieldBinding field;
719
	if ((this.bits & Binding.FIELD) != 0) {
720
		field = (FieldBinding) this.binding;
721
		if (!field.isStatic()) {
722
			//must check for the static status....
723
			if (this.indexOfFirstFieldBinding > 1  //accessing to a field using a type as "receiver" is allowed only with static field
724
					 || scope.methodScope().isStatic) { 	// the field is the first token of the qualified reference....
725
				scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field);
726
				return null;
727
			 }
705
		} else {
728
		} else {
706
			return this.otherCodegenBindings[index-1];
729
			// indirect static reference ?
707
		}
730
			if (this.indexOfFirstFieldBinding > 1 
731
					&& field.declaringClass != this.actualReceiverType
732
					&& field.declaringClass.canBeSeenBy(scope)) {
733
				scope.problemReporter().indirectAccessToStaticField(this, field);
734
			}
735
		}
736
		// only last field is actually a write access if any
737
		if (isFieldUseDeprecated(field, scope, (this.bits & ASTNode.IsStrictlyAssigned) != 0 && this.indexOfFirstFieldBinding == length))
738
			scope.problemReporter().deprecatedField(field, this);
739
	} else {
740
		field = null;
741
	}
742
	TypeBinding type = ((VariableBinding) this.binding).type;
743
	int index = this.indexOfFirstFieldBinding;
744
	if (index == length) { //	restrictiveFlag == FIELD
745
		this.constant = ((FieldBinding) this.binding).constant();
746
		// perform capture conversion if read access
747
		return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0)
748
				? type.capture(scope, this.sourceEnd)
749
				: type;
708
	}
750
	}
751
	// allocation of the fieldBindings array	and its respective constants
752
	int otherBindingsLength = length - index;
753
	this.otherCodegenBindings = this.otherBindings = new FieldBinding[otherBindingsLength];
754
	this.otherDepths = new int[otherBindingsLength];
709
	
755
	
710
	// get the matching generic cast
756
	// fill the first constant (the one of the binding)
711
	protected TypeBinding getGenericCast(int index) {
757
	this.constant = ((VariableBinding) this.binding).constant();
712
	   if (index == 0){
758
	// save first depth, since will be updated by visibility checks of other bindings
713
			return this.genericCast;
759
	int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
714
		} else {
760
	// iteration on each field	
715
		    if (this.otherGenericCasts == null) return null;
761
	while (index < length) {
716
			return this.otherGenericCasts[index-1];
762
		char[] token = this.tokens[index];
717
		}
763
		if (type == null)
718
	}
764
			return null; // could not resolve type prior to this point
765
766
		this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any		
767
		FieldBinding previousField = field;
768
		field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this);
769
		int place = index - this.indexOfFirstFieldBinding;
770
		this.otherBindings[place] = field;
771
		this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
772
		if (field.isValidBinding()) {
773
			// set generic cast of for previous field (if any)
774
			if (previousField != null) {
775
				TypeBinding fieldReceiverType = type;
776
				TypeBinding receiverErasure = type.erasure();
777
				if (receiverErasure instanceof ReferenceBinding) {
778
					if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) {
779
						fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound
780
					}
781
				}				
782
				FieldBinding originalBinding = previousField.original();
783
			    if ((originalBinding.type.tagBits &  TagBits.HasTypeVariable) != 0 && fieldReceiverType.id != TypeIds.T_JavaLangObject) {
784
			    	setGenericCast(index-1,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case
785
			    }
786
		    }
787
			// only last field is actually a write access if any
788
			if (isFieldUseDeprecated(field, scope, (this.bits & ASTNode.IsStrictlyAssigned) !=0 && index+1 == length)) {
789
				scope.problemReporter().deprecatedField(field, this);
790
			}
791
			// constant propagation can only be performed as long as the previous one is a constant too.
792
			if (this.constant != Constant.NotAConstant) {
793
				this.constant = field.constant();					
794
			}
719
795
720
	public TypeBinding getOtherFieldBindings(BlockScope scope) {
796
			if (field.isStatic()) {
721
		// At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
797
				// static field accessed through receiver? legal but unoptimal (optional warning)
722
		int length = tokens.length;
798
				scope.problemReporter().nonStaticAccessToStaticField(this, field);
723
		FieldBinding field;
724
		if ((bits & Binding.FIELD) != 0) {
725
			field = (FieldBinding) this.binding;
726
			if (!field.isStatic()) {
727
				//must check for the static status....
728
				if (indexOfFirstFieldBinding > 1  //accessing to a field using a type as "receiver" is allowed only with static field
729
						 || scope.methodScope().isStatic) { 	// the field is the first token of the qualified reference....
730
					scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field);
731
					return null;
732
				 }
733
			} else {
734
				// indirect static reference ?
799
				// indirect static reference ?
735
				if (indexOfFirstFieldBinding > 1 
800
				if (field.declaringClass != type) {
736
						&& field.declaringClass != actualReceiverType
737
						&& field.declaringClass.canBeSeenBy(scope)) {
738
					scope.problemReporter().indirectAccessToStaticField(this, field);
801
					scope.problemReporter().indirectAccessToStaticField(this, field);
739
				}
802
				}
740
			}
803
			}
741
			// only last field is actually a write access if any
804
			type = field.type;
742
			if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssigned) != 0 && indexOfFirstFieldBinding == length))
805
			index++;
743
				scope.problemReporter().deprecatedField(field, this);
744
		} else {
806
		} else {
745
			field = null;
807
			this.constant = Constant.NotAConstant; //don't fill other constants slots...
808
			scope.problemReporter().invalidField(this, field, index, type);
809
			setDepth(firstDepth);
810
			return null;
746
		}
811
		}
747
		TypeBinding type = ((VariableBinding) binding).type;
812
	}
748
		int index = indexOfFirstFieldBinding;
813
	setDepth(firstDepth);
749
		if (index == length) { //	restrictiveFlag == FIELD
814
	type = (this.otherBindings[otherBindingsLength - 1]).type;
750
			this.constant = ((FieldBinding) binding).constant();
815
	// perform capture conversion if read access
751
			// perform capture conversion if read access
816
	return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0)
752
			return (type != null && (this.bits & IsStrictlyAssigned) == 0)
817
			? type.capture(scope, this.sourceEnd)
753
					? type.capture(scope, this.sourceEnd)
818
			: type;		
754
					: type;
819
}
755
		}
756
		// allocation of the fieldBindings array	and its respective constants
757
		int otherBindingsLength = length - index;
758
		otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
759
		otherDepths = new int[otherBindingsLength];
760
		
761
		// fill the first constant (the one of the binding)
762
		this.constant = ((VariableBinding) binding).constant();
763
		// save first depth, since will be updated by visibility checks of other bindings
764
		int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
765
		// iteration on each field	
766
		while (index < length) {
767
			char[] token = tokens[index];
768
			if (type == null)
769
				return null; // could not resolve type prior to this point
770
771
			bits &= ~DepthMASK; // flush previous depth if any		
772
			FieldBinding previousField = field;
773
			field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this);
774
			int place = index - indexOfFirstFieldBinding;
775
			otherBindings[place] = field;
776
			otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
777
			if (field.isValidBinding()) {
778
				// set generic cast of for previous field (if any)
779
				if (previousField != null) {
780
					TypeBinding fieldReceiverType = type;
781
					TypeBinding receiverErasure = type.erasure();
782
					if (receiverErasure instanceof ReferenceBinding) {
783
						if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) {
784
							fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound
785
						}
786
					}				
787
					FieldBinding originalBinding = previousField.original();
788
				    if ((originalBinding.type.tagBits &  TagBits.HasTypeVariable) != 0 && fieldReceiverType.id != T_JavaLangObject) {
789
				    	setGenericCast(index-1,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case
790
				    }
791
			    }
792
				// only last field is actually a write access if any
793
				if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssigned) !=0 && index+1 == length)) {
794
					scope.problemReporter().deprecatedField(field, this);
795
				}
796
				// constant propagation can only be performed as long as the previous one is a constant too.
797
				if (this.constant != Constant.NotAConstant) {
798
					this.constant = field.constant();					
799
				}
800
820
801
				if (field.isStatic()) {
821
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
802
					// static field accessed through receiver? legal but unoptimal (optional warning)
822
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
803
					scope.problemReporter().nonStaticAccessToStaticField(this, field);
823
	//If inlinable field, forget the access emulation, the code gen will directly target it
804
					// indirect static reference ?
824
	if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) {
805
					if (field.declaringClass != type) {
825
		return;
806
						scope.problemReporter().indirectAccessToStaticField(this, field);
826
	}
807
					}
827
	if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
808
				}
828
		currentScope.emulateOuterAccess((LocalVariableBinding) this.binding);
809
				type = field.type;
810
				index++;
811
			} else {
812
				constant = Constant.NotAConstant; //don't fill other constants slots...
813
				scope.problemReporter().invalidField(this, field, index, type);
814
				setDepth(firstDepth);
815
				return null;
816
			}
817
		}
818
		setDepth(firstDepth);
819
		type = (otherBindings[otherBindingsLength - 1]).type;
820
		// perform capture conversion if read access
821
		return (type != null && (this.bits & IsStrictlyAssigned) == 0)
822
				? type.capture(scope, this.sourceEnd)
823
				: type;		
824
	}
829
	}
830
	}
831
}
825
832
826
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
833
/**
827
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
834
 * index is <0 to denote write access emulation
828
		//If inlinable field, forget the access emulation, the code gen will directly target it
835
 */
829
		if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) {
836
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FieldBinding fieldBinding, TypeBinding lastReceiverType, 	int index, FlowInfo flowInfo) {
830
			return;
837
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
831
		}
838
	// index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
832
		if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
839
	if (fieldBinding.constant() != Constant.NotAConstant)
833
			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
840
		return;
834
		}
841
835
		}
842
	// if field from parameterized type got found, use the original field at codegen time
843
	FieldBinding originalField = fieldBinding.original();
844
	if (originalField != fieldBinding) {
845
		setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField);
836
	}
846
	}
837
	/**
847
	
838
	 * index is <0 to denote write access emulation
848
	if (fieldBinding.isPrivate()) { // private access
839
	 */
849
	    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
840
	public void manageSyntheticAccessIfNecessary(
850
		if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) {
841
			BlockScope currentScope,
851
		    setSyntheticAccessor(fieldBinding, index, 
842
			FieldBinding fieldBinding,
852
		            ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
843
			TypeBinding lastReceiverType,
853
			currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
844
			int index,
845
			FlowInfo flowInfo) {
846
847
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
848
		// index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
849
		if (fieldBinding.constant() != Constant.NotAConstant)
850
			return;
854
			return;
851
852
		// if field from parameterized type got found, use the original field at codegen time
853
		FieldBinding originalField = fieldBinding.original();
854
		if (originalField != fieldBinding) {
855
			setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField);
856
		}
855
		}
856
	} else if (fieldBinding.isProtected()){
857
	    int depth = (index == 0 || (index < 0 && this.otherDepths == null))
858
	    		? (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT 
859
	    		 : this.otherDepths[index < 0 ? this.otherDepths.length-1 : index-1];
857
		
860
		
858
		if (fieldBinding.isPrivate()) { // private access
861
		// implicit protected access 
862
		if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
859
		    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
863
		    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
860
			if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) {
864
		    setSyntheticAccessor(fieldBinding, index, 
861
			    setSyntheticAccessor(fieldBinding, index, 
865
		            ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
862
			            ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
866
			currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
863
				currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
867
			return;
864
				return;
868
		}
865
			}
869
	}
866
		} else if (fieldBinding.isProtected()){
870
	// if the binding declaring class is not visible, need special action
867
		    int depth = (index == 0 || (index < 0 && this.otherDepths == null))
871
	// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
868
		    		? (bits & DepthMASK) >> DepthSHIFT 
872
	// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
869
		    		 : otherDepths[index < 0 ? otherDepths.length-1 : index-1];
873
	// and not from Object or implicit static field access.	
870
			
874
	if (fieldBinding.declaringClass != lastReceiverType
871
			// implicit protected access 
875
			&& !lastReceiverType.isArrayType()
872
			if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
876
			&& fieldBinding.declaringClass != null // array.length
873
			    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
877
			&& fieldBinding.constant() == Constant.NotAConstant) {
874
			    setSyntheticAccessor(fieldBinding, index, 
878
		CompilerOptions options = currentScope.compilerOptions();
875
			            ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
879
		if ((options.targetJDK >= ClassFileConstants.JDK1_2
876
				currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
880
				&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(index <= 1 &&  this.indexOfFirstFieldBinding == 1 && fieldBinding.isStatic()))
877
				return;
881
				&& fieldBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object fields
878
			}
879
		}
880
		// if the binding declaring class is not visible, need special action
881
		// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
882
		// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
883
		// and not from Object or implicit static field access.	
884
		if (fieldBinding.declaringClass != lastReceiverType
885
				&& !lastReceiverType.isArrayType()
886
				&& fieldBinding.declaringClass != null // array.length
887
				&& fieldBinding.constant() == Constant.NotAConstant) {
888
			CompilerOptions options = currentScope.compilerOptions();
889
			if ((options.targetJDK >= ClassFileConstants.JDK1_2
890
					&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(index <= 1 &&  indexOfFirstFieldBinding == 1 && fieldBinding.isStatic()))
891
					&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
892
				|| !fieldBinding.declaringClass.canBeSeenBy(currentScope)) {
882
				|| !fieldBinding.declaringClass.canBeSeenBy(currentScope)) {
893
	
883
	
894
		    setCodegenBinding(
884
		    setCodegenBinding(
Lines 896-1105 Link Here
896
		            currentScope.enclosingSourceType().getUpdatedFieldBinding(
886
		            currentScope.enclosingSourceType().getUpdatedFieldBinding(
897
		                    getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index), 
887
		                    getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index), 
898
		                    (ReferenceBinding)lastReceiverType.erasure()));
888
		                    (ReferenceBinding)lastReceiverType.erasure()));
899
			}
889
		}
900
		}			
890
	}			
901
	}
891
}
902
892
903
public int nullStatus(FlowInfo flowInfo) {
893
public int nullStatus(FlowInfo flowInfo) {
904
	return FlowInfo.UNKNOWN;
894
	return FlowInfo.UNKNOWN;
905
}
895
}
906
896
907
	public Constant optimizedBooleanConstant() {
897
public Constant optimizedBooleanConstant() {
908
898
	switch (this.resolvedType.id) {
909
		switch (this.resolvedType.id) {
899
		case T_boolean :
910
			case T_boolean :
900
		case T_JavaLangBoolean :
911
			case T_JavaLangBoolean :
901
			if (this.constant != Constant.NotAConstant) return this.constant;
912
				if (this.constant != Constant.NotAConstant) return this.constant;
902
			switch (this.bits & ASTNode.RestrictiveFlagMASK) {
913
				switch (bits & RestrictiveFlagMASK) {
903
				case Binding.FIELD : // reading a field
914
					case Binding.FIELD : // reading a field
904
				if (this.otherBindings == null)
915
						if (this.otherBindings == null)
905
					return ((FieldBinding)this.binding).constant();
916
							return ((FieldBinding)this.binding).constant();
906
				// fall thru
917
						// fall thru
907
			case Binding.LOCAL : // reading a local variable
918
					case Binding.LOCAL : // reading a local variable
908
				return this.otherBindings[this.otherBindings.length-1].constant();
919
						return this.otherBindings[this.otherBindings.length-1].constant();
920
				}
921
		}
909
		}
922
		return Constant.NotAConstant;
923
	}
910
	}
911
	return Constant.NotAConstant;
912
}
924
913
925
	/**
914
/**
926
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
915
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
927
	 */
916
 */
928
	public TypeBinding postConversionType(Scope scope) {
917
public TypeBinding postConversionType(Scope scope) {
929
		TypeBinding convertedType = this.resolvedType;
918
	TypeBinding convertedType = this.resolvedType;
930
		TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
919
	TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
931
		if (requiredGenericCast != null) 
920
	if (requiredGenericCast != null) 
932
			convertedType = requiredGenericCast;
921
		convertedType = requiredGenericCast;
933
		int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4;
922
	int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
934
		switch (runtimeType) {
923
	switch (runtimeType) {
935
			case T_boolean :
924
		case T_boolean :
936
				convertedType = TypeBinding.BOOLEAN;
925
			convertedType = TypeBinding.BOOLEAN;
937
				break;
926
			break;
938
			case T_byte :
927
		case T_byte :
939
				convertedType = TypeBinding.BYTE;
928
			convertedType = TypeBinding.BYTE;
940
				break;
929
			break;
941
			case T_short :
930
		case T_short :
942
				convertedType = TypeBinding.SHORT;
931
			convertedType = TypeBinding.SHORT;
943
				break;
932
			break;
944
			case T_char :
933
		case T_char :
945
				convertedType = TypeBinding.CHAR;
934
			convertedType = TypeBinding.CHAR;
946
				break;
935
			break;
947
			case T_int :
936
		case T_int :
948
				convertedType = TypeBinding.INT;
937
			convertedType = TypeBinding.INT;
949
				break;
938
			break;
950
			case T_float :
939
		case T_float :
951
				convertedType = TypeBinding.FLOAT;
940
			convertedType = TypeBinding.FLOAT;
952
				break;
941
			break;
953
			case T_long :
942
		case T_long :
954
				convertedType = TypeBinding.LONG;
943
			convertedType = TypeBinding.LONG;
955
				break;
944
			break;
956
			case T_double :
945
		case T_double :
957
				convertedType = TypeBinding.DOUBLE;
946
			convertedType = TypeBinding.DOUBLE;
958
				break;
947
			break;
959
			default :
948
		default :
960
		}		
949
	}		
961
		if ((this.implicitConversion & BOXING) != 0) {
950
	if ((this.implicitConversion & TypeIds.BOXING) != 0) {
962
			convertedType = scope.environment().computeBoxingType(convertedType);
951
		convertedType = scope.environment().computeBoxingType(convertedType);
963
		}
964
		return convertedType;
965
	}
952
	}
966
	
953
	return convertedType;
967
	public StringBuffer printExpression(int indent, StringBuffer output) {
954
}
968
		
955
969
		for (int i = 0; i < tokens.length; i++) {
956
public StringBuffer printExpression(int indent, StringBuffer output) {
970
			if (i > 0) output.append('.');
957
	for (int i = 0; i < this.tokens.length; i++) {
971
			output.append(tokens[i]);
958
		if (i > 0) output.append('.');
972
		}
959
		output.append(this.tokens[i]);
973
		return output;
974
	}
960
	}
975
		
961
	return output;
976
	/**
962
}
977
	 * Normal field binding did not work, try to bind to a field of the delegate receiver.
963
	
978
	 */
964
/**
979
	public TypeBinding reportError(BlockScope scope) {
965
 * Normal field binding did not work, try to bind to a field of the delegate receiver.
980
		if (binding instanceof ProblemFieldBinding) {
966
 */
981
			scope.problemReporter().invalidField(this, (FieldBinding) binding);
967
public TypeBinding reportError(BlockScope scope) {
982
		} else if (binding instanceof ProblemReferenceBinding) {
968
	if (this.binding instanceof ProblemFieldBinding) {
983
			scope.problemReporter().invalidType(this, (TypeBinding) binding);
969
		scope.problemReporter().invalidField(this, (FieldBinding) this.binding);
984
		} else {
970
	} else if (this.binding instanceof ProblemReferenceBinding) {
985
			scope.problemReporter().unresolvableReference(this, binding);
971
		scope.problemReporter().invalidType(this, (TypeBinding) this.binding);
986
		}
972
	} else {
987
		return null;
973
		scope.problemReporter().unresolvableReference(this, this.binding);
988
	}
974
	}
989
	public TypeBinding resolveType(BlockScope scope) {
975
	return null;
990
		// field and/or local are done before type lookups
976
}
991
		// the only available value for the restrictiveFlag BEFORE
977
992
		// the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField 
978
public TypeBinding resolveType(BlockScope scope) {
993
		this.actualReceiverType = scope.enclosingReceiverType();
979
	// field and/or local are done before type lookups
994
		constant = Constant.NotAConstant;
980
	// the only available value for the restrictiveFlag BEFORE
995
		if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
981
	// the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField 
996
			switch (bits & RestrictiveFlagMASK) {
982
	this.actualReceiverType = scope.enclosingReceiverType();
997
				case Binding.VARIABLE : //============only variable===========
983
	this.constant = Constant.NotAConstant;
998
				case Binding.TYPE | Binding.VARIABLE :
984
	if ((this.codegenBinding = this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
999
					if (binding instanceof LocalVariableBinding) {
985
		switch (this.bits & ASTNode.RestrictiveFlagMASK) {
1000
						if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
986
			case Binding.VARIABLE : //============only variable===========
1001
							scope.problemReporter().cannotReferToNonFinalOuterLocal(
987
			case Binding.TYPE | Binding.VARIABLE :
1002
								(LocalVariableBinding) binding,
988
				if (this.binding instanceof LocalVariableBinding) {
1003
								this);
989
					if (!((LocalVariableBinding) this.binding).isFinal() && ((this.bits & ASTNode.DepthMASK) != 0))
1004
						bits &= ~RestrictiveFlagMASK; // clear bits
990
						scope.problemReporter().cannotReferToNonFinalOuterLocal(
1005
						bits |= Binding.LOCAL;
991
							(LocalVariableBinding) this.binding,
1006
						return this.resolvedType = getOtherFieldBindings(scope);
992
							this);
993
					this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
994
					this.bits |= Binding.LOCAL;
995
					return this.resolvedType = getOtherFieldBindings(scope);
996
				}
997
				if (this.binding instanceof FieldBinding) {
998
					FieldBinding fieldBinding = (FieldBinding) this.binding;
999
					MethodScope methodScope = scope.methodScope();
1000
					// check for forward references
1001
					if (this.indexOfFirstFieldBinding == 1
1002
							&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
1003
							&& methodScope.lastVisibleFieldID >= 0
1004
							&& fieldBinding.id >= methodScope.lastVisibleFieldID
1005
							&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
1006
						scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
1007
					}
1007
					}
1008
					if (binding instanceof FieldBinding) {
1008
					if (!fieldBinding.isStatic() 
1009
						FieldBinding fieldBinding = (FieldBinding) binding;
1009
							&& this.indexOfFirstFieldBinding == 1
1010
						MethodScope methodScope = scope.methodScope();
1010
							&& scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
1011
						// check for forward references
1011
						scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
1012
						if (this.indexOfFirstFieldBinding == 1
1012
					}
1013
								&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
1013
					this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1014
								&& methodScope.lastVisibleFieldID >= 0
1014
					this.bits |= Binding.FIELD;
1015
								&& fieldBinding.id >= methodScope.lastVisibleFieldID
1015
					
1016
								&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
1017
							scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
1018
						}
1019
						if (!fieldBinding.isStatic() 
1020
								&& this.indexOfFirstFieldBinding == 1
1021
								&& scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
1022
							scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
1023
						}
1024
						bits &= ~RestrictiveFlagMASK; // clear bits
1025
						bits |= Binding.FIELD;
1026
						
1027
//						// check for deprecated receiver type
1016
//						// check for deprecated receiver type
1028
//						// deprecation check for receiver type if not first token
1017
//						// deprecation check for receiver type if not first token
1029
//						if (indexOfFirstFieldBinding > 1) {
1018
//						if (indexOfFirstFieldBinding > 1) {
1030
//							if (isTypeUseDeprecated(this.actualReceiverType, scope))
1019
//							if (isTypeUseDeprecated(this.actualReceiverType, scope))
1031
//								scope.problemReporter().deprecatedType(this.actualReceiverType, this);
1020
//								scope.problemReporter().deprecatedType(this.actualReceiverType, this);
1032
//						}
1021
//						}
1033
						
1022
					
1034
						return this.resolvedType = getOtherFieldBindings(scope);
1023
					return this.resolvedType = getOtherFieldBindings(scope);
1035
					}
1024
				}
1036
					// thus it was a type
1025
				// thus it was a type
1037
					bits &= ~RestrictiveFlagMASK; // clear bits
1026
				this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1038
					bits |= Binding.TYPE;
1027
				this.bits |= Binding.TYPE;
1039
				case Binding.TYPE : //=============only type ==============
1028
			case Binding.TYPE : //=============only type ==============
1040
				    TypeBinding type = (TypeBinding) binding;
1029
			    TypeBinding type = (TypeBinding) this.binding;
1041
//					if (isTypeUseDeprecated(type, scope))
1030
//					if (isTypeUseDeprecated(type, scope))
1042
//						scope.problemReporter().deprecatedType(type, this);
1031
//						scope.problemReporter().deprecatedType(type, this);
1043
					type = scope.environment().convertToRawType(type);
1032
				type = scope.environment().convertToRawType(type);
1044
					return this.resolvedType = type;
1033
				return this.resolvedType = type;
1045
			}
1046
		}
1034
		}
1047
		//========error cases===============
1048
		return this.resolvedType = this.reportError(scope);
1049
	}
1035
	}
1036
	//========error cases===============
1037
	return this.resolvedType = this.reportError(scope);
1038
}
1050
1039
1051
	// set the matching codegenBinding and generic cast
1040
// set the matching codegenBinding and generic cast
1052
	protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) {
1041
protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) {
1053
1042
	if (index == 0){
1054
		if (index == 0){
1043
		this.codegenBinding = someCodegenBinding;
1055
			this.codegenBinding = someCodegenBinding;
1044
	} else {
1056
		} else {
1045
	    int length = this.otherBindings.length;
1057
		    int length = this.otherBindings.length;
1046
		if (this.otherCodegenBindings == this.otherBindings){
1058
			if (this.otherCodegenBindings == this.otherBindings){
1047
			System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length);
1059
				System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length);
1048
		}
1060
			}
1049
		this.otherCodegenBindings[index-1] = someCodegenBinding;
1061
			this.otherCodegenBindings[index-1] = someCodegenBinding;
1050
	}	    
1062
		}	    
1051
}
1063
	}
1064
1052
1065
	public void setFieldIndex(int index) {
1053
public void setFieldIndex(int index) {
1066
		this.indexOfFirstFieldBinding = index;
1054
	this.indexOfFirstFieldBinding = index;
1067
	}
1055
}
1068
	
1069
	// set the matching codegenBinding and generic cast
1070
	protected void setGenericCast(int index, TypeBinding someGenericCast) {
1071
1056
1072
		if (index == 0){
1057
// set the matching codegenBinding and generic cast
1073
			this.genericCast = someGenericCast;
1058
protected void setGenericCast(int index, TypeBinding someGenericCast) {
1074
		} else {
1059
	if (index == 0){
1075
		    if (this.otherGenericCasts == null) {
1060
		this.genericCast = someGenericCast;
1076
		        this.otherGenericCasts = new TypeBinding[this.otherBindings.length];
1061
	} else {
1077
		    }
1062
	    if (this.otherGenericCasts == null) {
1078
		    this.otherGenericCasts[index-1] = someGenericCast;
1063
	        this.otherGenericCasts = new TypeBinding[this.otherBindings.length];
1079
		}	    
1080
	}
1081
	
1082
	// set the matching synthetic accessor
1083
	protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) {
1084
		if (index < 0) { // write-access ?
1085
			syntheticWriteAccessor = syntheticAccessor;
1086
	    } else {
1087
			if (syntheticReadAccessors == null) {
1088
				syntheticReadAccessors = new SyntheticMethodBinding[otherBindings == null ? 1 : otherBindings.length + 1];
1089
			}
1090
			syntheticReadAccessors[index] = syntheticAccessor;
1091
	    }
1064
	    }
1092
	}
1065
	    this.otherGenericCasts[index-1] = someGenericCast;
1066
	}	    
1067
}
1093
1068
1094
	public void traverse(ASTVisitor visitor, BlockScope scope) {
1069
// set the matching synthetic accessor
1095
		visitor.visit(this, scope);
1070
protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) {
1096
		visitor.endVisit(this, scope);
1071
	if (index < 0) { // write-access ?
1097
	}
1072
		this.syntheticWriteAccessor = syntheticAccessor;
1098
	public void traverse(ASTVisitor visitor, ClassScope scope) {
1073
    } else {
1099
		visitor.visit(this, scope);
1074
		if (this.syntheticReadAccessors == null) {
1100
		visitor.endVisit(this, scope);
1075
			this.syntheticReadAccessors = new SyntheticMethodBinding[this.otherBindings == null ? 1 : this.otherBindings.length + 1];
1101
	}
1076
		}
1102
	public String unboundReferenceErrorName() {
1077
		this.syntheticReadAccessors[index] = syntheticAccessor;
1103
		return new String(tokens[0]);
1078
    }
1104
	}
1079
}
1080
1081
public void traverse(ASTVisitor visitor, BlockScope scope) {
1082
	visitor.visit(this, scope);
1083
	visitor.endVisit(this, scope);
1084
}
1085
1086
public void traverse(ASTVisitor visitor, ClassScope scope) {
1087
	visitor.visit(this, scope);
1088
	visitor.endVisit(this, scope);
1089
}
1090
1091
public String unboundReferenceErrorName() {
1092
	return new String(this.tokens[0]);
1093
}
1105
}
1094
}

Return to bug 151787