mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 09:53:18 +00:00
8347471: Provide valid flags and mask in AccessFlag.Location
Reviewed-by: rriggs
This commit is contained in:
parent
83d0bd85af
commit
dcffd9d9ac
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 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
|
||||
@ -25,12 +25,31 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.FieldModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.attribute.InnerClassInfo;
|
||||
import java.lang.classfile.attribute.MethodParameterInfo;
|
||||
import java.lang.classfile.attribute.ModuleAttribute;
|
||||
import java.lang.classfile.attribute.ModuleExportInfo;
|
||||
import java.lang.classfile.attribute.ModuleOpenInfo;
|
||||
import java.lang.classfile.attribute.ModuleRequireInfo;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import static java.util.Map.entry;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static java.lang.classfile.ClassFile.*;
|
||||
import static java.lang.reflect.ClassFileFormatVersion.*;
|
||||
|
||||
/**
|
||||
* Represents a JVM access or module-related flag on a runtime member,
|
||||
@ -93,26 +112,14 @@ import static java.util.Map.entry;
|
||||
*/
|
||||
@SuppressWarnings("doclint:reference") // cross-module link
|
||||
public enum AccessFlag {
|
||||
// Note to maintainers: anonymous class instances are used rather
|
||||
// than lambdas to initialize the functions used for the
|
||||
// cffvToLocations field to avoid using lambdas too early in JDK
|
||||
// initialization.
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_PUBLIC}, corresponding to the source
|
||||
* modifier {@link Modifier#PUBLIC public}, with a mask value of
|
||||
* <code>{@value "0x%04x" Modifier#PUBLIC}</code>.
|
||||
*/
|
||||
PUBLIC(Modifier.PUBLIC, true,
|
||||
Location.SET_PUBLIC_1,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||
Location.SET_CLASS_FIELD_METHOD:
|
||||
Location.SET_PUBLIC_1;
|
||||
}
|
||||
}),
|
||||
Location.SET_CLASS_FIELD_METHOD_INNER_CLASS,
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_PRIVATE}, corresponding to the
|
||||
@ -120,14 +127,7 @@ public enum AccessFlag {
|
||||
* value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>.
|
||||
*/
|
||||
PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||
Location.SET_FIELD_METHOD:
|
||||
Location.SET_FIELD_METHOD_INNER_CLASS;
|
||||
}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_PROTECTED}, corresponding to the
|
||||
@ -135,14 +135,7 @@ public enum AccessFlag {
|
||||
* value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>.
|
||||
*/
|
||||
PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||
Location.SET_FIELD_METHOD:
|
||||
Location.SET_FIELD_METHOD_INNER_CLASS;
|
||||
}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_STATIC}, corresponding to the source
|
||||
@ -150,13 +143,7 @@ public enum AccessFlag {
|
||||
* <code>{@value "0x%04x" Modifier#STATIC}</code>.
|
||||
*/
|
||||
STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||
Location.SET_FIELD_METHOD:
|
||||
Location.SET_FIELD_METHOD_INNER_CLASS;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_FINAL}, corresponding to the source
|
||||
@ -165,18 +152,8 @@ public enum AccessFlag {
|
||||
*/
|
||||
FINAL(Modifier.FINAL, true,
|
||||
Location.SET_FINAL_8,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) {
|
||||
return Location.SET_FINAL_8;
|
||||
} else {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||
Location.SET_CLASS_FIELD_METHOD :
|
||||
Location.SET_CLASS_FIELD_METHOD_INNER_CLASS;
|
||||
}
|
||||
}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_7, Location.SET_CLASS_FIELD_METHOD_INNER_CLASS),
|
||||
Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_SUPER} with a mask value of {@code
|
||||
@ -186,21 +163,15 @@ public enum AccessFlag {
|
||||
* In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
|
||||
* flag as set in every class file (JVMS {@jvms 4.1}).
|
||||
*/
|
||||
SUPER(0x0000_0020, false, Location.SET_CLASS, null),
|
||||
SUPER(0x0000_0020, false, Location.SET_CLASS, List.of()),
|
||||
|
||||
/**
|
||||
* The module flag {@code ACC_OPEN} with a mask value of {@code
|
||||
* 0x0020}.
|
||||
* @see java.lang.module.ModuleDescriptor#isOpen
|
||||
*/
|
||||
OPEN(0x0000_0020, false, Location.SET_MODULE,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||
Location.SET_MODULE:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
OPEN(0x0000_0020, false, Location.SET_MODULE,
|
||||
List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The module requires flag {@code ACC_TRANSITIVE} with a mask
|
||||
@ -208,20 +179,14 @@ public enum AccessFlag {
|
||||
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
|
||||
*/
|
||||
TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||
Location.SET_MODULE_REQUIRES:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
|
||||
* source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
|
||||
* a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
|
||||
*/
|
||||
SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
|
||||
SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, List.of()),
|
||||
|
||||
/**
|
||||
* The module requires flag {@code ACC_STATIC_PHASE} with a mask
|
||||
@ -229,20 +194,14 @@ public enum AccessFlag {
|
||||
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
|
||||
*/
|
||||
STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||
Location.SET_MODULE_REQUIRES:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
/**
|
||||
* The access flag {@code ACC_VOLATILE}, corresponding to the
|
||||
* source modifier {@link Modifier#VOLATILE volatile}, with a mask
|
||||
* value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
|
||||
*/
|
||||
VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
|
||||
VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, List.of()),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_BRIDGE} with a mask value of
|
||||
@ -250,41 +209,29 @@ public enum AccessFlag {
|
||||
* @see Method#isBridge()
|
||||
*/
|
||||
BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||
Location.SET_METHOD:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_TRANSIENT}, corresponding to the
|
||||
* source modifier {@link Modifier#TRANSIENT transient}, with a
|
||||
* mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
|
||||
*/
|
||||
TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null),
|
||||
TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, List.of()),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_VARARGS} with a mask value of
|
||||
<code>{@value "0x%04x" Modifier#VARARGS}</code>.
|
||||
* <code>{@value "0x%04x" Modifier#VARARGS}</code>.
|
||||
* @see Executable#isVarArgs()
|
||||
*/
|
||||
VARARGS(Modifier.VARARGS, false, Location.SET_METHOD,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||
Location.SET_METHOD:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_NATIVE}, corresponding to the source
|
||||
* modifier {@link Modifier#NATIVE native}, with a mask value of
|
||||
* <code>{@value "0x%04x" Modifier#NATIVE}</code>.
|
||||
*/
|
||||
NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, null),
|
||||
NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, List.of()),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_INTERFACE} with a mask value of
|
||||
@ -292,13 +239,7 @@ public enum AccessFlag {
|
||||
* @see Class#isInterface()
|
||||
*/
|
||||
INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
|
||||
Location.SET_CLASS:
|
||||
Location.SET_CLASS_INNER_CLASS;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_CLASS))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_ABSTRACT}, corresponding to the
|
||||
@ -307,13 +248,7 @@ public enum AccessFlag {
|
||||
*/
|
||||
ABSTRACT(Modifier.ABSTRACT, true,
|
||||
Location.SET_CLASS_METHOD_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
|
||||
Location.SET_CLASS_METHOD:
|
||||
Location.SET_CLASS_METHOD_INNER_CLASS;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_0, Location.SET_CLASS_METHOD))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_STRICT}, corresponding to the source
|
||||
@ -326,14 +261,8 @@ public enum AccessFlag {
|
||||
* corresponding to Java SE 1.2 through 16.
|
||||
*/
|
||||
STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_2) >= 0 &&
|
||||
cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ?
|
||||
Location.SET_METHOD:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_16, Location.SET_METHOD),
|
||||
Map.entry(RELEASE_1, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_SYNTHETIC} with a mask value of
|
||||
@ -343,21 +272,9 @@ public enum AccessFlag {
|
||||
* @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
|
||||
*/
|
||||
SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 )
|
||||
return Location.SET_SYNTHETIC_9;
|
||||
else {
|
||||
return
|
||||
switch(cffv) {
|
||||
case RELEASE_7 -> Location.SET_SYNTHETIC_7;
|
||||
case RELEASE_8 -> Location.SET_SYNTHETIC_8;
|
||||
default -> Location.EMPTY_SET;
|
||||
};
|
||||
}
|
||||
}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_8, Location.SET_SYNTHETIC_8),
|
||||
Map.entry(RELEASE_7, Location.SET_SYNTHETIC_5),
|
||||
Map.entry(RELEASE_4, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_ANNOTATION} with a mask value of
|
||||
@ -365,13 +282,7 @@ public enum AccessFlag {
|
||||
* @see Class#isAnnotation()
|
||||
*/
|
||||
ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||
Location.SET_CLASS_INNER_CLASS:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_ENUM} with a mask value of
|
||||
@ -379,44 +290,22 @@ public enum AccessFlag {
|
||||
* @see Class#isEnum()
|
||||
*/
|
||||
ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||
Location.SET_CLASS_FIELD_INNER_CLASS:
|
||||
Location.EMPTY_SET;}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_MANDATED} with a mask value of
|
||||
* <code>{@value "0x%04x" Modifier#MANDATED}</code>.
|
||||
*/
|
||||
MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) {
|
||||
return Location.SET_MANDATED_9;
|
||||
} else {
|
||||
return (cffv == ClassFileFormatVersion.RELEASE_8) ?
|
||||
Location.SET_METHOD_PARAM:
|
||||
Location.EMPTY_SET;
|
||||
}
|
||||
}
|
||||
}),
|
||||
List.of(Map.entry(RELEASE_8, Location.SET_METHOD_PARAM),
|
||||
Map.entry(RELEASE_7, Location.EMPTY_SET))),
|
||||
|
||||
/**
|
||||
* The access flag {@code ACC_MODULE} with a mask value of {@code
|
||||
* 0x8000}.
|
||||
*/
|
||||
MODULE(0x0000_8000, false, Location.SET_CLASS,
|
||||
new Function<ClassFileFormatVersion, Set<Location>>() {
|
||||
@Override
|
||||
public Set<Location> apply(ClassFileFormatVersion cffv) {
|
||||
return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||
Location.SET_CLASS:
|
||||
Location.EMPTY_SET;}
|
||||
})
|
||||
List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
|
||||
;
|
||||
|
||||
// May want to override toString for a different enum constant ->
|
||||
@ -425,31 +314,31 @@ public enum AccessFlag {
|
||||
private final int mask;
|
||||
private final boolean sourceModifier;
|
||||
|
||||
// Intentionally using Set rather than EnumSet since EnumSet is
|
||||
// mutable.
|
||||
// immutable
|
||||
private final Set<Location> locations;
|
||||
// Lambda to implement locations(ClassFileFormatVersion cffv)
|
||||
private final Function<ClassFileFormatVersion, Set<Location>> cffvToLocations;
|
||||
// historical locations up to a given version; immutable
|
||||
private final List<Map.Entry<ClassFileFormatVersion, Set<Location>>> historicalLocations;
|
||||
|
||||
private AccessFlag(int mask,
|
||||
boolean sourceModifier,
|
||||
Set<Location> locations,
|
||||
Function<ClassFileFormatVersion, Set<Location>> cffvToLocations) {
|
||||
List<Map.Entry<ClassFileFormatVersion, Set<Location>>> historicalLocations) {
|
||||
this.mask = mask;
|
||||
this.sourceModifier = sourceModifier;
|
||||
this.locations = locations;
|
||||
this.cffvToLocations = cffvToLocations;
|
||||
this.historicalLocations = Location.ensureHistoryOrdered(historicalLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the corresponding integer mask for the access flag}
|
||||
* {@return the corresponding mask for the access flag} The mask has
|
||||
* exactly one bit set and is in the range of {@code char}.
|
||||
*/
|
||||
public int mask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return whether or not the flag has a directly corresponding
|
||||
* {@return whether or not this flag has a directly corresponding
|
||||
* modifier in the Java programming language}
|
||||
*/
|
||||
public boolean sourceModifier() {
|
||||
@ -457,26 +346,28 @@ public enum AccessFlag {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return kinds of constructs the flag can be applied to in the
|
||||
* latest class file format version}
|
||||
* {@return locations this flag can be applied to in the current class file
|
||||
* format version}
|
||||
* <p>
|
||||
* This method returns an empty set if this flag is not defined in
|
||||
* the current class file format version.
|
||||
*/
|
||||
public Set<Location> locations() {
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return kinds of constructs the flag can be applied to in the
|
||||
* given class file format version}
|
||||
* {@return locations this flag can be applied to in the given class file
|
||||
* format version}
|
||||
* <p>
|
||||
* This method returns an empty set if this flag is not defined in
|
||||
* the given {@code cffv}.
|
||||
*
|
||||
* @param cffv the class file format version to use
|
||||
* @throws NullPointerException if the parameter is {@code null}
|
||||
*/
|
||||
public Set<Location> locations(ClassFileFormatVersion cffv) {
|
||||
Objects.requireNonNull(cffv);
|
||||
if (cffvToLocations == null) {
|
||||
return locations;
|
||||
} else {
|
||||
return cffvToLocations.apply(cffv);
|
||||
}
|
||||
return Location.findInHistory(locations, historicalLocations, cffv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -489,84 +380,160 @@ public enum AccessFlag {
|
||||
* positions not support for the location in question
|
||||
*/
|
||||
public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
|
||||
Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
|
||||
for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
|
||||
int accessMask = accessFlag.mask();
|
||||
if ((mask & accessMask) != 0) {
|
||||
result.add(accessFlag);
|
||||
mask = mask & ~accessMask;
|
||||
}
|
||||
}
|
||||
if (mask != 0) {
|
||||
var definition = findDefinition(location);
|
||||
int flagsMask = location.flagsMask();
|
||||
int parsingMask = location == Location.METHOD ? flagsMask | ACC_STRICT : flagsMask; // flagMask lacks strictfp
|
||||
int unmatchedMask = mask & (~parsingMask);
|
||||
if (unmatchedMask != 0) {
|
||||
throw new IllegalArgumentException("Unmatched bit position 0x" +
|
||||
Integer.toHexString(mask) +
|
||||
" for location " + location);
|
||||
Integer.toHexString(unmatchedMask) +
|
||||
" for location " + location);
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
return new AccessFlagSet(definition, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* A location within a class file where flags can be applied.
|
||||
*
|
||||
* Note that since these locations represent class file structures
|
||||
* rather than language structures many language structures, such
|
||||
* A location within a {@code class} file where flags can be applied.
|
||||
* <p>
|
||||
* Note that since these locations represent {@code class} file structures
|
||||
* rather than language structures, many language structures, such
|
||||
* as constructors and interfaces, are <em>not</em> present.
|
||||
* @since 20
|
||||
*/
|
||||
public enum Location {
|
||||
/**
|
||||
* Class location.
|
||||
* @jvms 4.1 The ClassFile Structure
|
||||
*
|
||||
* @see Class#accessFlags()
|
||||
* @see ClassModel#flags()
|
||||
* @see Modifier#classModifiers()
|
||||
* @see Modifier#interfaceModifiers()
|
||||
* @jvms 4.1 The {@code ClassFile} Structure
|
||||
*/
|
||||
CLASS,
|
||||
CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
|
||||
ACC_INTERFACE | ACC_ABSTRACT |
|
||||
ACC_SYNTHETIC | ACC_ANNOTATION |
|
||||
ACC_ENUM | ACC_MODULE,
|
||||
List.of(Map.entry(RELEASE_8, // no module
|
||||
ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
|
||||
ACC_INTERFACE | ACC_ABSTRACT |
|
||||
ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
|
||||
Map.entry(RELEASE_4, // no synthetic, annotation, enum
|
||||
ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
|
||||
ACC_INTERFACE | ACC_ABSTRACT))),
|
||||
|
||||
/**
|
||||
* Field location.
|
||||
*
|
||||
* @see Field#accessFlags()
|
||||
* @see FieldModel#flags()
|
||||
* @see Modifier#fieldModifiers()
|
||||
* @jvms 4.5 Fields
|
||||
*/
|
||||
FIELD,
|
||||
FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
|
||||
ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM,
|
||||
List.of(Map.entry(RELEASE_4, // no synthetic, enum
|
||||
ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
|
||||
ACC_TRANSIENT))),
|
||||
|
||||
/**
|
||||
* Method location.
|
||||
*
|
||||
* @see Executable#accessFlags()
|
||||
* @see MethodModel#flags()
|
||||
* @see Modifier#methodModifiers()
|
||||
* @see Modifier#constructorModifiers()
|
||||
* @jvms 4.6 Methods
|
||||
*/
|
||||
METHOD,
|
||||
METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
|
||||
ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
|
||||
ACC_ABSTRACT | ACC_SYNTHETIC,
|
||||
List.of(Map.entry(RELEASE_16, // had strict
|
||||
ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
|
||||
ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
|
||||
ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC),
|
||||
Map.entry(RELEASE_4, // no bridge, varargs, synthetic
|
||||
ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
|
||||
ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
|
||||
Map.entry(RELEASE_1, // no strict
|
||||
ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
|
||||
ACC_NATIVE | ACC_ABSTRACT))),
|
||||
|
||||
/**
|
||||
* Inner class location.
|
||||
* @jvms 4.7.6 The InnerClasses Attribute
|
||||
*
|
||||
* @see Class#accessFlags()
|
||||
* @see InnerClassInfo#flags()
|
||||
* @see Modifier#classModifiers()
|
||||
* @see Modifier#interfaceModifiers()
|
||||
* @jvms 4.7.6 The {@code InnerClasses} Attribute
|
||||
*/
|
||||
INNER_CLASS,
|
||||
INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
|
||||
ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
|
||||
List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
|
||||
ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
|
||||
ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
|
||||
ACC_ABSTRACT),
|
||||
Map.entry(RELEASE_0, 0))), // did not exist
|
||||
|
||||
/**
|
||||
* Method parameter location.
|
||||
* @jvms 4.7.24 The MethodParameters Attribute
|
||||
*
|
||||
* @see Parameter#accessFlags()
|
||||
* @see MethodParameterInfo#flags()
|
||||
* @see Modifier#parameterModifiers()
|
||||
* @jvms 4.7.24 The {@code MethodParameters} Attribute
|
||||
*/
|
||||
METHOD_PARAMETER,
|
||||
METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
|
||||
List.of(Map.entry(RELEASE_7, 0))), // did not exist
|
||||
|
||||
/**
|
||||
* Module location
|
||||
* @jvms 4.7.25 The Module Attribute
|
||||
* Module location.
|
||||
*
|
||||
* @see ModuleDescriptor#accessFlags()
|
||||
* @see ModuleAttribute#moduleFlags()
|
||||
* @jvms 4.7.25 The {@code Module} Attribute
|
||||
*/
|
||||
MODULE,
|
||||
MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,
|
||||
List.of(Map.entry(RELEASE_8, 0))), // did not exist
|
||||
|
||||
/**
|
||||
* Module requires location
|
||||
* @jvms 4.7.25 The Module Attribute
|
||||
* Module requires location.
|
||||
*
|
||||
* @see ModuleDescriptor.Requires#accessFlags()
|
||||
* @see ModuleRequireInfo#requiresFlags()
|
||||
* @jvms 4.7.25 The {@code Module} Attribute
|
||||
*/
|
||||
MODULE_REQUIRES,
|
||||
MODULE_REQUIRES(ACC_TRANSITIVE | ACC_STATIC_PHASE | ACC_SYNTHETIC | ACC_MANDATED,
|
||||
List.of(Map.entry(RELEASE_8, 0))), // did not exist
|
||||
|
||||
/**
|
||||
* Module exports location
|
||||
* @jvms 4.7.25 The Module Attribute
|
||||
* Module exports location.
|
||||
*
|
||||
* @see ModuleDescriptor.Exports#accessFlags()
|
||||
* @see ModuleExportInfo#exportsFlags()
|
||||
* @jvms 4.7.25 The {@code Module} Attribute
|
||||
*/
|
||||
MODULE_EXPORTS,
|
||||
MODULE_EXPORTS(ACC_SYNTHETIC | ACC_MANDATED,
|
||||
List.of(Map.entry(RELEASE_8, 0))), // did not exist
|
||||
|
||||
/**
|
||||
* Module opens location
|
||||
* @jvms 4.7.25 The Module Attribute
|
||||
* Module opens location.
|
||||
*
|
||||
* @see ModuleDescriptor.Opens#accessFlags()
|
||||
* @see ModuleOpenInfo#opensFlags()
|
||||
* @jvms 4.7.25 The {@code Module} Attribute
|
||||
*/
|
||||
MODULE_OPENS;
|
||||
MODULE_OPENS(ACC_SYNTHETIC | ACC_MANDATED,
|
||||
List.of(Map.entry(RELEASE_8, 0))), // did not exist
|
||||
;
|
||||
|
||||
// Repeated sets of locations used by AccessFlag constants
|
||||
private static final Set<Location> EMPTY_SET = Set.of();
|
||||
@ -593,20 +560,18 @@ public enum AccessFlag {
|
||||
Set.of(CLASS, INNER_CLASS);
|
||||
private static final Set<Location> SET_MODULE_REQUIRES =
|
||||
Set.of(MODULE_REQUIRES);
|
||||
private static final Set<Location> SET_PUBLIC_1 =
|
||||
Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
|
||||
private static final Set<Location> SET_FINAL_8 =
|
||||
Set.of(CLASS, FIELD, METHOD,
|
||||
INNER_CLASS, /* added in 1.1 */
|
||||
METHOD_PARAMETER); /* added in 8 */
|
||||
private static final Set<Location> SET_SYNTHETIC_7 =
|
||||
private static final Set<Location> SET_SYNTHETIC_5 =
|
||||
Set.of(CLASS, FIELD, METHOD,
|
||||
INNER_CLASS);
|
||||
private static final Set<Location> SET_SYNTHETIC_8 =
|
||||
Set.of(CLASS, FIELD, METHOD,
|
||||
INNER_CLASS, METHOD_PARAMETER);
|
||||
private static final Set<Location> SET_SYNTHETIC_9 =
|
||||
// Added as an access flag in 7
|
||||
// Added as an access flag in 5.0
|
||||
Set.of(CLASS, FIELD, METHOD,
|
||||
INNER_CLASS,
|
||||
METHOD_PARAMETER, // Added in 8
|
||||
@ -618,37 +583,227 @@ public enum AccessFlag {
|
||||
// Starting in 9
|
||||
MODULE, MODULE_REQUIRES,
|
||||
MODULE_EXPORTS, MODULE_OPENS);
|
||||
|
||||
private final int flagsMask;
|
||||
private final List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks;
|
||||
|
||||
Location(int flagsMask,
|
||||
List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks) {
|
||||
this.flagsMask = flagsMask;
|
||||
this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
|
||||
}
|
||||
|
||||
// Ensures the historical versions are from newest to oldest and do not include the latest
|
||||
// These 2 utilities reside in Location because Location must be initialized before AccessFlag
|
||||
private static <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
|
||||
List<Map.Entry<ClassFileFormatVersion, T>> history) {
|
||||
ClassFileFormatVersion lastVersion = ClassFileFormatVersion.latest();
|
||||
for (var e : history) {
|
||||
var historyVersion = e.getKey();
|
||||
if (lastVersion.compareTo(historyVersion) <= 0) {
|
||||
throw new IllegalArgumentException("Versions out of order");
|
||||
}
|
||||
lastVersion = historyVersion;
|
||||
}
|
||||
return history;
|
||||
}
|
||||
|
||||
private static <T> T findInHistory(T candidate, List<Map.Entry<ClassFileFormatVersion, T>> history,
|
||||
ClassFileFormatVersion cffv) {
|
||||
Objects.requireNonNull(cffv);
|
||||
for (var e : history) {
|
||||
if (e.getKey().compareTo(cffv) < 0) {
|
||||
// last version found was valid
|
||||
return candidate;
|
||||
}
|
||||
candidate = e.getValue();
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the union of masks of all access flags defined for
|
||||
* this location in the current class file format version}
|
||||
* <p>
|
||||
* This method returns {@code 0} if this location does not exist in
|
||||
* the current class file format version.
|
||||
*
|
||||
* @since 25
|
||||
*/
|
||||
public int flagsMask() {
|
||||
return flagsMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the union of masks of all access flags defined for
|
||||
* this location in the given class file format version}
|
||||
* <p>
|
||||
* This method returns {@code 0} if this location does not exist in
|
||||
* the given {@code cffv}.
|
||||
*
|
||||
* @param cffv the class file format version
|
||||
* @throws NullPointerException if {@code cffv} is {@code null}
|
||||
* @since 25
|
||||
*/
|
||||
public int flagsMask(ClassFileFormatVersion cffv) {
|
||||
return findInHistory(flagsMask, historicalFlagsMasks, cffv);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the set of access flags defined for this location in the
|
||||
* current class file format version} The set is immutable.
|
||||
* <p>
|
||||
* This method returns an empty set if this location does not exist
|
||||
* in the current class file format version.
|
||||
*
|
||||
* @since 25
|
||||
*/
|
||||
public Set<AccessFlag> flags() {
|
||||
return new AccessFlagSet(findDefinition(this), flagsMask());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the set of access flags defined for this location in the
|
||||
* given class file format version} The set is immutable.
|
||||
* <p>
|
||||
* This method returns an empty set if this location does not exist
|
||||
* in the given {@code cffv}.
|
||||
*
|
||||
* @param cffv the class file format version
|
||||
* @throws NullPointerException if {@code cffv} is {@code null}
|
||||
* @since 25
|
||||
*/
|
||||
public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
|
||||
// implicit null check cffv
|
||||
return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocationToFlags {
|
||||
private static Map<Location, Set<AccessFlag>> locationToFlags =
|
||||
Map.ofEntries(entry(Location.CLASS,
|
||||
Set.of(PUBLIC, FINAL, SUPER,
|
||||
INTERFACE, ABSTRACT,
|
||||
SYNTHETIC, ANNOTATION,
|
||||
ENUM, AccessFlag.MODULE)),
|
||||
entry(Location.FIELD,
|
||||
Set.of(PUBLIC, PRIVATE, PROTECTED,
|
||||
STATIC, FINAL, VOLATILE,
|
||||
TRANSIENT, SYNTHETIC, ENUM)),
|
||||
entry(Location.METHOD,
|
||||
Set.of(PUBLIC, PRIVATE, PROTECTED,
|
||||
STATIC, FINAL, SYNCHRONIZED,
|
||||
BRIDGE, VARARGS, NATIVE,
|
||||
ABSTRACT, STRICT, SYNTHETIC)),
|
||||
entry(Location.INNER_CLASS,
|
||||
Set.of(PUBLIC, PRIVATE, PROTECTED,
|
||||
STATIC, FINAL, INTERFACE, ABSTRACT,
|
||||
SYNTHETIC, ANNOTATION, ENUM)),
|
||||
entry(Location.METHOD_PARAMETER,
|
||||
Set.of(FINAL, SYNTHETIC, MANDATED)),
|
||||
entry(Location.MODULE,
|
||||
Set.of(OPEN, SYNTHETIC, MANDATED)),
|
||||
entry(Location.MODULE_REQUIRES,
|
||||
Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
|
||||
entry(Location.MODULE_EXPORTS,
|
||||
Set.of(SYNTHETIC, MANDATED)),
|
||||
entry(Location.MODULE_OPENS,
|
||||
Set.of(SYNTHETIC, MANDATED)));
|
||||
private static AccessFlag[] createDefinition(AccessFlag... known) {
|
||||
var ret = new AccessFlag[Character.SIZE];
|
||||
for (var flag : known) {
|
||||
var mask = flag.mask;
|
||||
int pos = Integer.numberOfTrailingZeros(mask);
|
||||
assert ret[pos] == null : ret[pos] + " " + flag;
|
||||
ret[pos] = flag;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Will take extra args in the future for valhalla switch
|
||||
private static AccessFlag[] findDefinition(Location location) {
|
||||
return switch (location) {
|
||||
case CLASS -> CLASS_FLAGS;
|
||||
case FIELD -> FIELD_FLAGS;
|
||||
case METHOD -> METHOD_FLAGS;
|
||||
case INNER_CLASS -> INNER_CLASS_FLAGS;
|
||||
case METHOD_PARAMETER -> METHOD_PARAMETER_FLAGS;
|
||||
case MODULE -> MODULE_FLAGS;
|
||||
case MODULE_REQUIRES -> MODULE_REQUIRES_FLAGS;
|
||||
case MODULE_EXPORTS -> MODULE_EXPORTS_FLAGS;
|
||||
case MODULE_OPENS -> MODULE_OPENS_FLAGS;
|
||||
};
|
||||
}
|
||||
|
||||
private static final @Stable AccessFlag[] // Can use stable array and lazy init in the future
|
||||
CLASS_FLAGS = createDefinition(PUBLIC, FINAL, SUPER, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE),
|
||||
FIELD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM),
|
||||
METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC),
|
||||
INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM),
|
||||
METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED),
|
||||
MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED),
|
||||
MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED),
|
||||
MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED),
|
||||
MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED);
|
||||
|
||||
private static int undefinedMask(AccessFlag[] definition, int mask) {
|
||||
assert definition.length == Character.SIZE;
|
||||
int definedMask = 0;
|
||||
for (int i = 0; i < Character.SIZE; i++) {
|
||||
if (definition[i] != null) {
|
||||
definedMask |= 1 << i;
|
||||
}
|
||||
}
|
||||
return mask & ~definedMask;
|
||||
}
|
||||
|
||||
private static final class AccessFlagSet extends AbstractSet<AccessFlag> {
|
||||
private final @Stable AccessFlag[] definition;
|
||||
private final int mask;
|
||||
|
||||
// all mutating methods throw UnsupportedOperationException
|
||||
@Override public boolean add(AccessFlag e) { throw uoe(); }
|
||||
@Override public boolean addAll(Collection<? extends AccessFlag> c) { throw uoe(); }
|
||||
@Override public void clear() { throw uoe(); }
|
||||
@Override public boolean remove(Object o) { throw uoe(); }
|
||||
@Override public boolean removeAll(Collection<?> c) { throw uoe(); }
|
||||
@Override public boolean removeIf(Predicate<? super AccessFlag> filter) { throw uoe(); }
|
||||
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
|
||||
private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
|
||||
|
||||
private AccessFlagSet(AccessFlag[] definition, int mask) {
|
||||
assert undefinedMask(definition, mask) == 0 : mask;
|
||||
this.definition = definition;
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<AccessFlag> iterator() {
|
||||
return new AccessFlagIterator(definition, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super AccessFlag> action) {
|
||||
Objects.requireNonNull(action); // in case of empty
|
||||
for (int i = 0; i < Character.SIZE; i++) {
|
||||
if ((mask & (1 << i)) != 0) {
|
||||
action.accept(definition[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AccessFlagIterator implements Iterator<AccessFlag> {
|
||||
private final @Stable AccessFlag[] definition;
|
||||
private int remainingMask;
|
||||
|
||||
private AccessFlagIterator(AccessFlag[] definition, int remainingMask) {
|
||||
this.definition = definition;
|
||||
this.remainingMask = remainingMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return remainingMask != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessFlag next() {
|
||||
int flagBit = Integer.lowestOneBit(remainingMask);
|
||||
if (flagBit == 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
remainingMask &= ~flagBit;
|
||||
return definition[Integer.numberOfTrailingZeros(flagBit)];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Integer.bitCount(mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (Objects.requireNonNull(o) instanceof AccessFlag flag) {
|
||||
int bit = flag.mask;
|
||||
return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return mask == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,6 +448,8 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to a class.
|
||||
*
|
||||
* @see AccessFlag.Location#CLASS
|
||||
* @see AccessFlag.Location#INNER_CLASS
|
||||
* @jls 8.1.1 Class Modifiers
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -461,6 +463,8 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to an interface.
|
||||
*
|
||||
* @see AccessFlag.Location#CLASS
|
||||
* @see AccessFlag.Location#INNER_CLASS
|
||||
* @jls 9.1.1 Interface Modifiers
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -474,6 +478,7 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to a constructor.
|
||||
*
|
||||
* @see AccessFlag.Location#METHOD
|
||||
* @jls 8.8.3 Constructor Modifiers
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -487,6 +492,7 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to a method.
|
||||
*
|
||||
* @see AccessFlag.Location#METHOD
|
||||
* @jls 8.4.3 Method Modifiers
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -500,6 +506,7 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to a field.
|
||||
*
|
||||
* @see AccessFlag.Location#FIELD
|
||||
* @jls 8.3.1 Field Modifiers
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -513,6 +520,7 @@ public final class Modifier {
|
||||
* @return an {@code int} value OR-ing together the source language
|
||||
* modifiers that can be applied to a parameter.
|
||||
*
|
||||
* @see AccessFlag.Location#METHOD_PARAMETER
|
||||
* @jls 8.4.1 Formal Parameters
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -158,5 +158,20 @@ public class BasicAccessFlagTest {
|
||||
; // Expected
|
||||
}
|
||||
}
|
||||
|
||||
for (var location : AccessFlag.Location.values()) {
|
||||
try {
|
||||
location.flags(null);
|
||||
throw new RuntimeException("Did not get NPE on " + location + ".flags(null)");
|
||||
} catch (NullPointerException npe ) {
|
||||
; // Expected
|
||||
}
|
||||
try {
|
||||
location.flagsMask(null);
|
||||
throw new RuntimeException("Did not get NPE on " + location + ".flagsMask(null)");
|
||||
} catch (NullPointerException npe ) {
|
||||
; // Expected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -31,6 +31,8 @@ import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.reflect.AccessFlag.*;
|
||||
|
||||
/*
|
||||
* Class access flags that can directly or indirectly declared in
|
||||
* source include:
|
||||
@ -47,7 +49,7 @@ import java.util.*;
|
||||
* file. Therefore, this test does not attempt to probe the setting of
|
||||
* that access flag.
|
||||
*/
|
||||
@ExpectedClassFlags("[PUBLIC, FINAL, SUPER]")
|
||||
@ExpectedClassFlags({PUBLIC, FINAL, SUPER})
|
||||
public final class ClassAccessFlagTest {
|
||||
public static void main(String... args) {
|
||||
// Top-level and auxiliary classes; i.e. non-inner classes
|
||||
@ -76,10 +78,12 @@ public final class ClassAccessFlagTest {
|
||||
ExpectedClassFlags expected =
|
||||
clazz.getAnnotation(ExpectedClassFlags.class);
|
||||
if (expected != null) {
|
||||
String actual = clazz.accessFlags().toString();
|
||||
if (!expected.value().equals(actual)) {
|
||||
Set<AccessFlag> base = EnumSet.noneOf(AccessFlag.class);
|
||||
Collections.addAll(base, expected.value());
|
||||
Set<AccessFlag> actual = clazz.accessFlags();
|
||||
if (!base.equals(actual)) {
|
||||
throw new RuntimeException("On " + clazz +
|
||||
" expected " + expected.value() +
|
||||
" expected " + base +
|
||||
" got " + actual);
|
||||
}
|
||||
}
|
||||
@ -98,7 +102,7 @@ public final class ClassAccessFlagTest {
|
||||
void.class // same access flag rules
|
||||
};
|
||||
|
||||
var expected = Set.of(AccessFlag.PUBLIC,
|
||||
var expected = Set.of(PUBLIC,
|
||||
AccessFlag.FINAL,
|
||||
AccessFlag.ABSTRACT);
|
||||
|
||||
@ -127,8 +131,8 @@ public final class ClassAccessFlagTest {
|
||||
for (var accessClass : accessClasses) {
|
||||
AccessFlag accessLevel;
|
||||
var flags = accessClass.accessFlags();
|
||||
if (flags.contains(AccessFlag.PUBLIC))
|
||||
accessLevel = AccessFlag.PUBLIC;
|
||||
if (flags.contains(PUBLIC))
|
||||
accessLevel = PUBLIC;
|
||||
else if (flags.contains(AccessFlag.PROTECTED))
|
||||
accessLevel = AccessFlag.PROTECTED;
|
||||
else if (flags.contains(AccessFlag.PRIVATE))
|
||||
@ -145,7 +149,7 @@ public final class ClassAccessFlagTest {
|
||||
}
|
||||
} else {
|
||||
if (containsAny(arrayClass.accessFlags(),
|
||||
Set.of(AccessFlag.PUBLIC,
|
||||
Set.of(PUBLIC,
|
||||
AccessFlag.PROTECTED,
|
||||
AccessFlag.PRIVATE))) {
|
||||
throw new RuntimeException("Unexpected access flags on " +
|
||||
@ -161,32 +165,32 @@ public final class ClassAccessFlagTest {
|
||||
// PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT,
|
||||
// SYNTHETIC, ANNOTATION, ENUM.
|
||||
|
||||
@ExpectedClassFlags("[PUBLIC, STATIC, INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({PUBLIC, STATIC, INTERFACE, ABSTRACT})
|
||||
public interface PublicInterface {}
|
||||
@ExpectedClassFlags("[PROTECTED, STATIC, INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({PROTECTED, STATIC, INTERFACE, ABSTRACT})
|
||||
protected interface ProtectedInterface {}
|
||||
@ExpectedClassFlags("[PRIVATE, STATIC, INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({PRIVATE, STATIC, INTERFACE, ABSTRACT})
|
||||
private interface PrivateInterface {}
|
||||
@ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT})
|
||||
/*package*/ interface PackageInterface {}
|
||||
|
||||
@ExpectedClassFlags("[FINAL]")
|
||||
@ExpectedClassFlags({FINAL})
|
||||
/*package*/ final class TestFinalClass {}
|
||||
|
||||
@ExpectedClassFlags("[ABSTRACT]")
|
||||
@ExpectedClassFlags({ABSTRACT})
|
||||
/*package*/ abstract class TestAbstractClass {}
|
||||
|
||||
@ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT, ANNOTATION]")
|
||||
@ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT, ANNOTATION})
|
||||
/*package*/ @interface TestMarkerAnnotation {}
|
||||
|
||||
@ExpectedClassFlags("[PUBLIC, STATIC, FINAL, ENUM]")
|
||||
@ExpectedClassFlags({PUBLIC, STATIC, FINAL, ENUM})
|
||||
public enum MetaSynVar {
|
||||
QUUX;
|
||||
}
|
||||
|
||||
// Is there is at least one special enum constant, the enum class
|
||||
// itself is implicitly abstract rather than final.
|
||||
@ExpectedClassFlags("[PROTECTED, STATIC, ABSTRACT, ENUM]")
|
||||
@ExpectedClassFlags({PROTECTED, STATIC, ABSTRACT, ENUM})
|
||||
protected enum MetaSynVar2 {
|
||||
WOMBAT{
|
||||
@Override
|
||||
@ -195,24 +199,24 @@ public final class ClassAccessFlagTest {
|
||||
public abstract int foo();
|
||||
}
|
||||
|
||||
@ExpectedClassFlags("[PRIVATE, ABSTRACT]")
|
||||
@ExpectedClassFlags({PRIVATE, ABSTRACT})
|
||||
private abstract class Foo {}
|
||||
|
||||
@ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT})
|
||||
interface StaticTestInterface {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ExpectedClassFlags("[INTERFACE, ABSTRACT, ANNOTATION]")
|
||||
@ExpectedClassFlags({INTERFACE, ABSTRACT, ANNOTATION})
|
||||
@interface ExpectedClassFlags {
|
||||
String value();
|
||||
AccessFlag[] value();
|
||||
}
|
||||
|
||||
@ExpectedClassFlags("[INTERFACE, ABSTRACT]")
|
||||
@ExpectedClassFlags({INTERFACE, ABSTRACT})
|
||||
interface TestInterface {}
|
||||
|
||||
|
||||
@ExpectedClassFlags("[FINAL, SUPER, ENUM]")
|
||||
@ExpectedClassFlags({FINAL, SUPER, ENUM})
|
||||
enum TestOuterEnum {
|
||||
INSTANCE;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -29,6 +29,11 @@
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.reflect.AccessFlag.*;
|
||||
|
||||
/*
|
||||
* Field modifiers include:
|
||||
@ -54,39 +59,41 @@ public class FieldAccessFlagTest {
|
||||
ExpectedFieldFlags expected =
|
||||
field.getAnnotation(ExpectedFieldFlags.class);
|
||||
if (expected != null) {
|
||||
String actual = field.accessFlags().toString();
|
||||
if (!expected.value().equals(actual)) {
|
||||
Set<AccessFlag> base = EnumSet.noneOf(AccessFlag.class);
|
||||
Collections.addAll(base, expected.value());
|
||||
Set<AccessFlag> actual = field.accessFlags();
|
||||
if (!base.equals(actual)) {
|
||||
throw new RuntimeException("On " + field +
|
||||
" expected " + expected.value() +
|
||||
" got " + actual);
|
||||
" expected " + base +
|
||||
" got " + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fields
|
||||
@ExpectedFieldFlags("[PUBLIC, STATIC, FINAL]")
|
||||
@ExpectedFieldFlags({PUBLIC, STATIC, FINAL})
|
||||
public static final String f1 = "foo";
|
||||
|
||||
@ExpectedFieldFlags("[PRIVATE, VOLATILE, TRANSIENT]")
|
||||
@ExpectedFieldFlags({PRIVATE, VOLATILE, TRANSIENT})
|
||||
private volatile transient String secret = "xxyzzy";
|
||||
|
||||
@ExpectedFieldFlags("[PROTECTED]")
|
||||
@ExpectedFieldFlags({PROTECTED})
|
||||
protected String meadow = "";
|
||||
|
||||
// Enum constant should have the enum access flag set
|
||||
static enum MetaSynVar {
|
||||
@ExpectedFieldFlags("[PUBLIC, STATIC, FINAL, ENUM]")
|
||||
@ExpectedFieldFlags({PUBLIC, STATIC, FINAL, ENUM})
|
||||
FOO,
|
||||
|
||||
@ExpectedFieldFlags("[PUBLIC, STATIC, FINAL, ENUM]")
|
||||
@ExpectedFieldFlags({PUBLIC, STATIC, FINAL, ENUM})
|
||||
BAR;
|
||||
|
||||
@ExpectedFieldFlags("[PRIVATE]") // no "ENUM"
|
||||
@ExpectedFieldFlags({PRIVATE}) // no "ENUM"
|
||||
private int field = 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface ExpectedFieldFlags {
|
||||
String value();
|
||||
AccessFlag[] value();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -34,6 +34,11 @@
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.reflect.AccessFlag.*;
|
||||
|
||||
/*
|
||||
* Method modifiers include:
|
||||
@ -49,7 +54,7 @@ import java.lang.reflect.*;
|
||||
* Method parameters can be final, synthetic, and mandated.
|
||||
*/
|
||||
public abstract class MethodAccessFlagTest {
|
||||
@ExpectedMethodFlags("[PUBLIC, STATIC, VARARGS]")
|
||||
@ExpectedMethodFlags({PUBLIC, STATIC, VARARGS})
|
||||
public static void main(String... args) {
|
||||
for (var ctor :
|
||||
MethodAccessFlagTest.class.getDeclaredConstructors()) {
|
||||
@ -136,11 +141,17 @@ public abstract class MethodAccessFlagTest {
|
||||
}
|
||||
|
||||
private static void checkExecutable(Executable method) {
|
||||
ExpectedMethodFlags emf =
|
||||
ExpectedMethodFlags expected =
|
||||
method.getAnnotation(ExpectedMethodFlags.class);
|
||||
if (emf != null) {
|
||||
String actual = method.accessFlags().toString();
|
||||
checkString(method.toString(), emf.value(), actual);
|
||||
if (expected != null) {
|
||||
Set<AccessFlag> base = EnumSet.noneOf(AccessFlag.class);
|
||||
Collections.addAll(base, expected.value());
|
||||
Set<AccessFlag> actual = method.accessFlags();
|
||||
if (!base.equals(actual)) {
|
||||
throw new RuntimeException("On " + method +
|
||||
" expected " + base +
|
||||
" got " + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,33 +166,33 @@ public abstract class MethodAccessFlagTest {
|
||||
}
|
||||
|
||||
// Constructors
|
||||
@ExpectedMethodFlags("[PUBLIC]")
|
||||
@ExpectedMethodFlags({PUBLIC})
|
||||
public MethodAccessFlagTest() {}
|
||||
|
||||
@ExpectedMethodFlags("[PROTECTED]")
|
||||
@ExpectedMethodFlags({PROTECTED})
|
||||
protected MethodAccessFlagTest(int i) {super();}
|
||||
|
||||
@ExpectedMethodFlags("[PRIVATE]")
|
||||
@ExpectedMethodFlags({PRIVATE})
|
||||
private MethodAccessFlagTest(String s) {super();}
|
||||
|
||||
// Methods
|
||||
@ExpectedMethodFlags("[PROTECTED, SYNCHRONIZED]")
|
||||
@ExpectedMethodFlags({PROTECTED, SYNCHRONIZED})
|
||||
protected synchronized void m0() {}
|
||||
|
||||
@ExpectedMethodFlags("[PRIVATE]")
|
||||
@ExpectedMethodFlags({PRIVATE})
|
||||
private void m1() {}
|
||||
|
||||
@ExpectedMethodFlags("[ABSTRACT]")
|
||||
@ExpectedMethodFlags({ABSTRACT})
|
||||
abstract void m2();
|
||||
|
||||
@ExpectedMethodFlags("[PUBLIC, FINAL]")
|
||||
@ExpectedMethodFlags({PUBLIC, FINAL})
|
||||
public final void m3() {}
|
||||
|
||||
@ExpectedMethodFlags("[NATIVE]")
|
||||
@ExpectedMethodFlags({NATIVE})
|
||||
native void m4();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface ExpectedMethodFlags {
|
||||
String value();
|
||||
AccessFlag[] value();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -35,6 +35,11 @@
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.reflect.AccessFlag.*;
|
||||
|
||||
/*
|
||||
* Test expected value of ACC_STRICT access flag.
|
||||
@ -42,7 +47,7 @@ import java.lang.reflect.*;
|
||||
// Declaring the class strictfp implicitly sets ACC_STRICT on all its
|
||||
// methods and constructors.
|
||||
public strictfp class StrictAccessFlagTest {
|
||||
@ExpectedFlags("[PUBLIC, STATIC, VARARGS, STRICT]")
|
||||
@ExpectedFlags({PUBLIC, STATIC, VARARGS, STRICT})
|
||||
public static void main(String... args) {
|
||||
for (var ctor :
|
||||
StrictAccessFlagTest.class.getDeclaredConstructors()) {
|
||||
@ -59,21 +64,23 @@ public strictfp class StrictAccessFlagTest {
|
||||
ExpectedFlags expected =
|
||||
method.getAnnotation(ExpectedFlags.class);
|
||||
if (expected != null) {
|
||||
String actual = method.accessFlags().toString();
|
||||
if (!expected.value().equals(actual)) {
|
||||
Set<AccessFlag> base = EnumSet.noneOf(AccessFlag.class);
|
||||
Collections.addAll(base, expected.value());
|
||||
Set<AccessFlag> actual = method.accessFlags();
|
||||
if (!base.equals(actual)) {
|
||||
throw new RuntimeException("On " + method +
|
||||
" expected " + expected.value() +
|
||||
" got " + actual);
|
||||
" expected " + base +
|
||||
" got " + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor
|
||||
@ExpectedFlags("[PUBLIC, STRICT]")
|
||||
@ExpectedFlags({PUBLIC, STRICT})
|
||||
public StrictAccessFlagTest() {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface ExpectedFlags {
|
||||
String value();
|
||||
AccessFlag[] value();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -24,7 +24,8 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8289106 8293627
|
||||
* @summary Tests of AccessFlag.locations(ClassFileFormatVersion)
|
||||
* @summary Tests of AccessFlag.locations(ClassFileFormatVersion) and
|
||||
* accessors on AccessFlag.Location
|
||||
*/
|
||||
|
||||
import java.lang.reflect.AccessFlag;
|
||||
@ -79,6 +80,8 @@ public class VersionedLocationsTest {
|
||||
testSynthetic();
|
||||
testStrict();
|
||||
testLatestMatch();
|
||||
testFlagVersionConsistency();
|
||||
testLocationMaskFlagConsistency();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,12 +244,13 @@ public class VersionedLocationsTest {
|
||||
private static void testSynthetic() {
|
||||
for (var cffv : ClassFileFormatVersion.values()) {
|
||||
Set<AccessFlag.Location> expected;
|
||||
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_6) <= 0) {
|
||||
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) < 0) {
|
||||
expected = Set.of();
|
||||
} else {
|
||||
expected =
|
||||
switch(cffv) {
|
||||
case RELEASE_7 -> Set.of(Location.CLASS, Location.FIELD,
|
||||
case RELEASE_5, RELEASE_6,
|
||||
RELEASE_7 -> Set.of(Location.CLASS, Location.FIELD,
|
||||
Location.METHOD,
|
||||
Location.INNER_CLASS);
|
||||
case RELEASE_8 -> Set.of(Location.CLASS, Location.FIELD,
|
||||
@ -285,4 +289,47 @@ public class VersionedLocationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static void testFlagVersionConsistency() {
|
||||
for (var flag : AccessFlag.values()) {
|
||||
for (var location : AccessFlag.Location.values()) {
|
||||
if (location.flags().contains(flag) != flag.locations().contains(location)) {
|
||||
throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
|
||||
"flag %s and location %s are inconsistent for the latest version"));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var cffv : ClassFileFormatVersion.values()) {
|
||||
for (var flag : AccessFlag.values()) {
|
||||
for (var location : AccessFlag.Location.values()) {
|
||||
if (location.flags(cffv).contains(flag) != flag.locations(cffv).contains(location)) {
|
||||
throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
|
||||
"flag %s and location %s are inconsistent for class file version %s"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLocationMaskFlagConsistency() {
|
||||
for (var location : AccessFlag.Location.values()) {
|
||||
if (!flagsAndMaskMatch(location.flags(), location.flagsMask())) {
|
||||
throw new RuntimeException(String.format("Flags and mask mismatch for %s", location));
|
||||
}
|
||||
for (var cffv : ClassFileFormatVersion.values()) {
|
||||
if (!flagsAndMaskMatch(location.flags(cffv), location.flagsMask(cffv))) {
|
||||
throw new RuntimeException(String.format("Flags and mask mismatch for %s in %s", location, cffv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean flagsAndMaskMatch(Set<AccessFlag> flags, int mask) {
|
||||
for (var flag : flags) {
|
||||
int bit = flag.mask();
|
||||
if (((mask & bit) == 0))
|
||||
return false;
|
||||
mask &= ~bit;
|
||||
}
|
||||
return mask == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@ -138,6 +138,8 @@ public class MOAT {
|
||||
|
||||
// Unmodifiable wrappers
|
||||
testImmutableSet(unmodifiableSet(new HashSet<>(Arrays.asList(1,2,3))), 99);
|
||||
testImmutableSet(AccessFlag.maskToAccessFlags(0, AccessFlag.Location.CLASS), AccessFlag.ABSTRACT);
|
||||
testImmutableSet(AccessFlag.maskToAccessFlags(Modifier.PUBLIC | Modifier.STATIC | Modifier.SYNCHRONIZED, AccessFlag.Location.METHOD), AccessFlag.ABSTRACT);
|
||||
testImmutableList(unmodifiableList(Arrays.asList(1,2,3)));
|
||||
testImmutableMap(unmodifiableMap(Collections.singletonMap(1,2)));
|
||||
testImmutableSeqColl(unmodifiableSequencedCollection(Arrays.asList(1,2,3)), 99);
|
||||
@ -478,6 +480,8 @@ public class MOAT {
|
||||
() -> c.remove(first),
|
||||
() -> c.removeAll(singleton(first)),
|
||||
() -> c.retainAll(emptyList()));
|
||||
} else {
|
||||
testEmptyIterator(c.iterator());
|
||||
}
|
||||
testForEachMatch(c);
|
||||
testSpliteratorMatch(c);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user