From 590a50636700c6e453b15f02cffae5ccc9144c3b Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Tue, 15 Apr 2025 16:21:01 -0400 Subject: [PATCH 1/6] Temp file --- AOSEN.FIXME | 64 ++ .../share/classes/java/util/HashSet.java.save | 410 ++++++++++++ .../share/classes/java/util/TreeSet.java.save | 604 ++++++++++++++++++ 3 files changed, 1078 insertions(+) create mode 100644 AOSEN.FIXME create mode 100644 src/java.base/share/classes/java/util/HashSet.java.save create mode 100644 src/java.base/share/classes/java/util/TreeSet.java.save diff --git a/AOSEN.FIXME b/AOSEN.FIXME new file mode 100644 index 00000000000..6942f0ced82 --- /dev/null +++ b/AOSEN.FIXME @@ -0,0 +1,64 @@ +Action to take: fix copyof and copyofrange method. + +1. PICO Flow +2. PICO inner class array field initializer + class A { + Object[] a; + class B { + Object[] b = a; + } + } +3. PICO constructor type + question: + @RDM class A { + @RDM Object obj; + A (@RDM Object obj) { + // If inside constructor `this` is @Mutable, then obj should @Mutable as well. + // This is bad, because new @Immutable A(obj) should not expect a obj to be @Mutable. + this.obj = obj; + } + } +4. Clone method. How to allow different reciever type +5. Unique type conversion + polymutable(elt) Object polymutable(container) [] copyof(polymutable(container) Collection coll){ + + polymutable Object @Mutable [] newArray = new ...; + + for () { + newArray[i] = coll.get(i); + } + + return newArray; // polymutable(elt) Object @Mutable @Unique [] + // polymutable(elt) Object polymutable(container) [] + } +6. Uniqueness typing design. Class bound annotation to identity move or copy semantics. Object creation should always be unique. +7. Cast is implemented incorrectly +8. Covariant annotation does not work correctly +9. Type state system for assignment once. Hashcode() @AssignHash0or1 +10. Allow @PolyMutable as a type argument +public @PolyMutable Set> entrySet(@PolyMutable AscendingSubMap this) { + EntrySetView es = entrySetView; + return (es != null) ? es : (entrySetView = new @PolyMutable AscendingEntrySetView()); + } +@ReceiverDependentMutable final class AscendingEntrySetView extends EntrySetView { + public Iterator> iterator(@Readonly AscendingEntrySetView this) { + return new SubMapEntryIterator(absLowest(), absHighFence()); + } + } + + @ReceiverDependentMutable abstract class EntrySetView extends AbstractSet> + + ./jdk/src/java.base/share/classes/java/util/TreeMap.java:2325: error: [return.type.incompatible] incompatible types in return. + return (es != null) ? es : (entrySetView = new @PolyMutable AscendingEntrySetView()); + ^ + type of expression: @PolyMutable Set<@Readonly Entry> + method return type: @PolyMutable Set<@PolyMutable Entry> + +11. ReceiverDependentMutable depends on the type of outer class. + Iterator { + @Readonly Entry e; + + + } + + diff --git a/src/java.base/share/classes/java/util/HashSet.java.save b/src/java.base/share/classes/java/util/HashSet.java.save new file mode 100644 index 00000000000..1ae965ccba5 --- /dev/null +++ b/src/java.base/share/classes/java/util/HashSet.java.save @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1997, 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.util; + +import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; +import org.checkerframework.checker.pico.qual.Immutable; +import org.checkerframework.checker.pico.qual.Mutable; +import org.checkerframework.checker.pico.qual.PolyMutable; +import org.checkerframework.checker.pico.qual.ReceiverDependentMutable; +import org.checkerframework.checker.pico.qual.Readonly; +import org.checkerframework.checker.signedness.qual.UnknownSignedness; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.dataflow.qual.SideEffectsOnly; +import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; +import org.checkerframework.framework.qual.DefaultQualifierForUse; + +import java.io.InvalidObjectException; +import jdk.internal.access.SharedSecrets; + +/** + * This class implements the {@code Set} interface, backed by a hash table + * (actually a {@code HashMap} instance). It makes no guarantees as to the + * iteration order of the set; in particular, it does not guarantee that the + * order will remain constant over time. This class permits the {@code null} + * element. + * + *

This class offers constant time performance for the basic operations + * ({@code add}, {@code remove}, {@code contains} and {@code size}), + * assuming the hash function disperses the elements properly among the + * buckets. Iterating over this set requires time proportional to the sum of + * the {@code HashSet} instance's size (the number of elements) plus the + * "capacity" of the backing {@code HashMap} instance (the number of + * buckets). Thus, it's very important not to set the initial capacity too + * high (or the load factor too low) if iteration performance is important. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a hash set concurrently, and at least one of + * the threads modifies the set, it must be synchronized externally. + * This is typically accomplished by synchronizing on some object that + * naturally encapsulates the set. + * + * If no such object exists, the set should be "wrapped" using the + * {@link Collections#synchronizedSet Collections.synchronizedSet} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the set:

+ *   Set s = Collections.synchronizedSet(new HashSet(...));
+ * + *

The iterators returned by this class's {@code iterator} method are + * fail-fast: if the set is modified at any time after the iterator is + * created, in any way except through the iterator's own {@code remove} + * method, the Iterator throws a {@link ConcurrentModificationException}. + * Thus, in the face of concurrent modification, the iterator fails quickly + * and cleanly, rather than risking arbitrary, non-deterministic behavior at + * an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see Set + * @see TreeSet + * @see HashMap + * @since 1.2 + */ + + @AnnotatedFor({"index", "initialization", "lock", "nullness"}) + @SuppressWarnings("pico:assignment.type.incompatible") // Revisit this, looks like CF bug + @ReceiverDependentMutable public class HashSet + extends AbstractSet + implements Set, Cloneable, java.io.Serializable +{ + @java.io.Serial + static final long serialVersionUID = -5024744406713321676L; + + private transient HashMap<@Immutable E, @Readonly Object> map; + + // Dummy value to associate with an Object in the backing Map + private static final Object PRESENT = new Object(); + + /** + * Constructs a new, empty set; the backing {@code HashMap} instance has + * default initial capacity (16) and load factor (0.75). + */ + public HashSet() { + map = new @ReceiverDependentMutable HashMap<@Immutable E, @Readonly Object>(); + } + + /** + * Constructs a new set containing the elements in the specified + * collection. The {@code HashMap} is created with default load factor + * (0.75) and an initial capacity sufficient to contain the elements in + * the specified collection. + * + * @param c the collection whose elements are to be placed into this set + * @throws NullPointerException if the specified collection is null + */ + @SuppressWarnings("pico") // PICO constructor fix + public @PolyNonEmpty HashSet(@PolyNonEmpty @Readonly Collection c) { + map = new @ReceiverDependentMutable HashMap<@Immutable E, @Readonly Object>(Math.max((int) (c.size()/.75f) + 1, 16)); + addAll(c); + } + + /** + * Constructs a new, empty set; the backing {@code HashMap} instance has + * the specified initial capacity and the specified load factor. + * + * @param initialCapacity the initial capacity of the hash map + * @param loadFactor the load factor of the hash map + * @throws IllegalArgumentException if the initial capacity is less + * than zero, or if the load factor is nonpositive + */ + public HashSet(@NonNegative int initialCapacity, float loadFactor) { + map = new @ReceiverDependentMutable HashMap<@Immutable E, @Readonly Object>(initialCapacity, loadFactor); + } + + /** + * Constructs a new, empty set; the backing {@code HashMap} instance has + * the specified initial capacity and default load factor (0.75). + * + * @param initialCapacity the initial capacity of the hash table + * @throws IllegalArgumentException if the initial capacity is less + * than zero + */ + public HashSet(@NonNegative int initialCapacity) { + map = new @ReceiverDependentMutable HashMap<@Immutable E, @Readonly Object>(initialCapacity); + } + + /** + * Constructs a new, empty linked hash set. (This package private + * constructor is only used by LinkedHashSet.) The backing + * HashMap instance is a LinkedHashMap with the specified initial + * capacity and the specified load factor. + * + * @param initialCapacity the initial capacity of the hash map + * @param loadFactor the load factor of the hash map + * @param dummy ignored (distinguishes this + * constructor from other int, float constructor.) + * @throws IllegalArgumentException if the initial capacity is less + * than zero, or if the load factor is nonpositive + */ + HashSet(int initialCapacity, float loadFactor, boolean dummy) { + map = new @ReceiverDependentMutable LinkedHashMap<@Immutable E, @Readonly Object>(initialCapacity, loadFactor); + } + + /** + * Returns an iterator over the elements in this set. The elements + * are returned in no particular order. + * + * @return an Iterator over the elements in this set + * @see ConcurrentModificationException + */ + @SideEffectFree + @SuppressWarnings("pico") // lost can not invoke poly method. + public @PolyNonEmpty Iterator iterator(@PolyNonEmpty @Readonly HashSet this) { + return map.keySet().iterator(); + } + + /** + * Returns the number of elements in this set (its cardinality). + * + * @return the number of elements in this set (its cardinality) + */ + @Pure + public @NonNegative int size(@GuardSatisfied @Readonly HashSet this) { + return map.size(); + } + + /** + * Returns {@code true} if this set contains no elements. + * + * @return {@code true} if this set contains no elements + */ + @Pure + @EnsuresNonEmptyIf(result = false, expression = "this") + public boolean isEmpty(@Readonly @GuardSatisfied HashSet this) { + return map.isEmpty(); + } + + /** + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * {@code Objects.equals(o, e)}. + * + * @param o element whose presence in this set is to be tested + * @return {@code true} if this set contains the specified element + */ + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") + public boolean contains(@Readonly @GuardSatisfied HashSet this, @GuardSatisfied @Nullable @UnknownSignedness @Readonly Object o) { + return map.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element {@code e} to this set if + * this set contains no element {@code e2} such that + * {@code Objects.equals(e, e2)}. + * If this set already contains the element, the call leaves the set + * unchanged and returns {@code false}. + * + * @param e element to be added to this set + * @return {@code true} if this set did not already contain the specified + * element + */ + @SideEffectsOnly("this") + @EnsuresNonEmpty("this") + public boolean add(@Mutable @GuardSatisfied HashSet this, E e) { + return map.put(e, PRESENT)==null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element {@code e} such that + * {@code Objects.equals(o, e)}, + * if this set contains such an element. Returns {@code true} if + * this set contained the element (or equivalently, if this set + * changed as a result of the call). (This set will not contain the + * element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return {@code true} if the set contained the specified element + */ + @SideEffectsOnly("this") + public boolean remove(@Mutable @GuardSatisfied HashSet this, @GuardSatisfied @Nullable @UnknownSignedness @Readonly Object o) { + return map.remove(o)==PRESENT; + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + @SideEffectsOnly("this") + public void clear(@Mutable @GuardSatisfied HashSet this) { + map.clear(); + } + + /** + * Returns a shallow copy of this {@code HashSet} instance: the elements + * themselves are not cloned. + * + * @return a shallow copy of this set + */ + @SideEffectFree + @SuppressWarnings("unchecked") + public Object clone(@GuardSatisfied @Mutable HashSet this) { + try { + HashSet newSet = (HashSet) super.clone(); + newSet.map = (HashMap) map.clone(); + return newSet; + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + } + + /** + * Save the state of this {@code HashSet} instance to a stream (that is, + * serialize it). + * + * @serialData The capacity of the backing {@code HashMap} instance + * (int), and its load factor (float) are emitted, followed by + * the size of the set (the number of elements it contains) + * (int), followed by all of its elements (each an Object) in + * no particular order. + */ + @java.io.Serial + private void writeObject(@Mutable HashSet this, java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden serialization magic + s.defaultWriteObject(); + + // Write out HashMap capacity and load factor + s.writeInt(map.capacity()); + s.writeFloat(map.loadFactor()); + + // Write out size + s.writeInt(map.size()); + + // Write out all elements in the proper order. + for (E e : map.keySet()) + s.writeObject(e); + } + + /** + * Reconstitute the {@code HashSet} instance from a stream (that is, + * deserialize it). + */ + @java.io.Serial + private void readObject(@Mutable HashSet this, java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden serialization magic + s.defaultReadObject(); + + // Read capacity and verify non-negative. + int capacity = s.readInt(); + if (capacity < 0) { + throw new InvalidObjectException("Illegal capacity: " + + capacity); + } + + // Read load factor and verify positive and non NaN. + float loadFactor = s.readFloat(); + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { + throw new InvalidObjectException("Illegal load factor: " + + loadFactor); + } + + // Read size and verify non-negative. + int size = s.readInt(); + if (size < 0) { + throw new InvalidObjectException("Illegal size: " + + size); + } + + // Set the capacity according to the size and load factor ensuring that + // the HashMap is at least 25% full but clamping to maximum capacity. + capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f), + HashMap.MAXIMUM_CAPACITY); + + // Constructing the backing map will lazily create an array when the first element is + // added, so check it before construction. Call HashMap.tableSizeFor to compute the + // actual allocation size. Check Map.Entry[].class since it's the nearest public type to + // what is actually created. + SharedSecrets.getJavaObjectInputStreamAccess() + .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity)); + + // Create backing HashMap + map = (((HashSet)this) instanceof LinkedHashSet ? + new LinkedHashMap<@Immutable E, @Readonly Object>(capacity, loadFactor) : + new HashMap<@Immutable E, @Readonly Object>(capacity, loadFactor)); + + // Read in all elements in the proper order. + for (int i=0; ilate-binding + * and fail-fast {@link Spliterator} over the elements in this + * set. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED} and + * {@link Spliterator#DISTINCT}. Overriding implementations should document + * the reporting of additional characteristic values. + * + * @return a {@code Spliterator} over the elements in this set + * @since 1.8 + */ + public Spliterator spliterator(@Readonly HashSet this) { + return new HashMap.KeySpliterator<>(map, 0, -1, 0, 0); + } + + @Override + public @PolyMutable Object[] toArray(@Readonly HashSet<@PolyMutable E> this) { + return map.keysToArray(new @PolyMutable Object[map.size()]); + } + + @Override + public @Nullable T[] toArray(@Readonly HashSet this, @PolyNull T[] a) { + return map.keysToArray(map.prepareArray(a)); + } +} diff --git a/src/java.base/share/classes/java/util/TreeSet.java.save b/src/java.base/share/classes/java/util/TreeSet.java.save new file mode 100644 index 00000000000..2ac7c888479 --- /dev/null +++ b/src/java.base/share/classes/java/util/TreeSet.java.save @@ -0,0 +1,604 @@ +/* + * Copyright (c) 1998, 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.util; + +import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.pico.qual.Immutable; +import org.checkerframework.checker.pico.qual.Mutable; +import org.checkerframework.checker.pico.qual.PolyMutable; +import org.checkerframework.checker.pico.qual.Readonly; +import org.checkerframework.checker.pico.qual.ReceiverDependentMutable; +import org.checkerframework.checker.signedness.qual.UnknownSignedness; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; + +/** + * A {@link NavigableSet} implementation based on a {@link TreeMap}. + * The elements are ordered using their {@linkplain Comparable natural + * ordering}, or by a {@link Comparator} provided at set creation + * time, depending on which constructor is used. + * + *

This implementation provides guaranteed log(n) time cost for the basic + * operations ({@code add}, {@code remove} and {@code contains}). + * + *

Note that the ordering maintained by a set (whether or not an explicit + * comparator is provided) must be consistent with equals if it is to + * correctly implement the {@code Set} interface. (See {@code Comparable} + * or {@code Comparator} for a precise definition of consistent with + * equals.) This is so because the {@code Set} interface is defined in + * terms of the {@code equals} operation, but a {@code TreeSet} instance + * performs all element comparisons using its {@code compareTo} (or + * {@code compare}) method, so two elements that are deemed equal by this method + * are, from the standpoint of the set, equal. The behavior of a set + * is well-defined even if its ordering is inconsistent with equals; it + * just fails to obey the general contract of the {@code Set} interface. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a tree set concurrently, and at least one + * of the threads modifies the set, it must be synchronized + * externally. This is typically accomplished by synchronizing on some + * object that naturally encapsulates the set. + * If no such object exists, the set should be "wrapped" using the + * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the set:

+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
+ * + *

The iterators returned by this class's {@code iterator} method are + * fail-fast: if the set is modified at any time after the iterator is + * created, in any way except through the iterator's own {@code remove} + * method, the iterator will throw a {@link ConcurrentModificationException}. + * Thus, in the face of concurrent modification, the iterator fails quickly + * and cleanly, rather than risking arbitrary, non-deterministic behavior at + * an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @see Collection + * @see Set + * @see HashSet + * @see Comparable + * @see Comparator + * @see TreeMap + * @since 1.2 + */ + +@CFComment({"lock/nullness: Subclasses of this interface/class may opt to prohibit null elements"}) +@AnnotatedFor({"lock", "nullness"}) +@SuppressWarnings("pico:assignment.type.incompatible") // Revisit this, looks like CF bug +@ReceiverDependentMutable public class TreeSet extends AbstractSet + implements NavigableSet, Cloneable, java.io.Serializable +{ + /** + * The backing map. + */ + private transient NavigableMap<@Immutable E, @Readonly Object> m; + + // Dummy value to associate with an Object in the backing Map + private static final Object PRESENT = new Object(); + + /** + * Constructs a set backed by the specified navigable map. + */ + TreeSet(@ReceiverDependentMutable NavigableMap<@Immutable E, @Readonly Object> m) { + this.m = m; + } + + /** + * Constructs a new, empty tree set, sorted according to the + * natural ordering of its elements. All elements inserted into + * the set must implement the {@link Comparable} interface. + * Furthermore, all such elements must be mutually + * comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. If the user attempts to add an element + * to the set that violates this constraint (for example, the user + * attempts to add a string element to a set whose elements are + * integers), the {@code add} call will throw a + * {@code ClassCastException}. + */ + public TreeSet() { + this(new @ReceiverDependentMutable TreeMap<@Immutable E, @Readonly Object>()); + } + + /** + * Constructs a new, empty tree set, sorted according to the specified + * comparator. All elements inserted into the set must be mutually + * comparable by the specified comparator: {@code comparator.compare(e1, + * e2)} must not throw a {@code ClassCastException} for any elements + * {@code e1} and {@code e2} in the set. If the user attempts to add + * an element to the set that violates this constraint, the + * {@code add} call will throw a {@code ClassCastException}. + * + * @param comparator the comparator that will be used to order this set. + * If {@code null}, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public TreeSet(@Nullable Comparator comparator) { + this(new @ReceiverDependentMutable TreeMap<@Immutable E, @Readonly Object>(comparator)); + } + + /** + * Constructs a new tree set containing the elements in the specified + * collection, sorted according to the natural ordering of its + * elements. All elements inserted into the set must implement the + * {@link Comparable} interface. Furthermore, all such elements must be + * mutually comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. + * + * @param c collection whose elements will comprise the new set + * @throws ClassCastException if the elements in {@code c} are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection is null + */ + @SuppressWarnings("pico") // PICO constructor fix + public @PolyNonEmpty TreeSet(@PolyNonEmpty Collection c) { + this(); + addAll(c); + } + + /** + * Constructs a new tree set containing the same elements and + * using the same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set is null + */ + @SuppressWarnings("pico") // PICO constructor fix + public @PolyNonEmpty TreeSet(@PolyNonEmpty SortedSet s) { + this(s.comparator()); + addAll(s); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + @SideEffectFree + @SuppressWarnings("pico") // lost can not invoke poly method. + public @PolyNonEmpty Iterator iterator(@PolyNonEmpty @Readonly TreeSet this) { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + * @since 1.6 + */ + @SuppressWarnings("pico") // lost can not invoke poly method. + public @PolyNonEmpty Iterator descendingIterator(@PolyNonEmpty @Readonly TreeSet this) { + return m.descendingKeySet().iterator(); + } + + /** + * @since 1.6 + */ + public @PolyMutable NavigableSet descendingSet(@PolyMutable TreeSet this) { + return new @PolyMutable TreeSet<>(m.descendingMap()); + } + + /** + * Returns the number of elements in this set (its cardinality). + * + * @return the number of elements in this set (its cardinality) + */ + @Pure + public @NonNegative int size(@GuardSatisfied @Readonly TreeSet this) { + return m.size(); + } + + /** + * Returns {@code true} if this set contains no elements. + * + * @return {@code true} if this set contains no elements + */ + @EnsuresNonNullIf(expression={"pollFirst()", "pollLast()"}, result=false) + @Pure + @EnsuresNonEmptyIf(result = false, expression = "this") + public boolean isEmpty(@GuardSatisfied @Readonly TreeSet this) { + return m.isEmpty(); + } + + /** + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * {@code Objects.equals(o, e)}. + * + * @param o object to be checked for containment in this set + * @return {@code true} if this set contains the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") + public boolean contains(@GuardSatisfied @Readonly TreeSet this, @GuardSatisfied @UnknownSignedness @Readonly Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element {@code e} to this set if + * the set contains no element {@code e2} such that + * {@code Objects.equals(e, e2)}. + * If this set already contains the element, the call leaves the set + * unchanged and returns {@code false}. + * + * @param e element to be added to this set + * @return {@code true} if this set did not already contain the specified + * element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + @EnsuresNonEmpty("this") + public boolean add(@GuardSatisfied @Mutable TreeSet this, E e) { + return m.put(e, PRESENT)==null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element {@code e} such that + * {@code Objects.equals(o, e)}, + * if this set contains such an element. Returns {@code true} if + * this set contained the element (or equivalently, if this set + * changed as a result of the call). (This set will not contain the + * element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return {@code true} if this set contained the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean remove(@GuardSatisfied @Mutable TreeSet this, @GuardSatisfied @UnknownSignedness @Readonly Object o) { + return m.remove(o)==PRESENT; + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + public void clear(@GuardSatisfied @Mutable TreeSet this) { + m.clear(); + } + + /** + * Adds all of the elements in the specified collection to this set. + * + * @param c collection containing elements to be added to this set + * @return {@code true} if this set changed as a result of the call + * @throws ClassCastException if the elements provided cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified collection is null or + * if any element is null and this set uses natural ordering, or + * its comparator does not permit null elements + */ + public boolean addAll(@GuardSatisfied @Mutable TreeSet this, @Readonly Collection c) { + // Use linear-time version if applicable + if (m.size()==0 && c.size() > 0 && + c instanceof SortedSet && + m instanceof TreeMap<@Immutable E, Object> map) { + SortedSet set = (SortedSet) c; + if (Objects.equals(set.comparator(), map.comparator())) { + map.addAllForTreeSet(set, PRESENT); + return true; + } + } + return super.addAll(c); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or {@code toElement} + * is null and this set uses natural ordering, or its comparator + * does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + @SideEffectFree + public @PolyMutable NavigableSet subSet(@GuardSatisfied @PolyMutable TreeSet this, @GuardSatisfied E fromElement, boolean fromInclusive, + @GuardSatisfied E toElement, boolean toInclusive) { + return new @PolyMutable TreeSet<>(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + @SideEffectFree + public @PolyMutable NavigableSet headSet(@GuardSatisfied @PolyMutable TreeSet this, @GuardSatisfied E toElement, boolean inclusive) { + return new @PolyMutable TreeSet<>(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + @SideEffectFree + public @PolyMutable NavigableSet tailSet(@GuardSatisfied @PolyMutable TreeSet this, @GuardSatisfied E fromElement, boolean inclusive) { + return new @PolyMutable TreeSet<>(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set uses natural ordering, + * or its comparator does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + @SideEffectFree + public @PolyMutable SortedSet subSet(@GuardSatisfied @PolyMutable TreeSet this, @GuardSatisfied E fromElement, @GuardSatisfied E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + @SideEffectFree + public @PolyMutable SortedSet headSet(@GuardSatisfied @PolyMutable TreeSet this, E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + @SideEffectFree + public @PolyMutable SortedSet tailSet(@GuardSatisfied @PolyMutable TreeSet this, E fromElement) { + return tailSet(fromElement, true); + } + + @Pure + public @Nullable Comparator comparator(@GuardSatisfied @Readonly TreeSet this) { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + @SideEffectFree + public E first(@GuardSatisfied @NonEmpty @Readonly TreeSet this) { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + @SideEffectFree + public E last(@GuardSatisfied @NonEmpty @Readonly TreeSet this) { + return m.lastKey(); + } + + // NavigableSet API methods + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public @Nullable E lower(@Readonly TreeSet this, E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public @Nullable E floor(@Readonly TreeSet this, E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public @Nullable E ceiling(@Readonly TreeSet this, E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public @Nullable E higher(@Readonly TreeSet this, E e) { + return m.higherKey(e); + } + + /** + * @since 1.6 + */ + public @Nullable E pollFirst(@GuardSatisfied @Mutable TreeSet this) { + Map.Entry<@Immutable E,?> e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * @since 1.6 + */ + public @Nullable E pollLast(@GuardSatisfied @Mutable TreeSet this) { + Map.Entry<@Immutable E,?> e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns a shallow copy of this {@code TreeSet} instance. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this set + */ + @SideEffectFree + @SuppressWarnings("unchecked") + public Object clone(@GuardSatisfied @Mutable TreeSet this) { + TreeSet clone; + try { + clone = (TreeSet) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + + clone.m = new TreeMap<@Immutable E, @Readonly Object>(m); + return clone; + } + + /** + * Save the state of the {@code TreeSet} instance to a stream (that is, + * serialize it). + * + * @serialData Emits the comparator used to order this set, or + * {@code null} if it obeys its elements' natural ordering + * (Object), followed by the size of the set (the number of + * elements it contains) (int), followed by all of its + * elements (each an Object) in order (as determined by the + * set's Comparator, or by the elements' natural ordering if + * the set has no Comparator). + */ + @java.io.Serial + private void writeObject(@Mutable TreeSet this, java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out Comparator + s.writeObject(m.comparator()); + + // Write out size + s.writeInt(m.size()); + + // Write out all elements in the proper order. + for (E e : m.keySet()) + s.writeObject(e); + } + + /** + * Reconstitute the {@code TreeSet} instance from a stream (that is, + * deserialize it). + */ + @java.io.Serial + private void readObject(@Mutable TreeSet this, java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden stuff + s.defaultReadObject(); + + // Read in Comparator + @SuppressWarnings("unchecked") + Comparator c = (Comparator) s.readObject(); + + // Create backing TreeMap + TreeMap<@Immutable E, @Readonly Object> tm = new TreeMap<@Immutable E, @Readonly Object>(c); + m = tm; + + // Read in size + int size = s.readInt(); + + tm.readTreeSet(size, s, PRESENT); + } + + /** + * Creates a late-binding + * and fail-fast {@link Spliterator} over the elements in this + * set. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED}, + * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and + * {@link Spliterator#ORDERED}. Overriding implementations should document + * the reporting of additional characteristic values. + * + *

The spliterator's comparator (see + * {@link java.util.Spliterator#getComparator()}) is {@code null} if + * the tree set's comparator (see {@link #comparator()}) is {@code null}. + * Otherwise, the spliterator's comparator is the same as or imposes the + * same total ordering as the tree set's comparator. + * + * @return a {@code Spliterator} over the elements in this set + * @since 1.8 + */ + public Spliterator spliterator() { + return TreeMap.keySpliteratorFor(m); + } + + @java.io.Serial + private static final long serialVersionUID = -2479143000061671589L; +} From 5effe5420ff00fb3e47b6645d3a28269255ba549 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Wed, 7 May 2025 17:55:43 -0400 Subject: [PATCH 2/6] First round of annotations for `java.lang` --- .../java/lang/ApplicationShutdownHooks.java | 3 +- .../share/classes/java/lang/Character.java | 4 +- .../classes/java/lang/CharacterData.java | 3 +- .../classes/java/lang/CharacterName.java | 3 +- .../share/classes/java/lang/Class.java | 50 +++++++++---------- .../share/classes/java/lang/ClassLoader.java | 26 +++++----- .../share/classes/java/lang/ClassValue.java | 15 +++--- .../java/lang/ConditionalSpecialCasing.java | 7 +-- .../lang/LayerInstantiationException.java | 4 +- .../share/classes/java/lang/Module.java | 20 ++++---- .../share/classes/java/lang/ModuleLayer.java | 4 +- .../share/classes/java/lang/NamedPackage.java | 4 +- .../share/classes/java/lang/Package.java | 36 ++++++------- .../classes/java/lang/ProcessBuilder.java | 4 +- .../classes/java/lang/ProcessHandle.java | 4 +- .../classes/java/lang/ProcessHandleImpl.java | 10 ++-- .../classes/java/lang/PublicMethods.java | 4 +- .../lang/ReflectiveOperationException.java | 8 +-- .../share/classes/java/lang/Runtime.java | 2 +- .../classes/java/lang/RuntimePermission.java | 4 +- .../classes/java/lang/StackStreamFactory.java | 8 +-- .../classes/java/lang/StackTraceElement.java | 16 +++--- .../share/classes/java/lang/StackWalker.java | 2 +- .../share/classes/java/lang/StringBuffer.java | 2 +- .../share/classes/java/lang/StringLatin1.java | 20 ++++---- .../share/classes/java/lang/StringUTF16.java | 24 +++++---- .../share/classes/java/lang/System.java | 11 ++-- .../share/classes/java/lang/Thread.java | 18 +++---- .../share/classes/java/lang/ThreadGroup.java | 2 +- .../share/classes/java/lang/ThreadLocal.java | 2 +- .../share/classes/java/lang/Throwable.java | 19 +++---- .../share/classes/java/lang/WeakPairMap.java | 6 +-- .../classes/java/lang/ref/Reference.java | 2 +- .../classes/java/lang/reflect/Method.java | 2 +- .../java/security/BasicPermission.java | 6 +-- .../classes/java/security/Permission.java | 4 +- .../java/security/ProtectionDomain.java | 2 +- .../org/objectweb/asm/ClassVisitor.java | 4 +- .../org/objectweb/asm/ClassWriter.java | 6 ++- 39 files changed, 203 insertions(+), 168 deletions(-) diff --git a/src/java.base/share/classes/java/lang/ApplicationShutdownHooks.java b/src/java.base/share/classes/java/lang/ApplicationShutdownHooks.java index 7d8b25aac94..e1bf8f2b033 100644 --- a/src/java.base/share/classes/java/lang/ApplicationShutdownHooks.java +++ b/src/java.base/share/classes/java/lang/ApplicationShutdownHooks.java @@ -25,6 +25,7 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.*; @@ -40,7 +41,7 @@ @AnnotatedFor({"interning"}) @UsesObjectEquals class ApplicationShutdownHooks { /* The set of registered hooks */ - private static IdentityHashMap hooks; + private static @Nullable IdentityHashMap hooks; static { try { Shutdown.add(1 /* shutdown hook invocation order */, diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 37f024e1d59..f40c7672ecd 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -3813,7 +3813,7 @@ private UnicodeBlock(String idName, String... aliases) { 0x100000, // 100000..10FFFF; Supplementary Private Use Area-B }; - private static final UnicodeBlock[] blocks = { + private static final @Nullable UnicodeBlock[] blocks = { BASIC_LATIN, LATIN_1_SUPPLEMENT, LATIN_EXTENDED_A, @@ -11542,7 +11542,7 @@ public static char reverseBytes(char ch) { */ @Pure @StaticallyExecutable - public static String getName(int codePoint) { + public static @Nullable String getName(int codePoint) { if (!isValidCodePoint(codePoint)) { throw new IllegalArgumentException( String.format("Not a valid Unicode code point: 0x%X", codePoint)); diff --git a/src/java.base/share/classes/java/lang/CharacterData.java b/src/java.base/share/classes/java/lang/CharacterData.java index 566dbbabe5d..43a5e68b07d 100644 --- a/src/java.base/share/classes/java/lang/CharacterData.java +++ b/src/java.base/share/classes/java/lang/CharacterData.java @@ -26,6 +26,7 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.value.qual.IntRange; import org.checkerframework.framework.qual.AnnotatedFor; @@ -55,7 +56,7 @@ int toUpperCaseEx(int ch) { return toUpperCase(ch); } - char[] toUpperCaseCharArray(int ch) { + char @Nullable [] toUpperCaseCharArray(int ch) { return null; } diff --git a/src/java.base/share/classes/java/lang/CharacterName.java b/src/java.base/share/classes/java/lang/CharacterName.java index 007ddf57a33..c0adb7298ef 100644 --- a/src/java.base/share/classes/java/lang/CharacterName.java +++ b/src/java.base/share/classes/java/lang/CharacterName.java @@ -26,6 +26,7 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.DataInputStream; @@ -144,7 +145,7 @@ public static CharacterName getInstance() { return cname; } - public String getName(int cp) { + public @Nullable String getName(int cp) { int off = 0; int bk = bkIndices[cp >> 8]; if (bk == -1 || (off = lookup[(bk << 8) + (cp & 0xff)]) == 0) diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index dbb50a98bb3..70ea9dfebb4 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -403,7 +403,7 @@ static String typeVarBounds(TypeVariable typeVar) { */ @ForName @CallerSensitive - public static Class forName(@ClassGetName String className) + public static Class forName(@ClassGetName String className) throws ClassNotFoundException { Class caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); @@ -479,7 +479,7 @@ public static Class forName(@ClassGetName String className) * @since 1.2 */ @CallerSensitive - public static Class forName(@ClassGetName String name, boolean initialize, + public static Class forName(@ClassGetName String name, boolean initialize, @Nullable ClassLoader loader) throws ClassNotFoundException { @@ -503,8 +503,8 @@ public static Class forName(@ClassGetName String name, boolean /** Called after security check for system loader access checks have been made. */ private static native Class forName0(String name, boolean initialize, - ClassLoader loader, - Class caller) + @Nullable ClassLoader loader, + @Nullable Class caller) throws ClassNotFoundException; @@ -556,7 +556,7 @@ private static native Class forName0(String name, boolean initialize, */ @SuppressWarnings("removal") @CallerSensitive - public static Class forName(Module module, String name) { + public static Class forName(Module module, String name) { Objects.requireNonNull(module); Objects.requireNonNull(name); @@ -635,7 +635,7 @@ public static Class forName(Module module, String name) { * s.checkPackageAccess()} denies access to the package * of this class. */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal","nullness:return.type.incompatible"}) @CallerSensitive @Deprecated(since="9") public @NonNull T newInstance() @@ -1272,7 +1272,7 @@ public Type[] getGenericInterfaces() { * @since 1.1 */ @Pure - public @Nullable Class getComponentType(@GuardSatisfied Class this) { + public @Nullable Class getComponentType(@GuardSatisfied Class this) { // Only return for array types. Storage may be reused for Class for instance types. if (isArray()) { return componentType; @@ -1288,7 +1288,7 @@ public Type[] getGenericInterfaces() { * If this class does not represent an array class, then this method returns * {@code null}. */ - private Class elementType() { + private @Nullable Class elementType() { if (!isArray()) return null; Class c = this; @@ -1444,7 +1444,7 @@ private Class elementType() { private native Object[] getEnclosingMethod0(); - private EnclosingMethodInfo getEnclosingMethodInfo() { + private @Nullable EnclosingMethodInfo getEnclosingMethodInfo() { Object[] enclosingInfo = getEnclosingMethod0(); if (enclosingInfo == null) return null; @@ -1547,7 +1547,7 @@ private static Class toClass(Type o) { * @since 1.5 */ @CallerSensitive - public @Nullable Constructor getEnclosingConstructor() throws SecurityException { + public @Nullable Constructor getEnclosingConstructor() throws SecurityException { EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); if (enclosingInfo == null) @@ -1645,7 +1645,7 @@ private static Class toClass(Type o) { */ @Pure @CallerSensitive - public @Nullable Class getEnclosingClass() throws SecurityException { + public @Nullable Class getEnclosingClass() throws SecurityException { // There are five kinds of classes (or interfaces): // a) Top level classes // b) Nested classes (static member classes) @@ -1842,7 +1842,7 @@ public boolean isMemberClass(@GuardSatisfied Class this) { * Returns {@code null} if the underlying class is a top level * class. */ - private String getSimpleBinaryName() { + private @Nullable String getSimpleBinaryName() { if (isTopLevelClass()) return null; String name = getSimpleBinaryName0(); @@ -2107,7 +2107,7 @@ public Method[] getMethods() throws SecurityException { * @since 1.1 */ @CallerSensitive - public Constructor[] getConstructors() throws SecurityException { + public Constructor[] getConstructors() throws SecurityException { @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2369,7 +2369,7 @@ public Constructor getConstructor(Class... parameterTypes) * @jls 8.5 Member Type Declarations */ @CallerSensitive - public Class[] getDeclaredClasses() throws SecurityException { + public Class[] getDeclaredClasses() throws SecurityException { @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2484,7 +2484,7 @@ public Field[] getDeclaredFields() throws SecurityException { * @since 16 */ @CallerSensitive - public RecordComponent[] getRecordComponents() { + public RecordComponent @Nullable [] getRecordComponents() { @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -3519,7 +3519,7 @@ private Method[] privateGetPublicMethods() { // // This method does not copy the returned Field object! - private static Field searchFields(Field[] fields, String name) { + private static @Nullable Field searchFields(Field[] fields, String name) { for (Field field : fields) { if (field.getName().equals(name)) { return field; @@ -3531,7 +3531,7 @@ private static Field searchFields(Field[] fields, String name) { // Returns a "root" Field object. This Field object must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyField. - private Field getField0(String name) { + private @Nullable Field getField0(String name) { // Note: the intent is that the search algorithm this routine // uses be equivalent to the ordering imposed by // privateGetPublicFields(). It fetches only the declared @@ -3564,7 +3564,7 @@ private Field getField0(String name) { } // This method does not copy the returned Method object! - private static Method searchMethods(Method[] methods, + private static @Nullable Method searchMethods(Method[] methods, String name, Class[] parameterTypes) { @@ -3587,7 +3587,7 @@ && arrayContentsEq(parameterTypes, // Returns a "root" Method object. This Method object must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyMethod. - private Method getMethod0(String name, Class[] parameterTypes) { + private @Nullable Method getMethod0(String name, Class @Nullable [] parameterTypes) { PublicMethods.MethodList res = getMethodsRecursive( name, parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes, @@ -3884,7 +3884,7 @@ private static ReflectionFactory getReflectionFactory() { * uncloned, cached, and shared by all callers. */ @SuppressWarnings("removal") - T[] getEnumConstantsShared() { + T @Nullable [] getEnumConstantsShared() { T[] constants = enumConstants; if (constants == null) { if (!isEnum()) return null; @@ -4201,7 +4201,7 @@ Map, Annotation> getDeclaredAnnotationMap() { * @return an object representing the superclass * @since 1.8 */ - public AnnotatedType getAnnotatedSuperclass() { + public @Nullable AnnotatedType getAnnotatedSuperclass() { if (this == Object.class || isInterface() || isArray() || @@ -4285,7 +4285,7 @@ public AnnotatedType[] getAnnotatedInterfaces() { * @jvms 5.4.4 Access Control */ @CallerSensitive - public Class getNestHost() { + public Class getNestHost() { if (isPrimitive() || isArray()) { return this; } @@ -4377,7 +4377,7 @@ public boolean isNestmateOf(Class c) { * @jvms 4.7.29 The {@code NestMembers} Attribute */ @CallerSensitive - public Class[] getNestMembers() { + public Class[] getNestMembers() { if (isPrimitive() || isArray()) { return new Class[] { this }; } @@ -4494,7 +4494,7 @@ public String descriptorString() { */ @Override @Pure - public @Nullable Class componentType() { + public @Nullable Class componentType() { return isArray() ? componentType : null; } @@ -4575,7 +4575,7 @@ public Optional describeConstable() { * @since 17 */ @CallerSensitive - public Class[] getPermittedSubclasses() { + public Class @Nullable [] getPermittedSubclasses() { Class[] subClasses; if (isArray() || isPrimitive() || (subClasses = getPermittedSubclasses0()) == null) { return null; diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 5e197dfa8e1..ae133aa0b0b 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -254,7 +254,7 @@ private final @Nullable ClassLoader parent; // class loader name - private final String name; + private final @Nullable String name; // the unnamed module for this ClassLoader private final Module unnamedModule; @@ -373,7 +373,7 @@ private NamedPackage getNamedPackage(String pn, Module m) { return checkCreateClassLoader(null); } - private static Void checkCreateClassLoader(String name) { + private static Void checkCreateClassLoader(@Nullable String name) { if (name != null && name.isEmpty()) { throw new IllegalArgumentException("name must be non-empty or null"); } @@ -386,7 +386,7 @@ private static Void checkCreateClassLoader(String name) { return null; } - private ClassLoader(Void unused, String name, ClassLoader parent) { + private ClassLoader(Void unused, @Nullable String name, @Nullable ClassLoader parent) { this.name = name; this.parent = parent; this.unnamedModule = new Module(this); @@ -640,7 +640,7 @@ protected Class loadClass(@BinaryName String name, boolean resolve) * this class loader, or {@code null} if the class could not be found. */ @ForName - final Class loadClass(Module module, @BinaryName String name) { + final @Nullable Class loadClass(Module module, @BinaryName String name) { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); @@ -759,7 +759,7 @@ protected Class findClass(@BinaryName String name) throws ClassNotFoundExcept * * @since 9 */ - protected Class findClass(String moduleName, String name) { + protected @Nullable Class findClass(String moduleName, String name) { if (moduleName == null) { try { return findClass(name); @@ -1122,11 +1122,11 @@ protected final Class defineClass(@Nullable @BinaryName String name, java.nio return c; } - static native Class defineClass1(ClassLoader loader, @BinaryName String name, byte[] b, int off, int len, - ProtectionDomain pd, String source); + static native Class defineClass1(ClassLoader loader, @BinaryName @Nullable String name, byte[] b, int off, int len, + @Nullable ProtectionDomain pd, String source); - static native Class defineClass2(ClassLoader loader, @BinaryName String name, java.nio.ByteBuffer b, - int off, int len, ProtectionDomain pd, + static native Class defineClass2(ClassLoader loader, @BinaryName @Nullable String name, java.nio.ByteBuffer b, + int off, int len, @Nullable ProtectionDomain pd, String source); /** @@ -1357,7 +1357,7 @@ protected final void setSigners(Class c, Object[] signers) { * @see java.lang.module.ModuleReader#find(String) * @since 9 */ - protected URL findResource(String moduleName, String name) throws IOException { + protected @Nullable URL findResource(String moduleName, String name) throws IOException { if (moduleName == null) { return findResource(name); } else { @@ -2088,7 +2088,7 @@ static void checkClassLoaderPermission(ClassLoader cl, Class caller) { * * This method does not throw IllegalArgumentException. */ - Package definePackage(Class c) { + @Nullable Package definePackage(Class c) { if (c.isPrimitive() || c.isArray()) { return null; } @@ -2245,7 +2245,7 @@ protected Package definePackage(@FullyQualifiedName String name, @Nullable Strin * * @since 9 */ - public final Package getDefinedPackage(String name) { + public final @Nullable Package getDefinedPackage(String name) { Objects.requireNonNull(name, "name cannot be null"); NamedPackage p = packages.get(name); @@ -2708,7 +2708,7 @@ private void initializeJavaAssertionMaps() { } // the storage for ClassLoaderValue(s) associated with this ClassLoader - private volatile ConcurrentHashMap classLoaderValueMap; + private volatile @Nullable ConcurrentHashMap classLoaderValueMap; /** * Attempts to atomically set a volatile field in this object. Returns diff --git a/src/java.base/share/classes/java/lang/ClassValue.java b/src/java.base/share/classes/java/lang/ClassValue.java index c92e4f4749f..c56a933ccad 100644 --- a/src/java.base/share/classes/java/lang/ClassValue.java +++ b/src/java.base/share/classes/java/lang/ClassValue.java @@ -26,6 +26,7 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.WeakHashMap; @@ -199,7 +200,7 @@ private static Entry[] getCacheCarefully(Class type) { } /** Initial, one-element, empty cache used by all Class instances. Must never be filled. */ - private static final Entry[] EMPTY_CACHE = { null }; + private static final @Nullable Entry[] EMPTY_CACHE = { null }; /** * Slow tail of ClassValue.get to retry at nearby locations in the cache, @@ -327,7 +328,7 @@ static class Version { */ static class Entry extends WeakReference> { final Object value; // usually of type T, but sometimes (Entry)this - Entry(Version version, T value) { + Entry(@Nullable Version version, T value) { super(version); this.value = value; // for a regular entry, value is of type T } @@ -474,7 +475,7 @@ Entry startEntry(ClassValue classValue) { /** Finish a query. Overwrite a matching placeholder. Drop stale incoming values. */ synchronized - Entry finishEntry(ClassValue classValue, Entry e) { + @Nullable Entry finishEntry(ClassValue classValue, Entry e) { @SuppressWarnings("unchecked") // one map has entries for all value types Entry e0 = (Entry) get(classValue.identity); if (e == e0) { @@ -558,7 +559,7 @@ static Entry probeHomeLocation(Entry[] cache, ClassValue classValue } /** Given that first probe was a collision, retry at nearby locations. */ - static Entry probeBackupLocations(Entry[] cache, ClassValue classValue) { + static @Nullable Entry probeBackupLocations(Entry[] cache, ClassValue classValue) { if (PROBE_LIMIT <= 0) return null; // Probe the cache carefully, in a range of slots. int mask = (cache.length-1); @@ -660,7 +661,7 @@ private void removeStaleEntries(Entry[] cache, int begin, int count) { * to be found via reprobes. Find an entry after cache[begin] * to plug into the hole, or return null if none is needed. */ - private Entry findReplacement(Entry[] cache, int home1) { + private @Nullable Entry findReplacement(Entry[] cache, int home1) { Entry replacement = null; int haveReplacement = -1, replacementPos = 0; int mask = (cache.length-1); @@ -741,7 +742,7 @@ private void addToCache(ClassValue classValue, Entry e) { /** Store the given entry. Update cacheLoad, and return any live victim. * 'Gently' means return self rather than dislocating a live victim. */ - private Entry placeInCache(Entry[] cache, int pos, Entry e, boolean gently) { + private @Nullable Entry placeInCache(Entry[] cache, int pos, Entry e, boolean gently) { Entry e2 = overwrittenEntry(cache[pos]); if (gently && e2 != null) { // do not overwrite a live entry @@ -758,7 +759,7 @@ private Entry placeInCache(Entry[] cache, int pos, Entry e, boolean gen * because the caller is going to store something * in its place. */ - private Entry overwrittenEntry(Entry e2) { + private @Nullable Entry overwrittenEntry(Entry e2) { if (e2 == null) cacheLoad += 1; else if (e2.isLive()) return e2; return null; diff --git a/src/java.base/share/classes/java/lang/ConditionalSpecialCasing.java b/src/java.base/share/classes/java/lang/ConditionalSpecialCasing.java index 386cbe416cc..41f74600a91 100644 --- a/src/java.base/share/classes/java/lang/ConditionalSpecialCasing.java +++ b/src/java.base/share/classes/java/lang/ConditionalSpecialCasing.java @@ -26,6 +26,7 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.text.BreakIterator; @@ -150,7 +151,7 @@ static char[] toUpperCaseCharArray(String src, int index, Locale locale) { } } - private static char[] lookUpTable(String src, int index, Locale locale, boolean bLowerCasing) { + private static char @Nullable [] lookUpTable(String src, int index, Locale locale, boolean bLowerCasing) { HashSet set = entryTable.get(src.codePointAt(index)); char[] ret = null; @@ -430,10 +431,10 @@ static class Entry { int ch; char [] lower; char [] upper; - String lang; + @Nullable String lang; int condition; - Entry(int ch, char[] lower, char[] upper, String lang, int condition) { + Entry(int ch, char[] lower, char[] upper, @Nullable String lang, int condition) { this.ch = ch; this.lower = lower; this.upper = upper; diff --git a/src/java.base/share/classes/java/lang/LayerInstantiationException.java b/src/java.base/share/classes/java/lang/LayerInstantiationException.java index 6c1469df79b..5bdafbc1241 100644 --- a/src/java.base/share/classes/java/lang/LayerInstantiationException.java +++ b/src/java.base/share/classes/java/lang/LayerInstantiationException.java @@ -25,6 +25,8 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Thrown when creating a {@linkplain ModuleLayer module layer} fails. * @@ -48,7 +50,7 @@ public LayerInstantiationException() { * @param msg * The detail message; can be {@code null} */ - public LayerInstantiationException(String msg) { + public LayerInstantiationException(@Nullable String msg) { super(msg); } diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index ab7d2103850..c754a474e02 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -25,6 +25,8 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; @@ -100,14 +102,14 @@ public final class Module implements AnnotatedElement { // the layer that contains this module, can be null - private final ModuleLayer layer; + private final @Nullable ModuleLayer layer; // module name and loader, these fields are read by VM - private final String name; - private final ClassLoader loader; + private final @Nullable String name; + private final @Nullable ClassLoader loader; // the module descriptor - private final ModuleDescriptor descriptor; + private final @Nullable ModuleDescriptor descriptor; // true, if this module allows restricted native access private volatile boolean enableNativeAccess; @@ -147,7 +149,7 @@ public final class Module implements AnnotatedElement { * * @see ClassLoader#getUnnamedModule */ - Module(ClassLoader loader) { + Module(@Nullable ClassLoader loader) { this.layer = null; this.name = null; this.loader = loader; @@ -1541,7 +1543,7 @@ public void visitAttribute(Attribute attr) { // drop non-annotation attributes } @Override - public ModuleVisitor visitModule(String name, int flags, String version) { + public @Nullable ModuleVisitor visitModule(String name, int flags, String version) { // drop Module attribute return null; } @@ -1642,7 +1644,7 @@ protected Class loadClass(String cn, boolean resolve) * @see Class#getResourceAsStream(String) */ @CallerSensitive - public InputStream getResourceAsStream(String name) throws IOException { + public @Nullable InputStream getResourceAsStream(String name) throws IOException { if (name.startsWith("/")) { name = name.substring(1); } @@ -1707,7 +1709,7 @@ public String toString() { * Returns the module that a given caller class is a member of. Returns * {@code null} if the caller is {@code null}. */ - private Module getCallerModule(Class caller) { + private @Nullable Module getCallerModule(Class caller) { return (caller != null) ? caller.getModule() : null; } @@ -1722,7 +1724,7 @@ private static native void defineModule0(Module module, Object[] pns); // JVM_AddReadsModule - private static native void addReads0(Module from, Module to); + private static native void addReads0(Module from, @Nullable Module to); // JVM_AddModuleExports private static native void addExports0(Module from, String pn, Module to); diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java index 6cecfe6d388..5a8daaca3ef 100644 --- a/src/java.base/share/classes/java/lang/ModuleLayer.java +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java @@ -25,6 +25,8 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ResolvedModule; @@ -173,7 +175,7 @@ public final class ModuleLayer { */ private ModuleLayer(Configuration cf, List parents, - Function clf) + @Nullable Function clf) { this.cf = cf; this.parents = parents; // no need to do defensive copy diff --git a/src/java.base/share/classes/java/lang/NamedPackage.java b/src/java.base/share/classes/java/lang/NamedPackage.java index 6234b949e65..f5be603a50a 100644 --- a/src/java.base/share/classes/java/lang/NamedPackage.java +++ b/src/java.base/share/classes/java/lang/NamedPackage.java @@ -24,6 +24,8 @@ */ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.module.Configuration; import java.lang.module.ModuleReference; import java.net.URI; @@ -70,7 +72,7 @@ Module module() { * Returns the location of the module if this named package is in * a named module; otherwise, returns null. */ - URI location() { + @Nullable URI location() { if (module.isNamed() && module.getLayer() != null) { Configuration cf = module.getLayer().configuration(); ModuleReference mref diff --git a/src/java.base/share/classes/java/lang/Package.java b/src/java.base/share/classes/java/lang/Package.java index 5682bb8be75..33162305856 100644 --- a/src/java.base/share/classes/java/lang/Package.java +++ b/src/java.base/share/classes/java/lang/Package.java @@ -560,9 +560,9 @@ public Annotation[] getDeclaredAnnotations() { * @param loader defining class loader */ Package(@DotSeparatedIdentifiers String name, - String spectitle, String specversion, String specvendor, - String impltitle, String implversion, String implvendor, - URL sealbase, ClassLoader loader) + @Nullable String spectitle, @Nullable String specversion, @Nullable String specvendor, + @Nullable String impltitle, @Nullable String implversion, @Nullable String implvendor, + @Nullable URL sealbase, ClassLoader loader) { super(Objects.requireNonNull(name), loader != null ? loader.getUnnamedModule() @@ -586,18 +586,18 @@ static class VersionInfo { static final VersionInfo NULL_VERSION_INFO = new VersionInfo(null, null, null, null, null, null, null); - private final String specTitle; - private final String specVersion; - private final String specVendor; - private final String implTitle; - private final String implVersion; - private final String implVendor; - private final URL sealBase; - - static VersionInfo getInstance(String spectitle, String specversion, - String specvendor, String impltitle, - String implversion, String implvendor, - URL sealbase) { + private final @Nullable String specTitle; + private final @Nullable String specVersion; + private final @Nullable String specVendor; + private final @Nullable String implTitle; + private final @Nullable String implVersion; + private final @Nullable String implVendor; + private final @Nullable URL sealBase; + + static VersionInfo getInstance(@Nullable String spectitle, @Nullable String specversion, + @Nullable String specvendor, @Nullable String impltitle, + @Nullable String implversion, @Nullable String implvendor, + @Nullable URL sealbase) { if (spectitle == null && specversion == null && specvendor == null && impltitle == null && implversion == null && implvendor == null && @@ -609,9 +609,9 @@ static VersionInfo getInstance(String spectitle, String specversion, sealbase); } - private VersionInfo(String spectitle, String specversion, - String specvendor, String impltitle, - String implversion, String implvendor, + private VersionInfo(@Nullable String spectitle, @Nullable String specversion, + @Nullable String specvendor, @Nullable String impltitle, + @Nullable String implversion, @Nullable String implvendor, URL sealbase) { this.implTitle = impltitle; diff --git a/src/java.base/share/classes/java/lang/ProcessBuilder.java b/src/java.base/share/classes/java/lang/ProcessBuilder.java index 85a2fe3b703..81b040362d6 100644 --- a/src/java.base/share/classes/java/lang/ProcessBuilder.java +++ b/src/java.base/share/classes/java/lang/ProcessBuilder.java @@ -581,7 +581,7 @@ public enum Type { * @return the file associated with this redirect, * or {@code null} if there is no such file */ - public File file() { return null; } + public @Nullable File file() { return null; } /** * When redirected to a destination file, indicates if the output @@ -679,7 +679,7 @@ public String toString() { * instances of the same type associated with non-null equal * {@code File} instances. */ - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj == this) return true; if (! (obj instanceof Redirect r)) diff --git a/src/java.base/share/classes/java/lang/ProcessHandle.java b/src/java.base/share/classes/java/lang/ProcessHandle.java index 229f98d0b6f..aff82c93b9f 100644 --- a/src/java.base/share/classes/java/lang/ProcessHandle.java +++ b/src/java.base/share/classes/java/lang/ProcessHandle.java @@ -24,6 +24,8 @@ */ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.time.Duration; import java.time.Instant; import java.util.Optional; @@ -415,7 +417,7 @@ public interface Info { * the same system process; otherwise returns {@code false} */ @Override - boolean equals(Object other); + boolean equals(@Nullable Object other); /** * Compares this ProcessHandle with the specified ProcessHandle for order. diff --git a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java index 593ee48f27d..2a4ddd8f541 100644 --- a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java +++ b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java @@ -341,7 +341,7 @@ public Optional parent() { * if greater than the length of the arrays, the arrays are too small */ private static native int getProcessPids0(long pid, long[] pids, - long[] ppids, long[] starttimes); + long @Nullable [] ppids, long[] starttimes); /** * Destroy the process for this ProcessHandle. @@ -563,12 +563,12 @@ static class Info implements ProcessHandle.Info { */ private native void info0(long pid); - String command; - String commandLine; - String[] arguments; + @Nullable String command; + @Nullable String commandLine; + String @Nullable [] arguments; long startTime; long totalTime; - String user; + @Nullable String user; Info() { command = null; diff --git a/src/java.base/share/classes/java/lang/PublicMethods.java b/src/java.base/share/classes/java/lang/PublicMethods.java index b9851e2f049..4cdcb8f4b15 100644 --- a/src/java.base/share/classes/java/lang/PublicMethods.java +++ b/src/java.base/share/classes/java/lang/PublicMethods.java @@ -24,6 +24,8 @@ */ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import jdk.internal.reflect.ReflectionFactory; import java.lang.reflect.Method; @@ -112,7 +114,7 @@ static boolean matches(Method method, } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (this == o) return true; //noinspection StringEquality (guaranteed interned String(s)) return (o instanceof Key that) diff --git a/src/java.base/share/classes/java/lang/ReflectiveOperationException.java b/src/java.base/share/classes/java/lang/ReflectiveOperationException.java index 0c79de008be..2296582813c 100644 --- a/src/java.base/share/classes/java/lang/ReflectiveOperationException.java +++ b/src/java.base/share/classes/java/lang/ReflectiveOperationException.java @@ -25,6 +25,8 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Common superclass of exceptions thrown by reflective operations in * core reflection. @@ -53,7 +55,7 @@ public ReflectiveOperationException() { * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ - public ReflectiveOperationException(String message) { + public ReflectiveOperationException(@Nullable String message) { super(message); } @@ -72,7 +74,7 @@ public ReflectiveOperationException(String message) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public ReflectiveOperationException(String message, Throwable cause) { + public ReflectiveOperationException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -86,7 +88,7 @@ public ReflectiveOperationException(String message, Throwable cause) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public ReflectiveOperationException(Throwable cause) { + public ReflectiveOperationException(@Nullable Throwable cause) { super(cause); } } diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java index 9e20a7e0a31..157c198a36b 100644 --- a/src/java.base/share/classes/java/lang/Runtime.java +++ b/src/java.base/share/classes/java/lang/Runtime.java @@ -1418,7 +1418,7 @@ public String toString() { * */ @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { boolean ret = equalsIgnoreOptional(obj); if (!ret) return false; diff --git a/src/java.base/share/classes/java/lang/RuntimePermission.java b/src/java.base/share/classes/java/lang/RuntimePermission.java index d19b1125fa3..19f0d85f804 100644 --- a/src/java.base/share/classes/java/lang/RuntimePermission.java +++ b/src/java.base/share/classes/java/lang/RuntimePermission.java @@ -419,7 +419,7 @@ public final class RuntimePermission extends BasicPermission { * @throws IllegalArgumentException if {@code name} is empty. */ - public RuntimePermission(String name) + public RuntimePermission(@Nullable String name) { super(name); } @@ -436,7 +436,7 @@ public RuntimePermission(String name) * @throws IllegalArgumentException if {@code name} is empty. */ - public RuntimePermission(String name, @Nullable String actions) + public RuntimePermission(@Nullable String name, @Nullable String actions) { super(name, actions); } diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index 55b276e393f..144c904ae5d 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -24,8 +24,10 @@ */ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.dataflow.qual.Pure; + import jdk.internal.reflect.MethodAccessor; import jdk.internal.reflect.ConstructorAccessor; import java.lang.StackWalker.Option; @@ -334,7 +336,7 @@ private int getNextBatch() { * * @see #tryNextFrame */ - final Class nextFrame() { + final @Nullable Class nextFrame() { if (!hasNext()) { return null; } @@ -519,7 +521,7 @@ final Class at(int index) { * Returns next StackFrame object in the current batch of stack frames; * or null if no more stack frame. */ - StackFrame nextStackFrame() { + @Nullable StackFrame nextStackFrame() { if (!hasNext()) { return null; } @@ -563,7 +565,7 @@ protected int batchSize(int lastBatchFrameCount) { // ------- Implementation of Spliterator @Override - public Spliterator trySplit() { + public @Nullable Spliterator trySplit() { return null; // ordered stream and do not allow to split } diff --git a/src/java.base/share/classes/java/lang/StackTraceElement.java b/src/java.base/share/classes/java/lang/StackTraceElement.java index 27b5bd237a2..c49c0807beb 100644 --- a/src/java.base/share/classes/java/lang/StackTraceElement.java +++ b/src/java.base/share/classes/java/lang/StackTraceElement.java @@ -65,21 +65,21 @@ public final class StackTraceElement implements java.io.Serializable { // construct the 'format' bitmap, and then is cleared. // // For STEs constructed using the public constructors, this field is not used. - private transient Class declaringClassObject; + private transient @Nullable Class declaringClassObject; // Normally initialized by VM /** * The name of the class loader. */ - private String classLoaderName; + private @Nullable String classLoaderName; /** * The module name. */ - private String moduleName; + private @Nullable String moduleName; /** * The module version. */ - private String moduleVersion; + private @Nullable String moduleVersion; /** * The declaring class. */ @@ -91,7 +91,7 @@ public final class StackTraceElement implements java.io.Serializable { /** * The source file name. */ - private String fileName; + private @Nullable String fileName; /** * The source line number. */ @@ -160,10 +160,10 @@ public StackTraceElement(@FullyQualifiedName String declaringClass, String metho * * @since 9 */ - public StackTraceElement(String classLoaderName, - String moduleName, String moduleVersion, + public StackTraceElement(@Nullable String classLoaderName, + @Nullable String moduleName, @Nullable String moduleVersion, String declaringClass, String methodName, - String fileName, int lineNumber) { + @Nullable String fileName, int lineNumber) { this.classLoaderName = classLoaderName; this.moduleName = moduleName; this.moduleVersion = moduleVersion; diff --git a/src/java.base/share/classes/java/lang/StackWalker.java b/src/java.base/share/classes/java/lang/StackWalker.java index c703e4caf6f..7838eaad08a 100644 --- a/src/java.base/share/classes/java/lang/StackWalker.java +++ b/src/java.base/share/classes/java/lang/StackWalker.java @@ -411,7 +411,7 @@ private StackWalker(EnumSet