8356894: Adjust CreateSymbols to properly handle the newly added @jdk.internal.RequiresIdentity
Reviewed-by: vromero, liach
This commit is contained in:
parent
99e01301cd
commit
9d9e41f5b4
@ -46,6 +46,8 @@ import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.TypeAnnotation.TargetInfo;
|
||||
import java.lang.classfile.TypeAnnotation.TypePathComponent;
|
||||
import java.lang.classfile.attribute.*;
|
||||
import java.lang.classfile.constantpool.ClassEntry;
|
||||
import java.lang.classfile.constantpool.ConstantPoolBuilder;
|
||||
@ -991,6 +993,12 @@ public class CreateSymbols {
|
||||
if (desc.runtimeAnnotations != null && !desc.runtimeAnnotations.isEmpty()) {
|
||||
builder.accept(RuntimeVisibleAnnotationsAttribute.of(createAnnotations(desc.runtimeAnnotations)));
|
||||
}
|
||||
if (desc.classTypeAnnotations != null && !desc.classTypeAnnotations.isEmpty()) {
|
||||
builder.accept(RuntimeInvisibleTypeAnnotationsAttribute.of(createTypeAnnotations(desc.classTypeAnnotations)));
|
||||
}
|
||||
if (desc.runtimeTypeAnnotations != null && !desc.runtimeTypeAnnotations.isEmpty()) {
|
||||
builder.accept(RuntimeVisibleTypeAnnotationsAttribute.of(createTypeAnnotations(desc.runtimeTypeAnnotations)));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Annotation> createAnnotations(List<AnnotationDescription> desc) {
|
||||
@ -1066,6 +1074,44 @@ public class CreateSymbols {
|
||||
default -> throw new IllegalArgumentException(value.getClass().getName());
|
||||
};
|
||||
}
|
||||
|
||||
private List<TypeAnnotation> createTypeAnnotations(List<TypeAnnotationDescription> desc) {
|
||||
return desc.stream().map(this::createTypeAnnotation).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private TypeAnnotation createTypeAnnotation(TypeAnnotationDescription desc) {
|
||||
Annotation baseAnn = createAnnotation(desc.annotation);
|
||||
TargetInfo targetInfo = switch ((String) desc.targetInfo.get("targetType")) {
|
||||
case "CLASS_TYPE_PARAMETER" -> //TODO: test!
|
||||
TargetInfo.ofClassTypeParameter((int) desc.targetInfo.get("typeParameterIndex"));
|
||||
case "METHOD_TYPE_PARAMETER" ->
|
||||
TargetInfo.ofMethodTypeParameter((int) desc.targetInfo.get("typeParameterIndex"));
|
||||
case "CLASS_EXTENDS" ->
|
||||
TargetInfo.ofClassExtends((int) desc.targetInfo.get("supertypeIndex"));
|
||||
case "CLASS_TYPE_PARAMETER_BOUND" ->
|
||||
TargetInfo.ofClassTypeParameterBound((int) desc.targetInfo.get("typeParameterIndex"),
|
||||
(int) desc.targetInfo.get("boundIndex"));
|
||||
case "METHOD_TYPE_PARAMETER_BOUND" ->
|
||||
TargetInfo.ofMethodTypeParameterBound((int) desc.targetInfo.get("typeParameterIndex"),
|
||||
(int) desc.targetInfo.get("boundIndex"));
|
||||
case "METHOD_RETURN" ->
|
||||
TargetInfo.ofMethodReturn();
|
||||
case "METHOD_RECEIVER" ->
|
||||
TargetInfo.ofMethodReceiver();
|
||||
case "METHOD_FORMAL_PARAMETER" ->
|
||||
TargetInfo.ofMethodFormalParameter((int) desc.targetInfo.get("formalParameterIndex"));
|
||||
case "THROWS" ->
|
||||
TargetInfo.ofThrows((int) desc.targetInfo.get("throwsTargetIndex"));
|
||||
case "FIELD" ->
|
||||
TargetInfo.ofField();
|
||||
case String targetType ->
|
||||
throw new IllegalStateException("Unsupported targetType: " + targetType);
|
||||
};
|
||||
|
||||
List<TypePathComponent> typePath = desc.typePath.stream().map(d -> TypePathComponent.of(TypePathComponent.Kind.valueOf(d.tag()), d.index())).toList();
|
||||
|
||||
return TypeAnnotation.of(targetInfo, typePath, baseAnn);
|
||||
}
|
||||
//</editor-fold>
|
||||
//</editor-fold>
|
||||
|
||||
@ -2213,7 +2259,10 @@ public class CreateSymbols {
|
||||
chd.permittedSubclasses = a.permittedSubclasses().stream().map(ClassEntry::asInternalName).collect(Collectors.toList());
|
||||
}
|
||||
case ModuleMainClassAttribute a -> ((ModuleHeaderDescription) feature).moduleMainClass = a.mainClass().asInternalName();
|
||||
case RuntimeVisibleTypeAnnotationsAttribute a -> {/* do nothing for now */}
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute a ->
|
||||
feature.classTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
|
||||
case RuntimeVisibleTypeAnnotationsAttribute a ->
|
||||
feature.runtimeTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
|
||||
default -> throw new IllegalArgumentException("Unhandled attribute: " + attr.attributeName()); // Do nothing
|
||||
}
|
||||
|
||||
@ -2270,6 +2319,31 @@ public class CreateSymbols {
|
||||
|
||||
return new AnnotationDescription(annotationType, values);
|
||||
}
|
||||
|
||||
private List<TypeAnnotationDescription> typeAnnotations2Descriptions(List<TypeAnnotation> annos) {
|
||||
return annos.stream().map(ta -> {
|
||||
TypeAnnotationDescription desc = new TypeAnnotationDescription();
|
||||
desc.annotation = annotation2Description(ta.annotation());
|
||||
desc.targetInfo = new HashMap<>();
|
||||
desc.targetInfo.put("targetType", ta.targetInfo().targetType().name());
|
||||
switch (ta.targetInfo()) {
|
||||
case TypeAnnotation.TypeParameterTarget tpt -> desc.targetInfo.put("typeParameterIndex", tpt.typeParameterIndex());
|
||||
case TypeAnnotation.SupertypeTarget st -> desc.targetInfo.put("supertypeIndex", st.supertypeIndex());
|
||||
case TypeAnnotation.TypeParameterBoundTarget tpbt -> {
|
||||
desc.targetInfo.put("typeParameterIndex", tpbt.typeParameterIndex());
|
||||
desc.targetInfo.put("boundIndex", tpbt.boundIndex());
|
||||
}
|
||||
case TypeAnnotation.EmptyTarget _ -> {
|
||||
// nothing to write
|
||||
}
|
||||
case TypeAnnotation.FormalParameterTarget fpt -> desc.targetInfo.put("formalParameterIndex", fpt.formalParameterIndex());
|
||||
case TypeAnnotation.ThrowsTarget tt -> desc.targetInfo.put("throwsTargetIndex", tt.throwsTargetIndex());
|
||||
default -> throw new IllegalStateException(ta.targetInfo().targetType().name());
|
||||
}
|
||||
desc.typePath = ta.targetPath().stream().map(tpc -> new TypeAnnotationDescription.TypePathComponentDesc(tpc.typePathKind().name(), tpc.typeArgumentIndex())).toList();
|
||||
return desc;
|
||||
}).toList();
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) {
|
||||
@ -2391,6 +2465,8 @@ public class CreateSymbols {
|
||||
String versions = "";
|
||||
List<AnnotationDescription> classAnnotations;
|
||||
List<AnnotationDescription> runtimeAnnotations;
|
||||
List<TypeAnnotationDescription> classTypeAnnotations;
|
||||
List<TypeAnnotationDescription> runtimeTypeAnnotations;
|
||||
|
||||
protected void writeAttributes(Appendable output) throws IOException {
|
||||
if (flags != 0)
|
||||
@ -2413,6 +2489,18 @@ public class CreateSymbols {
|
||||
output.append(quote(a.toString(), false));
|
||||
}
|
||||
}
|
||||
if (classTypeAnnotations != null && !classTypeAnnotations.isEmpty()) {
|
||||
output.append(" classTypeAnnotations ");
|
||||
for (TypeAnnotationDescription a : classTypeAnnotations) {
|
||||
output.append(quote(a.toString(), false));
|
||||
}
|
||||
}
|
||||
if (runtimeTypeAnnotations != null && !runtimeTypeAnnotations.isEmpty()) {
|
||||
output.append(" runtimeTypeAnnotations ");
|
||||
for (TypeAnnotationDescription a : runtimeTypeAnnotations) {
|
||||
output.append(quote(a.toString(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldIgnore(String baselineVersion, String version) {
|
||||
@ -2442,6 +2530,14 @@ public class CreateSymbols {
|
||||
if (inRuntimeAnnotations != null) {
|
||||
runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]);
|
||||
}
|
||||
String inClassTypeAnnotations = reader.attributes.get("classTypeAnnotations");
|
||||
if (inClassTypeAnnotations != null) {
|
||||
classTypeAnnotations = parseTypeAnnotations(inClassTypeAnnotations, new int[1]);
|
||||
}
|
||||
String inRuntimeTypeAnnotations = reader.attributes.get("runtimeTypeAnnotations");
|
||||
if (inRuntimeTypeAnnotations != null) {
|
||||
runtimeTypeAnnotations = parseTypeAnnotations(inRuntimeTypeAnnotations, new int[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean read(LineBasedReader reader) throws IOException;
|
||||
@ -2454,6 +2550,8 @@ public class CreateSymbols {
|
||||
hash = 89 * hash + Objects.hashCode(this.signature);
|
||||
hash = 89 * hash + listHashCode(this.classAnnotations);
|
||||
hash = 89 * hash + listHashCode(this.runtimeAnnotations);
|
||||
hash = 89 * hash + listHashCode(this.classTypeAnnotations);
|
||||
hash = 89 * hash + listHashCode(this.runtimeTypeAnnotations);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -2481,6 +2579,12 @@ public class CreateSymbols {
|
||||
if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) {
|
||||
return false;
|
||||
}
|
||||
if (!listEquals(this.classTypeAnnotations, other.classTypeAnnotations)) {
|
||||
return false;
|
||||
}
|
||||
if (!listEquals(this.runtimeTypeAnnotations, other.runtimeTypeAnnotations)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3285,6 +3389,8 @@ public class CreateSymbols {
|
||||
hash = 59 * hash + Objects.hashCode(this.descriptor);
|
||||
hash = 59 * hash + Objects.hashCode(this.thrownTypes);
|
||||
hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue);
|
||||
hash = 59 * hash + Objects.hashCode(this.classParameterAnnotations);
|
||||
hash = 59 * hash + Objects.hashCode(this.runtimeParameterAnnotations);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -3309,6 +3415,12 @@ public class CreateSymbols {
|
||||
if (!Objects.equals(this.annotationDefaultValue, other.annotationDefaultValue)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.classParameterAnnotations, other.classParameterAnnotations)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.runtimeParameterAnnotations, other.runtimeParameterAnnotations)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3636,6 +3748,40 @@ public class CreateSymbols {
|
||||
}
|
||||
}
|
||||
|
||||
static final class TypeAnnotationDescription {
|
||||
AnnotationDescription annotation;
|
||||
Map<String, Object> targetInfo;
|
||||
List<TypePathComponentDesc> typePath;
|
||||
|
||||
public TypeAnnotationDescription() {
|
||||
}
|
||||
|
||||
public TypeAnnotationDescription(AnnotationDescription annotation, Map<String, Object> targetInfo, List<TypePathComponentDesc> typePath) {
|
||||
this.annotation = annotation;
|
||||
this.targetInfo = targetInfo;
|
||||
this.typePath = typePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return annotation.toString() + "{" + targetInfo.entrySet().stream().map(e -> e.getKey() + "=" + quote(printValue(e.getValue()), false)).collect(Collectors.joining(",")) + "}" +
|
||||
(!typePath.isEmpty() ? "[" + typePath.stream().map(desc -> desc.tag + ":" + desc.index).collect(Collectors.joining(",")) + "]" : "");
|
||||
}
|
||||
|
||||
private String printValue(Object obj) {
|
||||
if (obj instanceof String s) {
|
||||
return "\"" + s + "\"";
|
||||
} else if (obj instanceof Integer i) {
|
||||
return "I" + String.valueOf(i);
|
||||
} else {
|
||||
throw new IllegalStateException("Unsupported value: " + obj.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: path
|
||||
record TypePathComponentDesc(String tag, int index) {}
|
||||
}
|
||||
|
||||
static final class EnumConstant {
|
||||
String type;
|
||||
String constant;
|
||||
@ -3975,10 +4121,19 @@ public class CreateSymbols {
|
||||
|
||||
private static AnnotationDescription parseAnnotation(String value, int[] valuePointer) {
|
||||
String className = className(value, valuePointer);
|
||||
Map<String, Object> attribute2Value = new HashMap<>();
|
||||
Map<String, Object> attribute2Value = Map.of();
|
||||
|
||||
if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '(') {
|
||||
while (value.charAt(valuePointer[0]) != ')') {
|
||||
attribute2Value = parseMap(value, valuePointer, ')');
|
||||
}
|
||||
|
||||
return new AnnotationDescription(className, attribute2Value);
|
||||
}
|
||||
|
||||
private static Map<String, Object> parseMap(String value, int[] valuePointer, char endBracket) {
|
||||
Map<String, Object> attribute2Value = new HashMap<>();
|
||||
|
||||
while (value.charAt(valuePointer[0]) != endBracket) {
|
||||
int nameStart = ++valuePointer[0];
|
||||
|
||||
while (value.charAt(valuePointer[0]++) != '=');
|
||||
@ -3989,9 +4144,46 @@ public class CreateSymbols {
|
||||
}
|
||||
|
||||
valuePointer[0]++;
|
||||
|
||||
return attribute2Value;
|
||||
}
|
||||
|
||||
return new AnnotationDescription(className, attribute2Value);
|
||||
public static List<TypeAnnotationDescription> parseTypeAnnotations(String encoded, int[] pointer) {
|
||||
List<TypeAnnotationDescription> result = new ArrayList<>();
|
||||
|
||||
while (pointer[0] < encoded.length() && encoded.charAt(pointer[0]) == '@') {
|
||||
pointer[0]++;
|
||||
result.add(parseTypeAnnotation(encoded, pointer));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static TypeAnnotationDescription parseTypeAnnotation(String value, int[] valuePointer) {
|
||||
AnnotationDescription ann = parseAnnotation(value, valuePointer);
|
||||
Map<String, Object> targetInfo = Map.of();
|
||||
|
||||
if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '{') {
|
||||
targetInfo = parseMap(value, valuePointer, '}');
|
||||
}
|
||||
|
||||
List<TypeAnnotationDescription.TypePathComponentDesc> typePath = new ArrayList<>();
|
||||
|
||||
if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '[') {
|
||||
while (value.charAt(valuePointer[0]) != ']') {
|
||||
int nameStart = ++valuePointer[0];
|
||||
|
||||
while (value.charAt(valuePointer[0]++) != ':');
|
||||
|
||||
String name = value.substring(nameStart, valuePointer[0] - 1);
|
||||
|
||||
typePath.add(new TypeAnnotationDescription.TypePathComponentDesc(name, Integer.parseInt(readDigits(value, valuePointer))));
|
||||
}
|
||||
|
||||
valuePointer[0]++;
|
||||
}
|
||||
|
||||
return new TypeAnnotationDescription(ann, targetInfo, typePath);
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
|
@ -399,6 +399,11 @@ public class Flags {
|
||||
*/
|
||||
public static final long RESTRICTED = 1L<<62; // MethodSymbols
|
||||
|
||||
/**
|
||||
* Flag to indicate parameters that require identity.
|
||||
*/
|
||||
public static final long REQUIRES_IDENTITY = 1L<<62; // VarSymbols (parameters)
|
||||
|
||||
/**
|
||||
* Flag to indicate type annotations have been queued for field initializers.
|
||||
*/
|
||||
|
@ -969,7 +969,8 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
boolean isCurrentSymbolsAnnotation(Attribute.TypeCompound anno, int index) {
|
||||
return (anno.position.type == TargetType.CLASS_TYPE_PARAMETER ||
|
||||
anno.position.type == TargetType.METHOD_TYPE_PARAMETER) &&
|
||||
anno.position.parameter_index == index;
|
||||
anno.position.parameter_index == index &&
|
||||
anno.type.tsym.flatName() != name.table.names.requiresIdentityInternal;
|
||||
}
|
||||
|
||||
|
||||
|
@ -384,9 +384,15 @@ public class Symtab {
|
||||
// Enter a synthetic class that is used to mark classes in ct.sym.
|
||||
// This class does not have a class file.
|
||||
private Type enterSyntheticAnnotation(String name) {
|
||||
return enterSyntheticAnnotation(names.fromString(name));
|
||||
}
|
||||
|
||||
// Enter a synthetic class that is used to mark classes in ct.sym.
|
||||
// This class does not have a class file.
|
||||
private Type enterSyntheticAnnotation(Name name) {
|
||||
// for now, leave the module null, to prevent problems from synthesizing the
|
||||
// existence of a class in any specific module, including noModule
|
||||
ClassType type = (ClassType)enterClass(java_base, names.fromString(name)).type;
|
||||
ClassType type = (ClassType)enterClass(java_base, name).type;
|
||||
ClassSymbol sym = (ClassSymbol)type.tsym;
|
||||
sym.completer = Completer.NULL_COMPLETER;
|
||||
sym.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE;
|
||||
@ -613,7 +619,7 @@ public class Symtab {
|
||||
valueBasedType = enterClass("jdk.internal.ValueBased");
|
||||
valueBasedInternalType = enterSyntheticAnnotation("jdk.internal.ValueBased+Annotation");
|
||||
requiresIdentityType = enterClass("jdk.internal.RequiresIdentity");
|
||||
requiresIdentityInternalType = enterSyntheticAnnotation("jdk.internal.RequiresIdentity+Annotation");
|
||||
requiresIdentityInternalType = enterSyntheticAnnotation(names.requiresIdentityInternal);
|
||||
classDescType = enterClass("java.lang.constant.ClassDesc");
|
||||
enumDescType = enterClass("java.lang.Enum$EnumDesc");
|
||||
// For serialization lint checking
|
||||
|
@ -384,6 +384,12 @@ public class Annotate {
|
||||
&& types.isSameType(c.type, syms.restrictedType)) {
|
||||
toAnnotate.flags_field |= Flags.RESTRICTED;
|
||||
}
|
||||
|
||||
if (!c.type.isErroneous()
|
||||
&& toAnnotate.kind == VAR
|
||||
&& types.isSameType(c.type, syms.requiresIdentityType)) {
|
||||
toAnnotate.flags_field |= Flags.REQUIRES_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
List<T> buf = List.nil();
|
||||
|
@ -5729,14 +5729,14 @@ public class Check {
|
||||
if (!argExps.isEmpty() && msym instanceof MethodSymbol ms && ms.params != null) {
|
||||
VarSymbol lastParam = ms.params.head;
|
||||
for (VarSymbol param: ms.params) {
|
||||
if (param.attribute(syms.requiresIdentityType.tsym) != null && argExps.head.type.isValueBased()) {
|
||||
if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
|
||||
lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
|
||||
}
|
||||
lastParam = param;
|
||||
argExps = argExps.tail;
|
||||
}
|
||||
while (argExps != null && !argExps.isEmpty() && lastParam != null) {
|
||||
if (lastParam.attribute(syms.requiresIdentityType.tsym) != null && argExps.head.type.isValueBased()) {
|
||||
if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
|
||||
lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
|
||||
}
|
||||
argExps = argExps.tail;
|
||||
@ -5813,7 +5813,7 @@ public class Check {
|
||||
SymbolMetadata sm = t.tsym.getMetadata();
|
||||
if (sm != null && !t.getTypeArguments().isEmpty()) {
|
||||
if (sm.getTypeAttributes().stream()
|
||||
.filter(ta -> ta.type.tsym == syms.requiresIdentityType.tsym &&
|
||||
.filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) &&
|
||||
t.getTypeArguments().get(ta.position.parameter_index) != null &&
|
||||
t.getTypeArguments().get(ta.position.parameter_index).isValueBased()).findAny().isPresent()) {
|
||||
requiresWarning = true;
|
||||
@ -5838,11 +5838,16 @@ public class Check {
|
||||
}
|
||||
if (sm != null)
|
||||
sm.getTypeAttributes().stream()
|
||||
.filter(ta -> (ta.type.tsym == syms.requiresIdentityType.tsym) &&
|
||||
.filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) &&
|
||||
typeParamTrees.get(ta.position.parameter_index).type != null &&
|
||||
typeParamTrees.get(ta.position.parameter_index).type.isValueBased())
|
||||
.forEach(ta -> lint.logIfEnabled(typeParamTrees.get(ta.position.parameter_index).pos(),
|
||||
CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRequiresIdentityAnnotation(TypeSymbol annoType) {
|
||||
return annoType == syms.requiresIdentityType.tsym ||
|
||||
annoType.flatName() == syms.requiresIdentityInternalType.tsym.flatName();
|
||||
}
|
||||
}
|
||||
|
@ -1556,6 +1556,9 @@ public class ClassReader {
|
||||
} else if (proxy.type.tsym.flatName() == syms.restrictedInternalType.tsym.flatName()) {
|
||||
Assert.check(sym.kind == MTH);
|
||||
sym.flags_field |= RESTRICTED;
|
||||
} else if (proxy.type.tsym.flatName() == syms.requiresIdentityInternalType.tsym.flatName()) {
|
||||
Assert.check(sym.kind == VAR);
|
||||
sym.flags_field |= REQUIRES_IDENTITY;
|
||||
} else {
|
||||
if (proxy.type.tsym == syms.annotationTargetType.tsym) {
|
||||
target = proxy;
|
||||
@ -1572,6 +1575,9 @@ public class ClassReader {
|
||||
} else if (proxy.type.tsym == syms.restrictedType.tsym) {
|
||||
Assert.check(sym.kind == MTH);
|
||||
sym.flags_field |= RESTRICTED;
|
||||
} else if (proxy.type.tsym == syms.requiresIdentityType.tsym) {
|
||||
Assert.check(sym.kind == VAR);
|
||||
sym.flags_field |= REQUIRES_IDENTITY;
|
||||
}
|
||||
proxies.append(proxy);
|
||||
}
|
||||
@ -2809,9 +2815,8 @@ public class ClassReader {
|
||||
params.append(param);
|
||||
if (parameterAnnotations != null) {
|
||||
ParameterAnnotations annotations = parameterAnnotations[annotationIndex];
|
||||
if (annotations != null && annotations.proxies != null
|
||||
&& !annotations.proxies.isEmpty()) {
|
||||
annotate.normal(new AnnotationCompleter(param, annotations.proxies));
|
||||
if (annotations != null && annotations.proxies != null) {
|
||||
attachAnnotations(param, annotations.proxies);
|
||||
}
|
||||
}
|
||||
nameIndexLvt += Code.width(t);
|
||||
|
@ -228,6 +228,9 @@ public class Names {
|
||||
public final Name enumSwitch;
|
||||
public final Name enumConstant;
|
||||
|
||||
// special annotation names
|
||||
public final Name requiresIdentityInternal;
|
||||
|
||||
public final Name.Table table;
|
||||
|
||||
@SuppressWarnings("this-escape")
|
||||
@ -412,6 +415,9 @@ public class Names {
|
||||
typeSwitch = fromString("typeSwitch");
|
||||
enumSwitch = fromString("enumSwitch");
|
||||
enumConstant = fromString("enumConstant");
|
||||
|
||||
// special annotations:
|
||||
requiresIdentityInternal = fromString("jdk.internal.RequiresIdentity+Annotation");
|
||||
}
|
||||
|
||||
protected Name.Table createTable(Options options) {
|
||||
|
166
test/langtools/tools/javac/platform/RequiresIdentityTest.java
Normal file
166
test/langtools/tools/javac/platform/RequiresIdentityTest.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 8356894
|
||||
* @summary Verify source level checks are performed properly
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
* @build toolbox.ToolBox toolbox.JavacTask
|
||||
* @run main RequiresIdentityTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
import toolbox.TestRunner;
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class RequiresIdentityTest extends TestRunner {
|
||||
|
||||
ToolBox tb;
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new RequiresIdentityTest().runTests();
|
||||
}
|
||||
|
||||
RequiresIdentityTest() {
|
||||
super(System.err);
|
||||
tb = new ToolBox();
|
||||
}
|
||||
|
||||
public void runTests() throws Exception {
|
||||
runTests(m -> new Object[] { Paths.get(m.getName()) });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseWorksAsCurrentVersion(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
Path classes = base.resolve("classes");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Test {
|
||||
void test() {
|
||||
WeakHashMap<Optional<Integer>, Object> m = null;
|
||||
m.put(Optional.empty(), 1);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
var expectedErrors = List.of(
|
||||
"Test.java:6:20: compiler.warn.attempt.to.use.value.based.where.identity.expected",
|
||||
"Test.java:7:29: compiler.warn.attempt.to.use.value.based.where.identity.expected",
|
||||
"2 warnings"
|
||||
);
|
||||
|
||||
{
|
||||
var actualErrors =
|
||||
new JavacTask(tb)
|
||||
.options("-XDrawDiagnostics")
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
if (!expectedErrors.equals(actualErrors)) {
|
||||
throw new AssertionError("Incorrect errors, expected: " + List.of(expectedErrors) +
|
||||
", actual: " + actualErrors);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var actualErrors =
|
||||
new JavacTask(tb)
|
||||
.options("--release", System.getProperty("java.specification.version"),
|
||||
"-XDrawDiagnostics")
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
if (!expectedErrors.equals(actualErrors)) {
|
||||
throw new AssertionError("Incorrect errors, expected: " + List.of(expectedErrors) +
|
||||
", actual: " + actualErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModel(Path base) throws Exception {
|
||||
{
|
||||
List<String> printed =
|
||||
new JavacTask(tb)
|
||||
.options("-Xprint")
|
||||
.classes("java.util.WeakHashMap")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.STDOUT);
|
||||
|
||||
printed.removeIf(l -> !l.contains("put(") && !l.contains("class WeakHashMap<"));
|
||||
|
||||
List<String> expected = List.of(
|
||||
"public class WeakHashMap<@jdk.internal.RequiresIdentity K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {",
|
||||
" public V put(@jdk.internal.RequiresIdentity sealed K key,"
|
||||
);
|
||||
if (!expected.equals(printed)) {
|
||||
throw new AssertionError("Expected: " + expected +
|
||||
", but got: " + printed);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
List<String> printed =
|
||||
new JavacTask(tb)
|
||||
.options("--release", System.getProperty("java.specification.version"),
|
||||
"-Xprint")
|
||||
.classes("java.util.WeakHashMap")
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.STDOUT);
|
||||
|
||||
printed.removeIf(l -> !l.contains("put(") && !l.contains("class WeakHashMap<"));
|
||||
|
||||
List<String> expected = List.of(
|
||||
"public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {",
|
||||
" public V put(sealed K arg0,"
|
||||
);
|
||||
if (!expected.equals(printed)) {
|
||||
throw new AssertionError("Expected: " + expected +
|
||||
", but got: " + printed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
RequiresIdentityTest.java:16:18: compiler.warn.attempt.to.use.value.based.where.identity.expected
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
1 warning
|
@ -21,19 +21,6 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072480 8277106 8331027
|
||||
* @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
|
||||
* @clean *
|
||||
* @run main/othervm CreateSymbolsTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
@ -21,6 +21,19 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072480 8277106 8331027
|
||||
* @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
|
||||
* @clean *
|
||||
* @run main/othervm CreateSymbolsTest
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.Writer;
|
||||
@ -908,6 +921,109 @@ public class CreateSymbolsTestImpl {
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTypeAnnotations() throws Exception {
|
||||
doPrintElementTest("""
|
||||
package t;
|
||||
public class T {
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package t;
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
public class T<@AnnInvisible @AnnVisible E extends @AnnInvisible @AnnVisible ArrayList<@AnnInvisible @AnnVisible ArrayList>> extends @AnnInvisible @AnnVisible ArrayList {
|
||||
public @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible E> field;
|
||||
public <@AnnInvisible @AnnVisible M extends @AnnInvisible @AnnVisible ArrayList<@AnnInvisible @AnnVisible ArrayList>> @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible M> convert(@AnnInvisible @AnnVisible T<E> this, @AnnInvisible @AnnVisible M e1, @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible E> e2) throws @AnnInvisible @AnnVisible IllegalStateException, @AnnInvisible @AnnVisible IllegalArgumentException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface AnnVisible {
|
||||
}
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface AnnInvisible {
|
||||
}
|
||||
""",
|
||||
"t.T",
|
||||
"""
|
||||
package t;
|
||||
|
||||
public class T {
|
||||
|
||||
public T();
|
||||
}
|
||||
""",
|
||||
"t.T",
|
||||
"""
|
||||
package t;
|
||||
|
||||
public class T<@t.AnnInvisible @t.AnnVisible E extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList<java.util.@t.AnnInvisible @t.AnnVisible ArrayList>> extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList {
|
||||
public java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible E> field;
|
||||
|
||||
public T();
|
||||
|
||||
public <@t.AnnInvisible @t.AnnVisible M extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList<java.util.@t.AnnInvisible @t.AnnVisible ArrayList>> java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible M> convert(@t.AnnInvisible @t.AnnVisible M arg0,
|
||||
java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible E> arg1) throws java.lang.@t.AnnInvisible @t.AnnVisible IllegalStateException,\s
|
||||
java.lang.@t.AnnInvisible @t.AnnVisible IllegalArgumentException;
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParameterAnnotations() throws Exception {
|
||||
doPrintElementTest("""
|
||||
package t;
|
||||
public class T {
|
||||
public void test(int p1, int p2) {
|
||||
}
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package t;
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
public class T {
|
||||
public void test(@AnnVisible int p1, @AnnInvisible int p2) {
|
||||
}
|
||||
}
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@interface AnnVisible {
|
||||
}
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@interface AnnInvisible {
|
||||
}
|
||||
""",
|
||||
"t.T",
|
||||
"""
|
||||
package t;
|
||||
|
||||
public class T {
|
||||
|
||||
public T();
|
||||
|
||||
public void test(int arg0,
|
||||
int arg1);
|
||||
}
|
||||
""",
|
||||
"t.T",
|
||||
"""
|
||||
package t;
|
||||
|
||||
public class T {
|
||||
|
||||
public T();
|
||||
|
||||
public void test(@t.AnnVisible int arg0,
|
||||
@t.AnnInvisible int arg1);
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
void doTestData(String data,
|
||||
String... code) throws Exception {
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
|
Loading…
x
Reference in New Issue
Block a user