8039026: Definitely unassigned field can be accessed
Reviewed-by: vromero, jlahoda
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Fri Apr 25 13:08:41 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Fri Apr 25 22:00:58 2014 +0100
@@ -195,6 +195,9 @@
public boolean allowObjectToPrimitiveCast() {
return compareTo(JDK1_7) >= 0;
}
+ public boolean enforceThisDotInit() {
+ return compareTo(JDK1_7) >= 0;
+ }
public boolean allowPoly() {
return compareTo(JDK1_8) >= 0;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Apr 25 13:08:41 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Apr 25 22:00:58 2014 +0100
@@ -196,6 +196,7 @@
private final boolean allowImprovedRethrowAnalysis;
private final boolean allowImprovedCatchAnalysis;
private final boolean allowEffectivelyFinalInInnerClasses;
+ private final boolean enforceThisDotInit;
public static Flow instance(Context context) {
Flow instance = context.get(flowKey);
@@ -206,7 +207,7 @@
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
- new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
+ new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
@@ -238,7 +239,7 @@
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
- new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
+ new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
@@ -288,6 +289,7 @@
allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
+ enforceThisDotInit = source.enforceThisDotInit();
}
/**
@@ -1422,6 +1424,8 @@
protected Names names;
+ final boolean enforceThisDotInit;
+
public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
final Bits inits;
@@ -1444,7 +1448,7 @@
}
}
- public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
+ public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names, boolean enforceThisDotInit) {
this.inits = inits;
uninits = new Bits();
uninitsTry = new Bits();
@@ -1454,6 +1458,7 @@
uninitsWhenFalse = new Bits(true);
this.syms = syms;
this.names = names;
+ this.enforceThisDotInit = enforceThisDotInit;
}
private boolean isInitialConstructor = false;
@@ -2275,12 +2280,34 @@
public void visitAssign(JCAssign tree) {
JCTree lhs = TreeInfo.skipParens(tree.lhs);
- if (!(lhs instanceof JCIdent)) {
+ if (!isIdentOrThisDotIdent(lhs))
scanExpr(lhs);
- }
scanExpr(tree.rhs);
letInit(lhs);
}
+ private boolean isIdentOrThisDotIdent(JCTree lhs) {
+ if (lhs.hasTag(IDENT))
+ return true;
+ if (!lhs.hasTag(SELECT))
+ return false;
+
+ JCFieldAccess fa = (JCFieldAccess)lhs;
+ return fa.selected.hasTag(IDENT) &&
+ ((JCIdent)fa.selected).name == names._this;
+ }
+
+ // check fields accessed through this.<field> are definitely
+ // assigned before reading their value
+ public void visitSelect(JCFieldAccess tree) {
+ super.visitSelect(tree);
+ if (enforceThisDotInit &&
+ tree.selected.hasTag(IDENT) &&
+ ((JCIdent)tree.selected).name == names._this &&
+ tree.sym.kind == VAR)
+ {
+ checkInit(tree.pos(), (VarSymbol)tree.sym);
+ }
+ }
public void visitAssignop(JCAssignOp tree) {
scanExpr(tree.lhs);
@@ -2410,8 +2437,8 @@
}
}
- public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
- super(new Bits(), syms, names);
+ public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names, boolean enforceThisDotInit) {
+ super(new Bits(), syms, names, enforceThisDotInit);
this.log = log;
this.lint = lint;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Apr 25 13:08:41 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Apr 25 22:00:58 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2812,7 +2812,7 @@
}
private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
- super(new LVTBits(), syms, names);
+ super(new LVTBits(), syms, names, false);
lvtInits = (LVTBits)inits;
this.lvtRanges = lvtRanges;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/DefiniteAssignment/T8039026.java Fri Apr 25 22:00:58 2014 +0100
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8039026
+ * @summary Definitely unassigned field can be accessed
+ * @compile/fail/ref=T8039026.out -XDrawDiagnostics T8039026.java
+ */
+
+public class T8039026 {
+ final int x,y,z;
+ final int a = this.y; // <- error
+ {
+ int b = true ? this.x : 0; // <- error
+ System.out.println(this.x); // <- error
+ this.y = 1;
+ }
+ T8039026() {
+ this.x = 1; // <- no error!
+ this.y = 1; // <- error
+ this.z = this.x; // <- no error
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/DefiniteAssignment/T8039026.out Fri Apr 25 22:00:58 2014 +0100
@@ -0,0 +1,4 @@
+T8039026.java:10:23: compiler.err.var.might.not.have.been.initialized: y
+T8039026.java:12:28: compiler.err.var.might.not.have.been.initialized: x
+T8039026.java:18:13: compiler.err.var.might.already.be.assigned: y
+3 errors