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
This commit is contained in:
Jan Lahoda 2023-05-23 11:47:00 +00:00
parent eb11508eff
commit 1cfb265bef
4 changed files with 135 additions and 23 deletions

View File

@ -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<? extends RecordComponent> 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<>());

View File

@ -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<Integer> 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<Integer> 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) {

View File

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

View File

@ -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<Integer> expectedLines;
public final boolean exactLines;
public final List<String> extraCompilerOptions;
private final String name;
private final MethodData[] methodData;
public String getName() {
return name;
}
public TestCase(String src, Collection<Integer> 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<Integer> expectedLines,
boolean exactLines, List<String> extraCompilerOptions,
String name) {
this(src, extraCompilerOptions, name, new MethodData(null, expectedLines, exactLines));
}
public TestCase(String src, List<String> 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<Integer> expectedLines, boolean exactLines) {
public MethodData {
expectedLines = new HashSet<>(expectedLines);
}
}
}