diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5958853701..3366885ee58 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ on: platforms: description: 'Platform(s) to execute on (comma separated, e.g. "linux-x64, macos, aarch64")' required: true - default: 'linux-x64, linux-x86-hs, linux-x64-variants, linux-cross-compile, alpine-linux-x64, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' + default: 'linux-x64' configure-arguments: description: 'Additional configure arguments' required: false @@ -153,8 +153,9 @@ jobs: uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 + debug-levels: '[ "debug" ]' gcc-major-version: '10' - configure-arguments: ${{ github.event.inputs.configure-arguments }} + configure-arguments: ${{ github.event.inputs.configure-arguments }} --disable-jvm-feature-jvmti make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.linux-x64 == 'true' diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 4e43245e520..65c11cd5fad 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -135,6 +135,7 @@ exports javax.security.auth.spi; exports javax.security.auth.x500; exports javax.security.cert; + exports org.jspecify.annotations; // additional qualified exports may be inserted at build time diff --git a/src/java.base/share/classes/org/jspecify/annotations/NonNull.java b/src/java.base/share/classes/org/jspecify/annotations/NonNull.java new file mode 100644 index 00000000000..31bcb076d95 --- /dev/null +++ b/src/java.base/share/classes/org/jspecify/annotations/NonNull.java @@ -0,0 +1,96 @@ +/* + * Copyright 2022 The JSpecify Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jspecify.annotations; + +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Indicates that the annotated type + * usage (commonly a parameter type or return type) is considered to exclude {@code null} + * as a value; rarely needed within {@linkplain NullMarked null-marked} code. + * + *
This annotation serves two primary purposes: + * + *
For a comprehensive introduction to JSpecify, please see jspecify.org. + * + *
In the following example, {@code MyOptional}'s type parameter {@code T} accepts only non-null + * type arguments, but {@code MyList}'s type parameter {@code E} will accept either a non-null or + * nullable type argument. + * + *
{@code + * // All the below is null-marked code + * + * class MyOptional+ * + *{ … } + * + * interface MyList { + * // Returns the first non-null element, if such element exists. + * MyOptional firstNonNull() { … } // problem here! + * } + * + * MyList<@Nullable String> maybeNulls = … + * MyList nonNulls = … + * }
Because {@code MyOptional} accepts only non-null type arguments, we need both {@code
+ * maybeNulls.firstNonNull()} and {@code nonNulls.firstNonNull()} to produce the same return type:
+ * {@code MyOptional! The solution is to project the type argument to its non-null counterpart:
+ *
+ * Here, {@code @NonNull E} selects the non-null form of the type argument, whether it was
+ * already non-null or not, which is just what we need in this scenario.
+ *
+ * If {@code E} has a non-null upper bound, then the apparent projection {@code @NonNull E} is
+ * redundant but harmless.
+ *
+ * Nullable projection serves the equivalent purpose in
+ * the opposite direction, and is far more commonly useful.
+ *
+ * If a type variable has all its usages being projected in one direction or the other, it
+ * should be given a non-null upper bound, and any non-null projections can then be removed.
+ *
+ * {@code @NonNull} is applicable in all the same
+ * locations as {@link Nullable}.
+ */
+@Documented
+@Target(TYPE_USE)
+@Retention(RUNTIME)
+public @interface NonNull {}
diff --git a/src/java.base/share/classes/org/jspecify/annotations/NullMarked.java b/src/java.base/share/classes/org/jspecify/annotations/NullMarked.java
new file mode 100644
index 00000000000..44e95104874
--- /dev/null
+++ b/src/java.base/share/classes/org/jspecify/annotations/NullMarked.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018-2020 The JSpecify Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jspecify.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.MODULE;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated element and the code transitively {@linkplain
+ * javax.lang.model.element.Element#getEnclosedElements() enclosed} within it are null-marked
+ * code: there, type usages are generally considered to exclude {@code null} as a value unless
+ * specified otherwise. Using this annotation avoids the need to write {@link NonNull @NonNull} many
+ * times throughout your code.
+ *
+ * For a comprehensive introduction to JSpecify, please see jspecify.org.
+ *
+ * Within null-marked code, as a general rule, a type usage is considered non-null (to
+ * exclude {@code null} as a value) unless explicitly annotated as {@link Nullable}. However, there
+ * are several special cases to address.
+ *
+ * Within null-marked code:
+ *
+ * This annotation's purpose is to ease migration of a large existing codebase to null-marked
+ * status. It makes it possible to "flip the default" for new code added to a class or package even
+ * before that class or package has been fully migrated. Since new code is the most important code
+ * to analyze, this is strongly recommended as a temporary measure whenever necessary. However, once
+ * a codebase has been fully migrated it would be appropriate to ban use of this annotation.
+ *
+ * For a comprehensive introduction to JSpecify, please see jspecify.org.
+ *
+ * {@link NullMarked} and this annotation work as a pair to include and exclude sections of code
+ * from null-marked status (respectively). Specifically, code is considered null-marked if the most
+ * narrowly enclosing element annotated with either of these two annotations exists and is annotated
+ * with {@code @NullMarked}.
+ *
+ * Otherwise it is considered null-unmarked. This can happen in two ways: either it is more
+ * narrowly enclosed by a {@code @NullUnmarked}-annotated element than by any
+ * {@code @NullMarked}-annotated element, or neither annotation is present on any enclosing element.
+ * No distinction is made between these cases.
+ *
+ * The effects of being null-marked are described in the Effects section of {@code NullMarked}.
+ *
+ * Within null-unmarked code, a type usage with no nullness annotation has unspecified
+ * nullness (Why?). This means that, while there is always
+ * some correct way to annotate it for nullness, that information is missing: we do not
+ * know whether it includes or excludes {@code null} as a value. In such a case, tools can vary
+ * widely in how strict or lenient their enforcement is, or might make it configurable.
+ *
+ * For more, please see this more comprehensive
+ * discussion of unspecified nullness.
+ *
+ * There is no way for an individual type usage within null-marked code to have unspecified
+ * nullness. (Why?)
+ *
+ * Example usages:
+ *
+ * For a comprehensive introduction to JSpecify, please see jspecify.org.
+ *
+ * The essential meaning of this annotation is always the same: the type it annotates is
+ * considered to include {@code null} as a value. But this may affect your code a little differently
+ * based on the kind of type usage involved.
+ *
+ * This annotation and {@link NonNull} are applicable to any type usage except the
+ * following cases, where they have no defined meaning:
+ *
+ * For a type usage where nullness annotations are applicable but
+ * not present, its nullness depends on whether it appears within {@linkplain NullMarked
+ * null-marked} code; see that class for details. Note in particular that nullness information from
+ * a superclass is never automatically "inherited".
+ */
+@Documented
+@Target(TYPE_USE)
+@Retention(RUNTIME)
+public @interface Nullable {}
diff --git a/src/java.base/share/classes/org/jspecify/annotations/package-info.java b/src/java.base/share/classes/org/jspecify/annotations/package-info.java
new file mode 100644
index 00000000000..bcc0e4da7e2
--- /dev/null
+++ b/src/java.base/share/classes/org/jspecify/annotations/package-info.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The JSpecify Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * JSpecify annotations. See jspecify.org for general information.
+ *
+ * For a comprehensive introduction to JSpecify, please see jspecify.org.
+ *
+ * Each of these annotations defines a single meaning shared by all compatible tools (and
+ * libraries). JSpecify documentation aims to provide unambiguous, tool-independent answers for how
+ * to properly annotate your APIs in all circumstances. However, tools are permitted to
+ * respond to the information you provide however they see fit (or not at all). JSpecify
+ * compatibility does not require that any particular finding must or must not be issued to the
+ * user, let alone its message or severity.
+ *
+ * In fact, it's important to remember that declarative annotations are merely one source
+ * of information an analyzer may consult in concluding an expression is safely non-null. Just like
+ * one analyzer might determine that an {@code int} expression can take on only positive values,
+ * another might likewise determine that a declaratively nullable expression can take on only
+ * non-null values. In both cases the declarative knowledge is correct, but the inferred
+ * knowledge is both correct and more specific.
+ *
+ * On the other end, the tools might even enforce nothing at all. In particular, your
+ * annotated code (or other code dependent on its annotated APIs) might be compiled and run without
+ * any appropriate tool even in use. Therefore adopting JSpecify annotations is not a replacement
+ * for explicitly checking arguments at runtime.
+ */
+package org.jspecify.annotations;
{@code
+ * // Returns the first non-null element, if such element exists.
+ * MyOptional<@NonNull E> firstNonNull() { … } // problem fixed!
+ * }
+ *
+ * Where it is applicable
+ *
+ * Effects of being null-marked
+ *
+ * Special cases
+ *
+ *
+ *
+ *
+ *
+ *
+ * Where it can be used
+ *
+ * {@code @NullMarked} and {@link NullUnmarked @NullUnmarked} can be used on any package, class,
+ * method, or constructor declaration; {@code @NullMarked} can be used on a module declaration as
+ * well. Special considerations:
+ *
+ *
+ *
+ */
+@Documented
+@Target({MODULE, PACKAGE, TYPE, METHOD, CONSTRUCTOR})
+@Retention(RUNTIME)
+public @interface NullMarked {}
diff --git a/src/java.base/share/classes/org/jspecify/annotations/NullUnmarked.java b/src/java.base/share/classes/org/jspecify/annotations/NullUnmarked.java
new file mode 100644
index 00000000000..f2da1df9ce6
--- /dev/null
+++ b/src/java.base/share/classes/org/jspecify/annotations/NullUnmarked.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 The JSpecify Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jspecify.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated element and the code transitively {@linkplain
+ * javax.lang.model.element.Element#getEnclosedElements() enclosed} within it is null-unmarked
+ * code: there, type usages generally have unspecified nullness unless explicitly
+ * annotated otherwise.
+ *
+ * Null-marked and null-unmarked code
+ *
+ * Unspecified nullness
+ *
+ * Where it can be used
+ *
+ * The information in the Where it can be used section of {@code
+ * NullMarked} applies as well to this annotation.
+ */
+// TODO(kevinb9n): word the middle section better with good words
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR})
+public @interface NullUnmarked {}
diff --git a/src/java.base/share/classes/org/jspecify/annotations/Nullable.java b/src/java.base/share/classes/org/jspecify/annotations/Nullable.java
new file mode 100644
index 00000000000..a87d30da269
--- /dev/null
+++ b/src/java.base/share/classes/org/jspecify/annotations/Nullable.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018-2020 The JSpecify Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jspecify.annotations;
+
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated type
+ * usage (commonly a parameter type or return type) is considered to include {@code null} as a
+ * value.
+ *
+ * {@code
+ * @Nullable String field;
+ *
+ * @Nullable String getField() { return field; }
+ *
+ * void setField(@Nullable String value) { field = value; }
+ *
+ * List<@Nullable String> getList() { … }
+ * }
+ *
+ * Meaning per each kind of type usage
+ *
+ *
+ *
+ *
+ * Where it is applicable
+ *
+ *
+ *
+ *
+ * Whether the code is {@link NullMarked} also has no consequence in the above locations.
+ *
+ * Unannotated type usages
+ *
+ * What's here?
+ *
+ * This package will contain annotations supporting a variety of static analyses. For now it
+ * supports just nullness analysis.
+ *
+ * Nullness
+ *
+ * The primary annotations of interest are {@link NullMarked} and {@link Nullable}. Together they
+ * provide declarative, use-site nullness for Java types. Less frequently, their negations
+ * may be useful: {@link NullUnmarked} and {@link NonNull}, respectively.
+ *
+ * Note on tool behavior
+ *
+ *