From 1cfb265befa497e4c1c9a75c0fb576bb75adea70 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 23 May 2023 11:47:00 +0000 Subject: [PATCH] 8307814: In the case of two methods with Record Patterns, the second one contains a line number from the first method Reviewed-by: vromero, godin --- .../sun/tools/javac/comp/TransPatterns.java | 4 +- .../LineNumberTable/LineNumberTestBase.java | 45 ++++++++---- .../MultipleRecordPatterns.java | 70 +++++++++++++++++++ .../attributes/LineNumberTable/TestCase.java | 39 +++++++++-- 4 files changed, 135 insertions(+), 23 deletions(-) create mode 100644 test/langtools/tools/javac/classfiles/attributes/LineNumberTable/MultipleRecordPatterns.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index b247895c5b2..c2c3852c1ca 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -304,7 +304,7 @@ public class TransPatterns extends TreeTranslator { BindingSymbol tempBind = new BindingSymbol(Flags.SYNTHETIC, names.fromString(target.syntheticNameChar() + "b" + target.syntheticNameChar() + variableIndex++), recordType, currentMethodSym); - JCVariableDecl recordBindingVar = make.VarDef(tempBind, null); + JCVariableDecl recordBindingVar = make.at(recordPattern.pos()).VarDef(tempBind, null); VarSymbol recordBinding = recordBindingVar.sym; List components = recordPattern.record.getRecordComponents(); @@ -341,7 +341,7 @@ public class TransPatterns extends TreeTranslator { types.boxedTypeOrType(types.erasure(nestedBinding.type))); } JCMethodInvocation componentAccessor = - make.App(make.Select(convert(make.Ident(recordBinding), recordBinding.type), //TODO - cast needed???? + make.at(recordPattern.pos()).App(make.Select(convert(make.Ident(recordBinding), recordBinding.type), component.accessor)).setType(types.erasure(component.accessor.getReturnType())); if (deconstructorCalls == null) { deconstructorCalls = Collections.newSetFromMap(new IdentityHashMap<>()); diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java index 8914617f2c9..f52e46455e7 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -35,7 +35,7 @@ import javax.tools.JavaFileObject; import static com.sun.tools.classfile.Attribute.Code; import static com.sun.tools.classfile.Attribute.LineNumberTable; import static java.lang.String.format; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; /** * Base class for line number table attribute tests. @@ -82,22 +82,25 @@ public class LineNumberTestBase extends TestBase { LineNumberTable_attribute tableAttribute = (LineNumberTable_attribute) code_attribute.attributes.get(LineNumberTable); checkAttribute(testCase, tableAttribute, code_attribute.code_length); - coveredLines.addAll( + Set methodCoveredLines = Stream.of(tableAttribute.line_number_table) .map(e -> e.line_number) - .collect(toList())); + .collect(toSet()); + + TestCase.MethodData expected = testCase.findData(m.getName(classFile.constant_pool)); + + if (expected != null) { + verifyCoveredLines(methodCoveredLines, expected); + } + + coveredLines.addAll(methodCoveredLines); } } - if (testCase.exactLines) { - assertTrue(coveredLines.equals(testCase.expectedLines), - format("Incorrect covered lines.%n" + - "Covered: %s%n" + - "Expected: %s%n", coveredLines, testCase.expectedLines)); - } else { - assertTrue(coveredLines.containsAll(testCase.expectedLines), - format("All significant lines are not covered.%n" + - "Covered: %s%n" + - "Expected: %s%n", coveredLines, testCase.expectedLines)); + + TestCase.MethodData expected = testCase.findData(null); + + if (expected != null) { + verifyCoveredLines(coveredLines, expected); } } catch (AssertionFailedException | CompilationException ex) { System.err.printf("# %-20s#%n", testCase.getName()); @@ -117,6 +120,20 @@ public class LineNumberTestBase extends TestBase { } } + private void verifyCoveredLines(Set actualCoveredLines, TestCase.MethodData expected) { + if (expected.exactLines()) { + assertTrue(actualCoveredLines.equals(expected.expectedLines()), + format("Incorrect covered lines.%n" + + "Covered: %s%n" + + "Expected: %s%n", actualCoveredLines, expected.expectedLines())); + } else { + assertTrue(actualCoveredLines.containsAll(expected.expectedLines()), + format("All significant lines are not covered.%n" + + "Covered: %s%n" + + "Expected: %s%n", actualCoveredLines, expected.expectedLines())); + } + } + private int countAttributes(String name, Attribute[] attrs, ConstantPool constant_pool) throws ConstantPoolException { int i = 0; for (Attribute attribute : attrs) { diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/MultipleRecordPatterns.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/MultipleRecordPatterns.java new file mode 100644 index 00000000000..32ab561f2ce --- /dev/null +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/MultipleRecordPatterns.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023, 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 8307814 + * @summary Verify correct LineNumberTable is generated for unrolled record patterns. + * @library /tools/lib /tools/javac/lib ../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * jdk.jdeps/com.sun.tools.classfile + * @build toolbox.ToolBox InMemoryFileManager TestBase + * @build LineNumberTestBase TestCase + * @run main MultipleRecordPatterns + */ + +import java.util.List; + +public class MultipleRecordPatterns extends LineNumberTestBase { + public static void main(String[] args) throws Exception { + new MultipleRecordPatterns().test(); + } + + public void test() throws Exception { + test(List.of(TEST_CASE)); + } + + private static final TestCase[] TEST_CASE = new TestCase[] { + new TestCase(""" + public class Patterns { // 1 + private void test1(Object o) { // 2 + if (o instanceof R(var v)) { // 3 + System.err.println(v); // 4 + } // 5 + } // 6 + private void test2(Object o) { // 7 + if (o instanceof R(var v)) { // 8 + System.err.println(v); // 9 + } //10 + } //11 + record R(int i) {} //12 + } //13 + """, + "Patterns", + new TestCase.MethodData("test1", List.of(3, 4, 6), true), + new TestCase.MethodData("test2", List.of(8, 9, 11), true)) + }; + +} diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/TestCase.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/TestCase.java index dfb5a778825..94d33c1cf8c 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/TestCase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/TestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -24,7 +24,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Set; +import java.util.Objects; /** * TestCase contains source code to be compiled @@ -32,28 +32,53 @@ import java.util.Set; */ public class TestCase { public final String src; - public final Set expectedLines; - public final boolean exactLines; public final List extraCompilerOptions; private final String name; + private final MethodData[] methodData; public String getName() { return name; } public TestCase(String src, Collection expectedLines, String name) { - this(src, expectedLines, false, List.of(), name); + this(src, name, new MethodData(null, expectedLines, false)); + } + + public TestCase(String src, String name, MethodData... methodData) { + this(src, List.of(), name, methodData); } public TestCase(String src, Collection expectedLines, boolean exactLines, List extraCompilerOptions, String name) { + this(src, extraCompilerOptions, name, new MethodData(null, expectedLines, exactLines)); + } + + public TestCase(String src, List extraCompilerOptions, + String name, MethodData... methodData) { this.src = src; - this.expectedLines = new HashSet<>(expectedLines); - this.exactLines = exactLines; this.extraCompilerOptions = extraCompilerOptions; this.name = name; + this.methodData = methodData; + } + + public MethodData findData(String methodName) { + for (MethodData md : methodData) { + if (Objects.equals(md.methodName(), methodName)) { + return md; + } + } + + return null; + } + + record MethodData(String methodName, Collection expectedLines, boolean exactLines) { + + public MethodData { + expectedLines = new HashSet<>(expectedLines); + } + } }