8258515: javac should issue an error if an annotation is nested in a local class or interface
Reviewed-by: jjg
This commit is contained in:
parent
cb5a6b1a7d
commit
47c180da43
@ -439,10 +439,10 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
* Also includes fields of inner classes which are in
|
||||
* turn local to a method or variable initializer.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
public boolean isDirectlyOrIndirectlyLocal() {
|
||||
return
|
||||
(owner.kind.matches(KindSelector.VAL_MTH) ||
|
||||
(owner.kind == TYP && owner.isLocal()));
|
||||
(owner.kind == TYP && owner.isDirectlyOrIndirectlyLocal()));
|
||||
}
|
||||
|
||||
/** Has this symbol an empty name? This includes anonymous
|
||||
@ -760,7 +760,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
public Symbol baseSymbol() { return other; }
|
||||
public Type erasure(Types types) { return other.erasure(types); }
|
||||
public Type externalType(Types types) { return other.externalType(types); }
|
||||
public boolean isLocal() { return other.isLocal(); }
|
||||
public boolean isDirectlyOrIndirectlyLocal() { return other.isDirectlyOrIndirectlyLocal(); }
|
||||
public boolean isConstructor() { return other.isConstructor(); }
|
||||
public Name getQualifiedName() { return other.getQualifiedName(); }
|
||||
public Name flatName() { return other.flatName(); }
|
||||
|
@ -5165,7 +5165,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c.isLocal() && !c.isEnum()) {
|
||||
if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local));
|
||||
}
|
||||
|
||||
|
@ -1216,7 +1216,8 @@ public class Check {
|
||||
implicit |= sym.owner.flags_field & STRICTFP;
|
||||
break;
|
||||
case TYP:
|
||||
if (sym.owner.kind.matches(KindSelector.VAL_MTH)) {
|
||||
if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
|
||||
(sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
|
||||
boolean implicitlyStatic = !sym.isAnonymous() &&
|
||||
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
|
||||
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
|
||||
@ -1225,7 +1226,7 @@ public class Check {
|
||||
implicit = implicitlyStatic ? STATIC : implicit;
|
||||
} else if (sym.owner.kind == TYP) {
|
||||
// statics in inner classes are allowed only if records are allowed too
|
||||
mask = ((flags & STATIC) != 0) && allowRecords ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
|
||||
mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
|
||||
if (sym.owner.owner.kind == PCK ||
|
||||
(sym.owner.flags_field & STATIC) != 0) {
|
||||
mask |= STATIC;
|
||||
@ -2729,7 +2730,7 @@ public class Check {
|
||||
|
||||
if (sym.kind == VAR) {
|
||||
if ((sym.flags() & PARAMETER) != 0 ||
|
||||
sym.isLocal() ||
|
||||
sym.isDirectlyOrIndirectlyLocal() ||
|
||||
sym.name == names._this ||
|
||||
sym.name == names._super) {
|
||||
return;
|
||||
|
@ -498,7 +498,7 @@ public class Enter extends JCTree.Visitor {
|
||||
|
||||
// Add non-local class to uncompleted, to make sure it will be
|
||||
// completed later.
|
||||
if (!c.isLocal() && uncompleted != null) uncompleted.append(c);
|
||||
if (!c.isDirectlyOrIndirectlyLocal() && uncompleted != null) uncompleted.append(c);
|
||||
// System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG
|
||||
|
||||
// Recursively enter all member classes.
|
||||
|
@ -2904,7 +2904,7 @@ public class Flow {
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
JCTree prevTree = currentTree;
|
||||
try {
|
||||
currentTree = tree.sym.isLocal() ? tree : null;
|
||||
currentTree = tree.sym.isDirectlyOrIndirectlyLocal() ? tree : null;
|
||||
super.visitClassDef(tree);
|
||||
} finally {
|
||||
currentTree = prevTree;
|
||||
|
@ -1438,7 +1438,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
public void visitNewClass(JCNewClass tree) {
|
||||
TypeSymbol def = tree.type.tsym;
|
||||
boolean inReferencedClass = currentlyInClass(def);
|
||||
boolean isLocal = def.isLocal();
|
||||
boolean isLocal = def.isDirectlyOrIndirectlyLocal();
|
||||
if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
|
||||
TranslationContext<?> localContext = context();
|
||||
final TypeSymbol outerInstanceSymbol = tree.type.getEnclosingType().tsym;
|
||||
@ -1592,7 +1592,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
while (frameStack2.nonEmpty()) {
|
||||
switch (frameStack2.head.tree.getTag()) {
|
||||
case VARDEF:
|
||||
if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
|
||||
if (((JCVariableDecl)frameStack2.head.tree).sym.isDirectlyOrIndirectlyLocal()) {
|
||||
frameStack2 = frameStack2.tail;
|
||||
break;
|
||||
}
|
||||
@ -2313,7 +2313,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
!receiverAccessible() ||
|
||||
(tree.getMode() == ReferenceMode.NEW &&
|
||||
tree.kind != ReferenceKind.ARRAY_CTOR &&
|
||||
(tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
|
||||
(tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner()));
|
||||
}
|
||||
|
||||
Type generatedRefSig() {
|
||||
|
@ -378,11 +378,11 @@ public class Lower extends TreeTranslator {
|
||||
}
|
||||
|
||||
ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
|
||||
if (!c.isLocal()) {
|
||||
if (!c.isDirectlyOrIndirectlyLocal()) {
|
||||
return null;
|
||||
}
|
||||
Symbol currentOwner = c.owner;
|
||||
while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isLocal()) {
|
||||
while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isDirectlyOrIndirectlyLocal()) {
|
||||
currentOwner = currentOwner.owner;
|
||||
}
|
||||
if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
|
||||
@ -1049,7 +1049,7 @@ public class Lower extends TreeTranslator {
|
||||
}
|
||||
if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
|
||||
return false;
|
||||
} else if (sym.name == names.init && sym.owner.isLocal()) {
|
||||
} else if (sym.name == names.init && sym.owner.isDirectlyOrIndirectlyLocal()) {
|
||||
// private constructor in local class: relax protection
|
||||
sym.flags_field &= ~PRIVATE;
|
||||
return false;
|
||||
@ -2203,7 +2203,7 @@ public class Lower extends TreeTranslator {
|
||||
tree.extending = translate(tree.extending);
|
||||
tree.implementing = translate(tree.implementing);
|
||||
|
||||
if (currentClass.isLocal()) {
|
||||
if (currentClass.isDirectlyOrIndirectlyLocal()) {
|
||||
ClassSymbol encl = currentClass.owner.enclClass();
|
||||
if (encl.trans_local == null) {
|
||||
encl.trans_local = List.nil();
|
||||
@ -2654,7 +2654,7 @@ public class Lower extends TreeTranslator {
|
||||
|
||||
private void visitMethodDefInternal(JCMethodDecl tree) {
|
||||
if (tree.name == names.init &&
|
||||
(currentClass.isInner() || currentClass.isLocal())) {
|
||||
(currentClass.isInner() || currentClass.isDirectlyOrIndirectlyLocal())) {
|
||||
// We are seeing a constructor of an inner class.
|
||||
MethodSymbol m = tree.sym;
|
||||
|
||||
@ -2794,7 +2794,7 @@ public class Lower extends TreeTranslator {
|
||||
|
||||
// If created class is local, add free variables after
|
||||
// explicit constructor arguments.
|
||||
if (c.isLocal()) {
|
||||
if (c.isDirectlyOrIndirectlyLocal()) {
|
||||
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
|
||||
}
|
||||
|
||||
@ -2813,7 +2813,7 @@ public class Lower extends TreeTranslator {
|
||||
if (tree.encl != null) {
|
||||
thisArg = attr.makeNullCheck(translate(tree.encl));
|
||||
thisArg.type = tree.encl.type;
|
||||
} else if (c.isLocal()) {
|
||||
} else if (c.isDirectlyOrIndirectlyLocal()) {
|
||||
// local class
|
||||
thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
|
||||
} else {
|
||||
@ -2996,7 +2996,7 @@ public class Lower extends TreeTranslator {
|
||||
// If we are calling a constructor of a local class, add
|
||||
// free variables after explicit constructor arguments.
|
||||
ClassSymbol c = (ClassSymbol)constructor.owner;
|
||||
if (c.isLocal()) {
|
||||
if (c.isDirectlyOrIndirectlyLocal()) {
|
||||
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
|
||||
}
|
||||
|
||||
@ -3024,7 +3024,7 @@ public class Lower extends TreeTranslator {
|
||||
makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
|
||||
tree.meth = make.Ident(constructor);
|
||||
((JCIdent) tree.meth).name = methName;
|
||||
} else if (c.isLocal() || methName == names._this){
|
||||
} else if (c.isDirectlyOrIndirectlyLocal() || methName == names._this){
|
||||
// local class or this() call
|
||||
thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
|
||||
} else {
|
||||
|
@ -521,7 +521,7 @@ public class TypeEnter implements Completer {
|
||||
WriteableScope baseScope = WriteableScope.create(tree.sym);
|
||||
//import already entered local classes into base scope
|
||||
for (Symbol sym : env.outer.info.scope.getSymbols(NON_RECURSIVE)) {
|
||||
if (sym.isLocal()) {
|
||||
if (sym.isDirectlyOrIndirectlyLocal()) {
|
||||
baseScope.enter(sym);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ public class JNIWriter {
|
||||
|
||||
public boolean needsHeader(ClassSymbol c) {
|
||||
lazyInit();
|
||||
if (c.isLocal() || isSynthetic(c))
|
||||
if (c.isDirectlyOrIndirectlyLocal() || isSynthetic(c))
|
||||
return false;
|
||||
return (checkAll)
|
||||
? needsHeader(c.outermostClass(), true)
|
||||
@ -151,7 +151,7 @@ public class JNIWriter {
|
||||
}
|
||||
|
||||
private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) {
|
||||
if (c.isLocal() || isSynthetic(c))
|
||||
if (c.isDirectlyOrIndirectlyLocal() || isSynthetic(c))
|
||||
return false;
|
||||
|
||||
for (Symbol sym : c.members_field.getSymbols(NON_RECURSIVE)) {
|
||||
|
@ -1027,6 +1027,110 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
public void testAnnoInsideLocalOrAnonymous() {
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
class Local {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
interface I {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
record R() {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
enum E {
|
||||
E1;
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
class Local1 {
|
||||
class Local2 {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
class Local {
|
||||
interface I {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
class Local {
|
||||
record R() {
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
public void test() {
|
||||
class Local {
|
||||
enum E {
|
||||
E1;
|
||||
@interface A {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertFail("compiler.err.annotation.decl.not.allowed.here",
|
||||
"""
|
||||
class Outer {
|
||||
Runnable run = new Runnable() {
|
||||
@interface A {}
|
||||
public void run() {}
|
||||
};
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
public void testReceiverParameter() {
|
||||
assertFail("compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class",
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user