From 84daaafd3bb69156d5523c82e1dd8b4c59a5372a Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Sun, 9 Nov 2025 01:14:40 -0500 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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 = From 32e42ad3f672b7ca1d03944a2ffdc802092bcd2c Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Sun, 24 May 2026 12:32:22 -0400 Subject: [PATCH 5/8] Clarify raw type wildcard propagation --- .../type/typeannotator/PropagationTypeAnnotator.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 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 28627ddd275d..00e085d9614e 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 @@ -127,13 +127,10 @@ 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. + // A wildcard type argument of a raw type is already fixed up in visitDeclared. + // Do not scan its bounds here: they are derived from the raw type's declaration + // bounds and cannot usefully propagate annotations back to a type parameter. if (AnnotatedTypes.isTypeArgOfRawType(wildcard)) { - scan(wildcard.getExtendsBound(), null); - scan(wildcard.getSuperBound(), null); return null; } @@ -222,8 +219,7 @@ 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}, or - * null if not found (which can happen with raw types) + * @return the type parameter in {@code declaredType} that corresponds to {@code typeArg} */ private Element getTypeParameterElement( @FindDistinct AnnotatedTypeMirror typeArg, AnnotatedDeclaredType declaredType) { From a63bd2c38de4ea35eb6dd4ead40394ccdf4d9c9c Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Mon, 25 May 2026 11:10:34 -0400 Subject: [PATCH 6/8] Fix changelog punctuation --- docs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e63c1caa22d2..81a20305452f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,7 +11,7 @@ Optional Checker. **Closed issues:** -eisop#792 +eisop#792. Version 3.49.5-eisop1 (April 26, 2026) -------------------------------------- From ffdd7156b8963cc8e540a24f38d58391730dad10 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Mon, 25 May 2026 11:12:51 -0400 Subject: [PATCH 7/8] Clarify raw wildcard propagation comment --- .../type/typeannotator/PropagationTypeAnnotator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 00e085d9614e..b306cad2363f 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 @@ -127,9 +127,10 @@ public Void visitWildcard(AnnotatedWildcardType wildcard, Void aVoid) { } visitedNodes.put(wildcard, null); - // A wildcard type argument of a raw type is already fixed up in visitDeclared. - // Do not scan its bounds here: they are derived from the raw type's declaration - // bounds and cannot usefully propagate annotations back to a type parameter. + // visitDeclared already copies annotations from the declaration to synthetic wildcard type + // arguments of raw types. If this visitor scans those wildcards' bounds, it may visit a + // nested wildcard that is not itself a type argument of the raw parent, so there is no + // corresponding type parameter from which to propagate annotations. if (AnnotatedTypes.isTypeArgOfRawType(wildcard)) { return null; } From fc3b1f633953d28627821f0133c61f2222a964fc Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Wed, 10 Jun 2026 11:24:42 -0400 Subject: [PATCH 8/8] Add all-systems rawtype crash coverage --- framework/tests/all-systems/RawtypeCrash.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 framework/tests/all-systems/RawtypeCrash.java diff --git a/framework/tests/all-systems/RawtypeCrash.java b/framework/tests/all-systems/RawtypeCrash.java new file mode 100644 index 000000000000..03f0412c7202 --- /dev/null +++ b/framework/tests/all-systems/RawtypeCrash.java @@ -0,0 +1,5 @@ +@SuppressWarnings("all") // Raw type use is intentional: this is a no-crash regression test. +public class RawtypeCrash { + RawtypeCrash nullObj = null; + Object obj = ((RawtypeCrash) null).nullObj; +}