8282714: synthetic arguments are being added to the constructors of static local classes

Reviewed-by: jlahoda
This commit is contained in:
Vicente Romero 2022-07-08 17:24:27 +00:00
parent e7795851d2
commit 9c86c82091
4 changed files with 125 additions and 19 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac
test/langtools/tools/javac/records

@ -491,7 +491,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return kind == TYP && type.getEnclosingType().hasTag(CLASS);
}
/** An inner class has an outer instance if it is not an interface
/** An inner class has an outer instance if it is not an interface, enum or record,
* it has an enclosing instance class which might be referenced from the class.
* Nested classes can see instance members of their enclosing class.
* Their constructors carry an additional this$n parameter, inserted
@ -501,7 +501,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
*/
public boolean hasOuterInstance() {
return
type.getEnclosingType().hasTag(CLASS) && (flags() & (INTERFACE | NOOUTERTHIS)) == 0;
type.getEnclosingType().hasTag(CLASS) && (flags() & (INTERFACE | ENUM | RECORD | NOOUTERTHIS)) == 0;
}
/** The closest enclosing class of this symbol's declaration.

@ -396,7 +396,7 @@ public class Lower extends TreeTranslator {
if (fvs != null) {
return fvs;
}
if (c.owner.kind.matches(KindSelector.VAL_MTH)) {
if (c.owner.kind.matches(KindSelector.VAL_MTH) && !c.isStatic()) {
FreeVarCollector collector = new FreeVarCollector(c);
collector.scan(classDef(c));
fvs = collector.fvs;
@ -2688,6 +2688,7 @@ public class Lower extends TreeTranslator {
private void visitMethodDefInternal(JCMethodDecl tree) {
if (tree.name == names.init &&
!currentClass.isStatic() &&
(currentClass.isInner() || currentClass.isDirectlyOrIndirectlyLocal())) {
// We are seeing a constructor of an inner class.
MethodSymbol m = tree.sym;
@ -2823,7 +2824,7 @@ public class Lower extends TreeTranslator {
// If created class is local, add free variables after
// explicit constructor arguments.
if (c.isDirectlyOrIndirectlyLocal()) {
if (c.isDirectlyOrIndirectlyLocal() && !c.isStatic()) {
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
}
@ -3025,7 +3026,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.isDirectlyOrIndirectlyLocal()) {
if (c.isDirectlyOrIndirectlyLocal() && !c.isStatic()) {
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
}

@ -0,0 +1,76 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8282714
* @summary synthetic arguments are being added to the constructors of static local classes
* @library /lib/combo /tools/lib /tools/javac/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.util
* @run testng/othervm LocalStaticDeclarations2
*/
import org.testng.annotations.Test;
import tools.javac.combo.CompilationTestCase;
import static org.testng.Assert.assertEquals;
@Test
public class LocalStaticDeclarations2 extends CompilationTestCase {
public void testLocalStatic() {
assertOK(
"""
class Test {
class Inner {
Inner() { enum E { A } }
}
}
""");
assertOK(
"""
class Test {
class Inner {
Inner() {
record R(Object o) {
static R create() { return new R("hi"); }
}
}
}
}
""");
assertOK(
"""
class Test {
class Inner {
Inner() {
record R(Object o) {
static R create(Object obj) { return new R(obj); }
}
}
}
}
""");
}
}

@ -25,7 +25,7 @@
* RecordCompilationTests
*
* @test
* @bug 8250629 8252307 8247352 8241151 8246774 8259025 8288130
* @bug 8250629 8252307 8247352 8241151 8246774 8259025 8288130 8282714
* @summary Negative compilation tests, and positive compilation (smoke) tests for records
* @library /lib/combo /tools/lib /tools/javac/lib
* @modules
@ -1259,23 +1259,52 @@ public class RecordCompilationTests extends CompilationTestCase {
}
public void testOnlyOneFieldRef() throws Exception {
int numberOfFieldRefs = 0;
File dir = assertOK(true, "record R(int recordComponent) {}");
for (final File fileEntry : dir.listFiles()) {
if (fileEntry.getName().equals("R.class")) {
ClassFile classFile = ClassFile.read(fileEntry);
for (CPInfo cpInfo : classFile.constant_pool.entries()) {
if (cpInfo instanceof ConstantPool.CONSTANT_Fieldref_info) {
numberOfFieldRefs++;
ConstantPool.CONSTANT_NameAndType_info nameAndType =
(ConstantPool.CONSTANT_NameAndType_info)classFile.constant_pool
.get(((ConstantPool.CONSTANT_Fieldref_info)cpInfo).name_and_type_index);
Assert.check(nameAndType.getName().equals("recordComponent"));
for (String source : List.of(
"record R(int recordComponent) {}",
"""
class Test {
class Inner {
Inner() {
record R(int recordComponent) {}
}
}
}
""",
"""
class Test {
class Inner {
void m() {
record R(int recordComponent) {}
}
}
}
""",
"""
class Test {
void m() {
record R(int recordComponent) {}
}
}
"""
)) {
File dir = assertOK(true, source);
int numberOfFieldRefs = 0;
for (final File fileEntry : dir.listFiles()) {
if (fileEntry.getName().endsWith("R.class")) {
ClassFile classFile = ClassFile.read(fileEntry);
for (CPInfo cpInfo : classFile.constant_pool.entries()) {
if (cpInfo instanceof ConstantPool.CONSTANT_Fieldref_info) {
numberOfFieldRefs++;
ConstantPool.CONSTANT_NameAndType_info nameAndType =
(ConstantPool.CONSTANT_NameAndType_info)classFile.constant_pool
.get(((ConstantPool.CONSTANT_Fieldref_info)cpInfo).name_and_type_index);
Assert.check(nameAndType.getName().equals("recordComponent"));
}
}
Assert.check(numberOfFieldRefs == 1);
}
}
}
Assert.check(numberOfFieldRefs == 1);
}
// check that fields are initialized in a canonical constructor in the same declaration order as the corresponding