Skip to content
This repository has been archived by the owner on Aug 27, 2022. It is now read-only.

Commit

Permalink
8258515: javac should issue an error if an annotation is nested in a …
Browse files Browse the repository at this point in the history
…local class or interface

Reviewed-by: jjg
  • Loading branch information
Vicente Romero committed Dec 17, 2020
1 parent cb5a6b1 commit 47c180d
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 24 deletions.
Expand Up @@ -439,10 +439,10 @@ public boolean isFinal() {
* 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
Expand Down Expand Up @@ -760,7 +760,7 @@ public DelegatedSymbol(T other) {
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(); }
Expand Down
Expand Up @@ -5165,7 +5165,7 @@ void attribClass(ClassSymbol c) throws CompletionFailure {
}
}
} 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));
}

Expand Down
Expand Up @@ -1216,7 +1216,8 @@ else if ((sym.owner.flags_field & INTERFACE) != 0)
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;
Expand All @@ -1225,7 +1226,7 @@ else if ((sym.owner.flags_field & INTERFACE) != 0)
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;
Expand Down Expand Up @@ -2729,7 +2730,7 @@ void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) {

if (sym.kind == VAR) {
if ((sym.flags() & PARAMETER) != 0 ||
sym.isLocal() ||
sym.isDirectlyOrIndirectlyLocal() ||
sym.name == names._this ||
sym.name == names._super) {
return;
Expand Down
Expand Up @@ -498,7 +498,7 @@ public void visitClassDef(JCClassDecl tree) {

// 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.
Expand Down
Expand Up @@ -2904,7 +2904,7 @@ void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
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;
Expand Down
Expand Up @@ -1438,7 +1438,7 @@ public void visitMethodDef(JCMethodDecl tree) {
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;
Expand Down Expand Up @@ -1592,7 +1592,7 @@ private Symbol owner(boolean skipLambda) {
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;
}
Expand Down Expand Up @@ -2313,7 +2313,7 @@ final boolean needsConversionToLambda() {
!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() {
Expand Down
Expand Up @@ -378,11 +378,11 @@ public void visitApply(JCMethodInvocation tree) {
}

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)) {
Expand Down Expand Up @@ -1049,7 +1049,7 @@ boolean needsPrivateAccess(Symbol sym) {
}
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;
Expand Down Expand Up @@ -2203,7 +2203,7 @@ public void visitClassDef(JCClassDecl tree) {
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();
Expand Down Expand Up @@ -2654,7 +2654,7 @@ public void visitMethodDef(JCMethodDecl tree) {

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;

Expand Down Expand Up @@ -2794,7 +2794,7 @@ public void visitNewClass(JCNewClass tree) {

// 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)));
}

Expand All @@ -2813,7 +2813,7 @@ public void visitNewClass(JCNewClass tree) {
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 {
Expand Down Expand Up @@ -2996,7 +2996,7 @@ public void visitApply(JCMethodInvocation tree) {
// 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)));
}

Expand Down Expand Up @@ -3024,7 +3024,7 @@ public void visitApply(JCMethodInvocation tree) {
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 {
Expand Down
Expand Up @@ -521,7 +521,7 @@ protected Env<AttrContext> baseEnv(JCClassDecl tree, Env<AttrContext> env) {
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);
}
}
Expand Down
Expand Up @@ -143,15 +143,15 @@ static private boolean hasFlag(Symbol m, int flag) {

public boolean needsHeader(ClassSymbol c) {
lazyInit();
if (c.isLocal() || isSynthetic(c))
if (c.isDirectlyOrIndirectlyLocal() || isSynthetic(c))
return false;
return (checkAll)
? needsHeader(c.outermostClass(), true)
: needsHeader(c, false);
}

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)) {
Expand Down
104 changes: 104 additions & 0 deletions test/langtools/tools/javac/records/RecordCompilationTests.java
Expand Up @@ -1027,6 +1027,110 @@ record B() { }
""");
}

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",
"""
Expand Down

0 comments on commit 47c180d

Please sign in to comment.