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

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java (-1 / +26 lines)
Lines 31-37 Link Here
31
31
32
public class FlowAnalysisTest extends AbstractRegressionTest {
32
public class FlowAnalysisTest extends AbstractRegressionTest {
33
static {
33
static {
34
//	TESTS_NAMES = new String[] { "testLocalClassInInitializer1" };
34
//	TESTS_NAMES = new String[] { "testFinalFieldInNested1" };
35
//	TESTS_NUMBERS = new int[] { 69 };
35
//	TESTS_NUMBERS = new int[] { 69 };
36
}
36
}
37
public FlowAnalysisTest(String name) {
37
public FlowAnalysisTest(String name) {
Lines 2490-2495 Link Here
2490
			"continue cannot be used outside of a loop\n" + 
2490
			"continue cannot be used outside of a loop\n" + 
2491
			"----------\n");
2491
			"----------\n");
2492
}
2492
}
2493
// final field in anonymous nested class
2494
// witness a regression during working on Bug 247564 - [compiler][null] Detecting null field reference
2495
public void testFinalFieldInNested1() {
2496
	this.runNegativeTest(
2497
			new String[] {
2498
				"X.java",
2499
				"public class X {\n" +
2500
				"    void print4() {\n" +
2501
				"        for (int i=0; i<4; i++)\n" +
2502
				"            new Runnable() {\n" +
2503
				"                final String s1local;\n" +
2504
				"                public void run() {\n" +
2505
				"                     s1local.toString();\n" +
2506
				"                }\n" +
2507
				"            }.run();\n" +
2508
				"    }\n" +
2509
				"}\n"
2510
			}, 
2511
			"----------\n" + 
2512
			"1. ERROR in X.java (at line 4)\n" + 
2513
			"	new Runnable() {\n" + 
2514
			"	    ^^^^^^^^^^\n" + 
2515
			"The blank final field s1local may not have been initialized\n" + 
2516
			"----------\n");
2517
}
2493
public static Class testClass() {
2518
public static Class testClass() {
2494
	return FlowAnalysisTest.class;
2519
	return FlowAnalysisTest.class;
2495
}
2520
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-23 / +29 lines)
Lines 199-205 Link Here
199
			localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
199
			localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
200
		}
200
		}
201
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
201
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
202
		updateMaxFieldCount(); // propagate down the max field count
203
		internalAnalyseCode(flowContext, flowInfo);
202
		internalAnalyseCode(flowContext, flowInfo);
204
	} catch (AbortType e) {
203
	} catch (AbortType e) {
205
		this.ignoreFurtherInvestigation = true;
204
		this.ignoreFurtherInvestigation = true;
Lines 215-222 Link Here
215
	if (this.ignoreFurtherInvestigation)
214
	if (this.ignoreFurtherInvestigation)
216
		return;
215
		return;
217
	try {
216
	try {
218
		// propagate down the max field count
219
		updateMaxFieldCount();
220
		internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount));
217
		internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount));
221
	} catch (AbortType e) {
218
	} catch (AbortType e) {
222
		this.ignoreFurtherInvestigation = true;
219
		this.ignoreFurtherInvestigation = true;
Lines 237-243 Link Here
237
			localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
234
			localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
238
		}
235
		}
239
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
236
		manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
240
		updateMaxFieldCount(); // propagate down the max field count
241
		internalAnalyseCode(flowContext, flowInfo);
237
		internalAnalyseCode(flowContext, flowInfo);
242
	} catch (AbortType e) {
238
	} catch (AbortType e) {
243
		this.ignoreFurtherInvestigation = true;
239
		this.ignoreFurtherInvestigation = true;
Lines 651-657 Link Here
651
				// branch, since the previous initializer already got the blame.
647
				// branch, since the previous initializer already got the blame.
652
				if (staticFieldInfo == FlowInfo.DEAD_END) {
648
				if (staticFieldInfo == FlowInfo.DEAD_END) {
653
					this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
649
					this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
654
					staticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
650
					staticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
655
				}
651
				}
656
			} else {
652
			} else {
657
				if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
653
				if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
Lines 667-673 Link Here
667
				// branch, since the previous initializer already got the blame.
663
				// branch, since the previous initializer already got the blame.
668
				if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
664
				if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
669
					this.initializerScope.problemReporter().initializerMustCompleteNormally(field);
665
					this.initializerScope.problemReporter().initializerMustCompleteNormally(field);
670
					nonStaticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
666
					nonStaticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
671
				}
667
				}
672
			}
668
			}
673
		}
669
		}
Lines 1049-1070 Link Here
1049
				this.typeParameters[i].resolve(this.scope);
1045
				this.typeParameters[i].resolve(this.scope);
1050
			}
1046
			}
1051
		}
1047
		}
1052
		// field count from supertypes should be included in maxFieldCount,
1048
		// field count from enclosing and supertypes should be included in maxFieldCount,
1053
		// so that a field from supertype doesn't end up with same id as a local variable
1049
		// to make field-ids unique among all fields in scope.
1054
		// in a method being analyzed.
1050
		// 1.: enclosing:
1051
		if (sourceType instanceof NestedTypeBinding) {
1052
			// note: local types have no enclosingType in the AST but only in the binding:
1053
			sourceType.cumulativeFieldCount += ((NestedTypeBinding)sourceType).enclosingType.cumulativeFieldCount;
1054
		}
1055
		// 2.: supers:
1055
		int superFieldsCount = 0;
1056
		int superFieldsCount = 0;
1056
		ReferenceBinding superClassBinding = sourceType.superclass;
1057
		ReferenceBinding superClassBinding = sourceType.superclass;
1057
		while (superClassBinding != null) {
1058
		while (superClassBinding != null) {
1059
// TODO(stephan): this part is pending a discussion how deep we want to go into super types.
1060
// 1.: consistently avoid calling fields() (also from findFieldCountFromSuperInterfaces())
1061
// 2.: consistently check field.kind()  (also in findFieldCountFromSuperInterfaces())?
1058
			FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
1062
			FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
1059
			if (unResolvedFields != null) {
1063
			if (unResolvedFields != null) {
1060
				superFieldsCount += unResolvedFields.length;
1064
				for (int i=unResolvedFields.length-1; i>=0; i--) {
1065
					switch (unResolvedFields[i].kind()) {
1066
						case AbstractVariableDeclaration.FIELD:
1067
						case AbstractVariableDeclaration.ENUM_CONSTANT:
1068
							superFieldsCount++;
1069
					}
1070
				}
1061
			}
1071
			}
1072
//			superFieldsCount += superClassBinding.fieldCount();
1062
			superFieldsCount += findFieldCountFromSuperInterfaces(superClassBinding.superInterfaces());
1073
			superFieldsCount += findFieldCountFromSuperInterfaces(superClassBinding.superInterfaces());
1063
			superClassBinding = superClassBinding.superclass();
1074
			superClassBinding = superClassBinding.superclass();
1064
		}
1075
		}
1065
		ReferenceBinding[] superInterfacesBinding = this.binding.superInterfaces;
1076
		ReferenceBinding[] superInterfacesBinding = this.binding.superInterfaces;
1066
		superFieldsCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
1077
		superFieldsCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
1067
		this.scope.cumulativeFieldCount += superFieldsCount;
1078
		this.binding.cumulativeFieldCount += superFieldsCount;
1079
1068
		if (this.fields != null) {
1080
		if (this.fields != null) {
1069
			for (int i = 0, count = this.fields.length; i < count; i++) {
1081
			for (int i = 0, count = this.fields.length; i < count; i++) {
1070
				FieldDeclaration field = this.fields[i];
1082
				FieldDeclaration field = this.fields[i];
Lines 1085-1091 Link Here
1085
							this.ignoreFurtherInvestigation = true;
1097
							this.ignoreFurtherInvestigation = true;
1086
							continue;
1098
							continue;
1087
						}
1099
						}
1088
						field.binding.id += superFieldsCount;
1089
						if (needSerialVersion
1100
						if (needSerialVersion
1090
								&& ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal))
1101
								&& ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal))
1091
								&& CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
1102
								&& CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
Lines 1102-1111 Link Here
1102
				field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
1113
				field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
1103
			}
1114
			}
1104
		}		
1115
		}		
1105
		//		if (this.maxFieldCount < localMaxFieldCount) {
1116
		this.maxFieldCount = sourceType.cumulativeFieldCount;
1106
		//			this.maxFieldCount = localMaxFieldCount;
1107
		//		}
1108
		this.maxFieldCount = this.scope.cumulativeFieldCount;
1109
		if (this.memberTypes != null) {
1117
		if (this.memberTypes != null) {
1110
			for (int i = 0, count = this.memberTypes.length; i < count; i++) {
1118
			for (int i = 0, count = this.memberTypes.length; i < count; i++) {
1111
				this.memberTypes[i].resolve(this.scope);
1119
				this.memberTypes[i].resolve(this.scope);
Lines 1202-1207 Link Here
1202
	if (superinterfaces == null)
1210
	if (superinterfaces == null)
1203
		return numOfFields ;
1211
		return numOfFields ;
1204
	for (int i = 0; i < superinterfaces.length; i++) {
1212
	for (int i = 0; i < superinterfaces.length; i++) {
1213
		// FIXME(stephan): check indirect usage of fields() -> resolveTypeFor(FieldBinding)
1205
		numOfFields += superinterfaces[i].fieldCount();
1214
		numOfFields += superinterfaces[i].fieldCount();
1206
		numOfFields += findFieldCountFromSuperInterfaces(superinterfaces[i].superInterfaces());		
1215
		numOfFields += findFieldCountFromSuperInterfaces(superinterfaces[i].superInterfaces());		
1207
	}
1216
	}
Lines 1468-1479 Link Here
1468
/**
1477
/**
1469
 * MaxFieldCount's computation is necessary so as to reserve space for
1478
 * MaxFieldCount's computation is necessary so as to reserve space for
1470
 * the flow info field portions. It corresponds to the maximum amount of
1479
 * the flow info field portions. It corresponds to the maximum amount of
1471
 * fields this class or one of its innertypes have.
1480
 * accumulated fields this class or one of its innertypes have.
1472
 *
1481
 *
1473
 * During name resolution, types are traversed, and the max field count is recorded
1482
 * During buildFields() accumulative field counts are gather per class,
1474
 * on the outermost type. It is then propagated down during the flow analysis.
1483
 * which include fields of outer and super types.
1475
 *
1484
 * During resolve, the maximum of these counts is collected inside out.
1476
 * This method is doing either up/down propagation.
1477
 */
1485
 */
1478
void updateMaxFieldCount() {
1486
void updateMaxFieldCount() {
1479
	if (this.binding == null)
1487
	if (this.binding == null)
Lines 1481-1488 Link Here
1481
	TypeDeclaration outerMostType = this.scope.outerMostClassScope().referenceType();
1489
	TypeDeclaration outerMostType = this.scope.outerMostClassScope().referenceType();
1482
	if (this.maxFieldCount > outerMostType.maxFieldCount) {
1490
	if (this.maxFieldCount > outerMostType.maxFieldCount) {
1483
		outerMostType.maxFieldCount = this.maxFieldCount; // up
1491
		outerMostType.maxFieldCount = this.maxFieldCount; // up
1484
	} else {
1485
		this.maxFieldCount = outerMostType.maxFieldCount; // down
1486
	}
1492
	}
1487
}
1493
}
1488
1494
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java (-45 / +8 lines)
Lines 11-17 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.jdt.internal.compiler.flow;
12
package org.eclipse.jdt.internal.compiler.flow;
13
13
14
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
14
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
16
15
17
/**
16
/**
Lines 121-132 Link Here
121
	// protected from non-object locals in calling methods
120
	// protected from non-object locals in calling methods
122
	if (this != DEAD_END) {
121
	if (this != DEAD_END) {
123
    	this.tagBits |= NULL_FLAG_MASK;
122
    	this.tagBits |= NULL_FLAG_MASK;
124
    	int position;
123
    	int position = local.getAnalysisId(this.maxFieldCount);
125
    	if (local instanceof FieldBinding) {
126
			position = local.id;
127
		} else {
128
			position = local.id + this.maxFieldCount;
129
		}
130
    	// position is zero-based
124
    	// position is zero-based
131
    	if (position < BitCacheSize) { // use bits
125
    	if (position < BitCacheSize) { // use bits
132
    		// set protected non null
126
    		// set protected non null
Lines 171-183 Link Here
171
	// protected from non-object locals in calling methods
165
	// protected from non-object locals in calling methods
172
	if (this != DEAD_END) {
166
	if (this != DEAD_END) {
173
    	this.tagBits |= NULL_FLAG_MASK;
167
    	this.tagBits |= NULL_FLAG_MASK;
174
    	int position;
168
    	int position = local.getAnalysisId(this.maxFieldCount);
175
    	// position is zero-based
176
    	if (local instanceof FieldBinding) {
177
    		position = local.id;
178
    	} else {
179
    		position = local.id + this.maxFieldCount;
180
    	}
181
    	if (position < BitCacheSize) { // use bits
169
    	if (position < BitCacheSize) { // use bits
182
    		// set assigned non null
170
    		// set assigned non null
183
    		this.nullBit3 |= (1L << position);
171
    		this.nullBit3 |= (1L << position);
Lines 222-233 Link Here
222
	// protected from non-object locals in calling methods
210
	// protected from non-object locals in calling methods
223
	if (this != DEAD_END) {
211
	if (this != DEAD_END) {
224
    	this.tagBits |= NULL_FLAG_MASK;
212
    	this.tagBits |= NULL_FLAG_MASK;
225
    	int position;
213
    	int position = local.getAnalysisId(this.maxFieldCount);
226
    	if (local instanceof FieldBinding) {
227
    		position = local.id;
228
    	} else {
229
    		position = local.id + this.maxFieldCount;
230
    	}
231
    	// position is zero-based
214
    	// position is zero-based
232
    	if (position < BitCacheSize) { // use bits
215
    	if (position < BitCacheSize) { // use bits
233
    		// set assigned null
216
    		// set assigned null
Lines 272-283 Link Here
272
	// protected from non-object locals in calling methods
255
	// protected from non-object locals in calling methods
273
	if (this != DEAD_END) {
256
	if (this != DEAD_END) {
274
    	this.tagBits |= NULL_FLAG_MASK;
257
    	this.tagBits |= NULL_FLAG_MASK;
275
    	int position;
258
    	int position = local.getAnalysisId(this.maxFieldCount);
276
    	if (local instanceof FieldBinding) {
277
    		position = local.id;
278
    	} else {
279
    		position = local.id + this.maxFieldCount;
280
    	}
281
    	// position is zero-based
259
    	// position is zero-based
282
    	if (position < BitCacheSize) { // use bits
260
    	if (position < BitCacheSize) { // use bits
283
    		// set assigned unknown
261
    		// set assigned unknown
Lines 432-444 Link Here
432
	// protected from non-object locals in calling methods
410
	// protected from non-object locals in calling methods
433
	if (this != DEAD_END) {
411
	if (this != DEAD_END) {
434
		this.tagBits |= NULL_FLAG_MASK;
412
		this.tagBits |= NULL_FLAG_MASK;
435
        int position;
436
        long mask;
413
        long mask;
437
        if (local instanceof FieldBinding) {
414
    	int position = local.getAnalysisId(this.maxFieldCount);
438
        	position = local.id;
439
        } else {
440
        	position = local.id + this.maxFieldCount;
441
        }
442
        if (position < BitCacheSize) {
415
        if (position < BitCacheSize) {
443
            // use bits
416
            // use bits
444
        	mask = 1L << position;
417
        	mask = 1L << position;
Lines 483-495 Link Here
483
public void markPotentiallyNullBit(VariableBinding local) {
456
public void markPotentiallyNullBit(VariableBinding local) {
484
	if (this != DEAD_END) {
457
	if (this != DEAD_END) {
485
		this.tagBits |= NULL_FLAG_MASK;
458
		this.tagBits |= NULL_FLAG_MASK;
486
        int position;
459
		long mask;
487
        long mask;
460
    	int position = local.getAnalysisId(this.maxFieldCount);
488
        if (local instanceof FieldBinding) {
489
        	position = local.id;
490
        } else {
491
        	position = local.id + this.maxFieldCount;
492
        }
493
        if (position < BitCacheSize) {
461
        if (position < BitCacheSize) {
494
            // use bits
462
            // use bits
495
        	mask = 1L << position;
463
        	mask = 1L << position;
Lines 534-546 Link Here
534
public void markPotentiallyNonNullBit(VariableBinding local) {
502
public void markPotentiallyNonNullBit(VariableBinding local) {
535
	if (this != DEAD_END) {
503
	if (this != DEAD_END) {
536
		this.tagBits |= NULL_FLAG_MASK;
504
		this.tagBits |= NULL_FLAG_MASK;
537
        int position;
538
        long mask;
505
        long mask;
539
        if (local instanceof FieldBinding) {
506
    	int position = local.getAnalysisId(this.maxFieldCount);
540
        	position = local.id;
541
        } else {
542
        	position = local.id + this.maxFieldCount;
543
        }
544
        if (position < BitCacheSize) {
507
        if (position < BitCacheSize) {
545
            // use bits
508
            // use bits
546
        	mask = 1L << position;
509
        	mask = 1L << position;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (-106 / +21 lines)
Lines 526-537 Link Here
526
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
526
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
527
		return false;
527
		return false;
528
	}
528
	}
529
	int position;
529
	int position = local.getAnalysisId(this.maxFieldCount);
530
	if (local instanceof FieldBinding) {
531
		position = local.id;
532
	} else {
533
		position = local.id + this.maxFieldCount;
534
	}
535
	if (position < BitCacheSize) {
530
	if (position < BitCacheSize) {
536
		// use bits
531
		// use bits
537
		return (
532
		return (
Lines 562-573 Link Here
562
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
557
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
563
		return false;
558
		return false;
564
	}
559
	}
565
	int position;
560
	int position = local.getAnalysisId(this.maxFieldCount);
566
	if (local instanceof FieldBinding) {
567
		position = local.id;
568
	} else {
569
		position = local.id + this.maxFieldCount;
570
	}
571
	if (position < BitCacheSize) {
561
	if (position < BitCacheSize) {
572
		// use bits
562
		// use bits
573
		return (this.nullBit1 & this.nullBit3
563
		return (this.nullBit1 & this.nullBit3
Lines 594-605 Link Here
594
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
584
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
595
		return false;
585
		return false;
596
	}
586
	}
597
	int position;
587
	int position = local.getAnalysisId(this.maxFieldCount);
598
	if (local instanceof FieldBinding) {
599
		position = local.id;
600
	} else {
601
		position = local.id + this.maxFieldCount;
602
	}
603
	if (position < BitCacheSize) {
588
	if (position < BitCacheSize) {
604
		// use bits
589
		// use bits
605
		return (this.nullBit1 & this.nullBit2
590
		return (this.nullBit1 & this.nullBit2
Lines 755-761 Link Here
755
	if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0) {
740
	if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0) {
756
		return true;
741
		return true;
757
	}
742
	}
758
	return isDefinitelyAssigned(field.id);
743
	return isDefinitelyAssigned(field.getAnalysisId(this.maxFieldCount));
759
}
744
}
760
745
761
final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
746
final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
Lines 782-797 Link Here
782
			local.constant() != Constant.NotAConstant) { // String instances
767
			local.constant() != Constant.NotAConstant) { // String instances
783
		return true;
768
		return true;
784
	}
769
	}
785
	int position;
786
	if (local instanceof FieldBinding) {
770
	if (local instanceof FieldBinding) {
787
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
771
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
788
			// static final field's null status may not be in the flow info
772
			// static final field's null status may not be in the flow info
789
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NON_NULL);
773
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NON_NULL);
790
		}
774
		}
791
		position = local.id;
792
	} else {
793
		position = local.id + this.maxFieldCount;
794
	}
775
	}
776
	int position = local.getAnalysisId(this.maxFieldCount);
795
	if (position < BitCacheSize) { // use bits
777
	if (position < BitCacheSize) { // use bits
796
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
778
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
797
			    & (1L << position)) != 0;
779
			    & (1L << position)) != 0;
Lines 823-838 Link Here
823
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
805
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
824
		return false;
806
		return false;
825
	}
807
	}
826
	int position;
827
	if (local instanceof FieldBinding) {
808
	if (local instanceof FieldBinding) {
828
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
809
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
829
			// static final field's null status may not be in the flow info
810
			// static final field's null status may not be in the flow info
830
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NULL);
811
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NULL);
831
		}
812
		}
832
		position = local.id;
833
	} else {
834
		position = local.id + this.maxFieldCount;
835
	}
813
	}
814
	int position = local.getAnalysisId(this.maxFieldCount);
836
	if (position < BitCacheSize) { // use bits
815
	if (position < BitCacheSize) { // use bits
837
		return ((this.nullBit1 & this.nullBit2
816
		return ((this.nullBit1 & this.nullBit2
838
			        & (~this.nullBit3 | ~this.nullBit4))
817
			        & (~this.nullBit3 | ~this.nullBit4))
Lines 858-869 Link Here
858
			(this.tagBits & NULL_FLAG_MASK) == 0) {
837
			(this.tagBits & NULL_FLAG_MASK) == 0) {
859
		return false;
838
		return false;
860
	}
839
	}
861
	int position;
840
	int position = local.getAnalysisId(this.maxFieldCount);
862
	if (local instanceof FieldBinding) {
863
		position = local.id;
864
	} else {
865
		position = local.id + this.maxFieldCount;
866
	}
867
	if (position < BitCacheSize) { // use bits
841
	if (position < BitCacheSize) { // use bits
868
		return ((this.nullBit1 & this.nullBit4
842
		return ((this.nullBit1 & this.nullBit4
869
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
843
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
Lines 905-911 Link Here
905
}
879
}
906
880
907
final public boolean isPotentiallyAssigned(FieldBinding field) {
881
final public boolean isPotentiallyAssigned(FieldBinding field) {
908
	return isPotentiallyAssigned(field.id);
882
	return isPotentiallyAssigned(field.getAnalysisId(this.maxFieldCount));
909
}
883
}
910
884
911
final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
885
final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
Lines 922-933 Link Here
922
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
896
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
923
		return false;
897
		return false;
924
	}
898
	}
925
	int position;
899
	int position = local.getAnalysisId(this.maxFieldCount);
926
	if (local instanceof FieldBinding) {
927
		position = local.id;
928
	} else {
929
		position = local.id + this.maxFieldCount;
930
	}
931
	if (position < BitCacheSize) { // use bits
900
	if (position < BitCacheSize) { // use bits
932
		// use bits
901
		// use bits
933
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
902
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
Lines 953-968 Link Here
953
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
922
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
954
		return false;
923
		return false;
955
	}
924
	}
956
	int position;
957
	if (local instanceof FieldBinding) {
925
	if (local instanceof FieldBinding) {
958
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
926
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
959
			// static final field's null status may not be in the flow info
927
			// static final field's null status may not be in the flow info
960
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.POTENTIALLY_NULL);
928
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.POTENTIALLY_NULL);
961
		}
929
		}
962
		position = local.id;
963
	} else {
964
		position = local.id + this.maxFieldCount;
965
	}
930
	}
931
	int position = local.getAnalysisId(this.maxFieldCount);
966
	if (position < BitCacheSize) {
932
	if (position < BitCacheSize) {
967
		// use bits
933
		// use bits
968
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
934
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
Lines 988-999 Link Here
988
			(this.tagBits & NULL_FLAG_MASK) == 0) {
954
			(this.tagBits & NULL_FLAG_MASK) == 0) {
989
		return false;
955
		return false;
990
	}
956
	}
991
	int position;
957
	int position = local.getAnalysisId(this.maxFieldCount);
992
	if (local instanceof FieldBinding) {
993
		position = local.id;
994
	} else {
995
		position = local.id + this.maxFieldCount;
996
	}
997
	if (position < BitCacheSize) { // use bits
958
	if (position < BitCacheSize) { // use bits
998
		return (this.nullBit4
959
		return (this.nullBit4
999
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
960
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
Lines 1019-1030 Link Here
1019
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
980
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1020
		return false;
981
		return false;
1021
	}
982
	}
1022
	int position;
983
	int position = local.getAnalysisId(this.maxFieldCount);
1023
	if (local instanceof FieldBinding) {
1024
		position = local.id;
1025
	} else {
1026
		position = local.id + this.maxFieldCount;
1027
	}
1028
	if (position < BitCacheSize) { // use bits
984
	if (position < BitCacheSize) { // use bits
1029
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
985
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
1030
	}
986
	}
Lines 1048-1059 Link Here
1048
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1004
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1049
		return false;
1005
		return false;
1050
	}
1006
	}
1051
	int position;
1007
	int position = local.getAnalysisId(this.maxFieldCount);
1052
	if (local instanceof FieldBinding) {
1053
		position = local.id;
1054
	} else {
1055
		position = local.id + this.maxFieldCount;
1056
	}
1057
	if (position < BitCacheSize) {
1008
	if (position < BitCacheSize) {
1058
		// use bits
1009
		// use bits
1059
		return (this.nullBit1 & this.nullBit2
1010
		return (this.nullBit1 & this.nullBit2
Lines 1326-1332 Link Here
1326
1277
1327
public void markAsDefinitelyAssigned(FieldBinding field) {
1278
public void markAsDefinitelyAssigned(FieldBinding field) {
1328
	if (this != DEAD_END)
1279
	if (this != DEAD_END)
1329
		markAsDefinitelyAssigned(field.id);
1280
		markAsDefinitelyAssigned(field.getAnalysisId(this.maxFieldCount));
1330
}
1281
}
1331
1282
1332
public void markAsDefinitelyAssigned(LocalVariableBinding local) {
1283
public void markAsDefinitelyAssigned(LocalVariableBinding local) {
Lines 1465-1477 Link Here
1465
	if (this != DEAD_END) {
1416
	if (this != DEAD_END) {
1466
		this.tagBits |= NULL_FLAG_MASK;
1417
		this.tagBits |= NULL_FLAG_MASK;
1467
		long mask;
1418
		long mask;
1468
		int position;
1419
		int position = local.getAnalysisId(this.maxFieldCount);
1469
		// position is zero-based
1470
		if (local instanceof FieldBinding) {
1471
			position = local.id;
1472
		} else {
1473
			position = local.id + this.maxFieldCount;
1474
		}
1475
		if (position < BitCacheSize) {
1420
		if (position < BitCacheSize) {
1476
			// use bits
1421
			// use bits
1477
			// mark assigned null
1422
			// mark assigned null
Lines 1523-1535 Link Here
1523
public void resetNullInfo(VariableBinding local) {
1468
public void resetNullInfo(VariableBinding local) {
1524
	if (this != DEAD_END) {
1469
	if (this != DEAD_END) {
1525
		this.tagBits |= NULL_FLAG_MASK;
1470
		this.tagBits |= NULL_FLAG_MASK;
1526
        int position;
1527
        long mask;
1471
        long mask;
1528
        if (local instanceof FieldBinding) {
1472
    	int position = local.getAnalysisId(this.maxFieldCount);
1529
        	position = local.id;
1530
        } else {
1531
        	position = local.id + this.maxFieldCount;
1532
        }
1533
        if (position < BitCacheSize) {
1473
        if (position < BitCacheSize) {
1534
            // use bits
1474
            // use bits
1535
            this.nullBit1 &= (mask = ~(1L << position));
1475
            this.nullBit1 &= (mask = ~(1L << position));
Lines 1593-1605 Link Here
1593
	// protected from non-object locals in calling methods
1533
	// protected from non-object locals in calling methods
1594
	if (this != DEAD_END) {
1534
	if (this != DEAD_END) {
1595
		this.tagBits |= NULL_FLAG_MASK;
1535
		this.tagBits |= NULL_FLAG_MASK;
1596
        int position;
1597
        long mask;
1536
        long mask;
1598
        if (local instanceof FieldBinding) {
1537
    	int position = local.getAnalysisId(this.maxFieldCount);
1599
        	position = local.id;
1600
        } else {
1601
        	position = local.id + this.maxFieldCount;
1602
        }
1603
        if (position < BitCacheSize) {
1538
        if (position < BitCacheSize) {
1604
            // use bits
1539
            // use bits
1605
        	mask = 1L << position;
1540
        	mask = 1L << position;
Lines 1645-1657 Link Here
1645
public void markPotentiallyNullBit(VariableBinding local) {
1580
public void markPotentiallyNullBit(VariableBinding local) {
1646
	if (this != DEAD_END) {
1581
	if (this != DEAD_END) {
1647
		this.tagBits |= NULL_FLAG_MASK;
1582
		this.tagBits |= NULL_FLAG_MASK;
1648
        int position;
1649
        long mask;
1583
        long mask;
1650
        if (local instanceof FieldBinding) {
1584
    	int position = local.getAnalysisId(this.maxFieldCount);
1651
        	position = local.id;
1652
        } else {
1653
        	position = local.id + this.maxFieldCount;
1654
        }
1655
        if (position < BitCacheSize) {
1585
        if (position < BitCacheSize) {
1656
            // use bits
1586
            // use bits
1657
        	mask = 1L << position;
1587
        	mask = 1L << position;
Lines 1697-1709 Link Here
1697
public void markPotentiallyNonNullBit(VariableBinding local) {
1627
public void markPotentiallyNonNullBit(VariableBinding local) {
1698
	if (this != DEAD_END) {
1628
	if (this != DEAD_END) {
1699
		this.tagBits |= NULL_FLAG_MASK;
1629
		this.tagBits |= NULL_FLAG_MASK;
1700
        int position;
1701
        long mask;
1630
        long mask;
1702
        if (local instanceof FieldBinding) {
1631
    	int position = local.getAnalysisId(this.maxFieldCount);
1703
        	position = local.id;
1704
        } else {
1705
        	position = local.id + this.maxFieldCount;
1706
        }
1707
        if (position < BitCacheSize) {
1632
        if (position < BitCacheSize) {
1708
            // use bits
1633
            // use bits
1709
        	mask = 1L << position;
1634
        	mask = 1L << position;
Lines 2238-2249 Link Here
2238
}
2163
}
2239
2164
2240
public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2165
public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2241
	int position;
2166
	int position = binding.getAnalysisId(this.maxFieldCount);
2242
	if (binding instanceof FieldBinding) {
2243
		position = binding.id;
2244
	} else {
2245
		position = binding.id + this.maxFieldCount;
2246
	}
2247
	int oldLength;
2167
	int oldLength;
2248
	if (this.nullStatusChangedInAssert == null) {
2168
	if (this.nullStatusChangedInAssert == null) {
2249
		this.nullStatusChangedInAssert = new int[position + 1];
2169
		this.nullStatusChangedInAssert = new int[position + 1];
Lines 2257-2268 Link Here
2257
}
2177
}
2258
2178
2259
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2179
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2260
	int position;
2180
	int position = binding.getAnalysisId(this.maxFieldCount);
2261
	if (binding instanceof FieldBinding) {
2262
		position = binding.id;
2263
	} else {
2264
		position = binding.id + this.maxFieldCount;
2265
	}
2266
	if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) {
2181
	if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) {
2267
		return false;
2182
		return false;
2268
	}
2183
	}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java (-26 / +4 lines)
Lines 39-51 Link Here
39
	public TypeDeclaration referenceContext;
39
	public TypeDeclaration referenceContext;
40
	public TypeReference superTypeReference;
40
	public TypeReference superTypeReference;
41
	java.util.ArrayList deferredBoundChecks;
41
	java.util.ArrayList deferredBoundChecks;
42
	public int cumulativeFieldCount;   // cumulative field count from all enclosing types, used to build unique field id's for member types.
43
	public int localTypeFieldIdStart;
44
	public ClassScope(Scope parent, TypeDeclaration context) {
42
	public ClassScope(Scope parent, TypeDeclaration context) {
45
		super(Scope.CLASS_SCOPE, parent);
43
		super(Scope.CLASS_SCOPE, parent);
46
		this.referenceContext = context;
44
		this.referenceContext = context;
47
		this.deferredBoundChecks = null; // initialized if required
45
		this.deferredBoundChecks = null; // initialized if required
48
		this.localTypeFieldIdStart = this.cumulativeFieldCount = 0;
49
	}
46
	}
50
47
51
	void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
48
	void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
Lines 82-89 Link Here
82
				}
79
				}
83
			}
80
			}
84
		}
81
		}
85
		this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
82
		this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
86
		this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
87
		connectMemberTypes();
83
		connectMemberTypes();
88
		buildFieldsAndMethods();
84
		buildFieldsAndMethods();
89
		anonymousType.faultInTypesForFieldsAndMethods();
85
		anonymousType.faultInTypesForFieldsAndMethods();
Lines 113-135 Link Here
113
		FieldBinding[] fieldBindings = new FieldBinding[count];
109
		FieldBinding[] fieldBindings = new FieldBinding[count];
114
		HashtableOfObject knownFieldNames = new HashtableOfObject(count);
110
		HashtableOfObject knownFieldNames = new HashtableOfObject(count);
115
		count = 0;
111
		count = 0;
116
		ClassScope enclosingClass = this.enclosingClassScope();
117
		if (enclosingClass != null) {
118
			this.cumulativeFieldCount += enclosingClass.cumulativeFieldCount;
119
		}
120
//		SourceTypeBinding enclosingSourceType = this.enclosingSourceType();
121
//		if (enclosingSourceType != null) {
122
//			ReferenceBinding superClassBinding = sourceType.superclass;
123
//			while (superClassBinding != null) {
124
//				FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
125
//				if (unResolvedFields != null) {
126
//					this.cumulativeFieldCount += unResolvedFields.length;
127
//				}
128
//				superClassBinding = superClassBinding.superclass();
129
//			}
130
//			ReferenceBinding[] superInterfacesBinding = enclosingSourceType.superInterfaces;
131
//			this.cumulativeFieldCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
132
//		}
133
		for (int i = 0; i < size; i++) {
112
		for (int i = 0; i < size; i++) {
134
			FieldDeclaration field = fields[i];
113
			FieldDeclaration field = fields[i];
135
			if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
114
			if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
Lines 137-143 Link Here
137
				// now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713
116
				// now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713
138
			} else {
117
			} else {
139
				FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType);
118
				FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType);
140
				fieldBinding.id = count + this.cumulativeFieldCount;
119
				fieldBinding.id = count;
141
				// field's type will be resolved when needed for top level types
120
				// field's type will be resolved when needed for top level types
142
				checkAndSetModifiersForField(fieldBinding, field);
121
				checkAndSetModifiersForField(fieldBinding, field);
143
122
Lines 165-171 Link Here
165
		// remove duplicate fields
144
		// remove duplicate fields
166
		if (count != fieldBindings.length)
145
		if (count != fieldBindings.length)
167
			System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
146
			System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
168
		this.cumulativeFieldCount += count;
147
		sourceType.cumulativeFieldCount += count;
169
		sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type
148
		sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type
170
		sourceType.setFields(fieldBindings);
149
		sourceType.setFields(fieldBindings);
171
	}
150
	}
Lines 248-255 Link Here
248
			checkParameterizedTypeBounds();
227
			checkParameterizedTypeBounds();
249
			checkParameterizedSuperTypeCollisions();
228
			checkParameterizedSuperTypeCollisions();
250
		}
229
		}
251
		this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
230
		this.referenceContext.binding.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
252
		this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
253
		buildFieldsAndMethods();
231
		buildFieldsAndMethods();
254
		localType.faultInTypesForFieldsAndMethods();
232
		localType.faultInTypesForFieldsAndMethods();
255
233
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java (+6 lines)
Lines 279-284 Link Here
279
	return originalField.tagBits;
279
	return originalField.tagBits;
280
}
280
}
281
281
282
public int getAnalysisId(int maxFieldCount) {
283
	if (this.declaringClass instanceof NestedTypeBinding)
284
		return ((NestedTypeBinding) this.declaringClass).enclosingType.cumulativeFieldCount + this.id;
285
	return this.id;
286
}
287
282
public final boolean isDefault() {
288
public final boolean isDefault() {
283
	return !isPublic() && !isProtected() && !isPrivate();
289
	return !isPublic() && !isProtected() && !isPrivate();
284
}
290
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java (+2 lines)
Lines 41-46 Link Here
41
	public TypeVariableBinding[] typeVariables;
41
	public TypeVariableBinding[] typeVariables;
42
42
43
	public ClassScope scope;
43
	public ClassScope scope;
44
	public int cumulativeFieldCount;   // cumulative field count from all enclosing types, used to build unique field id's for member types.
44
45
45
	// Synthetics are separated into 4 categories: methods, super methods, fields, class literals and bridge methods
46
	// Synthetics are separated into 4 categories: methods, super methods, fields, class literals and bridge methods
46
	// if a new category is added, also increment MAX_SYNTHETICS
47
	// if a new category is added, also increment MAX_SYNTHETICS
Lines 62-67 Link Here
62
	this.modifiers = scope.referenceContext.modifiers;
63
	this.modifiers = scope.referenceContext.modifiers;
63
	this.sourceName = scope.referenceContext.name;
64
	this.sourceName = scope.referenceContext.name;
64
	this.scope = scope;
65
	this.scope = scope;
66
	this.cumulativeFieldCount = 0;
65
67
66
	// expect the fields & methods to be initialized correctly later
68
	// expect the fields & methods to be initialized correctly later
67
	this.fields = Binding.UNINITIALIZED_FIELDS;
69
	this.fields = Binding.UNINITIALIZED_FIELDS;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java (+4 lines)
Lines 37-42 Link Here
37
		return this.constant;
37
		return this.constant;
38
	}
38
	}
39
39
40
	public int getAnalysisId(int maxFieldCount) {
41
		return this.id + maxFieldCount;
42
	}
43
40
	public abstract AnnotationBinding[] getAnnotations();
44
	public abstract AnnotationBinding[] getAnnotations();
41
45
42
	public final boolean isBlankFinal(){
46
	public final boolean isBlankFinal(){

Return to bug 247564