8292275: javac does not emit SYNTHETIC and MANDATED flags for parameters by default
Co-authored-by: Chen Liang <liach@openjdk.org> Reviewed-by: vromero, jwaters
This commit is contained in:
parent
6d6d00b69c
commit
b3dbf28bc0
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2384,7 +2384,8 @@ public class CreateSymbols {
|
|||||||
MethodDescription method = (MethodDescription) feature;
|
MethodDescription method = (MethodDescription) feature;
|
||||||
method.methodParameters = new ArrayList<>();
|
method.methodParameters = new ArrayList<>();
|
||||||
for (MethodParameters_attribute.Entry e : params.method_parameter_table) {
|
for (MethodParameters_attribute.Entry e : params.method_parameter_table) {
|
||||||
String name = cf.constant_pool.getUTF8Value(e.name_index);
|
String name = e.name_index == 0 ? null
|
||||||
|
: cf.constant_pool.getUTF8Value(e.name_index);
|
||||||
MethodDescription.MethodParam param =
|
MethodDescription.MethodParam param =
|
||||||
new MethodDescription.MethodParam(e.flags, name);
|
new MethodDescription.MethodParam(e.flags, name);
|
||||||
method.methodParameters.add(param);
|
method.methodParameters.add(param);
|
||||||
|
@ -202,7 +202,13 @@ public class ClassReader {
|
|||||||
/** A table to hold the constant pool indices for method parameter
|
/** A table to hold the constant pool indices for method parameter
|
||||||
* names, as given in LocalVariableTable attributes.
|
* names, as given in LocalVariableTable attributes.
|
||||||
*/
|
*/
|
||||||
int[] parameterNameIndices;
|
int[] parameterNameIndicesLvt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A table to hold the constant pool indices for method parameter
|
||||||
|
* names, as given in the MethodParameters attribute.
|
||||||
|
*/
|
||||||
|
int[] parameterNameIndicesMp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A table to hold the access flags of the method parameters.
|
* A table to hold the access flags of the method parameters.
|
||||||
@ -229,18 +235,6 @@ public class ClassReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not any parameter names have been found.
|
|
||||||
*/
|
|
||||||
boolean haveParameterNameIndices;
|
|
||||||
|
|
||||||
/** Set this to false every time we start reading a method
|
|
||||||
* and are saving parameter names. Set it to true when we see
|
|
||||||
* MethodParameters, if it's set when we see a LocalVariableTable,
|
|
||||||
* then we ignore the parameter names from the LVT.
|
|
||||||
*/
|
|
||||||
boolean sawMethodParameters;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of attribute names for which warnings have been generated for the current class
|
* The set of attribute names for which warnings have been generated for the current class
|
||||||
*/
|
*/
|
||||||
@ -939,7 +933,7 @@ public class ClassReader {
|
|||||||
new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
|
new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
|
||||||
protected void read(Symbol sym, int attrLen) {
|
protected void read(Symbol sym, int attrLen) {
|
||||||
int newbp = bp + attrLen;
|
int newbp = bp + attrLen;
|
||||||
if (saveParameterNames && !sawMethodParameters) {
|
if (saveParameterNames) {
|
||||||
// Pick up parameter names from the variable table.
|
// Pick up parameter names from the variable table.
|
||||||
// Parameter names are not explicitly identified as such,
|
// Parameter names are not explicitly identified as such,
|
||||||
// but all parameter name entries in the LocalVariableTable
|
// but all parameter name entries in the LocalVariableTable
|
||||||
@ -958,14 +952,13 @@ public class ClassReader {
|
|||||||
int register = nextChar();
|
int register = nextChar();
|
||||||
if (start_pc == 0) {
|
if (start_pc == 0) {
|
||||||
// ensure array large enough
|
// ensure array large enough
|
||||||
if (register >= parameterNameIndices.length) {
|
if (register >= parameterNameIndicesLvt.length) {
|
||||||
int newSize =
|
int newSize =
|
||||||
Math.max(register + 1, parameterNameIndices.length + 8);
|
Math.max(register + 1, parameterNameIndicesLvt.length + 8);
|
||||||
parameterNameIndices =
|
parameterNameIndicesLvt =
|
||||||
Arrays.copyOf(parameterNameIndices, newSize);
|
Arrays.copyOf(parameterNameIndicesLvt, newSize);
|
||||||
}
|
}
|
||||||
parameterNameIndices[register] = nameIndex;
|
parameterNameIndicesLvt[register] = nameIndex;
|
||||||
haveParameterNameIndices = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1116,11 +1109,9 @@ public class ClassReader {
|
|||||||
protected void read(Symbol sym, int attrlen) {
|
protected void read(Symbol sym, int attrlen) {
|
||||||
int newbp = bp + attrlen;
|
int newbp = bp + attrlen;
|
||||||
if (saveParameterNames) {
|
if (saveParameterNames) {
|
||||||
sawMethodParameters = true;
|
|
||||||
int numEntries = nextByte();
|
int numEntries = nextByte();
|
||||||
parameterNameIndices = new int[numEntries];
|
parameterNameIndicesMp = new int[numEntries];
|
||||||
parameterAccessFlags = new int[numEntries];
|
parameterAccessFlags = new int[numEntries];
|
||||||
haveParameterNameIndices = true;
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < numEntries; i++) {
|
for (int i = 0; i < numEntries; i++) {
|
||||||
int nameIndex = nextChar();
|
int nameIndex = nextChar();
|
||||||
@ -1128,7 +1119,7 @@ public class ClassReader {
|
|||||||
if ((flags & (Flags.MANDATED | Flags.SYNTHETIC)) != 0) {
|
if ((flags & (Flags.MANDATED | Flags.SYNTHETIC)) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
parameterNameIndices[index] = nameIndex;
|
parameterNameIndicesMp[index] = nameIndex;
|
||||||
parameterAccessFlags[index] = flags;
|
parameterAccessFlags[index] = flags;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -2396,13 +2387,11 @@ public class ClassReader {
|
|||||||
final int excessSlots = 4;
|
final int excessSlots = 4;
|
||||||
int expectedParameterSlots =
|
int expectedParameterSlots =
|
||||||
Code.width(sym.type.getParameterTypes()) + excessSlots;
|
Code.width(sym.type.getParameterTypes()) + excessSlots;
|
||||||
if (parameterNameIndices == null
|
if (parameterNameIndicesLvt == null
|
||||||
|| parameterNameIndices.length < expectedParameterSlots) {
|
|| parameterNameIndicesLvt.length < expectedParameterSlots) {
|
||||||
parameterNameIndices = new int[expectedParameterSlots];
|
parameterNameIndicesLvt = new int[expectedParameterSlots];
|
||||||
} else
|
} else
|
||||||
Arrays.fill(parameterNameIndices, 0);
|
Arrays.fill(parameterNameIndicesLvt, 0);
|
||||||
haveParameterNameIndices = false;
|
|
||||||
sawMethodParameters = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2417,11 +2406,7 @@ public class ClassReader {
|
|||||||
* anonymous synthetic parameters.
|
* anonymous synthetic parameters.
|
||||||
*/
|
*/
|
||||||
void setParameters(MethodSymbol sym, Type jvmType) {
|
void setParameters(MethodSymbol sym, Type jvmType) {
|
||||||
// If we get parameter names from MethodParameters, then we
|
int firstParamLvt = ((sym.flags() & STATIC) == 0) ? 1 : 0;
|
||||||
// don't need to skip.
|
|
||||||
int firstParam = 0;
|
|
||||||
if (!sawMethodParameters) {
|
|
||||||
firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
|
|
||||||
// the code in readMethod may have skipped the first
|
// the code in readMethod may have skipped the first
|
||||||
// parameter when setting up the MethodType. If so, we
|
// parameter when setting up the MethodType. If so, we
|
||||||
// make a corresponding allowance here for the position of
|
// make a corresponding allowance here for the position of
|
||||||
@ -2433,7 +2418,7 @@ public class ClassReader {
|
|||||||
// instance, however, there is no reliable way to tell so
|
// instance, however, there is no reliable way to tell so
|
||||||
// we never strip this$n
|
// we never strip this$n
|
||||||
if (!currentOwner.name.isEmpty())
|
if (!currentOwner.name.isEmpty())
|
||||||
firstParam += 1;
|
firstParamLvt += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym.type != jvmType) {
|
if (sym.type != jvmType) {
|
||||||
@ -2448,15 +2433,20 @@ public class ClassReader {
|
|||||||
// passed into Enum constructors.
|
// passed into Enum constructors.
|
||||||
int skip = Code.width(jvmType.getParameterTypes())
|
int skip = Code.width(jvmType.getParameterTypes())
|
||||||
- Code.width(sym.type.getParameterTypes());
|
- Code.width(sym.type.getParameterTypes());
|
||||||
firstParam += skip;
|
firstParamLvt += skip;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Set<Name> paramNames = new HashSet<>();
|
Set<Name> paramNames = new HashSet<>();
|
||||||
ListBuffer<VarSymbol> params = new ListBuffer<>();
|
ListBuffer<VarSymbol> params = new ListBuffer<>();
|
||||||
int nameIndex = firstParam;
|
// we maintain two index pointers, one for the LocalVariableTable attribute
|
||||||
|
// and the other for the MethodParameters attribute.
|
||||||
|
// This is needed as the MethodParameters attribute may contain
|
||||||
|
// name_index = 0 in which case we want to fall back to the LocalVariableTable.
|
||||||
|
// In such case, we still want to read the flags from the MethodParameters with that index.
|
||||||
|
int nameIndexLvt = firstParamLvt;
|
||||||
|
int nameIndexMp = 0;
|
||||||
int annotationIndex = 0;
|
int annotationIndex = 0;
|
||||||
for (Type t: sym.type.getParameterTypes()) {
|
for (Type t: sym.type.getParameterTypes()) {
|
||||||
VarSymbol param = parameter(nameIndex, t, sym, paramNames);
|
VarSymbol param = parameter(nameIndexMp, nameIndexLvt, t, sym, paramNames);
|
||||||
params.append(param);
|
params.append(param);
|
||||||
if (parameterAnnotations != null) {
|
if (parameterAnnotations != null) {
|
||||||
ParameterAnnotations annotations = parameterAnnotations[annotationIndex];
|
ParameterAnnotations annotations = parameterAnnotations[annotationIndex];
|
||||||
@ -2465,7 +2455,8 @@ public class ClassReader {
|
|||||||
annotate.normal(new AnnotationCompleter(param, annotations.proxies));
|
annotate.normal(new AnnotationCompleter(param, annotations.proxies));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nameIndex += sawMethodParameters ? 1 : Code.width(t);
|
nameIndexLvt += Code.width(t);
|
||||||
|
nameIndexMp++;
|
||||||
annotationIndex++;
|
annotationIndex++;
|
||||||
}
|
}
|
||||||
if (parameterAnnotations != null && parameterAnnotations.length != annotationIndex) {
|
if (parameterAnnotations != null && parameterAnnotations.length != annotationIndex) {
|
||||||
@ -2474,24 +2465,34 @@ public class ClassReader {
|
|||||||
Assert.checkNull(sym.params);
|
Assert.checkNull(sym.params);
|
||||||
sym.params = params.toList();
|
sym.params = params.toList();
|
||||||
parameterAnnotations = null;
|
parameterAnnotations = null;
|
||||||
parameterNameIndices = null;
|
parameterNameIndicesLvt = null;
|
||||||
|
parameterNameIndicesMp = null;
|
||||||
parameterAccessFlags = null;
|
parameterAccessFlags = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
// Returns the name for the parameter at position 'index', either using
|
* Creates the parameter at the position {@code mpIndex} in the parameter list of the owning method.
|
||||||
// names read from the MethodParameters, or by synthesizing a name that
|
* Flags are optionally read from the MethodParameters attribute.
|
||||||
// is not on the 'exclude' list.
|
* Names are optionally read from the MethodParameters attribute. If the constant pool index
|
||||||
private VarSymbol parameter(int index, Type t, MethodSymbol owner, Set<Name> exclude) {
|
* of the name is 0, then the name is optionally read from the LocalVariableTable attribute.
|
||||||
|
* @param mpIndex the index of the parameter in the MethodParameters attribute
|
||||||
|
* @param lvtIndex the index of the parameter in the LocalVariableTable attribute
|
||||||
|
*/
|
||||||
|
private VarSymbol parameter(int mpIndex, int lvtIndex, Type t, MethodSymbol owner, Set<Name> exclude) {
|
||||||
long flags = PARAMETER;
|
long flags = PARAMETER;
|
||||||
Name argName;
|
Name argName;
|
||||||
if (parameterAccessFlags != null && index < parameterAccessFlags.length
|
if (parameterAccessFlags != null && mpIndex < parameterAccessFlags.length
|
||||||
&& parameterAccessFlags[index] != 0) {
|
&& parameterAccessFlags[mpIndex] != 0) {
|
||||||
flags |= parameterAccessFlags[index];
|
flags |= parameterAccessFlags[mpIndex];
|
||||||
}
|
}
|
||||||
if (parameterNameIndices != null && index < parameterNameIndices.length
|
if (parameterNameIndicesMp != null
|
||||||
&& parameterNameIndices[index] != 0) {
|
// if name_index is 0, then we might still get a name from the LocalVariableTable
|
||||||
argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty);
|
&& parameterNameIndicesMp[mpIndex] != 0) {
|
||||||
|
argName = optPoolEntry(parameterNameIndicesMp[mpIndex], poolReader::getName, names.empty);
|
||||||
|
flags |= NAME_FILLED;
|
||||||
|
} else if (parameterNameIndicesLvt != null && lvtIndex < parameterNameIndicesLvt.length
|
||||||
|
&& parameterNameIndicesLvt[lvtIndex] != 0) {
|
||||||
|
argName = optPoolEntry(parameterNameIndicesLvt[lvtIndex], poolReader::getName, names.empty);
|
||||||
flags |= NAME_FILLED;
|
flags |= NAME_FILLED;
|
||||||
} else {
|
} else {
|
||||||
String prefix = "arg";
|
String prefix = "arg";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,7 +40,6 @@ import javax.tools.JavaFileObject;
|
|||||||
import com.sun.tools.javac.code.*;
|
import com.sun.tools.javac.code.*;
|
||||||
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
||||||
import com.sun.tools.javac.code.Directive.*;
|
import com.sun.tools.javac.code.Directive.*;
|
||||||
import com.sun.tools.javac.code.Source.Feature;
|
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
import com.sun.tools.javac.code.Type.*;
|
import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
|
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
|
||||||
@ -383,7 +382,7 @@ public class ClassWriter extends ClassFile {
|
|||||||
/**
|
/**
|
||||||
* Write method parameter names attribute.
|
* Write method parameter names attribute.
|
||||||
*/
|
*/
|
||||||
int writeMethodParametersAttr(MethodSymbol m) {
|
int writeMethodParametersAttr(MethodSymbol m, boolean writeParamNames) {
|
||||||
MethodType ty = m.externalType(types).asMethodType();
|
MethodType ty = m.externalType(types).asMethodType();
|
||||||
final int allparams = ty.argtypes.size();
|
final int allparams = ty.argtypes.size();
|
||||||
if (m.params != null && allparams != 0) {
|
if (m.params != null && allparams != 0) {
|
||||||
@ -394,7 +393,10 @@ public class ClassWriter extends ClassFile {
|
|||||||
final int flags =
|
final int flags =
|
||||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||||
((int) m.flags() & SYNTHETIC);
|
((int) m.flags() & SYNTHETIC);
|
||||||
|
if (writeParamNames)
|
||||||
databuf.appendChar(poolWriter.putName(s.name));
|
databuf.appendChar(poolWriter.putName(s.name));
|
||||||
|
else
|
||||||
|
databuf.appendChar(0);
|
||||||
databuf.appendChar(flags);
|
databuf.appendChar(flags);
|
||||||
}
|
}
|
||||||
// Now write the real parameters
|
// Now write the real parameters
|
||||||
@ -402,7 +404,10 @@ public class ClassWriter extends ClassFile {
|
|||||||
final int flags =
|
final int flags =
|
||||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||||
((int) m.flags() & SYNTHETIC);
|
((int) m.flags() & SYNTHETIC);
|
||||||
|
if (writeParamNames)
|
||||||
databuf.appendChar(poolWriter.putName(s.name));
|
databuf.appendChar(poolWriter.putName(s.name));
|
||||||
|
else
|
||||||
|
databuf.appendChar(0);
|
||||||
databuf.appendChar(flags);
|
databuf.appendChar(flags);
|
||||||
}
|
}
|
||||||
// Now write the captured locals
|
// Now write the captured locals
|
||||||
@ -410,7 +415,10 @@ public class ClassWriter extends ClassFile {
|
|||||||
final int flags =
|
final int flags =
|
||||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||||
((int) m.flags() & SYNTHETIC);
|
((int) m.flags() & SYNTHETIC);
|
||||||
|
if (writeParamNames)
|
||||||
databuf.appendChar(poolWriter.putName(s.name));
|
databuf.appendChar(poolWriter.putName(s.name));
|
||||||
|
else
|
||||||
|
databuf.appendChar(0);
|
||||||
databuf.appendChar(flags);
|
databuf.appendChar(flags);
|
||||||
}
|
}
|
||||||
endAttr(attrIndex);
|
endAttr(attrIndex);
|
||||||
@ -1009,9 +1017,12 @@ public class ClassWriter extends ClassFile {
|
|||||||
endAttr(alenIdx);
|
endAttr(alenIdx);
|
||||||
acount++;
|
acount++;
|
||||||
}
|
}
|
||||||
if (target.hasMethodParameters() && (options.isSet(PARAMETERS) || m.isConstructor() && (m.flags_field & RECORD) != 0)) {
|
if (target.hasMethodParameters()) {
|
||||||
if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
|
if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies.
|
||||||
acount += writeMethodParametersAttr(m);
|
boolean requiresParamNames = requiresParamNames(m);
|
||||||
|
if (requiresParamNames || requiresParamFlags(m))
|
||||||
|
acount += writeMethodParametersAttr(m, requiresParamNames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
acount += writeMemberAttrs(m, false);
|
acount += writeMemberAttrs(m, false);
|
||||||
if (!m.isLambdaMethod())
|
if (!m.isLambdaMethod())
|
||||||
@ -1020,6 +1031,25 @@ public class ClassWriter extends ClassFile {
|
|||||||
endAttrs(acountIdx, acount);
|
endAttrs(acountIdx, acount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean requiresParamNames(MethodSymbol m) {
|
||||||
|
if (options.isSet(PARAMETERS))
|
||||||
|
return true;
|
||||||
|
if (m.isConstructor() && (m.flags_field & RECORD) != 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean requiresParamFlags(MethodSymbol m) {
|
||||||
|
if (!m.extraParams.isEmpty()) {
|
||||||
|
return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
|
||||||
|
}
|
||||||
|
if (m.params != null) {
|
||||||
|
// parameter is stored in params for Enum#valueOf(name)
|
||||||
|
return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Write code attribute of method.
|
/** Write code attribute of method.
|
||||||
*/
|
*/
|
||||||
void writeCode(Code code) {
|
void writeCode(Code code) {
|
||||||
|
@ -4153,7 +4153,7 @@ public class JavacParser implements Parser {
|
|||||||
for (JCVariableDecl param : headerFields) {
|
for (JCVariableDecl param : headerFields) {
|
||||||
tmpParams.add(F.at(param)
|
tmpParams.add(F.at(param)
|
||||||
// we will get flags plus annotations from the record component
|
// we will get flags plus annotations from the record component
|
||||||
.VarDef(F.Modifiers(Flags.PARAMETER | Flags.GENERATED_MEMBER | param.mods.flags & Flags.VARARGS,
|
.VarDef(F.Modifiers(Flags.PARAMETER | Flags.GENERATED_MEMBER | Flags.MANDATED | param.mods.flags & Flags.VARARGS,
|
||||||
param.mods.annotations),
|
param.mods.annotations),
|
||||||
param.name, param.vartype, null));
|
param.name, param.vartype, null));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import java.lang.reflect.AccessFlag;
|
||||||
|
import java.lang.reflect.Executable;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8292275
|
||||||
|
* @summary Test required flags on parameters
|
||||||
|
* @compile RequiredMethodParameterFlagTest.java
|
||||||
|
* @run junit RequiredMethodParameterFlagTest
|
||||||
|
*/
|
||||||
|
class RequiredMethodParameterFlagTest {
|
||||||
|
|
||||||
|
private static final Set<AccessFlag> CHECKED_FLAGS = Set.of(AccessFlag.MANDATED, AccessFlag.SYNTHETIC);
|
||||||
|
|
||||||
|
static Stream<Arguments> testCases() throws ReflectiveOperationException {
|
||||||
|
Set<AccessFlag> mandated = Set.of(AccessFlag.MANDATED);
|
||||||
|
Set<AccessFlag> synthetic = Set.of(AccessFlag.SYNTHETIC);
|
||||||
|
|
||||||
|
return Stream.of(
|
||||||
|
// test for implicit parameters
|
||||||
|
// inner class
|
||||||
|
Arguments.of(Outer.Inner.class.getDeclaredConstructors()[0],
|
||||||
|
List.of(mandated, Set.of())),
|
||||||
|
// anonymous class extending an inner class
|
||||||
|
Arguments.of(Class.forName("Outer$1")
|
||||||
|
.getDeclaredConstructors()[0],
|
||||||
|
List.of(mandated, Set.of(), Set.of())),
|
||||||
|
// anonymous class
|
||||||
|
Arguments.of(Class.forName("Outer$2")
|
||||||
|
.getDeclaredConstructors()[0],
|
||||||
|
List.of(mandated)),
|
||||||
|
// enum class
|
||||||
|
Arguments.of(Outer.MyEnum.class.getDeclaredMethod("valueOf", String.class),
|
||||||
|
List.of(mandated)),
|
||||||
|
// record class
|
||||||
|
Arguments.of(Outer.MyRecord.class.getDeclaredConstructors()[0],
|
||||||
|
List.of(mandated, mandated)),
|
||||||
|
// local class
|
||||||
|
Arguments.of(Class.forName("Outer$1Task")
|
||||||
|
.getDeclaredConstructors()[0],
|
||||||
|
List.of(mandated, Set.of(), synthetic)),
|
||||||
|
// test for synthetic parameters
|
||||||
|
// assuming javac creates two synthetic parameters corresponding to
|
||||||
|
// Enum(String name, int ordinal)
|
||||||
|
Arguments.of(Outer.MyEnum.class.getDeclaredConstructors()[0],
|
||||||
|
List.of(synthetic, synthetic, Set.of(), Set.of()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("testCases")
|
||||||
|
void check(Executable method, List<Set<AccessFlag>> paramFlags) {
|
||||||
|
Parameter[] parameters = method.getParameters();
|
||||||
|
assertEquals(paramFlags.size(), parameters.length, () -> "Parameter count of " + method);
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
|
Set<AccessFlag> expected = new HashSet<>(paramFlags.get(i));
|
||||||
|
expected.retainAll(CHECKED_FLAGS);
|
||||||
|
Set<AccessFlag> found = new HashSet<>(parameters[i].accessFlags());
|
||||||
|
found.retainAll(CHECKED_FLAGS);
|
||||||
|
final int index = i;
|
||||||
|
assertEquals(expected, found, () -> "Parameter " + index + " in " + method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep this in sync with test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java
|
||||||
|
class Outer {
|
||||||
|
class Inner {
|
||||||
|
public Inner(Inner notMandated) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inner anonymousInner = this.new Inner(null) {};
|
||||||
|
|
||||||
|
Object anonymous = new Object() {};
|
||||||
|
|
||||||
|
private void instanceMethod(int i) {
|
||||||
|
class Task implements Runnable {
|
||||||
|
final int j;
|
||||||
|
|
||||||
|
Task(int j) {
|
||||||
|
this.j = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println(Outer.this.toString() + (i * j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Task(5).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MyEnum {
|
||||||
|
;
|
||||||
|
MyEnum(String s, int i) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
record MyRecord(int a, Object b) {
|
||||||
|
MyRecord {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* 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 8292275
|
||||||
|
* @summary check that implicit parameter flags are available by default
|
||||||
|
* @library /tools/lib
|
||||||
|
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||||
|
* jdk.compiler/com.sun.tools.javac.main
|
||||||
|
* jdk.compiler/com.sun.tools.javac.code
|
||||||
|
* jdk.jdeps/com.sun.tools.classfile
|
||||||
|
* @run main ImplicitParameters
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.tools.classfile.ClassFile;
|
||||||
|
import com.sun.tools.classfile.ConstantPoolException;
|
||||||
|
import com.sun.tools.classfile.MethodParameters_attribute;
|
||||||
|
import com.sun.tools.javac.code.Flags;
|
||||||
|
import toolbox.Assert;
|
||||||
|
import toolbox.JavacTask;
|
||||||
|
import toolbox.Task;
|
||||||
|
import toolbox.TestRunner;
|
||||||
|
import toolbox.ToolBox;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.constant.ConstantDescs;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class ImplicitParameters extends TestRunner {
|
||||||
|
private static final int CHECKED_FLAGS = Flags.MANDATED | Flags.SYNTHETIC;
|
||||||
|
private static final int NO_FLAGS = 0;
|
||||||
|
|
||||||
|
public ImplicitParameters() {
|
||||||
|
super(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
new ImplicitParameters().runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runTests() throws Exception {
|
||||||
|
Path base = Path.of(".").toAbsolutePath();
|
||||||
|
compileClasses(base);
|
||||||
|
runTests(method -> new Object[]{ readClassFile(base.resolve("classes"), method) });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compileClasses(Path base) throws IOException {
|
||||||
|
// Keep this in sync with test/jdk/java/lang/reflect/AccessFlag/RequiredMethodParameterFlagTest.java
|
||||||
|
String outer = """
|
||||||
|
class Outer {
|
||||||
|
class Inner {
|
||||||
|
public Inner(Inner notMandated) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inner anonymousInner = this.new Inner(null) {};
|
||||||
|
|
||||||
|
Object anonymous = new Object() {};
|
||||||
|
|
||||||
|
private void instanceMethod(int i) {
|
||||||
|
class Task implements Runnable {
|
||||||
|
final int j;
|
||||||
|
|
||||||
|
Task(int j) {
|
||||||
|
this.j = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println(Outer.this.toString() + (i * j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Task(5).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MyEnum {
|
||||||
|
;
|
||||||
|
MyEnum(String s, int i) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
record MyRecord(int a, Object b) {
|
||||||
|
MyRecord {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Path src = base.resolve("src");
|
||||||
|
ToolBox tb = new ToolBox();
|
||||||
|
tb.writeJavaFiles(src, outer);
|
||||||
|
Path classes = base.resolve("classes");
|
||||||
|
Files.createDirectories(classes);
|
||||||
|
new JavacTask(tb)
|
||||||
|
.files(tb.findJavaFiles(src))
|
||||||
|
.outdir(classes)
|
||||||
|
.run(Task.Expect.SUCCESS)
|
||||||
|
.writeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassFile readClassFile(Path classes, Method method) {
|
||||||
|
String className = method.getAnnotation(ClassName.class).value();
|
||||||
|
try {
|
||||||
|
return ClassFile.read(classes.resolve("Outer$" + className + ".class"));
|
||||||
|
} catch (IOException | ConstantPoolException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface ClassName {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("Inner")
|
||||||
|
public void testInnerClassConstructor(ClassFile classFile) {
|
||||||
|
checkParameters(classFile.methods[0], Flags.MANDATED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("1Task")
|
||||||
|
public void testLocalClassConstructor(ClassFile classFile) throws ConstantPoolException {
|
||||||
|
for (com.sun.tools.classfile.Method method : classFile.methods) {
|
||||||
|
if (method.getName(classFile.constant_pool).equals(ConstantDescs.INIT_NAME)) {
|
||||||
|
checkParameters(method, Flags.MANDATED, NO_FLAGS, Flags.SYNTHETIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("1")
|
||||||
|
public void testAnonymousClassExtendingInnerClassConstructor(ClassFile classFile) {
|
||||||
|
checkParameters(classFile.methods[0], Flags.MANDATED, NO_FLAGS, NO_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("2")
|
||||||
|
public void testAnonymousClassConstructor(ClassFile classFile) {
|
||||||
|
checkParameters(classFile.methods[0], Flags.MANDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("MyEnum")
|
||||||
|
public void testValueOfInEnum(ClassFile classFile) throws ConstantPoolException {
|
||||||
|
for (com.sun.tools.classfile.Method method : classFile.methods) {
|
||||||
|
if (method.getName(classFile.constant_pool).equals("valueOf")) {
|
||||||
|
checkParameters(method, Flags.MANDATED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("MyEnum")
|
||||||
|
public void testEnumClassConstructor(ClassFile classFile) throws ConstantPoolException {
|
||||||
|
for (com.sun.tools.classfile.Method method : classFile.methods) {
|
||||||
|
if (method.getName(classFile.constant_pool).equals(ConstantDescs.INIT_NAME)) {
|
||||||
|
checkParameters(method, Flags.SYNTHETIC, Flags.SYNTHETIC, NO_FLAGS, NO_FLAGS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ClassName("MyRecord")
|
||||||
|
public void testCompactConstructor(ClassFile classFile) {
|
||||||
|
checkParameters(classFile.methods[0], Flags.MANDATED, Flags.MANDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkParameters(com.sun.tools.classfile.Method method, int... parametersFlags) {
|
||||||
|
MethodParameters_attribute methodParameters = (MethodParameters_attribute) method.attributes.get("MethodParameters");
|
||||||
|
Assert.checkNonNull(methodParameters, "MethodParameters attribute must be present");
|
||||||
|
MethodParameters_attribute.Entry[] table = methodParameters.method_parameter_table;
|
||||||
|
Assert.check(table.length == parametersFlags.length, () -> "Expected " + parametersFlags.length
|
||||||
|
+ " MethodParameters entries, found " + table.length);
|
||||||
|
for (int i = 0; i < methodParameters.method_parameter_table_length; i++) {
|
||||||
|
int foundFlags = table[i].flags & CHECKED_FLAGS;
|
||||||
|
int desiredFlags = parametersFlags[i] & CHECKED_FLAGS;
|
||||||
|
Assert.check(foundFlags == desiredFlags, () -> "Expected mandated and synthethic flags to be "
|
||||||
|
+ convertFlags(desiredFlags) + ", found " + convertFlags(foundFlags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String convertFlags(int flags) {
|
||||||
|
return ((flags & Flags.MANDATED) == Flags.MANDATED) + " and " + ((flags & Flags.SYNTHETIC) == Flags.SYNTHETIC);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -59,7 +59,7 @@ public class AnnotatedExtendsTest {
|
|||||||
.classes(classPath.toString())
|
.classes(classPath.toString())
|
||||||
.run()
|
.run()
|
||||||
.getOutput(Task.OutputKind.DIRECT);
|
.getOutput(Task.OutputKind.DIRECT);
|
||||||
if (!javapOut.contains("0: #20(): CLASS_EXTENDS, type_index=65535"))
|
if (!javapOut.contains("0: #21(): CLASS_EXTENDS, type_index=65535"))
|
||||||
throw new AssertionError("Expected output missing: " + javapOut);
|
throw new AssertionError("Expected output missing: " + javapOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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 8292275
|
||||||
|
* @summary Verify specific executables in enums and records have mandated parameters
|
||||||
|
* @library /tools/javac/lib
|
||||||
|
* @modules java.compiler
|
||||||
|
* jdk.compiler
|
||||||
|
* @build JavacTestingAbstractProcessor ImplicitParametersProcessor
|
||||||
|
* @compile -processor ImplicitParametersProcessor -proc:only ImplicitParametersProcessor.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static javax.lang.model.util.ElementFilter.constructorsIn;
|
||||||
|
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||||
|
import static javax.lang.model.util.ElementFilter.typesIn;
|
||||||
|
|
||||||
|
public class ImplicitParametersProcessor extends JavacTestingAbstractProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
|
if (roundEnv.processingOver()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean hasError = false;
|
||||||
|
for (TypeElement typeElement : typesIn(roundEnv.getRootElements())) {
|
||||||
|
for (TypeElement innerType : typesIn(typeElement.getEnclosedElements())) {
|
||||||
|
System.out.println("Visiting " + innerType);
|
||||||
|
ExpectedOrigin[] expectedOrigins = innerType.getAnnotationsByType(ExpectedOrigin.class);
|
||||||
|
hasError |= checkAllExecutables(innerType, Arrays.stream(expectedOrigins)
|
||||||
|
.collect(Collectors.toMap(ExpectedOrigin::method, ExpectedOrigin::origins)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasError) {
|
||||||
|
throw new IllegalStateException("Wrong element origins found");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean checkAllExecutables(TypeElement element, Map<String, Elements.Origin[]> expectations) {
|
||||||
|
boolean hasError = false;
|
||||||
|
for (ExecutableElement executable : constructorsIn(element.getEnclosedElements())) {
|
||||||
|
hasError |= checkExecutable(expectations, executable);
|
||||||
|
}
|
||||||
|
for (ExecutableElement executable : methodsIn(element.getEnclosedElements())) {
|
||||||
|
hasError |= checkExecutable(expectations, executable);
|
||||||
|
}
|
||||||
|
return hasError;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkExecutable(Map<String, Elements.Origin[]> expectations, ExecutableElement executable) {
|
||||||
|
System.out.println("Looking at executable " + executable);
|
||||||
|
Elements.Origin[] origins = expectations.get(executable.getSimpleName().toString());
|
||||||
|
if (origins == null) {
|
||||||
|
System.out.println("ignoring this executable due to missing expectations");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<? extends VariableElement> parameters = executable.getParameters();
|
||||||
|
boolean hasError = false;
|
||||||
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
VariableElement parameter = parameters.get(i);
|
||||||
|
Elements.Origin origin = eltUtils.getOrigin(parameter);
|
||||||
|
if (origin != origins[i]) {
|
||||||
|
System.err.println("ERROR: Wrong origin for " + executable + ". Expected: " + origins[i] + " but got " + origin + " at index " + i);
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the valueOf(String) method has one mandated parameter
|
||||||
|
@ExpectedOrigin(method = "valueOf", origins = {Elements.Origin.MANDATED})
|
||||||
|
enum MyEnum {}
|
||||||
|
|
||||||
|
// the parameters of a compact record constructor are mandated
|
||||||
|
@ExpectedOrigin(method = "<init>", origins = {Elements.Origin.MANDATED, Elements.Origin.MANDATED})
|
||||||
|
record MyRecord(int a, Object b) {
|
||||||
|
MyRecord {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface ExpectedOrigin {
|
||||||
|
String method();
|
||||||
|
Elements.Origin[] origins();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2017, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -49,50 +49,50 @@ public class AnnoTest {
|
|||||||
|
|
||||||
expect(out,
|
expect(out,
|
||||||
"RuntimeVisibleAnnotations:\n" +
|
"RuntimeVisibleAnnotations:\n" +
|
||||||
" 0: #17(#18=B#19)\n" +
|
" 0: #18(#19=B#20)\n" +
|
||||||
" AnnoTest$ByteAnno(\n" +
|
" AnnoTest$ByteAnno(\n" +
|
||||||
" value=(byte) 42\n" +
|
" value=(byte) 42\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 1: #20(#18=S#21)\n" +
|
" 1: #21(#19=S#22)\n" +
|
||||||
" AnnoTest$ShortAnno(\n" +
|
" AnnoTest$ShortAnno(\n" +
|
||||||
" value=(short) 3\n" +
|
" value=(short) 3\n" +
|
||||||
" )");
|
" )");
|
||||||
expect(out,
|
expect(out,
|
||||||
"RuntimeInvisibleAnnotations:\n" +
|
"RuntimeInvisibleAnnotations:\n" +
|
||||||
" 0: #23(#18=[J#24,J#26,J#28,J#30,J#32])\n" +
|
" 0: #24(#19=[J#25,J#27,J#29,J#31,J#33])\n" +
|
||||||
" AnnoTest$ArrayAnno(\n" +
|
" AnnoTest$ArrayAnno(\n" +
|
||||||
" value=[1l,2l,3l,4l,5l]\n" +
|
" value=[1l,2l,3l,4l,5l]\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 1: #34(#18=Z#35)\n" +
|
" 1: #35(#19=Z#36)\n" +
|
||||||
" AnnoTest$BooleanAnno(\n" +
|
" AnnoTest$BooleanAnno(\n" +
|
||||||
" value=false\n" +
|
" value=false\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 2: #36(#37=c#38)\n" +
|
" 2: #37(#38=c#39)\n" +
|
||||||
" AnnoTest$ClassAnno(\n" +
|
" AnnoTest$ClassAnno(\n" +
|
||||||
" type=class Ljava/lang/Object;\n" +
|
" type=class Ljava/lang/Object;\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 3: #39(#40=e#41.#42)\n" +
|
" 3: #40(#41=e#42.#43)\n" +
|
||||||
" AnnoTest$EnumAnno(\n" +
|
" AnnoTest$EnumAnno(\n" +
|
||||||
" kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" +
|
" kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 4: #43(#18=I#44)\n" +
|
" 4: #44(#19=I#45)\n" +
|
||||||
" AnnoTest$IntAnno(\n" +
|
" AnnoTest$IntAnno(\n" +
|
||||||
" value=2\n" +
|
" value=2\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 5: #45()\n" +
|
" 5: #46()\n" +
|
||||||
" AnnoTest$IntDefaultAnno\n" +
|
" AnnoTest$IntDefaultAnno\n" +
|
||||||
" 6: #46(#47=s#48)\n" +
|
" 6: #47(#48=s#49)\n" +
|
||||||
" AnnoTest$NameAnno(\n" +
|
" AnnoTest$NameAnno(\n" +
|
||||||
" name=\"NAME\"\n" +
|
" name=\"NAME\"\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 7: #49(#50=D#51,#53=F#54)\n" +
|
" 7: #50(#51=D#52,#54=F#55)\n" +
|
||||||
" AnnoTest$MultiAnno(\n" +
|
" AnnoTest$MultiAnno(\n" +
|
||||||
" d=3.14159d\n" +
|
" d=3.14159d\n" +
|
||||||
" f=2.71828f\n" +
|
" f=2.71828f\n" +
|
||||||
" )\n" +
|
" )\n" +
|
||||||
" 8: #55()\n" +
|
" 8: #56()\n" +
|
||||||
" AnnoTest$SimpleAnno\n" +
|
" AnnoTest$SimpleAnno\n" +
|
||||||
" 9: #56(#18=@#43(#18=I#57))\n" +
|
" 9: #57(#19=@#44(#19=I#58))\n" +
|
||||||
" AnnoTest$AnnoAnno(\n" +
|
" AnnoTest$AnnoAnno(\n" +
|
||||||
" value=@AnnoTest$IntAnno(\n" +
|
" value=@AnnoTest$IntAnno(\n" +
|
||||||
" value=5\n" +
|
" value=5\n" +
|
||||||
@ -100,7 +100,7 @@ public class AnnoTest {
|
|||||||
" )");
|
" )");
|
||||||
expect(out,
|
expect(out,
|
||||||
"RuntimeInvisibleTypeAnnotations:\n" +
|
"RuntimeInvisibleTypeAnnotations:\n" +
|
||||||
" 0: #59(): CLASS_EXTENDS, type_index=0\n" +
|
" 0: #60(): CLASS_EXTENDS, type_index=0\n" +
|
||||||
" AnnoTest$TypeAnno");
|
" AnnoTest$TypeAnno");
|
||||||
|
|
||||||
if (errors > 0)
|
if (errors > 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user