Repository navigation
Preserve covariant return types when merging null annotations - #5373
stephan-herrmann merged 3 commits into
Conversation
|
@stephan-herrmann please help review this PR, thanks |
|
@srikanth-sankaran please review this pr. |
|
@srikanth-sankaran @stephan-herrmann please review |
Sorry for the delay. @stephan-herrmann is Mr Null Analysis. But he is a volunteer. In case he is not able to wrap up the review by this week, I will certainly take a look and do some preparatory work for him. |
|
I'll take a look later today. |
|
Thanks for the PR, which is going in a good direction. To further harden the solution I created the following variant of import org.eclipse.jdt.annotation.*;
public class Test {
Builders.@NonNull Child build(Builders.ChildBuilder builder) {
return builder.build();
}
Builders.Child buildReversed(Builders.ReversedChildBuilder builder) {
return builder.build();
}
} import org.eclipse.jdt.annotation.*;
public class Builders {
public static class Parent {}
public static class Child extends Parent {}
public interface ParentBuilder {
@NonNull Parent build();
}
public interface GenericBuilder<T> {
T build();
}
public interface ChildBuilder extends ParentBuilder, GenericBuilder<Child> {}
public interface ReversedChildBuilder extends GenericBuilder<Child>, ParentBuilder {}
}Before the fix this was affected by the same bug, but with the proposed fix it still reports This indicates that I'll use the opportunity trying to improve Additionally I checked the other caller of |
Merge return annotations onto the method selected by Java resolution instead of the first inherited candidate. Cover both interface orders, source and binary builders, and merged null contracts. Related to redhat-developer/vscode-java#4500 Signed-off-by: wenytang-ms <wenyutang@microsoft.com>
+ make strongerType() even stronger
c478ec4 to
68bef92
Compare
|
Thanks @wenytang-ms ! |



Summary
Preserve the covariant return type already selected by Java method resolution when merging null annotations from override-equivalent inherited methods.
Addresses redhat-developer/vscode-java#4500. This is a follow-up to #5250, not a change to the language server's null-analysis settings.
Root cause
Scope.mostSpecificMethodBinding()can select a method whose return type is more specific than the first entry inmoreSpecific. However,methodWithMergedNullAnnotations()initializes the merged return type frommoreSpecific[0], rather than from the selected method.Since
strongerType()deliberately preserves its first argument's underlying Java type, merging annotations can replace the selected subtype with a supertype. In AWS SDK 2.42.26, this makesGetParametersByPathRequest.builder().build()appear to returnSsmRequestwhen annotation-based null analysis is enabled.The fix starts with
current.returnTypeand merges annotations from every candidate onto that type. Parameter annotation merging is unchanged.Regression history
Historical ECJ builds using the same AWS input and null-analysis settings show:
27f2d7a, parent of #523762bd2a3, #5237Objectreturn type618869e, #5250SsmRequestreturn typeThe earlier follow-up fixed the explicit covariant override reported in #5249, but did not cover the separately inherited generic builder methods used by the AWS SDK.
Regression coverage
testGH5249_inheritedBuilders: generic and covariantbuild()declarations in both interface orders, resolved from source and then from class files.testGH5249_inheritedNullAnnotations: preserve the covariant Java type while merging the strongest return nullness from three interfaces, in both orders.The tests do not depend on the AWS SDK.
Validation
The Maven/Tycho compiler reactor succeeded, and
NullTypeAnnotationTestreported 958 tests, 0 failures, 0 errors. The Maven-built ECJ also compiles both original AWS expressions with null analysis enabled.The test provider ran the full
NullTypeAnnotationTestsuite for this invocation.This draft fixes the compiler. The downstream VS Code issue will additionally require consuming the fixed JDT Core version through JDT LS.