From 4ab17621feda473cddc027b080183f65a808e5be Mon Sep 17 00:00:00 2001 From: Chris Povirk Date: Fri, 31 Jul 2020 19:25:18 -0400 Subject: [PATCH 1/4] Annotate much of java.time for nullness. --- .../share/classes/java/time/Clock.java | 2 + .../classes/java/time/DateTimeException.java | 11 ++++- .../share/classes/java/time/DayOfWeek.java | 6 ++- .../share/classes/java/time/Duration.java | 2 + .../share/classes/java/time/Instant.java | 6 ++- .../share/classes/java/time/LocalDate.java | 6 ++- .../classes/java/time/LocalDateTime.java | 6 ++- .../share/classes/java/time/LocalTime.java | 6 ++- .../share/classes/java/time/Month.java | 6 ++- .../share/classes/java/time/MonthDay.java | 4 +- .../classes/java/time/OffsetDateTime.java | 6 ++- .../share/classes/java/time/OffsetTime.java | 6 ++- .../share/classes/java/time/Period.java | 2 + .../share/classes/java/time/Year.java | 8 ++-- .../share/classes/java/time/YearMonth.java | 6 ++- .../share/classes/java/time/ZoneId.java | 2 + .../share/classes/java/time/ZoneOffset.java | 12 ++++- .../classes/java/time/ZonedDateTime.java | 8 ++-- .../java/time/chrono/ChronoLocalDate.java | 14 ++++-- .../java/time/chrono/ChronoLocalDateTime.java | 14 ++++-- .../java/time/chrono/ChronoPeriod.java | 10 +++- .../java/time/chrono/ChronoZonedDateTime.java | 14 ++++-- .../java/time/temporal/ChronoField.java | 3 ++ .../java/time/temporal/ChronoUnit.java | 3 ++ .../classes/java/time/temporal/IsoFields.java | 3 ++ .../java/time/temporal/JulianFields.java | 3 ++ .../classes/java/time/temporal/Temporal.java | 6 ++- .../java/time/temporal/TemporalAccessor.java | 6 ++- .../java/time/temporal/TemporalAdjuster.java | 3 ++ .../java/time/temporal/TemporalAmount.java | 3 ++ .../java/time/temporal/TemporalField.java | 6 ++- .../java/time/temporal/TemporalQueries.java | 46 ++++++++++--------- .../java/time/temporal/TemporalQuery.java | 3 ++ .../java/time/temporal/TemporalUnit.java | 3 ++ .../UnsupportedTemporalTypeException.java | 10 +++- .../java/time/temporal/WeekFields.java | 1 + 36 files changed, 193 insertions(+), 63 deletions(-) diff --git a/src/java.base/share/classes/java/time/Clock.java b/src/java.base/share/classes/java/time/Clock.java index b078b1cee9412..69283e5801bd9 100644 --- a/src/java.base/share/classes/java/time/Clock.java +++ b/src/java.base/share/classes/java/time/Clock.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import java.io.IOException; import java.io.ObjectInputStream; @@ -143,6 +144,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public abstract class Clock { /** diff --git a/src/java.base/share/classes/java/time/DateTimeException.java b/src/java.base/share/classes/java/time/DateTimeException.java index c2549fe0a328f..1e8d8c6c6e1c1 100644 --- a/src/java.base/share/classes/java/time/DateTimeException.java +++ b/src/java.base/share/classes/java/time/DateTimeException.java @@ -61,6 +61,10 @@ */ package java.time; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Exception used to indicate a problem while calculating a date-time. *

@@ -72,6 +76,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public class DateTimeException extends RuntimeException { /** @@ -84,7 +89,8 @@ public class DateTimeException extends RuntimeException { * * @param message the message to use for this exception, may be null */ - public DateTimeException(String message) { + @SideEffectFree + public DateTimeException(@Nullable String message) { super(message); } @@ -94,7 +100,8 @@ public DateTimeException(String message) { * @param message the message to use for this exception, may be null * @param cause the cause of the exception, may be null */ - public DateTimeException(String message, Throwable cause) { + @SideEffectFree + public DateTimeException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } diff --git a/src/java.base/share/classes/java/time/DayOfWeek.java b/src/java.base/share/classes/java/time/DayOfWeek.java index 43dc3aa9c1b0f..21169350b682f 100644 --- a/src/java.base/share/classes/java/time/DayOfWeek.java +++ b/src/java.base/share/classes/java/time/DayOfWeek.java @@ -64,6 +64,9 @@ import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoUnit.DAYS; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.format.DateTimeFormatterBuilder; import java.time.format.TextStyle; import java.time.temporal.ChronoField; @@ -106,6 +109,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { /** @@ -248,7 +252,7 @@ public String getDisplayName(TextStyle style, Locale locale) { * @return true if the field is supported on this day-of-week, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == DAY_OF_WEEK; } diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index f617fb45e598f..653e4a96634d8 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.LocalTime.MINUTES_PER_HOUR; import static java.time.LocalTime.NANOS_PER_MILLI; @@ -136,6 +137,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class Duration implements TemporalAmount, Comparable, Serializable { diff --git a/src/java.base/share/classes/java/time/Instant.java b/src/java.base/share/classes/java/time/Instant.java index aa95a72a0c1c9..6a90b2624603c 100644 --- a/src/java.base/share/classes/java/time/Instant.java +++ b/src/java.base/share/classes/java/time/Instant.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.LocalTime.NANOS_PER_SECOND; import static java.time.LocalTime.SECONDS_PER_DAY; @@ -210,6 +211,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class Instant implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -460,7 +462,7 @@ private Instant(long epochSecond, int nanos) { * @return true if the field is supported on this instant, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == INSTANT_SECONDS || field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND; } @@ -497,7 +499,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit.isTimeBased() || unit == DAYS; } diff --git a/src/java.base/share/classes/java/time/LocalDate.java b/src/java.base/share/classes/java/time/LocalDate.java index 988a8e0e9164c..3a34ace955a61 100644 --- a/src/java.base/share/classes/java/time/LocalDate.java +++ b/src/java.base/share/classes/java/time/LocalDate.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.LocalTime.SECONDS_PER_DAY; import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; @@ -142,6 +143,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class LocalDate implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { @@ -542,7 +544,7 @@ private LocalDate(int year, int month, int dayOfMonth) { * @return true if the field is supported on this date, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { return ChronoLocalDate.super.isSupported(field); } @@ -576,7 +578,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { return ChronoLocalDate.super.isSupported(unit); } diff --git a/src/java.base/share/classes/java/time/LocalDateTime.java b/src/java.base/share/classes/java/time/LocalDateTime.java index a4647f52701e1..e2d1c9849b341 100644 --- a/src/java.base/share/classes/java/time/LocalDateTime.java +++ b/src/java.base/share/classes/java/time/LocalDateTime.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.LocalTime.HOURS_PER_DAY; import static java.time.LocalTime.MICROS_PER_DAY; @@ -138,6 +139,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class LocalDateTime implements Temporal, TemporalAdjuster, ChronoLocalDateTime, Serializable { @@ -577,7 +579,7 @@ private LocalDateTime with(LocalDate newDate, LocalTime newTime) { * @return true if the field is supported on this date-time, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { ChronoField f = (ChronoField) field; return f.isDateBased() || f.isTimeBased(); @@ -622,7 +624,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { return ChronoLocalDateTime.super.isSupported(unit); } diff --git a/src/java.base/share/classes/java/time/LocalTime.java b/src/java.base/share/classes/java/time/LocalTime.java index 34dbef16db5a5..655b2fa4802fe 100644 --- a/src/java.base/share/classes/java/time/LocalTime.java +++ b/src/java.base/share/classes/java/time/LocalTime.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.HOUR_OF_DAY; import static java.time.temporal.ChronoField.MICRO_OF_DAY; @@ -128,6 +129,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class LocalTime implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -542,7 +544,7 @@ private LocalTime(int hour, int minute, int second, int nanoOfSecond) { * @return true if the field is supported on this time, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field.isTimeBased(); } @@ -578,7 +580,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit.isTimeBased(); } diff --git a/src/java.base/share/classes/java/time/Month.java b/src/java.base/share/classes/java/time/Month.java index 1a0d9eed9cbaf..1282868bd4acc 100644 --- a/src/java.base/share/classes/java/time/Month.java +++ b/src/java.base/share/classes/java/time/Month.java @@ -64,6 +64,9 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoUnit.MONTHS; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatterBuilder; @@ -103,6 +106,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public enum Month implements TemporalAccessor, TemporalAdjuster { /** @@ -275,7 +279,7 @@ public String getDisplayName(TextStyle style, Locale locale) { * @return true if the field is supported on this month-of-year, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == MONTH_OF_YEAR; } diff --git a/src/java.base/share/classes/java/time/MonthDay.java b/src/java.base/share/classes/java/time/MonthDay.java index 3dcb039d1ef3b..b19f343620a07 100644 --- a/src/java.base/share/classes/java/time/MonthDay.java +++ b/src/java.base/share/classes/java/time/MonthDay.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -130,6 +131,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class MonthDay implements TemporalAccessor, TemporalAdjuster, Comparable, Serializable { @@ -352,7 +354,7 @@ private MonthDay(int month, int dayOfMonth) { * @return true if the field is supported on this month-day, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == MONTH_OF_YEAR || field == DAY_OF_MONTH; } diff --git a/src/java.base/share/classes/java/time/OffsetDateTime.java b/src/java.base/share/classes/java/time/OffsetDateTime.java index a808ecb32a32a..620a5441947ce 100644 --- a/src/java.base/share/classes/java/time/OffsetDateTime.java +++ b/src/java.base/share/classes/java/time/OffsetDateTime.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.INSTANT_SECONDS; @@ -131,6 +132,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class OffsetDateTime implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -487,7 +489,7 @@ private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) { * @return true if the field is supported on this date-time, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } @@ -528,7 +530,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit != FOREVER; } diff --git a/src/java.base/share/classes/java/time/OffsetTime.java b/src/java.base/share/classes/java/time/OffsetTime.java index 98bc4caefe60a..44d86a78df10a 100644 --- a/src/java.base/share/classes/java/time/OffsetTime.java +++ b/src/java.base/share/classes/java/time/OffsetTime.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.LocalTime.NANOS_PER_HOUR; import static java.time.LocalTime.NANOS_PER_MINUTE; @@ -121,6 +122,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class OffsetTime implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -398,7 +400,7 @@ private OffsetTime with(LocalTime time, ZoneOffset offset) { * @return true if the field is supported on this time, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field.isTimeBased() || field == OFFSET_SECONDS; } @@ -434,7 +436,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit.isTimeBased(); } diff --git a/src/java.base/share/classes/java/time/Period.java b/src/java.base/share/classes/java/time/Period.java index d0e6510ab2005..6bd2baab2485e 100644 --- a/src/java.base/share/classes/java/time/Period.java +++ b/src/java.base/share/classes/java/time/Period.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.MONTHS; @@ -136,6 +137,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class Period implements ChronoPeriod, Serializable { diff --git a/src/java.base/share/classes/java/time/Year.java b/src/java.base/share/classes/java/time/Year.java index aafe65baa9a1a..3ce541c87f984 100644 --- a/src/java.base/share/classes/java/time/Year.java +++ b/src/java.base/share/classes/java/time/Year.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; @@ -138,6 +139,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class Year implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -371,7 +373,7 @@ public int getValue() { * @return true if the field is supported on this year, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == YEAR || field == YEAR_OF_ERA || field == ERA; } @@ -405,7 +407,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; } @@ -543,7 +545,7 @@ public boolean isLeap() { * @param monthDay the month-day to validate, null returns false * @return true if the month and day are valid for this year */ - public boolean isValidMonthDay(MonthDay monthDay) { + public boolean isValidMonthDay(@Nullable MonthDay monthDay) { return monthDay != null && monthDay.isValidYear(year); } diff --git a/src/java.base/share/classes/java/time/YearMonth.java b/src/java.base/share/classes/java/time/YearMonth.java index 46f4e701de2cc..5f6ea2b7b88df 100644 --- a/src/java.base/share/classes/java/time/YearMonth.java +++ b/src/java.base/share/classes/java/time/YearMonth.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -134,6 +135,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class YearMonth implements Temporal, TemporalAdjuster, Comparable, Serializable { @@ -357,7 +359,7 @@ private YearMonth with(int newYear, int newMonth) { * @return true if the field is supported on this year-month, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == YEAR || field == MONTH_OF_YEAR || field == PROLEPTIC_MONTH || field == YEAR_OF_ERA || field == ERA; @@ -393,7 +395,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; } diff --git a/src/java.base/share/classes/java/time/ZoneId.java b/src/java.base/share/classes/java/time/ZoneId.java index 396e217bea5e7..9f9aeab945690 100644 --- a/src/java.base/share/classes/java/time/ZoneId.java +++ b/src/java.base/share/classes/java/time/ZoneId.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import java.io.DataOutput; import java.io.IOException; @@ -181,6 +182,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public abstract class ZoneId implements Serializable { /** diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index 29b5909a57d42..9d4d856deac2b 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -66,6 +66,11 @@ import static java.time.LocalTime.SECONDS_PER_MINUTE; import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -127,6 +132,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class ZoneOffset extends ZoneId implements TemporalAccessor, TemporalAdjuster, Comparable, Serializable { @@ -526,7 +532,7 @@ public ZoneRules getRules() { * @return true if the field is supported on this offset, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field == OFFSET_SECONDS; } @@ -716,7 +722,9 @@ public int compareTo(ZoneOffset other) { * @return true if this is equal to the other offset */ @Override - public boolean equals(Object obj) { + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index a4d152b03b797..8dfbc79a8e96c 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.NANO_OF_SECOND; @@ -167,6 +168,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class ZonedDateTime implements Temporal, ChronoZonedDateTime, Serializable { @@ -369,7 +371,7 @@ public static ZonedDateTime of( * @param preferredOffset the zone offset, null if no preference * @return the zoned date-time, not null */ - public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) { + public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, @Nullable ZoneOffset preferredOffset) { Objects.requireNonNull(localDateTime, "localDateTime"); Objects.requireNonNull(zone, "zone"); if (zone instanceof ZoneOffset) { @@ -707,7 +709,7 @@ private ZonedDateTime resolveOffset(ZoneOffset offset) { * @return true if the field is supported on this date-time, false if not */ @Override - public boolean isSupported(TemporalField field) { + public boolean isSupported(@Nullable TemporalField field) { return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } @@ -748,7 +750,7 @@ public boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override // override for Javadoc - public boolean isSupported(TemporalUnit unit) { + public boolean isSupported(@Nullable TemporalUnit unit) { return ChronoZonedDateTime.super.isSupported(unit); } diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java index fb6938664ec0b..c439ef9b503ad 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java @@ -61,6 +61,11 @@ */ package java.time.chrono; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; @@ -238,6 +243,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface ChronoLocalDate extends Temporal, TemporalAdjuster, Comparable { @@ -383,7 +389,7 @@ default int lengthOfYear() { * @return true if the field can be queried, false if not */ @Override - default boolean isSupported(TemporalField field) { + default boolean isSupported(@Nullable TemporalField field) { if (field instanceof ChronoField) { return field.isDateBased(); } @@ -409,7 +415,7 @@ default boolean isSupported(TemporalField field) { * @return true if the unit can be added/subtracted, false if not */ @Override - default boolean isSupported(TemporalUnit unit) { + default boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit.isDateBased(); } @@ -778,7 +784,9 @@ default boolean isEqual(ChronoLocalDate other) { * @return true if this is equal to the other date */ @Override - boolean equals(Object obj); + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + boolean equals(@Nullable Object obj); /** * A hash code for this date. diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTime.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTime.java index 51637c2b5d87d..a93393f5b883d 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTime.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTime.java @@ -61,6 +61,11 @@ */ package java.time.chrono; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.NANO_OF_DAY; import static java.time.temporal.ChronoUnit.FOREVER; @@ -118,6 +123,7 @@ * @param the concrete type for the date of this date-time * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface ChronoLocalDateTime extends Temporal, TemporalAdjuster, Comparable> { @@ -233,7 +239,7 @@ default Chronology getChronology() { * @return true if the field can be queried, false if not */ @Override - boolean isSupported(TemporalField field); + boolean isSupported(@Nullable TemporalField field); /** * Checks if the specified unit is supported. @@ -254,7 +260,7 @@ default Chronology getChronology() { * @return true if the unit can be added/subtracted, false if not */ @Override - default boolean isSupported(TemporalUnit unit) { + default boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit != FOREVER; } @@ -585,7 +591,9 @@ default boolean isEqual(ChronoLocalDateTime other) { * @return true if this is equal to the other date */ @Override - boolean equals(Object obj); + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + boolean equals(@Nullable Object obj); /** * A hash code for this date-time. diff --git a/src/java.base/share/classes/java/time/chrono/ChronoPeriod.java b/src/java.base/share/classes/java/time/chrono/ChronoPeriod.java index 0ac1d395143a6..9a75d24e3843b 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoPeriod.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoPeriod.java @@ -61,6 +61,11 @@ */ package java.time.chrono; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; @@ -91,6 +96,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface ChronoPeriod extends TemporalAmount { @@ -341,7 +347,9 @@ default ChronoPeriod negated() { * @return true if this is equal to the other period */ @Override - boolean equals(Object obj); + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + boolean equals(@Nullable Object obj); /** * A hash code for this period. diff --git a/src/java.base/share/classes/java/time/chrono/ChronoZonedDateTime.java b/src/java.base/share/classes/java/time/chrono/ChronoZonedDateTime.java index eadcf9df958c2..226d91093d596 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoZonedDateTime.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoZonedDateTime.java @@ -61,6 +61,11 @@ */ package java.time.chrono; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoUnit.FOREVER; @@ -119,6 +124,7 @@ * @param the concrete type for the date of this date-time * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface ChronoZonedDateTime extends Temporal, Comparable> { @@ -380,7 +386,7 @@ default Chronology getChronology() { * @return true if the field can be queried, false if not */ @Override - boolean isSupported(TemporalField field); + boolean isSupported(@Nullable TemporalField field); /** * Checks if the specified unit is supported. @@ -401,7 +407,7 @@ default Chronology getChronology() { * @return true if the unit can be added/subtracted, false if not */ @Override - default boolean isSupported(TemporalUnit unit) { + default boolean isSupported(@Nullable TemporalUnit unit) { if (unit instanceof ChronoUnit) { return unit != FOREVER; } @@ -660,7 +666,9 @@ default boolean isEqual(ChronoZonedDateTime other) { * @return true if this is equal to the other date-time */ @Override - boolean equals(Object obj); + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + boolean equals(@Nullable Object obj); /** * A hash code for this date-time. diff --git a/src/java.base/share/classes/java/time/temporal/ChronoField.java b/src/java.base/share/classes/java/time/temporal/ChronoField.java index f1ef04ee07d6d..e1c60977d5971 100644 --- a/src/java.base/share/classes/java/time/temporal/ChronoField.java +++ b/src/java.base/share/classes/java/time/temporal/ChronoField.java @@ -56,6 +56,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.ERAS; import static java.time.temporal.ChronoUnit.FOREVER; @@ -99,6 +101,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public enum ChronoField implements TemporalField { /** diff --git a/src/java.base/share/classes/java/time/temporal/ChronoUnit.java b/src/java.base/share/classes/java/time/temporal/ChronoUnit.java index 8f94e061d4d48..c3885f764ce8d 100644 --- a/src/java.base/share/classes/java/time/temporal/ChronoUnit.java +++ b/src/java.base/share/classes/java/time/temporal/ChronoUnit.java @@ -56,6 +56,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.Duration; /** @@ -74,6 +76,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public enum ChronoUnit implements TemporalUnit { /** diff --git a/src/java.base/share/classes/java/time/temporal/IsoFields.java b/src/java.base/share/classes/java/time/temporal/IsoFields.java index 5a0d52555a381..2fe8e71304c36 100644 --- a/src/java.base/share/classes/java/time/temporal/IsoFields.java +++ b/src/java.base/share/classes/java/time/temporal/IsoFields.java @@ -56,6 +56,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.DayOfWeek.THURSDAY; import static java.time.DayOfWeek.WEDNESDAY; import static java.time.temporal.ChronoField.DAY_OF_WEEK; @@ -158,6 +160,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class IsoFields { /** diff --git a/src/java.base/share/classes/java/time/temporal/JulianFields.java b/src/java.base/share/classes/java/time/temporal/JulianFields.java index 7fc501cb9dd94..c2ba12811cde2 100644 --- a/src/java.base/share/classes/java/time/temporal/JulianFields.java +++ b/src/java.base/share/classes/java/time/temporal/JulianFields.java @@ -61,6 +61,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.FOREVER; @@ -87,6 +89,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class JulianFields { /** diff --git a/src/java.base/share/classes/java/time/temporal/Temporal.java b/src/java.base/share/classes/java/time/temporal/Temporal.java index 75ce67dd35f42..2ea2bff59b9a1 100644 --- a/src/java.base/share/classes/java/time/temporal/Temporal.java +++ b/src/java.base/share/classes/java/time/temporal/Temporal.java @@ -61,6 +61,9 @@ */ package java.time.temporal; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; /** @@ -126,6 +129,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface Temporal extends TemporalAccessor { /** @@ -149,7 +153,7 @@ public interface Temporal extends TemporalAccessor { * @param unit the unit to check, null returns false * @return true if the unit can be added/subtracted, false if not */ - boolean isSupported(TemporalUnit unit); + boolean isSupported(@Nullable TemporalUnit unit); /** * Returns an adjusted object of the same type as this object with the adjustment made. diff --git a/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java b/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java index 347e69d2bb2f1..7bba8407b32f2 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java @@ -61,6 +61,9 @@ */ package java.time.temporal; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; import java.util.Objects; @@ -100,6 +103,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface TemporalAccessor { /** @@ -123,7 +127,7 @@ public interface TemporalAccessor { * @param field the field to check, null returns false * @return true if this date-time can be queried for the field, false if not */ - boolean isSupported(TemporalField field); + boolean isSupported(@Nullable TemporalField field); /** * Gets the range of valid values for the specified field. diff --git a/src/java.base/share/classes/java/time/temporal/TemporalAdjuster.java b/src/java.base/share/classes/java/time/temporal/TemporalAdjuster.java index 09b5fba700343..b4e8cbe8c0198 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalAdjuster.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalAdjuster.java @@ -63,6 +63,8 @@ import java.time.DateTimeException; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Strategy for adjusting a temporal object. *

@@ -103,6 +105,7 @@ * @since 1.8 */ @FunctionalInterface +@AnnotatedFor({"nullness"}) public interface TemporalAdjuster { /** diff --git a/src/java.base/share/classes/java/time/temporal/TemporalAmount.java b/src/java.base/share/classes/java/time/temporal/TemporalAmount.java index 0d8b8a96bb06e..8bb3db809abd5 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalAmount.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalAmount.java @@ -61,6 +61,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; import java.time.Duration; import java.time.Period; @@ -96,6 +98,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface TemporalAmount { /** diff --git a/src/java.base/share/classes/java/time/temporal/TemporalField.java b/src/java.base/share/classes/java/time/temporal/TemporalField.java index a93caa6435139..55f2457ec9e5e 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalField.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalField.java @@ -61,6 +61,9 @@ */ package java.time.temporal; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; import java.time.chrono.Chronology; import java.time.format.ResolverStyle; @@ -91,6 +94,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface TemporalField { /** @@ -371,7 +375,7 @@ default String getDisplayName(Locale locale) { * @throws DateTimeException if resolving results in an error. This must not be thrown * by querying a field on the temporal without first checking if it is supported */ - default TemporalAccessor resolve( + default @Nullable TemporalAccessor resolve( Map fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { diff --git a/src/java.base/share/classes/java/time/temporal/TemporalQueries.java b/src/java.base/share/classes/java/time/temporal/TemporalQueries.java index 9df66bb7cd217..5732e8ceb1d43 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalQueries.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalQueries.java @@ -61,6 +61,9 @@ */ package java.time.temporal; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.NANO_OF_DAY; import static java.time.temporal.ChronoField.OFFSET_SECONDS; @@ -115,6 +118,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class TemporalQueries { // note that it is vital that each method supplies a constant, not a // calculated value, as they will be checked for using == @@ -164,7 +168,7 @@ private TemporalQueries() { * * @return a query that can obtain the zone ID of a temporal, not null */ - public static TemporalQuery zoneId() { + public static TemporalQuery<@Nullable ZoneId> zoneId() { return TemporalQueries.ZONE_ID; } @@ -203,7 +207,7 @@ public static TemporalQuery zoneId() { * * @return a query that can obtain the chronology of a temporal, not null */ - public static TemporalQuery chronology() { + public static TemporalQuery<@Nullable Chronology> chronology() { return TemporalQueries.CHRONO; } @@ -240,7 +244,7 @@ public static TemporalQuery chronology() { * * @return a query that can obtain the precision of a temporal, not null */ - public static TemporalQuery precision() { + public static TemporalQuery<@Nullable TemporalUnit> precision() { return TemporalQueries.PRECISION; } @@ -264,7 +268,7 @@ public static TemporalQuery precision() { * * @return a query that can obtain the zone ID or offset of a temporal, not null */ - public static TemporalQuery zone() { + public static TemporalQuery<@Nullable ZoneId> zone() { return TemporalQueries.ZONE; } @@ -287,7 +291,7 @@ public static TemporalQuery zone() { * * @return a query that can obtain the offset of a temporal, not null */ - public static TemporalQuery offset() { + public static TemporalQuery<@Nullable ZoneOffset> offset() { return TemporalQueries.OFFSET; } @@ -310,7 +314,7 @@ public static TemporalQuery offset() { * * @return a query that can obtain the date of a temporal, not null */ - public static TemporalQuery localDate() { + public static TemporalQuery<@Nullable LocalDate> localDate() { return TemporalQueries.LOCAL_DATE; } @@ -333,7 +337,7 @@ public static TemporalQuery localDate() { * * @return a query that can obtain the time of a temporal, not null */ - public static TemporalQuery localTime() { + public static TemporalQuery<@Nullable LocalTime> localTime() { return TemporalQueries.LOCAL_TIME; } @@ -341,9 +345,9 @@ public static TemporalQuery localTime() { /** * A strict query for the {@code ZoneId}. */ - static final TemporalQuery ZONE_ID = new TemporalQuery<>() { + static final TemporalQuery<@Nullable ZoneId> ZONE_ID = new TemporalQuery<@Nullable >() { @Override - public ZoneId queryFrom(TemporalAccessor temporal) { + public @Nullable ZoneId queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.ZONE_ID); } @@ -356,9 +360,9 @@ public String toString() { /** * A query for the {@code Chronology}. */ - static final TemporalQuery CHRONO = new TemporalQuery<>() { + static final TemporalQuery<@Nullable Chronology> CHRONO = new TemporalQuery<@Nullable >() { @Override - public Chronology queryFrom(TemporalAccessor temporal) { + public @Nullable Chronology queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.CHRONO); } @@ -372,9 +376,9 @@ public String toString() { /** * A query for the smallest supported unit. */ - static final TemporalQuery PRECISION = new TemporalQuery<>() { + static final TemporalQuery<@Nullable TemporalUnit> PRECISION = new TemporalQuery<@Nullable >() { @Override - public TemporalUnit queryFrom(TemporalAccessor temporal) { + public @Nullable TemporalUnit queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.PRECISION); } @@ -388,9 +392,9 @@ public String toString() { /** * A query for {@code ZoneOffset} returning null if not found. */ - static final TemporalQuery OFFSET = new TemporalQuery<>() { + static final TemporalQuery<@Nullable ZoneOffset> OFFSET = new TemporalQuery<@Nullable >() { @Override - public ZoneOffset queryFrom(TemporalAccessor temporal) { + public @Nullable ZoneOffset queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(OFFSET_SECONDS)) { return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); } @@ -406,9 +410,9 @@ public String toString() { /** * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. */ - static final TemporalQuery ZONE = new TemporalQuery<>() { + static final TemporalQuery<@Nullable ZoneId> ZONE = new TemporalQuery<@Nullable >() { @Override - public ZoneId queryFrom(TemporalAccessor temporal) { + public @Nullable ZoneId queryFrom(TemporalAccessor temporal) { ZoneId zone = temporal.query(ZONE_ID); return (zone != null ? zone : temporal.query(OFFSET)); } @@ -422,9 +426,9 @@ public String toString() { /** * A query for {@code LocalDate} returning null if not found. */ - static final TemporalQuery LOCAL_DATE = new TemporalQuery<>() { + static final TemporalQuery<@Nullable LocalDate> LOCAL_DATE = new TemporalQuery<@Nullable >() { @Override - public LocalDate queryFrom(TemporalAccessor temporal) { + public @Nullable LocalDate queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(EPOCH_DAY)) { return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); } @@ -440,9 +444,9 @@ public String toString() { /** * A query for {@code LocalTime} returning null if not found. */ - static final TemporalQuery LOCAL_TIME = new TemporalQuery<>() { + static final TemporalQuery<@Nullable LocalTime> LOCAL_TIME = new TemporalQuery<@Nullable >() { @Override - public LocalTime queryFrom(TemporalAccessor temporal) { + public @Nullable LocalTime queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(NANO_OF_DAY)) { return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); } diff --git a/src/java.base/share/classes/java/time/temporal/TemporalQuery.java b/src/java.base/share/classes/java/time/temporal/TemporalQuery.java index 9614296306235..78c57f4af6b95 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalQuery.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalQuery.java @@ -61,6 +61,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; /** @@ -100,6 +102,7 @@ * @since 1.8 */ @FunctionalInterface +@AnnotatedFor({"nullness"}) public interface TemporalQuery { /** diff --git a/src/java.base/share/classes/java/time/temporal/TemporalUnit.java b/src/java.base/share/classes/java/time/temporal/TemporalUnit.java index 1904bd2642d29..78313628a3b8b 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalUnit.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalUnit.java @@ -61,6 +61,8 @@ */ package java.time.temporal; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; import java.time.Duration; import java.time.LocalTime; @@ -94,6 +96,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public interface TemporalUnit { /** diff --git a/src/java.base/share/classes/java/time/temporal/UnsupportedTemporalTypeException.java b/src/java.base/share/classes/java/time/temporal/UnsupportedTemporalTypeException.java index e4b2b1281a3be..ac0cb40d05369 100644 --- a/src/java.base/share/classes/java/time/temporal/UnsupportedTemporalTypeException.java +++ b/src/java.base/share/classes/java/time/temporal/UnsupportedTemporalTypeException.java @@ -61,6 +61,10 @@ */ package java.time.temporal; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.time.DateTimeException; /** @@ -84,7 +88,8 @@ public class UnsupportedTemporalTypeException extends DateTimeException { * * @param message the message to use for this exception, may be null */ - public UnsupportedTemporalTypeException(String message) { + @SideEffectFree + public UnsupportedTemporalTypeException(@Nullable String message) { super(message); } @@ -94,7 +99,8 @@ public UnsupportedTemporalTypeException(String message) { * @param message the message to use for this exception, may be null * @param cause the cause of the exception, may be null */ - public UnsupportedTemporalTypeException(String message, Throwable cause) { + @SideEffectFree + public UnsupportedTemporalTypeException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } diff --git a/src/java.base/share/classes/java/time/temporal/WeekFields.java b/src/java.base/share/classes/java/time/temporal/WeekFields.java index 697bca97a95eb..9ef839d9d6f89 100644 --- a/src/java.base/share/classes/java/time/temporal/WeekFields.java +++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java @@ -190,6 +190,7 @@ * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public final class WeekFields implements Serializable { // implementation notes // querying week-of-month or week-of-year should return the week value bound within the month/year From d384f58c1caf1a3fba1a0395c97340aa9b855f5e Mon Sep 17 00:00:00 2001 From: Chris Povirk Date: Mon, 3 Aug 2020 15:37:01 -0400 Subject: [PATCH 2/4] Fix typos. --- .../java/time/temporal/TemporalQueries.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/time/temporal/TemporalQueries.java b/src/java.base/share/classes/java/time/temporal/TemporalQueries.java index 5732e8ceb1d43..97797f5292cbf 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalQueries.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalQueries.java @@ -345,7 +345,7 @@ private TemporalQueries() { /** * A strict query for the {@code ZoneId}. */ - static final TemporalQuery<@Nullable ZoneId> ZONE_ID = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable ZoneId> ZONE_ID = new TemporalQuery<@Nullable ZoneId>() { @Override public @Nullable ZoneId queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.ZONE_ID); @@ -360,7 +360,7 @@ public String toString() { /** * A query for the {@code Chronology}. */ - static final TemporalQuery<@Nullable Chronology> CHRONO = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable Chronology> CHRONO = new TemporalQuery<@Nullable Chronology>() { @Override public @Nullable Chronology queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.CHRONO); @@ -376,7 +376,7 @@ public String toString() { /** * A query for the smallest supported unit. */ - static final TemporalQuery<@Nullable TemporalUnit> PRECISION = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable TemporalUnit> PRECISION = new TemporalQuery<@Nullable TemporalUnit>() { @Override public @Nullable TemporalUnit queryFrom(TemporalAccessor temporal) { return temporal.query(TemporalQueries.PRECISION); @@ -392,7 +392,7 @@ public String toString() { /** * A query for {@code ZoneOffset} returning null if not found. */ - static final TemporalQuery<@Nullable ZoneOffset> OFFSET = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable ZoneOffset> OFFSET = new TemporalQuery<@Nullable ZoneOffset>() { @Override public @Nullable ZoneOffset queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(OFFSET_SECONDS)) { @@ -410,7 +410,7 @@ public String toString() { /** * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. */ - static final TemporalQuery<@Nullable ZoneId> ZONE = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable ZoneId> ZONE = new TemporalQuery<@Nullable ZoneId>() { @Override public @Nullable ZoneId queryFrom(TemporalAccessor temporal) { ZoneId zone = temporal.query(ZONE_ID); @@ -426,7 +426,7 @@ public String toString() { /** * A query for {@code LocalDate} returning null if not found. */ - static final TemporalQuery<@Nullable LocalDate> LOCAL_DATE = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable LocalDate> LOCAL_DATE = new TemporalQuery<@Nullable LocalDate>() { @Override public @Nullable LocalDate queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(EPOCH_DAY)) { @@ -444,7 +444,7 @@ public String toString() { /** * A query for {@code LocalTime} returning null if not found. */ - static final TemporalQuery<@Nullable LocalTime> LOCAL_TIME = new TemporalQuery<@Nullable >() { + static final TemporalQuery<@Nullable LocalTime> LOCAL_TIME = new TemporalQuery<@Nullable LocalTime>() { @Override public @Nullable LocalTime queryFrom(TemporalAccessor temporal) { if (temporal.isSupported(NANO_OF_DAY)) { From d0c98b0d3f54fd46081235842d880777403b3b9b Mon Sep 17 00:00:00 2001 From: Chris Povirk Date: Mon, 3 Aug 2020 15:58:10 -0400 Subject: [PATCH 3/4] Add missing import. --- src/java.base/share/classes/java/time/temporal/WeekFields.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.base/share/classes/java/time/temporal/WeekFields.java b/src/java.base/share/classes/java/time/temporal/WeekFields.java index 9ef839d9d6f89..cc52899da54a8 100644 --- a/src/java.base/share/classes/java/time/temporal/WeekFields.java +++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java @@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; +import org.checkerframework.framework.qual.AnnotatedFor; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; From 74f76ea58397d84a18bcd00c9921bcf0efa7df6d Mon Sep 17 00:00:00 2001 From: Chris Povirk Date: Fri, 14 Aug 2020 14:53:41 -0400 Subject: [PATCH 4/4] Add CFComment for TemporalQuery and TemporalAccessor. --- .../share/classes/java/time/temporal/TemporalAccessor.java | 3 +++ .../share/classes/java/time/temporal/TemporalQuery.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java b/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java index 7bba8407b32f2..8c146c7d5a590 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalAccessor.java @@ -63,6 +63,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; import java.time.DateTimeException; import java.util.Objects; @@ -309,6 +310,8 @@ default int get(TemporalField field) { * @throws DateTimeException if unable to query * @throws ArithmeticException if numeric overflow occurs */ + @CFComment({"nullness: TemporalQuery promises that this is equivalent to query.queryFrom, so " + + "it returns plain R, just like that method."}) default R query(TemporalQuery query) { if (query == TemporalQueries.zoneId() || query == TemporalQueries.chronology() diff --git a/src/java.base/share/classes/java/time/temporal/TemporalQuery.java b/src/java.base/share/classes/java/time/temporal/TemporalQuery.java index 78c57f4af6b95..97806f6f2e759 100644 --- a/src/java.base/share/classes/java/time/temporal/TemporalQuery.java +++ b/src/java.base/share/classes/java/time/temporal/TemporalQuery.java @@ -62,6 +62,7 @@ package java.time.temporal; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; import java.time.DateTimeException; @@ -143,6 +144,8 @@ public interface TemporalQuery { * @throws DateTimeException if unable to query * @throws ArithmeticException if numeric overflow occurs */ + @CFComment({"nullness: This is a function object, so we return plain R to distinguish between " + + "instances that can return null and those that cannot."}) R queryFrom(TemporalAccessor temporal); }