8247790: javac shouldn't allow type variable references from local static declarations
Reviewed-by: jlahoda
This commit is contained in:
parent
fd206e1e7e
commit
bcd4690bc3
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac/records
@ -105,6 +105,7 @@ public class Resolve {
|
||||
JCDiagnostic.Factory diags;
|
||||
public final boolean allowFunctionalInterfaceMostSpecific;
|
||||
public final boolean allowModules;
|
||||
public final boolean allowRecords;
|
||||
public final boolean checkVarargsAccessAfterResolution;
|
||||
private final boolean compactMethodDiags;
|
||||
private final boolean allowLocalVariableTypeInference;
|
||||
@ -147,6 +148,8 @@ public class Resolve {
|
||||
Feature.POST_APPLICABILITY_VARARGS_ACCESS_CHECK.allowedInSource(source);
|
||||
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
|
||||
allowModules = Feature.MODULES.allowedInSource(source);
|
||||
allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
|
||||
Feature.RECORDS.allowedInSource(source);
|
||||
}
|
||||
|
||||
/** error symbols, which are returned when resolution fails
|
||||
@ -1488,15 +1491,18 @@ public class Resolve {
|
||||
}
|
||||
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
|
||||
// only records so far, then error
|
||||
// then error
|
||||
allowRecords &&
|
||||
(sym.owner.kind == MTH) &&
|
||||
(env.enclClass.sym.flags() & STATIC) != 0 &&
|
||||
sym.enclClass() != env.enclClass.sym) &&
|
||||
(sym.flags() & STATIC) == 0)
|
||||
env1 != env &&
|
||||
!isInnerClassOfMethod(sym.owner, env.tree.hasTag(CLASSDEF) ?
|
||||
((JCClassDecl)env.tree).sym :
|
||||
env.enclClass.sym)))
|
||||
return new StaticError(sym);
|
||||
else
|
||||
return sym;
|
||||
@ -2261,19 +2267,37 @@ public class Resolve {
|
||||
return bestSoFar;
|
||||
}
|
||||
|
||||
Symbol findTypeVar(Env<AttrContext> env, Name name, boolean staticOnly) {
|
||||
for (Symbol sym : env.info.scope.getSymbolsByName(name)) {
|
||||
Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Name name, boolean staticOnly) {
|
||||
for (Symbol sym : currentEnv.info.scope.getSymbolsByName(name)) {
|
||||
if (sym.kind == TYP) {
|
||||
if (staticOnly &&
|
||||
sym.type.hasTag(TYPEVAR) &&
|
||||
sym.owner.kind == TYP)
|
||||
((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)))) {
|
||||
return new StaticError(sym);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
return typeNotFound;
|
||||
}
|
||||
|
||||
boolean isInnerClassOfMethod(Symbol msym, Symbol csym) {
|
||||
if (csym.owner == msym && !csym.isStatic()) {
|
||||
return true;
|
||||
} else if (csym.owner.kind == TYP) {
|
||||
return isInnerClassOfMethod(msym, csym.owner);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find an unqualified type symbol.
|
||||
* @param env The current environment.
|
||||
* @param name The type's name.
|
||||
@ -2287,7 +2311,7 @@ public class Resolve {
|
||||
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, name, staticOnly);
|
||||
final Symbol tyvar = findTypeVar(env1, env, name, staticOnly);
|
||||
sym = findImmediateMemberType(env1, env1.enclClass.sym.type,
|
||||
name, env1.enclClass.sym);
|
||||
|
||||
|
@ -488,7 +488,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
// Cant capture locals
|
||||
// Can't capture locals
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R { \n" +
|
||||
" void m(int y) { \n" +
|
||||
@ -504,6 +504,150 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m() {\n" +
|
||||
" String hello = \"hello\";\n" +
|
||||
" interface I {\n" +
|
||||
" public default void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(hello);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m() {\n" +
|
||||
" String hello = \"hello\";\n" +
|
||||
" record R(int i) {\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(hello);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m() {\n" +
|
||||
" String hello = \"hello\";\n" +
|
||||
" enum E {\n" +
|
||||
" A;\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(hello);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m(String param) {\n" +
|
||||
" interface I {\n" +
|
||||
" public default void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(param);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m(String param) {\n" +
|
||||
" record R(int i) {\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(param);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static void m(String param) {\n" +
|
||||
" enum E {\n" +
|
||||
" A;\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(param);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" String instanceField = \"instance\";\n" +
|
||||
" public static void m() {\n" +
|
||||
" interface I {\n" +
|
||||
" public default void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(instanceField);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" String instanceField = \"instance\";\n" +
|
||||
" public static void m(String param) {\n" +
|
||||
" record R(int i) {\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(instanceField);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" String instanceField = \"instance\";\n" +
|
||||
" public static void m(String param) {\n" +
|
||||
" enum E {\n" +
|
||||
" A;\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" System.err.println(instanceField);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
// instance fields
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R { \n" +
|
||||
@ -521,6 +665,114 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R {\n" +
|
||||
" static <U> U make(U u) { //method is static\n" +
|
||||
" interface Checker {\n" +
|
||||
" void check(U u);\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class LocalEnum {\n" +
|
||||
" static <U> U getAndSet(U u) { //method is static\n" +
|
||||
" enum X {\n" +
|
||||
" A;\n" +
|
||||
" U u;\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}\n");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R {\n" +
|
||||
" static <U> U make(U u) { //method is static\n" +
|
||||
" record Checker() {\n" +
|
||||
" void check(U u);\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R {\n" +
|
||||
" <U> U make(U u) { // enclosing method is not static\n" +
|
||||
" interface Checker {\n" +
|
||||
" void check(U u);\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class LocalEnum {\n" +
|
||||
" <U> U getAndSet(U u) { // enclosing method is not static\n" +
|
||||
" enum X {\n" +
|
||||
" A;\n" +
|
||||
" U u;\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}\n");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R {\n" +
|
||||
" <U> U make(U u) { // enclosing method is not static\n" +
|
||||
" record Checker() {\n" +
|
||||
" void check(U u);\n" +
|
||||
" }\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static <T> void main(String[] args) {\n" +
|
||||
" interface I {\n" +
|
||||
" public default void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" T t = null;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static <T> void main(String[] args) {\n" +
|
||||
" record R(int i) {\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" T t = null;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class C {\n" +
|
||||
" public static <T> void main(String[] args) {\n" +
|
||||
" enum E {\n" +
|
||||
" A;\n" +
|
||||
" public void test1() {\n" +
|
||||
" class X {\n" +
|
||||
" public void test2() {\n" +
|
||||
" T t = null;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
// but static fields are OK
|
||||
assertOK("class R { \n" +
|
||||
" static int z = 0;\n" +
|
||||
|
Loading…
x
Reference in New Issue
Block a user