From 6be0dfe67a7661b2cfc81852df75633b8f355e16 Mon Sep 17 00:00:00 2001 From: Lucien Bart Date: Mon, 20 Apr 2026 09:49:19 +0200 Subject: [PATCH 1/2] Check for null and first draft of tests --- .../main/java/org/sonar/java/model/JType.java | 12 +++++- .../java/org/sonar/java/model/JTypeTest.java | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/java-frontend/src/main/java/org/sonar/java/model/JType.java b/java-frontend/src/main/java/org/sonar/java/model/JType.java index f151d863991..ee13c72eebe 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JType.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JType.java @@ -137,7 +137,11 @@ public Type primitiveWrapperType() { if (name == null) { return null; } - primitiveWrapperType = sema.type(sema.resolveType(name)); + ITypeBinding resolvedType = sema.resolveType(name); + if (resolvedType == null) { + return null; + } + primitiveWrapperType = sema.type(resolvedType); } return primitiveWrapperType; } @@ -150,7 +154,11 @@ public Type primitiveType() { if (name == null) { return null; } - primitiveType = sema.type(sema.resolveType(name)); + ITypeBinding resolvedType = sema.resolveType(name); + if (resolvedType == null) { + return null; + } + primitiveType = sema.type(resolvedType); } return primitiveType; } diff --git a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java index 2ea2252d265..df95e5e204f 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java @@ -145,6 +145,43 @@ void primitiveType(){ assertThat(byteType.primitiveType()).isNotEqualTo(type("boolean")); } + @Test + void primitiveWrapperType_returns_null_when_semantic_cannot_resolve_wrapper_type() { + ITypeBinding primitiveBinding =sema.resolveType("byte"); + JSema semaThatCannotResolveWrapperType = spy(sema); + when(semaThatCannotResolveWrapperType.resolveType("java.lang.Byte")).thenReturn(null); + + JType primitiveType = new JType(semaThatCannotResolveWrapperType, primitiveBinding); + + assertThat(primitiveType.primitiveWrapperType()).isNull(); + } + + @Test + void primitiveType_returns_null_when_semantic_cannot_resolve_primitive_type() { + ITypeBinding wrapperBinding = sema.resolveType("java.lang.Byte"); + JSema semaThatCannotResolvePrimitiveType = spy(sema); + when(semaThatCannotResolvePrimitiveType.resolveType("byte")).thenReturn(null); + + JType wrapperType = new JType(semaThatCannotResolvePrimitiveType, wrapperBinding); + + assertThat(wrapperType.primitiveType()).isNull(); + } + + @Test + void primitive_conversions_return_null_without_mocking_when_semantic_cannot_resolve_types() { + JSema semaWithoutBindingResolution = new JSema(AST.newAST(AST.getJLSLatest())); + ITypeBinding primitiveBinding = sema.resolveType("byte"); + ITypeBinding wrapperBinding = sema.resolveType("java.lang.Byte"); + + JType primitiveType = new JType(semaWithoutBindingResolution, primitiveBinding); + JType wrapperType = new JType(semaWithoutBindingResolution, wrapperBinding); + + assertAll( + () -> assertThat(primitiveType.primitiveWrapperType()).isNull(), + () -> assertThat(wrapperType.primitiveType()).isNull() + ); + } + @Test void declaringType(){ Type byteType = type("java.lang.Byte"); From 5d915ffeceb50f0c9afe77f789fda6889f6e8691 Mon Sep 17 00:00:00 2001 From: Gabriel Fleischer Date: Mon, 20 Apr 2026 13:30:04 +0200 Subject: [PATCH 2/2] Finalize tests --- .../java/org/sonar/java/model/JTypeTest.java | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java index df95e5e204f..1d8e96d60fb 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java @@ -146,40 +146,47 @@ void primitiveType(){ } @Test - void primitiveWrapperType_returns_null_when_semantic_cannot_resolve_wrapper_type() { - ITypeBinding primitiveBinding =sema.resolveType("byte"); - JSema semaThatCannotResolveWrapperType = spy(sema); - when(semaThatCannotResolveWrapperType.resolveType("java.lang.Byte")).thenReturn(null); + void primitiveWrapperType(){ + Type booleanType = type("boolean"); + assertThat(booleanType.primitiveWrapperType()).isEqualTo(type("java.lang.Boolean")); + assertThat(booleanType.primitiveWrapperType()).isNotEqualTo(type("java.lang.Byte")); + } - JType primitiveType = new JType(semaThatCannotResolveWrapperType, primitiveBinding); + @Test + void non_primitive_type_has_no_primitive() { + Type stringType = type("java.lang.String"); + assertThat(stringType.primitiveType()).isNull(); + } - assertThat(primitiveType.primitiveWrapperType()).isNull(); + @Test + void non_primitive_wrapper_tpe_has_no_primitive_wrapper() { + Type stringType = type("java.lang.String"); + assertThat(stringType.primitiveWrapperType()).isNull(); } @Test - void primitiveType_returns_null_when_semantic_cannot_resolve_primitive_type() { - ITypeBinding wrapperBinding = sema.resolveType("java.lang.Byte"); - JSema semaThatCannotResolvePrimitiveType = spy(sema); - when(semaThatCannotResolvePrimitiveType.resolveType("byte")).thenReturn(null); + void primitiveWrapperType_returns_null_when_semantic_cannot_resolve_wrapper_type() { + // Sema that can resolve primitives, but fails to resolve wrapper types, which can happen when the classpath is not correctly set up + var brokenSema = spy(sema); + when(brokenSema.resolveType("java.lang.Byte")).thenReturn(null); - JType wrapperType = new JType(semaThatCannotResolvePrimitiveType, wrapperBinding); + var primitiveBinding = sema.resolveType("byte"); + var primitiveType = new JType(brokenSema, primitiveBinding); - assertThat(wrapperType.primitiveType()).isNull(); + assertThat(primitiveType.primitiveWrapperType()).isNull(); } @Test - void primitive_conversions_return_null_without_mocking_when_semantic_cannot_resolve_types() { - JSema semaWithoutBindingResolution = new JSema(AST.newAST(AST.getJLSLatest())); - ITypeBinding primitiveBinding = sema.resolveType("byte"); - ITypeBinding wrapperBinding = sema.resolveType("java.lang.Byte"); + void primitiveType_returns_null_when_semantic_cannot_resolve_primitive_type() { + // Sema that can resolve wrapper types, but fails to resolve a primitive, this should never happen in practice, + // but we want to make sure it doesn't throw an exception and returns null instead + var brokenSema = spy(sema); + when(brokenSema.resolveType("byte")).thenReturn(null); - JType primitiveType = new JType(semaWithoutBindingResolution, primitiveBinding); - JType wrapperType = new JType(semaWithoutBindingResolution, wrapperBinding); + var wrapperBinding = sema.resolveType("java.lang.Byte"); + var wrapperType = new JType(brokenSema, wrapperBinding); - assertAll( - () -> assertThat(primitiveType.primitiveWrapperType()).isNull(), - () -> assertThat(wrapperType.primitiveType()).isNull() - ); + assertThat(wrapperType.primitiveType()).isNull(); } @Test @@ -203,7 +210,7 @@ void isNumerical() { } @ParameterizedTest - @MethodSource("names") + @MethodSource("fullyQualifiedNamesToNames") void names(String expectedFullyQualifiedName, String expectedName) { assertThat(type(expectedFullyQualifiedName)) .is(expectedFullyQualifiedName) @@ -211,7 +218,7 @@ void names(String expectedFullyQualifiedName, String expectedName) { .hasToString(expectedName); } - private static Stream names() { + private static Stream fullyQualifiedNamesToNames() { return Stream.of( Arguments.of("int", "int"), Arguments.of("int[][]", "int[][]"),