Skip to content

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Aug 31, 2025

This PR fixes a bug in the Control Flow Graph (CFG) generation that prevented the Checker Framework from reporting unboxing NPE warnings for array access expressions like int x = nullableIntegerArray[0].

Problem

The issue was in CFGTranslationPhaseOne.visitArrayAccess() which incorrectly added the same ArrayAccessNode three times to the CFG:

  1. extendWithNode(arrayAccess) - as a regular node
  2. extendWithNodeWithException(arrayAccess, arrayIndexOutOfBoundsExceptionType) - with AIOOBE
  3. extendWithNodeWithException(arrayAccess, nullPointerExceptionType) - with NPE

When translateAssignment() later inserted unboxing nodes (like .intValue() calls), they were placed after the first occurrence. This caused the extra copies of array[0] to appear after the unboxing operation in the CFG, making the checker incorrectly conclude that array[0] was non-null.

Example

void f(@Nullable Integer[] array) { 
    int x = array[0]; // Should warn about unboxing.of.nullable but didn't
}

Before this fix, the CFG looked like:

  • RegularBlock([x, array, 0, array[0]])
  • ExceptionBlock(array[0].intValue) - NullPointerException
  • ExceptionBlock(array[0].intValue()) - RuntimeException+Error
  • ExceptionBlock(array[0]) - ArrayIndexOutOfBoundsException ← Extra copy after unboxing
  • ExceptionBlock(array[0]) - NullPointerException ← Extra copy after unboxing
  • RegularBlock([x = array[0].intValue()])

Solution

The fix uses extendWithNodeWithExceptions() (plural) with a set containing both exception types instead of multiple separate calls:

Set<TypeMirror> exceptions = new HashSet<>();
exceptions.add(arrayIndexOutOfBoundsExceptionType);
exceptions.add(nullPointerExceptionType);
extendWithNodeWithExceptions(arrayAccess, exceptions);

This creates a single CFG node with proper exception handling, allowing unboxing warnings to be generated correctly.

Additional Fixes

Similar node duplication issues were fixed in:

  • visitCompoundAssignment() for integer division/remainder operations
  • visitBinary() for integer division/remainder operations

These operations were incorrectly calling both extendWithNodeWithException() for arithmetic exceptions and then extendWithNode() at the end of the method.

Fixes #7229.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • central.sonatype.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx2g -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-9.0.0-bin/d6wjpkvcgsg3oed0qlfss3wgl/gradle-9.0.0/lib/gradle-daemon-main-9.0.0.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-9.0.0-bin/d6wjpkvcgsg3oed0qlfss3wgl/gradle-9.0.0/lib/agents/gradle-instrumentation-agent-9.0.0.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 9.0.0 (dns block)
  • groovy.jfrog.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx2g -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-9.0.0-bin/d6wjpkvcgsg3oed0qlfss3wgl/gradle-9.0.0/lib/gradle-daemon-main-9.0.0.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-9.0.0-bin/d6wjpkvcgsg3oed0qlfss3wgl/gradle-9.0.0/lib/agents/gradle-instrumentation-agent-9.0.0.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 9.0.0 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Copilot Copilot AI self-assigned this Aug 31, 2025
Copy link
Author

Copilot AI commented Aug 31, 2025

@mernst 👋 This repository doesn't have Copilot instructions. With Copilot instructions, I can understand the repository better, work faster and produce higher quality PRs.

I can generate a .github/copilot-instructions.md file for you automatically. Click here to open a pre-filled issue and assign it to me. I'll write the instructions, and then tag you for review.

@mernst mernst closed this Aug 31, 2025
@Copilot Copilot AI changed the title [WIP] No unboxing warning for int x = integerArray[0] due to bad CFG Fix CFG node duplication causing missing unboxing NPE warnings Aug 31, 2025
@Copilot Copilot AI requested a review from mernst August 31, 2025 09:12
Copilot finished work on behalf of mernst August 31, 2025 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No unboxing warning for int x = integerArray[0] due to bad CFG
2 participants