Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions org.eclipse.jdt.core.compiler.batch/.settings/.api_filters
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jdt.core.compiler.batch" version="2">
<resource path="META-INF/MANIFEST.MF">
<filter id="926941240">
<message_arguments>
<message_argument value="3.46.0"/>
<message_argument value="3.45.0"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jdt/core/compiler/CategorizedProblem.java" type="org.eclipse.jdt.core.compiler.CategorizedProblem">
<filter comment="BETA_JAVA22 temporary issue" id="576725006">
<message_arguments>
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Main-Class: org.eclipse.jdt.internal.compiler.batch.Main
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse Compiler for Java(TM)
Bundle-SymbolicName: org.eclipse.jdt.core.compiler.batch
Bundle-Version: 3.46.0.qualifier
Bundle-Version: 3.46.100.qualifier
Bundle-ClassPath: .
Bundle-Vendor: Eclipse.org
Automatic-Module-Name: org.eclipse.jdt.core.compiler.batch
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core.compiler.batch/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<version>4.41.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jdt.core.compiler.batch</artifactId>
<version>3.46.0-SNAPSHOT</version>
<version>3.46.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2025 IBM Corporation and others.
* Copyright (c) 2000, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -912,9 +912,16 @@ protected void checkNullAnnotations(BlockScope scope) {
providedLen--; // one parameter is 'consumed' as the receiver

TypeBinding descriptorParameter = this.descriptor.parameters[0];
if((descriptorParameter.tagBits & TagBits.AnnotationNullable) != 0) { // Note: normal dereferencing of 'unchecked' values is not reported, either
final TypeBinding receiver = scope.environment().createNonNullAnnotatedType(this.binding.declaringClass);
scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, receiver, descriptorParameter, this.descriptor, -1, NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH);
if((descriptorParameter.tagBits & TagBits.AnnotationNonNull) == 0) {
NullAnnotationMatching mismatch = (descriptorParameter.tagBits & TagBits.AnnotationNullable) != 0
? NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH : NullAnnotationMatching.NULL_ANNOTATIONS_UNCHECKED;
LookupEnvironment environment = scope.environment();
ReferenceBinding nonNull = environment.getType(environment.getNonNullAnnotationName());
if (nonNull != null) { // tolerate misconfigured annotations
AnnotationBinding nnAnnot = environment.createAnnotation(nonNull, Binding.NO_ELEMENT_VALUE_PAIRS);
final TypeBinding receiver = environment.createAnnotatedType(this.binding.declaringClass, new AnnotationBinding[] { nnAnnot });
reportParameterNullProblem(scope, descriptorParameter, 0, receiver, -1, mismatch);
}
}
}
boolean isVarArgs = false;
Expand All @@ -927,7 +934,8 @@ protected void checkNullAnnotations(BlockScope scope) {
len = Math.min(expectedlen, providedLen);
}
for (int i = 0; i < len; i++) {
TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)];
int descriptorIdx = i + (this.receiverPrecedesParameters ? 1 : 0);
TypeBinding descriptorParameter = this.descriptor.parameters[descriptorIdx];
TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs);
TypeBinding bindingParameterToCheck;
if (bindingParameter.isPrimitiveType() && !descriptorParameter.isPrimitiveType()) {
Expand All @@ -940,7 +948,7 @@ protected void checkNullAnnotations(BlockScope scope) {
NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameterToCheck, descriptorParameter, FlowInfo.UNKNOWN);
if (annotationStatus.isAnyMismatch()) {
// immediate reporting:
scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus);
reportParameterNullProblem(scope, descriptorParameter, descriptorIdx, bindingParameter, i, annotationStatus);
}
}
TypeBinding returnType = this.binding.returnType;
Expand All @@ -957,6 +965,20 @@ protected void checkNullAnnotations(BlockScope scope) {
}
}

private void reportParameterNullProblem(BlockScope scope, TypeBinding descriptorParameter, int descriptorParamIdx,
TypeBinding implParameter, int implIdx, NullAnnotationMatching mismatchKind) {
if (this.expectedType instanceof ReferenceBinding expectedRef) {
// recover the real inherited method having the constrained parameter
for (MethodBinding contract : expectedRef.getFunctionalInterfaceAbstractContracts(scope, argumentsTypeElided())) {
if (contract.parameters[descriptorParamIdx] == descriptorParameter) { //$IDENTITY-COMPARISON$
scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, implParameter, descriptorParameter,
contract, implIdx, mismatchKind);
break;
}
}
}
}

private TypeBinding[] descriptorParametersAsArgumentExpressions() {

if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,7 @@ public void detectWrapperResource() {
}
}

private MethodBinding[] getFunctionalInterfaceAbstractContracts(Scope scope, boolean replaceWildcards) throws DysfunctionalInterfaceException {
public MethodBinding[] getFunctionalInterfaceAbstractContracts(Scope scope, boolean replaceWildcards) throws DysfunctionalInterfaceException {

LookupEnvironment environment = scope.environment();
boolean isAnnotationBasedNullAnalysisEnabled = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8259,7 +8259,7 @@ public void testBug459967_Array_constructor_b() {
"----------\n");
}
public void testBug459967_Array_clone() {
runConformTestWithLibs(
runNegativeTestWithLibs(
new String[] {
"X.java",
"import org.eclipse.jdt.annotation.*;\n" +
Expand All @@ -8274,6 +8274,31 @@ public void testBug459967_Array_clone() {
"}\n"
},
getCompilerOptions(),
"""
----------
1. WARNING in X.java (at line 7)
consumer(String[]::clone);
^^^^^^^^^^^^^^^
Null type safety: parameter 'this' provided via method descriptor FI<String>.getArray(String[]) needs unchecked conversion to conform to '@NonNull Object'
----------
""");
}
public void testBug459967_Array_clone_fixed() {
runConformTestWithLibs(
new String[] {
"X.java",
"import org.eclipse.jdt.annotation.*;\n" +
"interface FI<T> {\n" +
" T @NonNull[] getArray(T @NonNull[] orig);" +
"}\n" +
"public class X {\n" +
" void consumer(FI<String> fis) {}\n" +
" void test() {\n" +
" consumer(String[]::clone);\n" +
" }\n" +
"}\n"
},
getCompilerOptions(),
"");
}
public void testBug459967_Array_clone_b() {
Expand All @@ -8283,7 +8308,7 @@ public void testBug459967_Array_clone_b() {
"X.java",
"import org.eclipse.jdt.annotation.*;\n" +
"interface FI<T> {\n" +
" @NonNull T @NonNull[] getArray(T[] orig);" +
" @NonNull T @NonNull[] getArray(T @NonNull[] orig);" +
"}\n" +
"public class X {\n" +
" void consumer(FI<String> fis) {}\n" +
Expand Down Expand Up @@ -15763,7 +15788,7 @@ public void testBug513495() {
" Function<@Nullable Integer, Object> sam = Integer::intValue;\n" +
" sam.apply(null); // <- NullPointerExpection\n" +
" Function<Integer, Object> sam2 = Integer::intValue;\n" +
" sam2.apply(null); // variation: unchecked, so intentionally no warning reported, but would give NPE too \n" +
" sam2.apply(null); // variation: unchecked, warning above\n" +
" }\n" +
" void wildcards(Class<?>[] params) { // unchecked case with wildcards\n" +
" java.util.Arrays.stream(params).map(Class::getName).toArray(String[]::new);\n" +
Expand All @@ -15777,6 +15802,16 @@ public void testBug513495() {
" Function<@Nullable Integer, Object> sam = Integer::intValue;\n" +
" ^^^^^^^^^^^^^^^^^\n" +
"Null type mismatch at parameter 'this': required \'@NonNull Integer\' but provided \'@Nullable Integer\' via method descriptor Function<Integer,Object>.apply(Integer)\n" +
"----------\n" +
"2. WARNING in test\\Test3.java (at line 11)\n" +
" Function<Integer, Object> sam2 = Integer::intValue;\n" +
" ^^^^^^^^^^^^^^^^^\n" +
"Null type safety: parameter \'this\' provided via method descriptor Function<Integer,Object>.apply(Integer) needs unchecked conversion to conform to \'@NonNull Integer\'\n" +
"----------\n" +
"3. WARNING in test\\Test3.java (at line 15)\n" +
" java.util.Arrays.stream(params).map(Class::getName).toArray(String[]::new);\n" +
" ^^^^^^^^^^^^^^\n" +
"Null type safety: parameter \'this\' provided via method descriptor Function<Class<?>,String>.apply(Class<?>) needs unchecked conversion to conform to \'@NonNull Class<capture#of ?>\'\n" +
"----------\n"
);
}
Expand Down Expand Up @@ -20006,4 +20041,126 @@ public class X {
----------
""");
}
public void testGH4297_1() {
Map options = getCompilerOptions();
options.put(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION, JavaCore.ERROR);
runNegativeTestWithLibs(
new String[] {
"GenericsOrder.java",
"""
import org.eclipse.jdt.annotation.*;

public class GenericsOrder {
public <T extends b & a> void test(@NonNull T my) {
my.method(null);
}

public <T extends I> void test(@NonNull T my) {
my.method(null); // The call goes through here
}

public static void main(String[] args) {
new GenericsOrder().test(String::length); // problem against implicit param 'this'
}
}

interface a { int method(@NonNull String a); }

interface b { int method(String a); }

interface I extends b, a { }
"""

},
options,
"""
----------
1. ERROR in GenericsOrder.java (at line 13)
new GenericsOrder().test(String::length); // problem against implicit param 'this'
^^^^^^^^^^^^^^
Null type safety: parameter 'this' provided via method descriptor b.method(String) needs unchecked conversion to conform to '@NonNull String'
----------
""");
}
public void testGH4297_2() {
runNegativeTestWithLibs(new String[] {
"GenericsOrder.java",
"""
import org.eclipse.jdt.annotation.*;

public class GenericsOrder {
public <T extends b & a> void test(@NonNull T my) {
my.method(null);
}

public <T extends I> void test(@NonNull T my) {
my.method(null); // The call goes through here
}

public static void main(String[] args) {
new GenericsOrder().test(String::length);
}
}

interface a { int method(@NonNull String a); }

interface b { int method(@Nullable String a); }

interface I extends b, a { }
"""

},
"""
----------
1. ERROR in GenericsOrder.java (at line 13)
new GenericsOrder().test(String::length);
^^^^^^^^^^^^^^
Null type mismatch at parameter 'this': required '@NonNull String' but provided '@Nullable String' via method descriptor b.method(String)
----------
""");
}
public void testGH4297_3() {
Map options = getCompilerOptions();
options.put(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION, JavaCore.ERROR);
runNegativeTestWithLibs(
new String[] {
"GenericsOrder.java",
"""
import org.eclipse.jdt.annotation.*;

public class GenericsOrder {
public <T extends b & a> void test(@NonNull T my) {
my.method(null);
}

public <T extends I> void test(@NonNull T my) {
my.method(null); // The call goes through here
}

public static void main(String[] args) {
new GenericsOrder().test(GenericsOrder::mImpl); // problem against regular param 's'
}

public static int mImpl(@NonNull String s) { return 0; }
}

interface a { int method(@NonNull String a); }

interface b { int method(String a); }

interface I extends b, a { }
"""

},
options,
"""
----------
1. ERROR in GenericsOrder.java (at line 13)
new GenericsOrder().test(GenericsOrder::mImpl); // problem against regular param 's'
^^^^^^^^^^^^^^^^^^^^
Null type safety: parameter 1 provided via method descriptor b.method(String) needs unchecked conversion to conform to '@NonNull String'
----------
""");
}

}
9 changes: 0 additions & 9 deletions org.eclipse.jdt.core/.settings/.api_filters
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jdt.core" version="2">
<resource path="dom/org/eclipse/jdt/core/dom/AST.java" type="org.eclipse.jdt.core.dom.AST">
<filter id="388194388">
<message_arguments>
<message_argument value="org.eclipse.jdt.core.dom.AST"/>
<message_argument value="JLS_Latest"/>
<message_argument value="25"/>
</message_arguments>
</filter>
</resource>
<resource path="dom/org/eclipse/jdt/core/dom/AbstractTagElement.java" type="org.eclipse.jdt.core.dom.AbstractTagElement">
<filter id="576725006">
<message_arguments>
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true
Bundle-Version: 3.46.0.qualifier
Bundle-Version: 3.46.100.qualifier
Bundle-Activator: org.eclipse.jdt.core.JavaCore
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<version>4.41.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.46.0-SNAPSHOT</version>
<version>3.46.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<properties>
Expand Down
Loading