8039026: Definitely unassigned field can be accessed
Reviewed-by: vromero, jlahoda
This commit is contained in:
parent
6c24c7e153
commit
218ce31908
@ -195,6 +195,9 @@ public enum Source {
|
|||||||
public boolean allowObjectToPrimitiveCast() {
|
public boolean allowObjectToPrimitiveCast() {
|
||||||
return compareTo(JDK1_7) >= 0;
|
return compareTo(JDK1_7) >= 0;
|
||||||
}
|
}
|
||||||
|
public boolean enforceThisDotInit() {
|
||||||
|
return compareTo(JDK1_7) >= 0;
|
||||||
|
}
|
||||||
public boolean allowPoly() {
|
public boolean allowPoly() {
|
||||||
return compareTo(JDK1_8) >= 0;
|
return compareTo(JDK1_8) >= 0;
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,7 @@ public class Flow {
|
|||||||
private final boolean allowImprovedRethrowAnalysis;
|
private final boolean allowImprovedRethrowAnalysis;
|
||||||
private final boolean allowImprovedCatchAnalysis;
|
private final boolean allowImprovedCatchAnalysis;
|
||||||
private final boolean allowEffectivelyFinalInInnerClasses;
|
private final boolean allowEffectivelyFinalInInnerClasses;
|
||||||
|
private final boolean enforceThisDotInit;
|
||||||
|
|
||||||
public static Flow instance(Context context) {
|
public static Flow instance(Context context) {
|
||||||
Flow instance = context.get(flowKey);
|
Flow instance = context.get(flowKey);
|
||||||
@ -206,7 +207,7 @@ public class Flow {
|
|||||||
|
|
||||||
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
||||||
new AliveAnalyzer().analyzeTree(env, 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 FlowAnalyzer().analyzeTree(env, make);
|
||||||
new CaptureAnalyzer().analyzeTree(env, make);
|
new CaptureAnalyzer().analyzeTree(env, make);
|
||||||
}
|
}
|
||||||
@ -238,7 +239,7 @@ public class Flow {
|
|||||||
//related errors, which will allow for more errors to be detected
|
//related errors, which will allow for more errors to be detected
|
||||||
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
|
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
|
||||||
try {
|
try {
|
||||||
new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
|
new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env);
|
||||||
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
|
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
|
||||||
flowAnalyzer.analyzeTree(env, that, make);
|
flowAnalyzer.analyzeTree(env, that, make);
|
||||||
return flowAnalyzer.inferredThrownTypes;
|
return flowAnalyzer.inferredThrownTypes;
|
||||||
@ -288,6 +289,7 @@ public class Flow {
|
|||||||
allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
|
allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
|
||||||
allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
|
allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
|
||||||
allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
|
allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
|
||||||
|
enforceThisDotInit = source.enforceThisDotInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1422,6 +1424,8 @@ public class Flow {
|
|||||||
|
|
||||||
protected Names names;
|
protected Names names;
|
||||||
|
|
||||||
|
final boolean enforceThisDotInit;
|
||||||
|
|
||||||
public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
|
public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
|
||||||
|
|
||||||
final Bits inits;
|
final Bits inits;
|
||||||
@ -1444,7 +1448,7 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
|
public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names, boolean enforceThisDotInit) {
|
||||||
this.inits = inits;
|
this.inits = inits;
|
||||||
uninits = new Bits();
|
uninits = new Bits();
|
||||||
uninitsTry = new Bits();
|
uninitsTry = new Bits();
|
||||||
@ -1454,6 +1458,7 @@ public class Flow {
|
|||||||
uninitsWhenFalse = new Bits(true);
|
uninitsWhenFalse = new Bits(true);
|
||||||
this.syms = syms;
|
this.syms = syms;
|
||||||
this.names = names;
|
this.names = names;
|
||||||
|
this.enforceThisDotInit = enforceThisDotInit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInitialConstructor = false;
|
private boolean isInitialConstructor = false;
|
||||||
@ -2275,12 +2280,34 @@ public class Flow {
|
|||||||
|
|
||||||
public void visitAssign(JCAssign tree) {
|
public void visitAssign(JCAssign tree) {
|
||||||
JCTree lhs = TreeInfo.skipParens(tree.lhs);
|
JCTree lhs = TreeInfo.skipParens(tree.lhs);
|
||||||
if (!(lhs instanceof JCIdent)) {
|
if (!isIdentOrThisDotIdent(lhs))
|
||||||
scanExpr(lhs);
|
scanExpr(lhs);
|
||||||
}
|
|
||||||
scanExpr(tree.rhs);
|
scanExpr(tree.rhs);
|
||||||
letInit(lhs);
|
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) {
|
public void visitAssignop(JCAssignOp tree) {
|
||||||
scanExpr(tree.lhs);
|
scanExpr(tree.lhs);
|
||||||
@ -2410,8 +2437,8 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
|
public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names, boolean enforceThisDotInit) {
|
||||||
super(new Bits(), syms, names);
|
super(new Bits(), syms, names, enforceThisDotInit);
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.lint = lint;
|
this.lint = lint;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2812,7 +2812,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
|
private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
|
||||||
super(new LVTBits(), syms, names);
|
super(new LVTBits(), syms, names, false);
|
||||||
lvtInits = (LVTBits)inits;
|
lvtInits = (LVTBits)inits;
|
||||||
this.lvtRanges = lvtRanges;
|
this.lvtRanges = lvtRanges;
|
||||||
}
|
}
|
||||||
|
21
langtools/test/tools/javac/DefiniteAssignment/T8039026.java
Normal file
21
langtools/test/tools/javac/DefiniteAssignment/T8039026.java
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user