Skip to content
Permalink
Browse files
8263614: javac allows local variables to be accessed from a static co…
…ntext

Reviewed-by: mcimadamore
  • Loading branch information
Vicente Romero committed May 17, 2021
1 parent ea36836 commit b8856b1c47895eae0a5563ee1a8ac454863ee0a6
Showing with 91 additions and 36 deletions.
  1. +17 −36 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
  2. +74 −0 test/langtools/tools/javac/records/RecordCompilationTests.java
@@ -1488,30 +1488,24 @@ Symbol findVar(Env<AttrContext> env, Name name) {
boolean staticOnly = false;
while (env1.outer != null) {
Symbol sym = null;
if (isStatic(env1)) staticOnly = true;
for (Symbol s : env1.info.scope.getSymbolsByName(name)) {
if (s.kind == VAR && (s.flags_field & SYNTHETIC) == 0) {
sym = s;
if (staticOnly) {
return new StaticError(sym);
}
break;
}
}
if (isStatic(env1)) staticOnly = true;
if (sym == null) {
sym = findField(env1, env1.enclClass.sym.type, name, env1.enclClass.sym);
}
if (sym.exists()) {
if (staticOnly &&
(sym.flags() & STATIC) == 0 &&
sym.kind == VAR &&
// if it is a field
(sym.owner.kind == TYP ||
// or it is a local variable but it is not declared inside of the static local type
// then error
allowRecords &&
(sym.owner.kind == MTH) &&
env1 != env &&
!isInnerClassOfMethod(sym.owner, env.tree.hasTag(CLASSDEF) ?
((JCClassDecl)env.tree).sym :
env.enclClass.sym)))
sym.kind == VAR &&
sym.owner.kind == TYP &&
(sym.flags() & STATIC) == 0)
return new StaticError(sym);
else
return sym;
@@ -2313,35 +2307,22 @@ Symbol findGlobalType(Env<AttrContext> env, Scope scope, Name name, RecoveryLoad
return bestSoFar;
}

Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Name name, boolean staticOnly) {
for (Symbol sym : currentEnv.info.scope.getSymbolsByName(name)) {
Symbol findTypeVar(Env<AttrContext> env, Name name, boolean staticOnly) {
for (Symbol sym : env.info.scope.getSymbolsByName(name)) {
if (sym.kind == TYP) {
if (staticOnly &&
sym.type.hasTag(TYPEVAR) &&
((sym.owner.kind == TYP) ||
// are we trying to access a TypeVar defined in a method from a local static type: interface, enum or record?
allowRecords &&
(sym.owner.kind == MTH &&
currentEnv != originalEnv &&
!isInnerClassOfMethod(sym.owner, originalEnv.tree.hasTag(CLASSDEF) ?
((JCClassDecl)originalEnv.tree).sym :
originalEnv.enclClass.sym)))) {
if (sym.type.hasTag(TYPEVAR) &&
(staticOnly || (isStatic(env) && sym.owner.kind == TYP)))
// if staticOnly is set, it means that we have recursed through a static declaration,
// so type variable symbols should not be accessible. If staticOnly is unset, but
// we are in a static declaration (field or method), we should not allow type-variables
// defined in the enclosing class to "leak" into this context.
return new StaticError(sym);
}
return sym;
}
}
return typeNotFound;
}

boolean isInnerClassOfMethod(Symbol msym, Symbol csym) {
while (csym.owner != msym) {
if (csym.isStatic()) return false;
csym = csym.owner.enclClass();
}
return (csym.owner == msym && !csym.isStatic());
}

/** Find an unqualified type symbol.
* @param env The current environment.
* @param name The type's name.
@@ -2353,9 +2334,9 @@ Symbol findType(Env<AttrContext> env, Name name) {
Symbol sym;
boolean staticOnly = false;
for (Env<AttrContext> env1 = env; env1.outer != null; env1 = env1.outer) {
if (isStatic(env1)) staticOnly = true;
// First, look for a type variable and the first member type
final Symbol tyvar = findTypeVar(env1, env, name, staticOnly);
final Symbol tyvar = findTypeVar(env1, name, staticOnly);
if (isStatic(env1)) staticOnly = true;
sym = findImmediateMemberType(env1, env1.enclClass.sym.type,
name, env1.enclClass.sym);

@@ -746,12 +746,24 @@ void test(T t) {}
}
""",
"""
record R() {
void test(U u) {}
}
""",
"""
record R() {
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
record R() {
void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
interface I {
@@ -801,12 +813,24 @@ default void test(T t) {}
}
""",
"""
interface I {
default void test(U u) {}
}
""",
"""
interface I {
default void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
interface I {
default void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
enum E {
@@ -863,13 +887,27 @@ void test(T t) {}
}
""",
"""
enum E {
A;
void test(U u) {}
}
""",
"""
enum E {
A;
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
enum E {
A;
void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
static class SC {
@@ -919,11 +957,23 @@ void test(T t) {}
}
""",
"""
static class SC {
void test(U u) {}
}
""",
"""
static class SC {
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
static class SC {
void test1() {
class X { void test2(U u) {} }
}
}
"""
)) {
assertFail("compiler.err.non-static.cant.be.ref",
@@ -965,6 +1015,30 @@ static void m() {}
}
"""
);

// but still non-static declarations can't be accessed from a static method inside a local class
for (String s : List.of(
"System.out.println(localVar)",
"System.out.println(param)",
"System.out.println(field)",
"T t",
"U u"
)) {
assertFail("compiler.err.non-static.cant.be.ref",
"""
class C<T> {
int field = 0;
<U> void foo(int param) {
int localVar = 1;
class Local {
static void m() {
#S;
}
}
}
}
""".replaceFirst("#S", s));
}
}

public void testReturnInCanonical_Compact() {

0 comments on commit b8856b1

Please sign in to comment.