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

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java (-1 / +272 lines)
Lines 47-53 Link Here
47
// Only the highest compliance level is run; add the VM argument
47
// Only the highest compliance level is run; add the VM argument
48
// -Dcompliance=1.4 (for example) to lower it if needed
48
// -Dcompliance=1.4 (for example) to lower it if needed
49
static {
49
static {
50
//		TESTS_NAMES = new String[] { "test358827" };
50
//		TESTS_NAMES = new String[] { "testBug360328" };
51
//		TESTS_NUMBERS = new int[] { 561 };
51
//		TESTS_NUMBERS = new int[] { 561 };
52
//		TESTS_RANGE = new int[] { 1, 2049 };
52
//		TESTS_RANGE = new int[] { 1, 2049 };
53
}
53
}
Lines 15124-15127 Link Here
15124
			true,
15124
			true,
15125
			compilerOptions);
15125
			compilerOptions);
15126
}
15126
}
15127
// Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop)
15128
public void testBug360328() {
15129
	Map customOptions = getCompilerOptions();
15130
	customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
15131
	customOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR);
15132
	runNegativeTest(
15133
		true, /* flushOutputDir */
15134
		new String[] {
15135
			"X.java",
15136
			"public class X {\n" +
15137
			"    void print4() {\n" +
15138
			"        final String s1 = \"\";\n" +
15139
			"        for (int i=0; i<4; i++)\n" +
15140
			"            new Runnable() {\n" +
15141
			"                public void run() {\n" +
15142
			"                     if (s1 != null)\n" +
15143
			"                         s1.toString();\n" +
15144
			"                }\n" +
15145
			"            }.run();\n" +
15146
			"    }\n" +
15147
			"    void print16(boolean b) {\n" +
15148
			"        final String s3 = b ? null : \"\";\n" +
15149
			"        for (int i=0; i<16; i++)\n" +
15150
			"            new Runnable() {\n" +
15151
			"                public void run() {\n" +
15152
			"                     s3.toString();\n" +
15153
			"                }\n" +
15154
			"            }.run();\n" +
15155
			"    }\n" +
15156
			"    void print23() {\n" +
15157
			"        final String s23 = null;\n" +
15158
			"        for (int i=0; i<23; i++)\n" +
15159
			"            new Runnable() {\n" +
15160
			"                public void run() {\n" +
15161
			"                     s23.toString();\n" +
15162
			"                }\n" +
15163
			"            }.run();\n" +
15164
			"    }\n" +
15165
			"}\n",
15166
15167
		},
15168
		null, /* classLibs */
15169
		customOptions,
15170
		"----------\n" +
15171
		"1. ERROR in X.java (at line 7)\n" +
15172
		"	if (s1 != null)\n" +
15173
		"	    ^^\n" +
15174
		"Redundant null check: The variable s1 cannot be null at this location\n" +
15175
		"----------\n" +
15176
		"2. ERROR in X.java (at line 17)\n" +
15177
		"	s3.toString();\n" +
15178
		"	^^\n" +
15179
		"Potential null pointer access: The variable s3 may be null at this location\n" +
15180
		"----------\n" +
15181
		"3. ERROR in X.java (at line 26)\n" +
15182
		"	s23.toString();\n" +
15183
		"	^^^\n" +
15184
		"Null pointer access: The variable s23 can only be null at this location\n" +
15185
		"----------\n",
15186
		"",/* expected output */
15187
		"",/* expected error */
15188
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15189
}
15190
// Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop)
15191
// constructors
15192
public void testBug360328b() {
15193
	Map customOptions = getCompilerOptions();
15194
	customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
15195
	customOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR);
15196
	runNegativeTest(
15197
		true, /* flushOutputDir */
15198
		new String[] {
15199
			"X.java",
15200
			"public class X {\n" +
15201
			"    void print4() {\n" +
15202
			"        final String s1 = \"\";\n" +
15203
			"        for (int i=0; i<4; i++) {\n" +
15204
			"            class R {\n" +
15205
			"                public R() {\n" +
15206
			"                     if (s1 != null)\n" +
15207
			"                         s1.toString();\n" +
15208
			"                }\n" +
15209
			"            };\n" +
15210
			"            new R();\n" +
15211
			"        }\n" +
15212
			"    }\n" +
15213
			"    void print16(boolean b) {\n" +
15214
			"        final String s3 = b ? null : \"\";\n" +
15215
			"        int i=0; while (i++<16) {\n" +
15216
			"            class R {\n" +
15217
			"                public R() {\n" +
15218
			"                     s3.toString();\n" +
15219
			"                }\n" +
15220
			"            };\n" +
15221
			"            new R();\n" +
15222
			"        };\n" +
15223
			"    }\n" +
15224
			"    void print23() {\n" +
15225
			"        final String s23 = null;\n" +
15226
			"        for (int i=0; i<23; i++) {\n" +
15227
			"            class R {\n" +
15228
			"                public R() {\n" +
15229
			"                     s23.toString();\n" +
15230
			"                }\n" +
15231
			"            };\n" +
15232
			"            new R();\n" +
15233
			"        };\n" +
15234
			"    }\n" +
15235
			"}\n",
15236
15237
		},
15238
		null, /* classLibs */
15239
		customOptions,
15240
		"----------\n" +
15241
		"1. ERROR in X.java (at line 7)\n" +
15242
		"	if (s1 != null)\n" +
15243
		"	    ^^\n" +
15244
		"Redundant null check: The variable s1 cannot be null at this location\n" +
15245
		"----------\n" +
15246
		"2. ERROR in X.java (at line 19)\n" +
15247
		"	s3.toString();\n" +
15248
		"	^^\n" +
15249
		"Potential null pointer access: The variable s3 may be null at this location\n" +
15250
		"----------\n" +
15251
		"3. ERROR in X.java (at line 30)\n" +
15252
		"	s23.toString();\n" +
15253
		"	^^^\n" +
15254
		"Null pointer access: The variable s23 can only be null at this location\n" +
15255
		"----------\n",
15256
		"",/* expected output */
15257
		"",/* expected error */
15258
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15259
}
15260
// Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop)
15261
// initializers
15262
public void testBug360328c() {
15263
	Map customOptions = getCompilerOptions();
15264
	customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
15265
	customOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR);
15266
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.IGNORE);
15267
	runNegativeTest(
15268
		true, /* flushOutputDir */
15269
		new String[] {
15270
			"X.java",
15271
			"public class X {\n" +
15272
			"    void print4() {\n" +
15273
			"        final String s1 = \"\";\n" +
15274
			"        for (int i=0; i<4; i++) {\n" +
15275
			"            class R {\n" +
15276
			"                String s1R;\n" +
15277
			"                {\n" +
15278
			"                    if (s1 != null)\n" +
15279
			"                         s1R = s1;\n" +
15280
			"                }\n" +
15281
			"            };\n" +
15282
			"            new R();\n" +
15283
			"        }\n" +
15284
			"    }\n" +
15285
			"    void print16(boolean b) {\n" +
15286
			"        final String s3 = b ? null : \"\";\n" +
15287
			"        for (int i=0; i<16; i++) {\n" +
15288
			"            class R {\n" +
15289
			"                String s3R = s3.toString();\n" +
15290
			"            };\n" +
15291
			"            new R();\n" +
15292
			"        };\n" +
15293
			"    }\n" +
15294
			"    void print23() {\n" +
15295
			"        final String s23 = null;\n" +
15296
			"        for (int i=0; i<23; i++) {\n" +
15297
			"            class R {\n" +
15298
			"                String s23R;\n" +
15299
			"                {\n" +
15300
			"                     s23R = s23.toString();\n" +
15301
			"                }\n" +
15302
			"            };\n" +
15303
			"            new R();\n" +
15304
			"        };\n" +
15305
			"    }\n" +
15306
			"}\n",
15307
15308
		},
15309
		null, /* classLibs */
15310
		customOptions,
15311
		"----------\n" +
15312
		"1. ERROR in X.java (at line 8)\n" +
15313
		"	if (s1 != null)\n" +
15314
		"	    ^^\n" +
15315
		"Redundant null check: The variable s1 cannot be null at this location\n" +
15316
		"----------\n" +
15317
		"2. ERROR in X.java (at line 19)\n" +
15318
		"	String s3R = s3.toString();\n" +
15319
		"	             ^^\n" +
15320
		"Potential null pointer access: The variable s3 may be null at this location\n" +
15321
		"----------\n" +
15322
		"3. ERROR in X.java (at line 30)\n" +
15323
		"	s23R = s23.toString();\n" +
15324
		"	       ^^^\n" +
15325
		"Null pointer access: The variable s23 can only be null at this location\n" +
15326
		"----------\n",
15327
		"",/* expected output */
15328
		"",/* expected error */
15329
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15330
}
15331
// Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop)
15332
// try-finally instead of loop
15333
public void testBug360328d() {
15334
	Map customOptions = getCompilerOptions();
15335
	customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
15336
	customOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR);
15337
	runNegativeTest(
15338
		true, /* flushOutputDir */
15339
		new String[] {
15340
			"X.java",
15341
			"public class X {\n" +
15342
			"    void print4() {\n" +
15343
			"        final String s1 = \"\";\n" +
15344
			"        try { } finally {\n" +
15345
			"            new Runnable() {\n" +
15346
			"                public void run() {\n" +
15347
			"                     if (s1 != null)\n" +
15348
			"                         s1.toString();\n" +
15349
			"                }\n" +
15350
			"            }.run();\n" +
15351
			"        }\n" +
15352
			"    }\n" +
15353
			"    void print16(boolean b) {\n" +
15354
			"        final String s3 = b ? null : \"\";\n" +
15355
			"        try { } finally {\n" +
15356
			"            new Runnable() {\n" +
15357
			"                public void run() {\n" +
15358
			"                     s3.toString();\n" +
15359
			"                }\n" +
15360
			"            }.run();\n" +
15361
			"        }\n" +
15362
			"    }\n" +
15363
			"    void print23() {\n" +
15364
			"        final String s23 = null;\n" +
15365
			"        try { } finally {\n" +
15366
			"            new Runnable() {\n" +
15367
			"                public void run() {\n" +
15368
			"                     s23.toString();\n" +
15369
			"                }\n" +
15370
			"            }.run();\n" +
15371
			"        }\n" +
15372
			"    }\n" +
15373
			"}\n",
15374
15375
		},
15376
		null, /* classLibs */
15377
		customOptions,
15378
		"----------\n" +
15379
		"1. ERROR in X.java (at line 7)\n" +
15380
		"	if (s1 != null)\n" +
15381
		"	    ^^\n" +
15382
		"Redundant null check: The variable s1 cannot be null at this location\n" +
15383
		"----------\n" +
15384
		"2. ERROR in X.java (at line 18)\n" +
15385
		"	s3.toString();\n" +
15386
		"	^^\n" +
15387
		"Potential null pointer access: The variable s3 may be null at this location\n" +
15388
		"----------\n" +
15389
		"3. ERROR in X.java (at line 28)\n" +
15390
		"	s23.toString();\n" +
15391
		"	^^^\n" +
15392
		"Null pointer access: The variable s23 can only be null at this location\n" +
15393
		"----------\n",
15394
		"",/* expected output */
15395
		"",/* expected error */
15396
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15397
}
15127
}
15398
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java (-4 lines)
Lines 12-19 Link Here
12
12
13
import org.eclipse.jdt.core.compiler.*;
13
import org.eclipse.jdt.core.compiler.*;
14
import org.eclipse.jdt.internal.compiler.*;
14
import org.eclipse.jdt.internal.compiler.*;
15
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
16
import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
17
import org.eclipse.jdt.internal.compiler.impl.*;
15
import org.eclipse.jdt.internal.compiler.impl.*;
18
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
19
import org.eclipse.jdt.internal.compiler.codegen.*;
17
import org.eclipse.jdt.internal.compiler.codegen.*;
Lines 68-75 Link Here
68
				throw new AbortMethod(this.compilationResult, problem);
66
				throw new AbortMethod(this.compilationResult, problem);
69
		}
67
		}
70
	}
68
	}
71
72
	public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info);
73
69
74
	/**
70
	/**
75
	 * Bind and add argument's binding into the scope of the method
71
	 * Bind and add argument's binding into the scope of the method
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java (-3 / +3 lines)
Lines 16-23 Link Here
16
import org.eclipse.jdt.internal.compiler.CompilationResult;
16
import org.eclipse.jdt.internal.compiler.CompilationResult;
17
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
17
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
18
import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
18
import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
19
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
19
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
20
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
20
import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
21
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
21
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22
import org.eclipse.jdt.internal.compiler.lookup.Binding;
22
import org.eclipse.jdt.internal.compiler.lookup.Binding;
23
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
23
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
Lines 44-50 Link Here
44
		super(compilationResult);
44
		super(compilationResult);
45
	}
45
	}
46
46
47
	public void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo flowInfo) {
47
	public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) {
48
		// starting of the code analysis for methods
48
		// starting of the code analysis for methods
49
		if (this.ignoreFurtherInvestigation)
49
		if (this.ignoreFurtherInvestigation)
50
			return;
50
			return;
Lines 72-78 Link Here
72
72
73
			ExceptionHandlingFlowContext methodContext =
73
			ExceptionHandlingFlowContext methodContext =
74
				new ExceptionHandlingFlowContext(
74
				new ExceptionHandlingFlowContext(
75
					initializationContext,
75
					flowContext,
76
					this,
76
					this,
77
					this.binding.thrownExceptions,
77
					this.binding.thrownExceptions,
78
					null,
78
					null,
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-3 / +9 lines)
Lines 625-631 Link Here
625
			this.scope.problemReporter().unusedPrivateType(this);
625
			this.scope.problemReporter().unusedPrivateType(this);
626
		}
626
		}
627
	}
627
	}
628
	InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, flowInfo, flowContext, this.initializerScope);
628
	// for local classes we use the flowContext as our parent, but never use an initialization context for this purpose
629
	// see Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop)
630
	FlowContext parentContext = (flowContext instanceof InitializationFlowContext) ? null : flowContext;
631
	InitializationFlowContext initializerContext = new InitializationFlowContext(parentContext, this, flowInfo, flowContext, this.initializerScope);
632
	// no static initializer in local classes, thus no need to set parent.
629
	InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, flowInfo, flowContext, this.staticInitializerScope);
633
	InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, flowInfo, flowContext, this.staticInitializerScope);
630
	FlowInfo nonStaticFieldInfo = flowInfo.unconditionalFieldLessCopy();
634
	FlowInfo nonStaticFieldInfo = flowInfo.unconditionalFieldLessCopy();
631
	FlowInfo staticFieldInfo = flowInfo.unconditionalFieldLessCopy();
635
	FlowInfo staticFieldInfo = flowInfo.unconditionalFieldLessCopy();
Lines 684-691 Link Here
684
			if (method.ignoreFurtherInvestigation)
688
			if (method.ignoreFurtherInvestigation)
685
				continue;
689
				continue;
686
			if (method.isInitializationMethod()) {
690
			if (method.isInitializationMethod()) {
691
				// pass down the appropriate initializerContext:
687
				if (method.isStatic()) { // <clinit>
692
				if (method.isStatic()) { // <clinit>
688
					method.analyseCode(
693
					((Clinit)method).analyseCode(
689
						this.scope,
694
						this.scope,
690
						staticInitializerContext,
695
						staticInitializerContext,
691
						staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo));
696
						staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo));
Lines 693-699 Link Here
693
					((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode());
698
					((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode());
694
				}
699
				}
695
			} else { // regular method
700
			} else { // regular method
696
				method.analyseCode(this.scope, null, flowInfo.copy());
701
				// pass down the parentFlowContext (NOT an initializer context, see above):
702
				((MethodDeclaration)method).analyseCode(this.scope, parentContext, flowInfo.copy());
697
			}
703
			}
698
		}
704
		}
699
	}
705
	}

Return to bug 360328