diff --git a/README-rewritten-jdk-history b/README-rewritten-jdk-history index 42f5c77655e..5760120dc50 100644 --- a/README-rewritten-jdk-history +++ b/README-rewritten-jdk-history @@ -62,4 +62,3 @@ At each URL: * Queue the project in hopes that will start automatic building for each commit. * If the above doesn't work, change the instructions to the below: * Delete and re-create the pipeline, because of apparent caching problems when checking out the projects. - diff --git a/README.md b/README.md index 7bc7d58f3b1..cad0c850e53 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,8 @@ Replace the existing export lines present in exports. If no new packages were added, then there are likely going to be no changes to the `module-info.java` file. -Commit the changes. Do not include the top-level `checker-qual-source.jar` file. +Commit the changes. Do not include the top-level `checker-qual-source.jar` file, +but include any new `.java` files in a `qual/` directory. ## The typetools/jdk17u repository diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2fc9b8bd4b6..9784c3888e0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,3 +1,6 @@ +# variables: +# system.debug: true + jobs: - job: build_jdk @@ -12,12 +15,7 @@ jobs: ls -al env | sort displayName: show environment - - bash: | - wget https://builds.shipilev.net/jtreg/jtreg-6.2%2B1.zip -O /tmp/$USER/jtreg.zip - unzip /tmp/$USER/jtreg.zip -d /tmp/$USER/ - chmod +x /tmp/$USER/jtreg/bin/jtdiff /tmp/$USER/jtreg/bin/jtreg - displayName: download jtreg - - bash: pwd && ls && bash ./configure --with-jtreg=/tmp/$USER/jtreg --disable-warnings-as-errors + - bash: pwd && ls && bash ./configure --with-jtreg=/usr/share/jtreg --disable-warnings-as-errors displayName: configure - bash: make jdk timeoutInMinutes: 90 @@ -43,29 +41,36 @@ jobs: env | sort displayName: show environment - bash: | - wget https://builds.shipilev.net/jtreg/jtreg-6.2%2B1.zip -O /tmp/$USER/jtreg.zip - unzip /tmp/$USER/jtreg.zip -d /tmp/$USER/ - chmod +x /tmp/$USER/jtreg/bin/jtdiff /tmp/$USER/jtreg/bin/jtreg - displayName: download jtreg + set -ex + if [ -d /tmp/$USER/git-scripts ]; \ + then git -C /tmp/$USER/git-scripts pull -q > /dev/null 2>&1 ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git ; \ + fi + displayName: git-scripts - bash: | set -ex if [ -d /tmp/$USER/plume-scripts ]; \ then git -C /tmp/$USER/plume-scripts pull -q > /dev/null 2>&1 ; \ - else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/plume-scripts.git ; \ fi displayName: plume-scripts - - bash: | - set -ex - if [ -d /tmp/$USER/git-scripts ]; \ - then git -C /tmp/$USER/git-scripts pull -q > /dev/null 2>&1 ; \ - else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git ; \ - fi - displayName: git-scripts # This creates ../jdk17u . - # If the depth is too small, the merge will fail. + # If the depth is too small, the merge will fail. However, we cannot use "--filter=blob:none" + # because that leads to "fatal: remote error: filter 'combine' not supported". - bash: | set -ex - /tmp/$USER/git-scripts/git-clone-related typetools jdk17u ../jdk17u -q --depth 1 + pwd + ls -al .. || true + ls -al ../jdk17u || true + df . + /tmp/$USER/git-scripts/git-clone-related typetools jdk17u ../jdk17u --depth 999 + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global core.longpaths true + git config --global core.protectNTFS false + cd ../jdk17u && git status + git diff --exit-code + echo $? displayName: clone-related-jdk17u - bash: | set -ex @@ -73,10 +78,14 @@ jobs: git config --global user.name "Your Name" git config --global pull.ff true git config --global pull.rebase false + git config --global core.longpaths true + git config --global core.protectNTFS false eval `/tmp/$USER/plume-scripts/ci-info eisop` - cd ../jdk17u && git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH} || (git --version && git show && echo "Merge failed; see 'Pull request merge conflicts' at https://github.com/eisop/jdk/blob/master/README" && false) + cd ../jdk17u && git status + echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH}" + cd ../jdk17u && git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH} || (git --version && git show && git status && echo "Merge failed; see 'Pull request merge conflicts' at https://github.com/eisop/jdk/blob/master/README.md" && false) displayName: git merge - - bash: cd ../jdk17u && export JT_HOME=/tmp/$USER/jtreg && bash ./configure --with-jtreg=/tmp/$USER/jtreg --disable-warnings-as-errors + - bash: cd ../jdk17u && export JT_HOME=/usr/share/jtreg && bash ./configure --with-jtreg=/usr/share/jtreg --disable-warnings-as-errors displayName: configure - bash: cd ../jdk17u && make jdk displayName: make jdk @@ -110,30 +119,19 @@ jobs: displayName: test-cftests-all.sh - job: test_cftests_all_jdk11 - timeoutInMinutes: 105 + timeoutInMinutes: 120 pool: vmImage: 'ubuntu-latest' container: wmdietl/cf-ubuntu-jdk11:latest steps: - checkout: self fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git displayName: clone git-scripts - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework displayName: clone checker-framework -# test-cftests-all.sh sometimes runs out of memory, but running its component parts in sequence does not. -# - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) -# displayName: test-cftests-all.sh - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-junit.sh) - displayName: test-cftests-junit.sh - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-nonjunit.sh) - displayName: test-cftests-nonjunit.sh - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-inference.sh) - displayName: test-cftests-inference.sh - - bash: (cd ../checker-framework && checker/bin-devel/test-typecheck.sh) - displayName: test-typecheck.sh + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) + displayName: test-cftests-all.sh ## Here is how to create artifacts that can be downloaded. # - bash: (cd ../checker-framework/checker/build/jtregJdk11/ && tar -czvf all.tgz all) # condition: succeededOrFailed() @@ -144,16 +142,14 @@ jobs: # displayName: publish all.tgz - job: test_cftests_all_jdk17 - timeoutInMinutes: 105 + timeoutInMinutes: 120 pool: vmImage: 'ubuntu-latest' container: wmdietl/cf-ubuntu-jdk17:latest steps: - checkout: self fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git displayName: clone git-scripts - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework displayName: clone checker-framework @@ -161,16 +157,14 @@ jobs: displayName: test-cftests-all.sh - job: test_cftests_all_jdk_latest - timeoutInMinutes: 105 + timeoutInMinutes: 120 pool: vmImage: 'ubuntu-latest' container: wmdietl/cf-ubuntu-jdk-latest:latest steps: - checkout: self fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git displayName: clone git-scripts - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework displayName: clone checker-framework @@ -185,9 +179,7 @@ jobs: steps: - checkout: self fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git displayName: clone git-scripts - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework displayName: clone checker-framework @@ -201,9 +193,7 @@ jobs: steps: - checkout: self fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git displayName: clone git-scripts - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework displayName: clone checker-framework diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java index bc66c9c86e1..e441312156a 100644 --- a/src/java.base/share/classes/java/io/BufferedReader.java +++ b/src/java.base/share/classes/java/io/BufferedReader.java @@ -33,9 +33,12 @@ import org.checkerframework.checker.index.qual.Positive; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.mustcall.qual.MustCallAlias; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.Iterator; @@ -578,6 +581,8 @@ public Stream lines(@GuardSatisfied BufferedReader this) { String nextLine = null; @Override + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { if (nextLine != null) { return true; @@ -592,7 +597,8 @@ public boolean hasNext() { } @Override - public String next() { + @SideEffectsOnly("this") + public String next(/*@NonEmpty Iterator this*/) { if (nextLine != null || hasNext()) { String line = nextLine; nextLine = null; diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 4736017b525..ea9f7ccfbc4 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -30,6 +30,7 @@ import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.lock.qual.ReleasesNoLocks; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.regex.qual.Regex; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; @@ -257,7 +258,7 @@ int getPrefixLength() { * for convenience. This string contains a single character, namely * {@link #pathSeparatorChar}. */ - public static final @Interned String pathSeparator = "" + pathSeparatorChar; + public static final @Interned @Regex String pathSeparator = "" + pathSeparatorChar; /* -- Constructors -- */ diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java index bc4a7ae3daf..520eb3f9e89 100644 --- a/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -33,6 +33,7 @@ import org.checkerframework.checker.mustcall.qual.MustCallAlias; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.SignedPositive; +import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.ObjectInputFilter.Config; @@ -2857,6 +2858,7 @@ private static class PeekInputStream extends InputStream { * Peeks at next byte value in stream. Similar to read(), except * that it does not consume the read value. */ + @Pure int peek() throws IOException { if (peekb >= 0) { return peekb; @@ -3181,6 +3183,7 @@ int currentBlockRemaining() { * the stream, or -1 if the end of the stream/block data (if in block * data mode) has been reached. */ + @Pure int peek() throws IOException { if (blkmode) { if (pos == end) { @@ -3197,6 +3200,7 @@ int peek() throws IOException { * the stream, or throws EOFException if end of stream/block data has * been reached. */ + @Pure byte peekByte() throws IOException { int val = peek(); if (val < 0) { diff --git a/src/java.base/share/classes/java/lang/CharSequence.java b/src/java.base/share/classes/java/lang/CharSequence.java index 48c24668d25..6f668ed42d5 100644 --- a/src/java.base/share/classes/java/lang/CharSequence.java +++ b/src/java.base/share/classes/java/lang/CharSequence.java @@ -30,8 +30,11 @@ import org.checkerframework.checker.index.qual.LengthOf; import org.checkerframework.checker.index.qual.SameLen; import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; 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 java.util.NoSuchElementException; @@ -110,6 +113,7 @@ public interface CharSequence { * @since 15 */ @Pure + @EnsuresNonEmptyIf(result = false, expression = "this") default boolean isEmpty() { return this.length() == 0; } @@ -164,11 +168,14 @@ public default IntStream chars() { class CharIterator implements PrimitiveIterator.OfInt { int cur = 0; + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return cur < length(); } - public int nextInt() { + @SideEffectsOnly("this") + public int nextInt(@NonEmpty CharIterator this) { if (hasNext()) { return charAt(cur++); } else { @@ -238,11 +245,14 @@ public void forEachRemaining(IntConsumer block) { } } + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return cur < length(); } - public int nextInt() { + @SideEffectsOnly("this") + public int nextInt(@NonEmpty CodePointIterator this) { final int length = length(); if (cur >= length) { diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 044271b4a90..5e197dfa8e1 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -27,6 +27,8 @@ package java.lang; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.RequiresNonNull; @@ -2754,11 +2756,12 @@ private boolean next() { return false; } + @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasMoreElements() { return next(); } - public E nextElement() { + public E nextElement(@NonEmpty CompoundEnumeration this) { if (!next()) { throw new NoSuchElementException(); } diff --git a/src/java.base/share/classes/java/lang/Enum.java b/src/java.base/share/classes/java/lang/Enum.java index 3814d663147..3628f0f3bf3 100644 --- a/src/java.base/share/classes/java/lang/Enum.java +++ b/src/java.base/share/classes/java/lang/Enum.java @@ -108,6 +108,7 @@ public abstract class Enum> * * @return the name of this enum constant */ + @Pure public final @PolyValue String name(@GuardedByUnknown @UnknownInitialization(java.lang.Enum.class) @PolyValue Enum this) { return name; } diff --git a/src/java.base/share/classes/java/lang/Iterable.java b/src/java.base/share/classes/java/lang/Iterable.java index 9e897add2fb..89990f6f8f7 100644 --- a/src/java.base/share/classes/java/lang/Iterable.java +++ b/src/java.base/share/classes/java/lang/Iterable.java @@ -24,6 +24,8 @@ */ package java.lang; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; +import org.checkerframework.common.aliasing.qual.NonLeaked; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.Iterator; @@ -41,14 +43,14 @@ * @since 1.5 * @jls 14.14.2 The enhanced {@code for} statement */ -@AnnotatedFor({"lock", "nullness"}) +@AnnotatedFor({"aliasing", "lock", "nullness"}) public interface Iterable { /** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */ - Iterator iterator(); + @PolyNonEmpty Iterator iterator(@PolyNonEmpty Iterable this); /** * Performs the given action for each element of the {@code Iterable} @@ -72,7 +74,7 @@ public interface Iterable { * @throws NullPointerException if the specified action is null * @since 1.8 */ - default void forEach(Consumer action) { + default void forEach(@NonLeaked Consumer action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 3e77e78169e..2dda336c3ca 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.index.qual.PolyLowerBound; import org.checkerframework.checker.index.qual.PolyUpperBound; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.common.value.qual.StaticallyExecutable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.framework.qual.AnnotatedFor; @@ -1594,6 +1595,7 @@ public static double abs(double a) { * @return the larger of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable @IntrinsicCandidate public static @PolyUpperBound int max(@PolyUpperBound int a, @PolyUpperBound int b) { return (a >= b) ? a : b; @@ -1610,6 +1612,7 @@ public static double abs(double a) { * @return the larger of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable public static @PolyUpperBound long max(@PolyUpperBound long a, @PolyUpperBound long b) { return (a >= b) ? a : b; } @@ -1633,6 +1636,7 @@ public static double abs(double a) { * @return the larger of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable @IntrinsicCandidate public static float max(float a, float b) { if (a != a) @@ -1661,6 +1665,7 @@ public static float max(float a, float b) { * @return the larger of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable @IntrinsicCandidate public static double max(double a, double b) { if (a != a) @@ -1701,6 +1706,7 @@ public static double max(double a, double b) { * @return the smaller of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable public static @PolyLowerBound long min(@PolyLowerBound long a, @PolyLowerBound long b) { return (a <= b) ? a : b; } @@ -1720,6 +1726,7 @@ public static double max(double a, double b) { * @return the smaller of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable @IntrinsicCandidate public static float min(float a, float b) { if (a != a) @@ -1748,6 +1755,7 @@ public static float min(float a, float b) { * @return the smaller of {@code a} and {@code b}. */ @Pure + @StaticallyExecutable @IntrinsicCandidate public static double min(double a, double b) { if (a != a) diff --git a/src/java.base/share/classes/java/lang/Record.java b/src/java.base/share/classes/java/lang/Record.java index 2f8bd60ac5b..b81674db188 100644 --- a/src/java.base/share/classes/java/lang/Record.java +++ b/src/java.base/share/classes/java/lang/Record.java @@ -24,6 +24,9 @@ */ package java.lang; +import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.signedness.qual.UnknownSignedness; + /** * This is the common base class of all Java language record classes. * @@ -139,7 +142,7 @@ protected Record() {} * argument; {@code false} otherwise. */ @Override - public abstract boolean equals(Object obj); + public abstract boolean equals(@GuardSatisfied Record this, @GuardSatisfied Object obj); /** * Returns a hash code value for the record. @@ -165,7 +168,7 @@ protected Record() {} * @return a hash code value for this record. */ @Override - public abstract int hashCode(); + public abstract int hashCode(@GuardSatisfied @UnknownSignedness Record this); /** * Returns a string representation of the record. @@ -196,5 +199,5 @@ protected Record() {} * @return a string representation of the object. */ @Override - public abstract String toString(); + public abstract String toString(@GuardSatisfied Record this); } diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index 328154dc04e..3e4518da8e5 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -24,6 +24,9 @@ */ package java.lang; +import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectsOnly; import jdk.internal.reflect.MethodAccessor; import jdk.internal.reflect.ConstructorAccessor; import java.lang.StackWalker.Option; @@ -332,6 +335,7 @@ private int getNextBatch() { * * @see #tryNextFrame */ + @SideEffectsOnly("this") final Class nextFrame() { if (!hasNext()) { return null; @@ -347,6 +351,7 @@ final Class nextFrame() { * This skips hidden frames unless this StackWalker has * {@link Option#SHOW_REFLECT_FRAMES} */ + @Pure final boolean hasNext() { return peekFrame() != null; } @@ -377,7 +382,7 @@ private R beginStackWalk() { * Fetches stack frames. * * @params batchSize number of elements of the frame buffers for this batch - * @returns number of frames fetched in this batch + * @return number of frames fetched in this batch */ private int fetchStackFrames(int batchSize) { int startIndex = frameBuffer.startIndex(); @@ -864,6 +869,7 @@ final int curBatchFrameCount() { /* * Tests if this frame buffer is empty. All frames are fetched. */ + @EnsuresNonEmptyIf(result = false, expression = "this") final boolean isEmpty() { return origin >= fence || (origin == START_POS && fence == 0); } diff --git a/src/java.base/share/classes/java/lang/StackWalker.java b/src/java.base/share/classes/java/lang/StackWalker.java index 9f8a24f1e9e..c703e4caf6f 100644 --- a/src/java.base/share/classes/java/lang/StackWalker.java +++ b/src/java.base/share/classes/java/lang/StackWalker.java @@ -24,6 +24,8 @@ */ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; + import jdk.internal.reflect.CallerSensitive; import java.lang.invoke.MethodType; @@ -484,7 +486,7 @@ private static EnumSet