-
Notifications
You must be signed in to change notification settings - Fork 1.2k
JSpecify big wave 2 #4184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
JSpecify big wave 2 #4184
Conversation
| ParseAndValidateResult parseResult = parse(executionInput, graphQLSchema, instrumentationState); | ||
| if (parseResult.isFailure()) { | ||
| return new PreparsedDocumentEntry(parseResult.getSyntaxException().toInvalidSyntaxError()); | ||
| return new PreparsedDocumentEntry(assertNotNull(parseResult.getSyntaxException(), "Parse result syntax exception cannot be null when failed").toInvalidSyntaxError()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A similar change now has to happen in a bunch of places: now we must be asserting not null on selected lines or else you'll get a NullAway compile warning because the nullity is not clear at this point in the execution
|
|
||
| Predicate<Class<?>> validationRulePredicate = executionInput.getGraphQLContext().getOrDefault(ParseAndValidate.INTERNAL_VALIDATION_PREDICATE_HINT, r -> true); | ||
| Locale locale = executionInput.getLocale() != null ? executionInput.getLocale() : Locale.getDefault(); | ||
| Locale locale = executionInput.getLocale(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And now there are IDE alerts of null checks we can remove. When we are done with all JSpecify annotations on public API classes, we will find many more null checks to remove
| * @return the parsed document or null if it's syntactically invalid. | ||
| */ | ||
| public Document getDocument() { | ||
| public @Nullable Document getDocument() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inferred from the Javadoc
| private final Map<String, Object> arguments; | ||
|
|
||
| public FieldComplexityEnvironment(Field field, GraphQLFieldDefinition fieldDefinition, GraphQLCompositeType parentType, Map<String, Object> arguments, FieldComplexityEnvironment parentEnvironment) { | ||
| public FieldComplexityEnvironment(Field field, GraphQLFieldDefinition fieldDefinition, GraphQLCompositeType parentType, Map<String, Object> arguments, @Nullable FieldComplexityEnvironment parentEnvironment) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be nullable because a method that calls this constructor may pass in a null value for parentEnvironment
|
|
||
| @Override | ||
| public @Nullable CompletableFuture<InstrumentationState> createStateAsync(InstrumentationCreateStateParameters parameters) { | ||
| public CompletableFuture<InstrumentationState> createStateAsync(InstrumentationCreateStateParameters parameters) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these @Nullable annotations were not correct initially. This method always will return a completed future
|
|
||
| @Override | ||
| public @Nullable InstrumentationContext<List<ValidationError>> beginValidation(InstrumentationValidationParameters parameters, InstrumentationState rawState) { | ||
| public InstrumentationContext<List<ValidationError>> beginValidation(InstrumentationValidationParameters parameters, InstrumentationState rawState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I think this was incorrectly marked as nullable initially
|
|
||
| @Override | ||
| public @Nullable InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters, InstrumentationState rawState) { | ||
| public InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters, InstrumentationState rawState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I think this was incorrectly marked as nullable initially
|
|
||
| @Override | ||
| public @Nullable InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters parameters, InstrumentationState state) { | ||
| public InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters parameters, InstrumentationState state) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I think this was incorrectly marked as nullable initially
|
|
||
| /** | ||
| * @return a list of {@link graphql.relay.Edge}s that are really a node of data and its cursor | ||
| * @return a list of {@link graphql.relay.Edge}s that contain a node of data and its cursor. Can be null as defined in the spec. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the specification
|
|
||
| public DefaultConnectionCursor(String value) { | ||
| Assert.assertTrue(value != null && !value.isEmpty(), "connection value cannot be null or empty"); | ||
| Assert.assertTrue(!value.isEmpty(), "connection value cannot be null or empty"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove null check
| import java.util.Objects; | ||
|
|
||
| @PublicApi | ||
| @NullMarked |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A wider question: these Relay classes are quite old and never got much love. Do we want to retain these classes at all?
| @Internal | ||
| private GraphQLScalarType(String name, | ||
| String description, | ||
| @Nullable String description, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By definition in the specification, the description, and specified by URL can be null.
| private final ImmutableList<SchemaExtensionDefinition> extensionDefinitions; | ||
| private final String description; | ||
| private final GraphQLCodeRegistry codeRegistry; | ||
| private final @Nullable GraphQLCodeRegistry codeRegistry; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous discussion in #4098 (comment) (this PR supercedes the older one)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to remove the nullable annotation here, we'd also need to change another callsite that assumes this parameter to be null
| private final String propertyName; | ||
| private final Function<Object, Object> function; | ||
| private final @Nullable String propertyName; | ||
| private final @Nullable Function<Object, Object> function; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the constructors below, it is possible for either field to be nullable
| return NonNullType.newNonNullType(replaceTypeName(((NonNullType) type).getType(), newName)).build(); | ||
| } else { | ||
| graphql.Assert.assertShouldNeverHappen(); | ||
| return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This throws, so the null is never reached
| "graphql.validation.ValidationError", | ||
| "graphql.validation.ValidationErrorClassification", | ||
| "graphql.validation.ValidationErrorType", | ||
| // These classes will not be public API later, exempt here while marked as experimental |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an edge case where some classes have been annotated with "Experimental API" for the purposes of the defer work. They won't become public API later so I made a note in the JSpecify exemption rule
| private final List<SourceLocation> locations; | ||
| private final Map<String, Object> extensions; | ||
| private final List<Object> path; | ||
| private final @Nullable List<SourceLocation> locations; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The builder creates a non-nullable list, but that's only if the builder is called
| * @return a value or null | ||
| */ | ||
| public <T> T get(Object key) { | ||
| public <T> @Nullable T get(Object key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: another case of the nullable generic issue
| */ | ||
| @SuppressWarnings("unchecked") | ||
| public <T> T getObject() { | ||
| public @Nullable <T> T getObject() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: another generic nullable check
We have many classes left to go for JSpecify, so rather than one class at a time I will do the remainder in large bundles. This adds annotations on ~50 classes.
The general recipe here is
What will be in a future PR: better Kotlin tooling as reported recently in #4179