8256950: Add record attribute support to symbol generator CreateSymbols
Reviewed-by: jjg, chegar
This commit is contained in:
parent
f148915d54
commit
6eff9315e1
@ -122,6 +122,7 @@ import com.sun.tools.classfile.Field;
|
||||
import com.sun.tools.classfile.InnerClasses_attribute;
|
||||
import com.sun.tools.classfile.InnerClasses_attribute.Info;
|
||||
import com.sun.tools.classfile.Method;
|
||||
import com.sun.tools.classfile.MethodParameters_attribute;
|
||||
import com.sun.tools.classfile.ModuleResolution_attribute;
|
||||
import com.sun.tools.classfile.ModuleTarget_attribute;
|
||||
import com.sun.tools.classfile.Module_attribute;
|
||||
@ -131,6 +132,8 @@ import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
|
||||
import com.sun.tools.classfile.Module_attribute.RequiresEntry;
|
||||
import com.sun.tools.classfile.NestHost_attribute;
|
||||
import com.sun.tools.classfile.NestMembers_attribute;
|
||||
import com.sun.tools.classfile.Record_attribute;
|
||||
import com.sun.tools.classfile.Record_attribute.ComponentInfo;
|
||||
import com.sun.tools.classfile.RuntimeAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
|
||||
@ -959,6 +962,22 @@ public class CreateSymbols {
|
||||
attributes.put(Attribute.NestMembers,
|
||||
new NestMembers_attribute(attributeString, nestMembers));
|
||||
}
|
||||
if (header.isRecord) {
|
||||
assert header.recordComponents != null;
|
||||
int attributeString = addString(constantPool, Attribute.Record);
|
||||
ComponentInfo[] recordComponents = new ComponentInfo[header.recordComponents.size()];
|
||||
int i = 0;
|
||||
for (RecordComponentDescription rcd : header.recordComponents) {
|
||||
int name = addString(constantPool, rcd.name);
|
||||
Descriptor desc = new Descriptor(addString(constantPool, rcd.descriptor));
|
||||
Map<String, Attribute> nestedAttrs = new HashMap<>();
|
||||
addGenericAttributes(rcd, constantPool, nestedAttrs);
|
||||
Attributes attrs = new Attributes(nestedAttrs);
|
||||
recordComponents[i++] = new ComponentInfo(name, desc, attrs);
|
||||
}
|
||||
attributes.put(Attribute.Record,
|
||||
new Record_attribute(attributeString, recordComponents));
|
||||
}
|
||||
addInnerClassesAttribute(header, constantPool, attributes);
|
||||
}
|
||||
|
||||
@ -1017,6 +1036,18 @@ public class CreateSymbols {
|
||||
new RuntimeVisibleParameterAnnotations_attribute(attributeString,
|
||||
annotations));
|
||||
}
|
||||
if (desc.methodParameters != null && !desc.methodParameters.isEmpty()) {
|
||||
int attributeString =
|
||||
addString(constantPool, Attribute.MethodParameters);
|
||||
MethodParameters_attribute.Entry[] entries =
|
||||
desc.methodParameters
|
||||
.stream()
|
||||
.map(p -> new MethodParameters_attribute.Entry(addString(constantPool, p.name),
|
||||
p.flags))
|
||||
.toArray(s -> new MethodParameters_attribute.Entry[s]);
|
||||
attributes.put(Attribute.MethodParameters,
|
||||
new MethodParameters_attribute(attributeString, entries));
|
||||
}
|
||||
}
|
||||
|
||||
private void addAttributes(FieldDescription desc, List<CPInfo> constantPool, Map<String, Attribute> attributes) {
|
||||
@ -1595,7 +1626,9 @@ public class CreateSymbols {
|
||||
StringWriter data = new StringWriter();
|
||||
ModuleDescription module = modules.get(e.getKey());
|
||||
|
||||
module.write(data, desc.basePlatform, desc.version);
|
||||
if (module != null) { //module == null should only be in tests.
|
||||
module.write(data, desc.basePlatform, desc.version);
|
||||
}
|
||||
|
||||
for (ClassDescription clazz : e.getValue()) {
|
||||
clazz.write(data, desc.basePlatform, desc.version);
|
||||
@ -2153,6 +2186,37 @@ public class CreateSymbols {
|
||||
.collect(Collectors.toList());
|
||||
break;
|
||||
}
|
||||
case Attribute.Record: {
|
||||
assert feature instanceof ClassHeaderDescription;
|
||||
Record_attribute record = (Record_attribute) attr;
|
||||
List<RecordComponentDescription> components = new ArrayList<>();
|
||||
for (ComponentInfo info : record.component_info_arr) {
|
||||
RecordComponentDescription rcd = new RecordComponentDescription();
|
||||
rcd.name = info.getName(cf.constant_pool);
|
||||
rcd.descriptor = info.descriptor.getValue(cf.constant_pool);
|
||||
for (Attribute nestedAttr : info.attributes) {
|
||||
readAttribute(cf, rcd, nestedAttr);
|
||||
}
|
||||
components.add(rcd);
|
||||
}
|
||||
ClassHeaderDescription chd = (ClassHeaderDescription) feature;
|
||||
chd.isRecord = true;
|
||||
chd.recordComponents = components;
|
||||
break;
|
||||
}
|
||||
case Attribute.MethodParameters: {
|
||||
assert feature instanceof MethodDescription;
|
||||
MethodParameters_attribute params = (MethodParameters_attribute) attr;
|
||||
MethodDescription method = (MethodDescription) feature;
|
||||
method.methodParameters = new ArrayList<>();
|
||||
for (MethodParameters_attribute.Entry e : params.method_parameter_table) {
|
||||
String name = cf.constant_pool.getUTF8Value(e.name_index);
|
||||
MethodDescription.MethodParam param =
|
||||
new MethodDescription.MethodParam(e.flags, name);
|
||||
method.methodParameters.add(param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException("Unhandled attribute: " +
|
||||
attrName);
|
||||
@ -2999,6 +3063,8 @@ public class CreateSymbols {
|
||||
List<String> implementsAttr;
|
||||
String nestHost;
|
||||
List<String> nestMembers;
|
||||
boolean isRecord;
|
||||
List<RecordComponentDescription> recordComponents;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@ -3007,6 +3073,8 @@ public class CreateSymbols {
|
||||
hash = 17 * hash + Objects.hashCode(this.implementsAttr);
|
||||
hash = 17 * hash + Objects.hashCode(this.nestHost);
|
||||
hash = 17 * hash + Objects.hashCode(this.nestMembers);
|
||||
hash = 17 * hash + Objects.hashCode(this.isRecord);
|
||||
hash = 17 * hash + Objects.hashCode(this.recordComponents);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -3031,6 +3099,12 @@ public class CreateSymbols {
|
||||
if (!listEquals(this.nestMembers, other.nestMembers)) {
|
||||
return false;
|
||||
}
|
||||
if (this.isRecord != other.isRecord) {
|
||||
return false;
|
||||
}
|
||||
if (!listEquals(this.recordComponents, other.recordComponents)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3048,8 +3122,12 @@ public class CreateSymbols {
|
||||
output.append(" nestHost " + nestHost);
|
||||
if (nestMembers != null && !nestMembers.isEmpty())
|
||||
output.append(" nestMembers " + serializeList(nestMembers));
|
||||
if (isRecord) {
|
||||
output.append(" record true");
|
||||
}
|
||||
writeAttributes(output);
|
||||
output.append("\n");
|
||||
writeRecordComponents(output, baselineVersion, version);
|
||||
writeInnerClasses(output, baselineVersion, version);
|
||||
}
|
||||
|
||||
@ -3065,14 +3143,37 @@ public class CreateSymbols {
|
||||
nestHost = reader.attributes.get("nestHost");
|
||||
String nestMembersList = reader.attributes.get("nestMembers");
|
||||
nestMembers = deserializeList(nestMembersList);
|
||||
isRecord = reader.attributes.containsKey("record");
|
||||
|
||||
readAttributes(reader);
|
||||
reader.moveNext();
|
||||
if (isRecord) {
|
||||
readRecordComponents(reader);
|
||||
}
|
||||
readInnerClasses(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void writeRecordComponents(Appendable output,
|
||||
String baselineVersion,
|
||||
String version) throws IOException {
|
||||
if (recordComponents != null) {
|
||||
for (RecordComponentDescription rcd : recordComponents) {
|
||||
rcd.write(output, "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void readRecordComponents(LineBasedReader reader) throws IOException {
|
||||
recordComponents = new ArrayList<>();
|
||||
|
||||
while ("recordcomponent".equals(reader.lineKey)) {
|
||||
RecordComponentDescription rcd = new RecordComponentDescription();
|
||||
rcd.read(reader);
|
||||
recordComponents.add(rcd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class HeaderDescription extends FeatureDescription {
|
||||
@ -3145,6 +3246,7 @@ public class CreateSymbols {
|
||||
Object annotationDefaultValue;
|
||||
List<List<AnnotationDescription>> classParameterAnnotations;
|
||||
List<List<AnnotationDescription>> runtimeParameterAnnotations;
|
||||
List<MethodParam> methodParameters;
|
||||
|
||||
public MethodDescription() {
|
||||
flagsNormalization = METHODS_FLAGS_NORMALIZATION;
|
||||
@ -3221,6 +3323,15 @@ public class CreateSymbols {
|
||||
output.append(";");
|
||||
}
|
||||
}
|
||||
if (methodParameters != null && !methodParameters.isEmpty()) {
|
||||
Function<MethodParam, String> param2String =
|
||||
p -> Integer.toHexString(p.flags) + ":" + p.name;
|
||||
List<String> paramsAsStrings =
|
||||
methodParameters.stream()
|
||||
.map(param2String)
|
||||
.collect(Collectors.toList());
|
||||
output.append(" methodParameters " + serializeList(paramsAsStrings));
|
||||
}
|
||||
output.append("\n");
|
||||
}
|
||||
|
||||
@ -3268,17 +3379,41 @@ public class CreateSymbols {
|
||||
runtimeParameterAnnotations = annos;
|
||||
}
|
||||
|
||||
String inMethodParameters = reader.attributes.get("methodParameters");
|
||||
if (inMethodParameters != null) {
|
||||
Function<String, MethodParam> string2Param =
|
||||
p -> {
|
||||
int sep = p.indexOf(':');
|
||||
return new MethodParam(Integer.parseInt(p.substring(0, sep)),
|
||||
p.substring(sep + 1));
|
||||
};
|
||||
methodParameters =
|
||||
deserializeList(inMethodParameters).stream()
|
||||
.map(string2Param)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
reader.moveNext();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class MethodParam {
|
||||
public final int flags;
|
||||
public final String name;
|
||||
|
||||
public MethodParam(int flags, String name) {
|
||||
this.flags = flags;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class FieldDescription extends FeatureDescription {
|
||||
String name;
|
||||
String descriptor;
|
||||
Object constantValue;
|
||||
String keyName = "field";
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@ -3315,13 +3450,13 @@ public class CreateSymbols {
|
||||
if (shouldIgnore(baselineVersion, version))
|
||||
return ;
|
||||
if (!versions.contains(version)) {
|
||||
output.append("-field");
|
||||
output.append("-" + keyName);
|
||||
output.append(" name " + quote(name, false));
|
||||
output.append(" descriptor " + quote(descriptor, false));
|
||||
output.append("\n");
|
||||
return ;
|
||||
}
|
||||
output.append("field");
|
||||
output.append(keyName);
|
||||
output.append(" name " + name);
|
||||
output.append(" descriptor " + descriptor);
|
||||
if (constantValue != null) {
|
||||
@ -3333,7 +3468,7 @@ public class CreateSymbols {
|
||||
|
||||
@Override
|
||||
public boolean read(LineBasedReader reader) throws IOException {
|
||||
if (!"field".equals(reader.lineKey))
|
||||
if (!keyName.equals(reader.lineKey))
|
||||
return false;
|
||||
|
||||
name = reader.attributes.get("name");
|
||||
@ -3366,6 +3501,19 @@ public class CreateSymbols {
|
||||
|
||||
}
|
||||
|
||||
static final class RecordComponentDescription extends FieldDescription {
|
||||
|
||||
public RecordComponentDescription() {
|
||||
this.keyName = "recordcomponent";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldIgnore(String baselineVersion, String version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class AnnotationDescription {
|
||||
String annotationType;
|
||||
Map<String, Object> values;
|
||||
|
@ -1516,7 +1516,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
}
|
||||
RecordComponent rc = null;
|
||||
if (addIfMissing) {
|
||||
recordComponents = recordComponents.append(rc = new RecordComponent(var, annotations));
|
||||
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, annotations));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -1527,6 +1527,10 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return recordComponents;
|
||||
}
|
||||
|
||||
public void setRecordComponents(List<RecordComponent> recordComponents) {
|
||||
this.recordComponents = recordComponents;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public NestingKind getNestingKind() {
|
||||
apiComplete();
|
||||
@ -1790,10 +1794,17 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
/**
|
||||
* Construct a record component, given its flags, name, type and owner.
|
||||
*/
|
||||
public RecordComponent(JCVariableDecl fieldDecl, List<JCAnnotation> annotations) {
|
||||
super(PUBLIC, fieldDecl.sym.name, fieldDecl.sym.type, fieldDecl.sym.owner);
|
||||
public RecordComponent(Name name, Type type, Symbol owner) {
|
||||
super(PUBLIC, name, type, owner);
|
||||
pos = -1;
|
||||
originalAnnos = List.nil();
|
||||
isVarargs = false;
|
||||
}
|
||||
|
||||
public RecordComponent(VarSymbol field, List<JCAnnotation> annotations) {
|
||||
super(PUBLIC, field.name, field.type, field.owner);
|
||||
this.originalAnnos = annotations;
|
||||
this.pos = fieldDecl.pos;
|
||||
this.pos = field.pos;
|
||||
/* it is better to store the original information for this one, instead of relying
|
||||
* on the info in the type of the symbol. This is because on the presence of APs
|
||||
* the symbol will be blown out and we won't be able to know if the original
|
||||
|
@ -1205,7 +1205,16 @@ public class ClassReader {
|
||||
if (sym.kind == TYP) {
|
||||
sym.flags_field |= RECORD;
|
||||
}
|
||||
bp = bp + attrLen;
|
||||
int componentCount = nextChar();
|
||||
ListBuffer<RecordComponent> components = new ListBuffer<>();
|
||||
for (int i = 0; i < componentCount; i++) {
|
||||
Name name = poolReader.getName(nextChar());
|
||||
Type type = poolReader.getType(nextChar());
|
||||
RecordComponent c = new RecordComponent(name, type, sym);
|
||||
readAttrs(c, AttributeKind.MEMBER);
|
||||
components.add(c);
|
||||
}
|
||||
((ClassSymbol) sym).setRecordComponents(components.toList());
|
||||
}
|
||||
},
|
||||
new AttributeReader(names.PermittedSubclasses, V59, CLASS_ATTRIBUTE) {
|
||||
|
@ -229,7 +229,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
writer.print("(");
|
||||
writer.print(e.getRecordComponents()
|
||||
.stream()
|
||||
.map(recordDes -> recordDes.asType().toString() + " " + recordDes.getSimpleName())
|
||||
.map(recordDes -> annotationsToString(recordDes) + recordDes.asType().toString() + " " + recordDes.getSimpleName())
|
||||
.collect(Collectors.joining(", ")));
|
||||
writer.print(")");
|
||||
}
|
||||
@ -448,7 +448,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
|
||||
private void printModifiers(Element e) {
|
||||
ElementKind kind = e.getKind();
|
||||
if (kind == PARAMETER) {
|
||||
if (kind == PARAMETER || kind == RECORD_COMPONENT) {
|
||||
// Print annotation inline
|
||||
writer.print(annotationsToString(e));
|
||||
} else {
|
||||
@ -456,7 +456,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
indent();
|
||||
}
|
||||
|
||||
if (kind == ENUM_CONSTANT)
|
||||
if (kind == ENUM_CONSTANT || kind == RECORD_COMPONENT)
|
||||
return;
|
||||
|
||||
Set<Modifier> modifiers = new LinkedHashSet<>();
|
||||
|
@ -362,16 +362,14 @@ public class ClassWriter {
|
||||
write(a, out);
|
||||
}
|
||||
|
||||
// Note: due to the use of shared resources, this method is not reentrant.
|
||||
public void write(Attribute attr, ClassOutputStream out) {
|
||||
out.writeShort(attr.attribute_name_index);
|
||||
sharedOut.reset();
|
||||
attr.accept(this, sharedOut);
|
||||
out.writeInt(sharedOut.size());
|
||||
sharedOut.writeTo(out);
|
||||
ClassOutputStream nestedOut = new ClassOutputStream();
|
||||
attr.accept(this, nestedOut);
|
||||
out.writeInt(nestedOut.size());
|
||||
nestedOut.writeTo(out);
|
||||
}
|
||||
|
||||
protected ClassOutputStream sharedOut = new ClassOutputStream();
|
||||
protected AnnotationWriter annotationWriter = new AnnotationWriter();
|
||||
|
||||
@Override
|
||||
@ -756,8 +754,8 @@ public class ClassWriter {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
|
||||
sharedOut.writeShort(flags.flags);
|
||||
protected void writeAccessFlags(AccessFlags flags, ClassOutputStream out) {
|
||||
out.writeShort(flags.flags);
|
||||
}
|
||||
|
||||
protected StackMapTableWriter stackMapWriter;
|
||||
|
@ -76,6 +76,11 @@ public class MethodParameters_attribute extends Attribute {
|
||||
flags = cr.readUnsignedShort();
|
||||
}
|
||||
|
||||
public Entry(int name_index, int flags) {
|
||||
this.name_index = name_index;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public static int length() {
|
||||
return 6;
|
||||
}
|
||||
|
@ -44,6 +44,12 @@ public class Record_attribute extends Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
public Record_attribute(int name_index, ComponentInfo[] component_info_arr) {
|
||||
super(name_index, 2);
|
||||
this.component_count = component_info_arr.length;
|
||||
this.component_info_arr = component_info_arr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(Visitor<R, D> visitor, D data) {
|
||||
return visitor.visitRecord(this, data);
|
||||
@ -59,6 +65,12 @@ public class Record_attribute extends Attribute {
|
||||
attributes = new Attributes(cr);
|
||||
}
|
||||
|
||||
public ComponentInfo(int name_index, Descriptor descriptor, Attributes attributes) {
|
||||
this.name_index = name_index;
|
||||
this.descriptor = descriptor;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getName(ConstantPool constant_pool) throws ConstantPoolException {
|
||||
return constant_pool.getUTF8Value(name_index);
|
||||
}
|
||||
|
@ -25,8 +25,14 @@
|
||||
* @test
|
||||
* @bug 8072480
|
||||
* @summary Unit test for CreateSymbols
|
||||
* @modules java.compiler
|
||||
* jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.jvm
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* @clean *
|
||||
* @run main CreateSymbolsTest
|
||||
* @run main/othervm CreateSymbolsTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
@ -38,7 +44,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.ToolProvider;
|
||||
@ -56,37 +63,58 @@ public class CreateSymbolsTest {
|
||||
Path compileDir = testClasses.resolve("data");
|
||||
deleteRecursively(compileDir);
|
||||
Files.createDirectories(compileDir);
|
||||
Path createSymbols = findFile("../../make/src/classes/build/tools/symbolgenerator/CreateSymbols.java");
|
||||
Path createSymbols = findFile("../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java");
|
||||
|
||||
if (createSymbols == null) {
|
||||
System.err.println("Warning: cannot find CreateSymbols, skipping.");
|
||||
return ;
|
||||
}
|
||||
|
||||
Path createTestImpl = findFile("../../make/test/sym/CreateSymbolsTestImpl.java");
|
||||
Path createTestImpl = findFile("tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java");
|
||||
|
||||
if (createTestImpl == null) {
|
||||
System.err.println("Warning: cannot find CreateSymbolsTestImpl, skipping.");
|
||||
return ;
|
||||
throw new AssertionError("Warning: cannot find CreateSymbolsTestImpl, skipping.");
|
||||
}
|
||||
|
||||
Path toolBox = findFile("../../test/tools/lib/ToolBox.java");
|
||||
Path toolBox = findFile("tools/lib/toolbox/");
|
||||
|
||||
if (toolBox == null) {
|
||||
System.err.println("Warning: cannot find ToolBox, skipping.");
|
||||
return ;
|
||||
throw new AssertionError("Warning: cannot find ToolBox, skipping.");
|
||||
}
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
|
||||
try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
|
||||
compiler.getTask(null,
|
||||
null,
|
||||
null,
|
||||
Arrays.asList("-d", compileDir.toAbsolutePath().toString()),
|
||||
null,
|
||||
fm.getJavaFileObjects(createSymbols, createTestImpl, toolBox)
|
||||
).call();
|
||||
List<Path> files = new ArrayList<>();
|
||||
|
||||
files.add(createSymbols);
|
||||
files.add(createTestImpl);
|
||||
|
||||
files.add(toolBox.resolve("AbstractTask.java"));
|
||||
files.add(toolBox.resolve("JavacTask.java"));
|
||||
files.add(toolBox.resolve("Task.java"));
|
||||
files.add(toolBox.resolve("ToolBox.java"));
|
||||
|
||||
Boolean res =
|
||||
compiler.getTask(null,
|
||||
null,
|
||||
null,
|
||||
List.of("-d",
|
||||
compileDir.toAbsolutePath().toString(),
|
||||
"-g",
|
||||
"--add-modules", "jdk.jdeps",
|
||||
"--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
|
||||
"--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
|
||||
"--add-exports", "jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED",
|
||||
"--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"--add-exports", "jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED"),
|
||||
null,
|
||||
fm.getJavaFileObjectsFromPaths(files)
|
||||
).call();
|
||||
if (!res) {
|
||||
throw new IllegalStateException("Cannot compile test.");
|
||||
}
|
||||
}
|
||||
|
||||
URLClassLoader cl = new URLClassLoader(new URL[] {testClasses.toUri().toURL(), compileDir.toUri().toURL()});
|
||||
@ -100,9 +128,9 @@ public class CreateSymbolsTest {
|
||||
|
||||
for (Path d = testSrc; d != null; d = d.getParent()) {
|
||||
if (Files.exists(d.resolve("TEST.ROOT"))) {
|
||||
Path createSymbols = d.resolve(path);
|
||||
if (Files.exists(createSymbols)) {
|
||||
return createSymbols;
|
||||
Path file = d.resolve(path);
|
||||
if (Files.exists(file)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import com.sun.tools.javac.file.ZipFileIndexCache;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
@ -37,14 +36,20 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
import toolbox.Task.Expect;
|
||||
import toolbox.ToolBox;
|
||||
import build.tools.symbolgenerator.CreateSymbols;
|
||||
import build.tools.symbolgenerator.CreateSymbols.ClassDescription;
|
||||
import build.tools.symbolgenerator.CreateSymbols.ClassList;
|
||||
import build.tools.symbolgenerator.CreateSymbols.CtSymKind;
|
||||
import build.tools.symbolgenerator.CreateSymbols.ExcludeIncludeList;
|
||||
import build.tools.symbolgenerator.CreateSymbols.VersionDescription;
|
||||
|
||||
@ -59,8 +64,6 @@ public class CreateSymbolsTestImpl {
|
||||
void doTest() throws Exception {
|
||||
boolean testRun = false;
|
||||
for (Method m : CreateSymbolsTestImpl.class.getDeclaredMethods()) {
|
||||
if (!"testIncluded".equals(m.getName()))
|
||||
continue;
|
||||
if (m.isAnnotationPresent(Test.class)) {
|
||||
m.invoke(this);
|
||||
testRun = true;
|
||||
@ -76,19 +79,19 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { public void m() { } }",
|
||||
"package t; public class T { }",
|
||||
"package t; public class Test { { T t = null; t.m(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.FAIL);
|
||||
Expect.SUCCESS,
|
||||
Expect.FAIL);
|
||||
doTest("package t; public class T { public void b() { } public void m() { } public void a() { } }",
|
||||
"package t; public class T { public void b() { } public void a() { } }",
|
||||
"package t; public class Test { { T t = null; t.b(); t.a(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
//with additional attribute (need to properly skip the member):
|
||||
doTest("package t; public class T { public void m() throws IllegalStateException { } public void a() { } }",
|
||||
"package t; public class T { public void a() { } }",
|
||||
"package t; public class Test { { T t = null; t.a(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -96,13 +99,13 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { }",
|
||||
"package t; public class T { public void m() { } }",
|
||||
"package t; public class Test { { T t = null; t.m(); } }",
|
||||
ToolBox.Expect.FAIL,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.FAIL,
|
||||
Expect.SUCCESS);
|
||||
doTest("package t; public class T { public void b() { } public void a() { } }",
|
||||
"package t; public class T { public void b() { } public void m() { } public void a() { } }",
|
||||
"package t; public class Test { { T t = null; t.b(); t.a(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
//verify fields added/modified/removed
|
||||
@ -112,8 +115,8 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("class Dummy {}",
|
||||
"package t; public class T { }",
|
||||
"package t; public class Test { { T t = new T(); } }",
|
||||
ToolBox.Expect.FAIL,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.FAIL,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -121,8 +124,8 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { public void m() { } }",
|
||||
"package t; public class T implements java.io.Serializable { public void m() { } }",
|
||||
"package t; public class Test { { java.io.Serializable t = new T(); } }",
|
||||
ToolBox.Expect.FAIL,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.FAIL,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -130,17 +133,17 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { }",
|
||||
"class Dummy {}",
|
||||
"package t; public class Test { { T t = new T(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.FAIL);
|
||||
Expect.SUCCESS,
|
||||
Expect.FAIL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInnerClassAttributes() throws Exception {
|
||||
doTest("package t; public class T { public static class Inner { } }",
|
||||
"package t; public class T { public static class Inner { } }",
|
||||
"package t; public class T { public static class Inner { } public void extra() {} }",
|
||||
"package t; import t.T.Inner; public class Test { Inner i; }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -148,8 +151,8 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { }",
|
||||
"package t; public class T { public static final int A = 0; }",
|
||||
"package t; public class Test { void t(int i) { switch (i) { case T.A: break;} } }",
|
||||
ToolBox.Expect.FAIL,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.FAIL,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -173,8 +176,8 @@ public class CreateSymbolsTestImpl {
|
||||
" public SuppressWarnings annotationValue() default @SuppressWarnings(\"cast\");\n" +
|
||||
"}\n",
|
||||
"package t; public @T class Test { }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -214,7 +217,7 @@ public class CreateSymbolsTestImpl {
|
||||
void testAnnotations() throws Exception {
|
||||
doPrintElementTest("package t;" +
|
||||
"import java.lang.annotation.*;" +
|
||||
"public @Visible @Invisible class T { }" +
|
||||
"public @Visible @Invisible class T { public void extra() { } }" +
|
||||
"@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" +
|
||||
"@Retention(RetentionPolicy.CLASS) @interface Invisible { }",
|
||||
"package t;" +
|
||||
@ -227,11 +230,12 @@ public class CreateSymbolsTestImpl {
|
||||
"@t.Invisible\n" +
|
||||
"@t.Visible\n" +
|
||||
"public class T {\n\n" +
|
||||
" public T();\n" +
|
||||
" public T();\n\n" +
|
||||
" public void extra();\n" +
|
||||
"}\n",
|
||||
"t.Visible",
|
||||
"package t;\n\n" +
|
||||
"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" +
|
||||
"@java.lang.annotation.Retention(RUNTIME)\n" +
|
||||
"@interface Visible {\n" +
|
||||
"}\n");
|
||||
doPrintElementTest("package t;" +
|
||||
@ -247,6 +251,7 @@ public class CreateSymbolsTestImpl {
|
||||
"import java.util.*;" +
|
||||
"public class T {" +
|
||||
" public void test(int h, @Invisible int i, @Visible List<String> j, int k) { }" +
|
||||
" public void extra() { }" +
|
||||
"}" +
|
||||
"@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" +
|
||||
"@Retention(RetentionPolicy.CLASS) @interface Invisible { }",
|
||||
@ -261,7 +266,7 @@ public class CreateSymbolsTestImpl {
|
||||
"}\n",
|
||||
"t.Visible",
|
||||
"package t;\n\n" +
|
||||
"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" +
|
||||
"@java.lang.annotation.Retention(RUNTIME)\n" +
|
||||
"@interface Visible {\n" +
|
||||
"}\n");
|
||||
doPrintElementTest("package t;" +
|
||||
@ -291,10 +296,10 @@ public class CreateSymbolsTestImpl {
|
||||
@Test
|
||||
void testStringConstant() throws Exception {
|
||||
doTest("package t; public class T { public static final String C = \"\"; }",
|
||||
"package t; public class T { public static final String C = \"\"; }",
|
||||
"package t; public class T { public static final String C = \"\"; public void extra() { } }",
|
||||
"package t; public class Test { { System.err.println(T.C); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -302,8 +307,8 @@ public class CreateSymbolsTestImpl {
|
||||
String oldProfileAnnotation = CreateSymbols.PROFILE_ANNOTATION;
|
||||
try {
|
||||
CreateSymbols.PROFILE_ANNOTATION = "Lt/Ann;";
|
||||
doTestEquivalence("package t; public class T { public void t() {} } @interface Ann { }",
|
||||
"package t; public @Ann class T { public void t() {} } @interface Ann { }",
|
||||
doTestEquivalence("package t; public @Ann class T { public void t() {} } @interface Ann { }",
|
||||
"package t; public class T { public void t() {} }",
|
||||
"t.T");
|
||||
} finally {
|
||||
CreateSymbols.PROFILE_ANNOTATION = oldProfileAnnotation;
|
||||
@ -351,13 +356,13 @@ public class CreateSymbolsTestImpl {
|
||||
doTest("package t; public class T { public class TT { public Object t() { return null; } } }",
|
||||
"package t; public class T<E> { public class TT { public E t() { return null; } } }",
|
||||
"package t; public class Test { { T.TT tt = null; tt.t(); } }",
|
||||
ToolBox.Expect.SUCCESS,
|
||||
ToolBox.Expect.SUCCESS);
|
||||
Expect.SUCCESS,
|
||||
Expect.SUCCESS);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
void doTest(String code7, String code8, String testCode, ToolBox.Expect result7, ToolBox.Expect result8) throws Exception {
|
||||
void doTest(String code7, String code8, String testCode, Expect result7, Expect result8) throws Exception {
|
||||
ToolBox tb = new ToolBox();
|
||||
Path classes = prepareVersionedCTSym(code7, code8);
|
||||
Path output = classes.getParent();
|
||||
@ -365,22 +370,24 @@ public class CreateSymbolsTestImpl {
|
||||
|
||||
Files.createDirectories(scratch);
|
||||
|
||||
tb.new JavacTask()
|
||||
new JavacTask(tb)
|
||||
.sources(testCode)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-XDuseOptimizedZip=false")
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"))
|
||||
.run(result7)
|
||||
.writeAll();
|
||||
tb.new JavacTask()
|
||||
new JavacTask(tb)
|
||||
.sources(testCode)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-XDuseOptimizedZip=false")
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"))
|
||||
.run(result8)
|
||||
.writeAll();
|
||||
}
|
||||
|
||||
private static String computeClassPath(Path classes, String version) throws IOException {
|
||||
try (Stream<Path> elements = Files.list(classes)) {
|
||||
return elements.map(el -> el.toAbsolutePath().toString())
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
return elements.filter(el -> el.getFileName().toString().contains(version))
|
||||
.map(el -> el.resolve("java.base"))
|
||||
.map(el -> el.toAbsolutePath().toString())
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,17 +400,19 @@ public class CreateSymbolsTestImpl {
|
||||
Files.createDirectories(scratch);
|
||||
|
||||
String out;
|
||||
out = tb.new JavacTask(ToolBox.Mode.CMDLINE)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-XDuseOptimizedZip=false", "-Xprint", className7)
|
||||
.run(ToolBox.Expect.SUCCESS)
|
||||
.getOutput(ToolBox.OutputKind.STDOUT);
|
||||
out = new JavacTask(tb, Task.Mode.CMDLINE)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-Xprint", className7)
|
||||
.run(Expect.SUCCESS)
|
||||
.getOutput(Task.OutputKind.STDOUT)
|
||||
.replaceAll("\\R", "\n");
|
||||
if (!out.equals(printed7)) {
|
||||
throw new AssertionError("out=" + out + "; printed7=" + printed7);
|
||||
}
|
||||
out = tb.new JavacTask(ToolBox.Mode.CMDLINE)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-XDuseOptimizedZip=false", "-Xprint", className8)
|
||||
.run(ToolBox.Expect.SUCCESS)
|
||||
.getOutput(ToolBox.OutputKind.STDOUT);
|
||||
out = new JavacTask(tb, Task.Mode.CMDLINE)
|
||||
.options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-Xprint", className8)
|
||||
.run(Expect.SUCCESS)
|
||||
.getOutput(Task.OutputKind.STDOUT)
|
||||
.replaceAll("\\R", "\n");
|
||||
if (!out.equals(printed8)) {
|
||||
throw new AssertionError("out=" + out + "; printed8=" + printed8);
|
||||
}
|
||||
@ -411,7 +420,7 @@ public class CreateSymbolsTestImpl {
|
||||
|
||||
void doTestEquivalence(String code7, String code8, String testClass) throws Exception {
|
||||
Path classes = prepareVersionedCTSym(code7, code8);
|
||||
Path classfile = classes.resolve("78").resolve(testClass.replace('.', '/') + ".class");
|
||||
Path classfile = classes.resolve("78").resolve("java.base").resolve(testClass.replace('.', '/') + ".class");
|
||||
|
||||
if (!Files.isReadable(classfile)) {
|
||||
throw new AssertionError("Cannot find expected class.");
|
||||
@ -470,12 +479,105 @@ public class CreateSymbolsTestImpl {
|
||||
"t.PPI");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecords() throws Exception {
|
||||
doPrintElementTest("package t;" +
|
||||
"public class T {" +
|
||||
" public record R(int i, java.util.List<String> l) { }" +
|
||||
"}",
|
||||
"package t;" +
|
||||
"public class T {" +
|
||||
" public record R(@Ann int i, long j, java.util.List<String> l) { }" +
|
||||
" public @interface Ann {} " +
|
||||
"}",
|
||||
"t.T$R",
|
||||
"""
|
||||
|
||||
public static record R(int i, java.util.List<java.lang.String> l) {
|
||||
|
||||
public R(int i,
|
||||
java.util.List<java.lang.String> l);
|
||||
|
||||
public final java.lang.String toString();
|
||||
|
||||
public final int hashCode();
|
||||
|
||||
public final boolean equals(java.lang.Object arg0);
|
||||
|
||||
public int i();
|
||||
|
||||
public java.util.List<java.lang.String> l();
|
||||
}
|
||||
""",
|
||||
"t.T$R",
|
||||
"""
|
||||
|
||||
public static record R(@t.T.Ann int i, long j, java.util.List<java.lang.String> l) {
|
||||
|
||||
public final java.lang.String toString();
|
||||
|
||||
public final int hashCode();
|
||||
|
||||
public final boolean equals(java.lang.Object arg0);
|
||||
|
||||
public java.util.List<java.lang.String> l();
|
||||
|
||||
public R(@t.T.Ann int i,
|
||||
long j,
|
||||
java.util.List<java.lang.String> l);
|
||||
|
||||
@t.T.Ann
|
||||
public int i();
|
||||
|
||||
public long j();
|
||||
}
|
||||
""");
|
||||
doPrintElementTest("package t;" +
|
||||
"public record R() {" +
|
||||
"}",
|
||||
"package t;" +
|
||||
"public record R(int i) {" +
|
||||
"}",
|
||||
"t.R",
|
||||
"""
|
||||
package t;
|
||||
\n\
|
||||
public record R() {
|
||||
\n\
|
||||
public R();
|
||||
\n\
|
||||
public final java.lang.String toString();
|
||||
\n\
|
||||
public final int hashCode();
|
||||
\n\
|
||||
public final boolean equals(java.lang.Object arg0);
|
||||
}
|
||||
""",
|
||||
"t.R",
|
||||
"""
|
||||
package t;
|
||||
\n\
|
||||
public record R(int i) {
|
||||
\n\
|
||||
public final java.lang.String toString();
|
||||
\n\
|
||||
public final int hashCode();
|
||||
\n\
|
||||
public final boolean equals(java.lang.Object arg0);
|
||||
\n\
|
||||
public R(int i);
|
||||
\n\
|
||||
public int i();
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
void doTestIncluded(String code, String... includedClasses) throws Exception {
|
||||
boolean oldIncludeAll = includeAll;
|
||||
try {
|
||||
includeAll = false;
|
||||
Path classes = prepareVersionedCTSym(code, "package other; public class Other {}");
|
||||
Path root = classes.resolve("7");
|
||||
Path root = classes.resolve("7").resolve("java.base");
|
||||
try (Stream<Path> classFiles = Files.walk(root)) {
|
||||
Set<String> names = classFiles.map(p -> root.relativize(p))
|
||||
.map(p -> p.toString())
|
||||
@ -503,11 +605,7 @@ public class CreateSymbolsTestImpl {
|
||||
Path ver8Jar = output.resolve("8.jar");
|
||||
compileAndPack(output, ver8Jar, code8);
|
||||
|
||||
ZipFileIndexCache.getSharedInstance().clearCache();
|
||||
|
||||
Path classes = output.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
Path classes = output.resolve("classes.zip");
|
||||
|
||||
Path ctSym = output.resolve("ct.sym");
|
||||
|
||||
@ -518,7 +616,21 @@ public class CreateSymbolsTestImpl {
|
||||
|
||||
testGenerate(ver7Jar, ver8Jar, ctSym, "8", classes.toAbsolutePath().toString());
|
||||
|
||||
return classes;
|
||||
Path classesDir = output.resolve("classes");
|
||||
|
||||
try (JarFile jf = new JarFile(classes.toFile())) {
|
||||
Enumeration<JarEntry> en = jf.entries();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
JarEntry je = en.nextElement();
|
||||
if (je.isDirectory()) continue;
|
||||
Path target = classesDir.resolve(je.getName());
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(jf.getInputStream(je), target);
|
||||
}
|
||||
}
|
||||
|
||||
return classesDir;
|
||||
}
|
||||
|
||||
boolean includeAll = true;
|
||||
@ -540,17 +652,18 @@ public class CreateSymbolsTestImpl {
|
||||
protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) {
|
||||
return includeAll ? true : super.includeEffectiveAccess(classes, clazz);
|
||||
}
|
||||
}.createBaseLine(versions, acceptAll, descDest, null);
|
||||
}.createBaseLine(versions, acceptAll, descDest, new String[0]);
|
||||
Path symbolsDesc = descDest.resolve("symbols");
|
||||
try (Writer symbolsFile = Files.newBufferedWriter(symbolsDesc)) {
|
||||
symbolsFile.write("generate platforms 7:8");
|
||||
symbolsFile.write(System.lineSeparator());
|
||||
symbolsFile.write("platform version 7 files java.base-7.sym.txt");
|
||||
symbolsFile.write(System.lineSeparator());
|
||||
symbolsFile.write("platform version 8 base 7 files java.base-8.sym.txt");
|
||||
symbolsFile.write(System.lineSeparator());
|
||||
Path systemModules = descDest.resolve("systemModules");
|
||||
|
||||
Files.newBufferedWriter(systemModules).close();
|
||||
|
||||
try {
|
||||
new CreateSymbols().createSymbols(null, symbolsDesc.toAbsolutePath().toString(), classDest, 0, "8", systemModules.toString());
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
throw t;
|
||||
}
|
||||
new CreateSymbols().createSymbols(symbolsDesc.toAbsolutePath().toString(), classDest, CtSymKind.JOINED_VERSIONS);
|
||||
}
|
||||
|
||||
void compileAndPack(Path output, Path outputFile, String... code) throws Exception {
|
||||
@ -559,7 +672,7 @@ public class CreateSymbolsTestImpl {
|
||||
deleteRecursively(scratch);
|
||||
Files.createDirectories(scratch);
|
||||
System.err.println(Arrays.asList(code));
|
||||
tb.new JavacTask().sources(code).options("-d", scratch.toAbsolutePath().toString()).run(ToolBox.Expect.SUCCESS);
|
||||
new JavacTask(tb).sources(code).options("-d", scratch.toAbsolutePath().toString()).run(Expect.SUCCESS);
|
||||
List<String> classFiles = collectClassFile(scratch);
|
||||
try (Writer out = Files.newBufferedWriter(outputFile)) {
|
||||
for (String classFile : classFiles) {
|
129
test/langtools/tools/javac/records/RecordReading.java
Normal file
129
test/langtools/tools/javac/records/RecordReading.java
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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
|
||||
* @summary test the records can be read by javac properly
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* @build toolbox.ToolBox toolbox.JavacTask
|
||||
* @run main RecordReading
|
||||
*/
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import toolbox.TestRunner;
|
||||
import toolbox.ToolBox;
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
|
||||
public class RecordReading extends TestRunner {
|
||||
ToolBox tb;
|
||||
|
||||
RecordReading() {
|
||||
super(System.err);
|
||||
tb = new ToolBox();
|
||||
}
|
||||
|
||||
protected void runTests() throws Exception {
|
||||
runTests(m -> new Object[]{Paths.get(m.getName())});
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
RecordReading t = new RecordReading();
|
||||
t.runTests();
|
||||
}
|
||||
|
||||
Path[] findJavaFiles(Path... paths) throws IOException {
|
||||
return tb.findJavaFiles(paths);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordClassFileReading(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
public record R(int i, @A long j, java.util.List<String> l) {}
|
||||
""",
|
||||
"""
|
||||
public @interface A {}
|
||||
""");
|
||||
|
||||
Path out = base.resolve("out");
|
||||
Files.createDirectories(out);
|
||||
|
||||
new JavacTask(tb)
|
||||
.outdir(out)
|
||||
.files(findJavaFiles(src))
|
||||
.run();
|
||||
|
||||
//read the class file back, to verify javac's ClassReader
|
||||
//reads the Record attribute properly:
|
||||
String output = new JavacTask(tb)
|
||||
.options("-Xprint")
|
||||
.classpath(out.toString())
|
||||
.classes("R")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT)
|
||||
.replaceAll("\\R", "\n");
|
||||
|
||||
String expected =
|
||||
"""
|
||||
\n\
|
||||
public record R(int i, @A long j, java.util.List<java.lang.String> l) {
|
||||
private final int i;
|
||||
@A
|
||||
private final long j;
|
||||
private final java.util.List<java.lang.String> l;
|
||||
\n\
|
||||
public R(int i,
|
||||
@A long j,
|
||||
java.util.List<java.lang.String> l);
|
||||
\n\
|
||||
public final java.lang.String toString();
|
||||
\n\
|
||||
public final int hashCode();
|
||||
\n\
|
||||
public final boolean equals(java.lang.Object arg0);
|
||||
\n\
|
||||
public int i();
|
||||
\n\
|
||||
@A
|
||||
public long j();
|
||||
\n\
|
||||
public java.util.List<java.lang.String> l();
|
||||
}
|
||||
""";
|
||||
if (!Objects.equals(expected, output)) {
|
||||
throw new AssertionError("Unexpected output: " + output);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user