Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8263614: javac allows local variables to be accessed from a static context #4004

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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() {