From 84daaafd3bb69156d5523c82e1dd8b4c59a5372a Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Sun, 9 Nov 2025 01:14:40 -0500 Subject: [PATCH 1/4] Add example to show the crash --- framework/tests/viewpointtest/RawtypeCrash.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 framework/tests/viewpointtest/RawtypeCrash.java diff --git a/framework/tests/viewpointtest/RawtypeCrash.java b/framework/tests/viewpointtest/RawtypeCrash.java new file mode 100644 index 000000000000..e095fe0a69fb --- /dev/null +++ b/framework/tests/viewpointtest/RawtypeCrash.java @@ -0,0 +1,4 @@ +public class RawtypeCrash { + RawtypeCrash nullObj = null; + Object obj = ((RawtypeCrash) null).nullObj; +} From 2a374b5257ec1a5af62c7e2d7bb016097e3db8e0 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Sun, 9 Nov 2025 01:16:24 -0500 Subject: [PATCH 2/4] Add fix --- .../type/typeannotator/PropagationTypeAnnotator.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java index b432c3ae96b7..ea8dbfe5b0ef 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java +++ b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java @@ -1,6 +1,7 @@ package org.checkerframework.framework.type.typeannotator; import org.checkerframework.checker.interning.qual.FindDistinct; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; @@ -212,9 +213,10 @@ private void applyAnnosFromBound( * * @param typeArg a typeArg of {@code declaredType} * @param declaredType the type in which {@code typeArg} is a type argument - * @return the type parameter in {@code declaredType} that corresponds to {@code typeArg} + * @return the type parameter in {@code declaredType} that corresponds to {@code typeArg}, or + * null if not found (which can happen with raw types) */ - private Element getTypeParameterElement( + private @Nullable Element getTypeParameterElement( @FindDistinct AnnotatedTypeMirror typeArg, AnnotatedDeclaredType declaredType) { for (int i = 0; i < declaredType.getTypeArguments().size(); i++) { if (declaredType.getTypeArguments().get(i) == typeArg) { @@ -223,6 +225,10 @@ private Element getTypeParameterElement( return typeElement.getTypeParameters().get(i); } } + // For raw types, return null instead of throwing an exception + if (declaredType.isUnderlyingTypeRaw()) { + return null; + } throw new BugInCF("Wildcard %s is not a type argument of %s", typeArg, declaredType); } } From e161f8ed7a4e006a5348be8877bb5e222c8ce265 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Sun, 9 Nov 2025 09:56:58 -0500 Subject: [PATCH 3/4] Optimize logic and update changelog --- docs/CHANGELOG.md | 2 +- .../type/typeannotator/PropagationTypeAnnotator.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3b0ab018c221..c6aad4441168 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -40,7 +40,7 @@ The Nullness Checker now recognizes references to private, final fields with zer **Closed issues:** -eisop#1247, eisop#1263, eisop#1310, typetools#7096. +eisop#792, eisop#1247, eisop#1263, eisop#1310, typetools#7096. Version 3.49.5 (June 30, 2025) diff --git a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java index ea8dbfe5b0ef..0ad793365e1f 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java +++ b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java @@ -218,6 +218,10 @@ private void applyAnnosFromBound( */ private @Nullable Element getTypeParameterElement( @FindDistinct AnnotatedTypeMirror typeArg, AnnotatedDeclaredType declaredType) { + // For raw types, return null instead of throwing an exception + if (declaredType.isUnderlyingTypeRaw()) { + return null; + } for (int i = 0; i < declaredType.getTypeArguments().size(); i++) { if (declaredType.getTypeArguments().get(i) == typeArg) { TypeElement typeElement = @@ -225,10 +229,6 @@ private void applyAnnosFromBound( return typeElement.getTypeParameters().get(i); } } - // For raw types, return null instead of throwing an exception - if (declaredType.isUnderlyingTypeRaw()) { - return null; - } throw new BugInCF("Wildcard %s is not a type argument of %s", typeArg, declaredType); } } From 4a7f36165edd36bcee7d887030b50cc13c3d101e Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Mon, 23 Mar 2026 14:35:10 -0400 Subject: [PATCH 4/4] Try new approach --- .../typeannotator/PropagationTypeAnnotator.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java index 0ad793365e1f..0d3f2af506a7 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java +++ b/framework/src/main/java/org/checkerframework/framework/type/typeannotator/PropagationTypeAnnotator.java @@ -1,7 +1,6 @@ package org.checkerframework.framework.type.typeannotator; import org.checkerframework.checker.interning.qual.FindDistinct; -import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; @@ -128,6 +127,16 @@ public Void visitWildcard(AnnotatedWildcardType wildcard, Void aVoid) { } visitedNodes.put(wildcard, null); + // Raw wildcard args are already fixed up in visitDeclared. + // Recursive traversal through scan(wildcard.getExtendsBound(), ...) can + // re-enter visitWildcard with a synthesized raw wildcard object that is + // not identity-equal to the parent type argument wildcard. + if (AnnotatedTypes.isTypeArgOfRawType(wildcard)) { + scan(wildcard.getExtendsBound(), null); + scan(wildcard.getSuperBound(), null); + return null; + } + Element typeParamElement = TypesUtils.wildcardToTypeParam(wildcard.getUnderlyingType()); if (typeParamElement == null && !parents.isEmpty()) { typeParamElement = getTypeParameterElement(wildcard, parents.peekFirst()); @@ -216,12 +225,8 @@ private void applyAnnosFromBound( * @return the type parameter in {@code declaredType} that corresponds to {@code typeArg}, or * null if not found (which can happen with raw types) */ - private @Nullable Element getTypeParameterElement( + private Element getTypeParameterElement( @FindDistinct AnnotatedTypeMirror typeArg, AnnotatedDeclaredType declaredType) { - // For raw types, return null instead of throwing an exception - if (declaredType.isUnderlyingTypeRaw()) { - return null; - } for (int i = 0; i < declaredType.getTypeArguments().size(); i++) { if (declaredType.getTypeArguments().get(i) == typeArg) { TypeElement typeElement =