typetools / typetools/checker-framework

-AwarnUnneededSuppressions leads to unsuppressable warning from Nullness Checker, when using a compound declaration

Open
#2,586 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
1.1k
Forks
440
Avg merge
1d 12h
Merged PRs (30d)
134

Description

Compile the below file with:
javac -g Issue2586.java -processor nullness -ArequirePrefixInWarningSuppressions -AwarnUnneededSuppressions

There is an error that is not possible to be suppressed. That is, suppressing it leads to an unsuppressable warning.
Methods m1 and m2 show this behavior: both with and without a @SuppressWarnings, the Nullness Checker issues a warning.
There are two ways to rewrite the code to avoid the error:
* by using manifest literals instead of a constant variable (m3), or
* by splitting the compound variable declaration into two declaranions (m5)

Here is the code:

// Compile this file with:
// javac -g Isuse2586.java -processor nullness -ArequirePrefixInWarningSuppressions -AwarnUnneededSuppressions

import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.EnsuresKeyForIf;
import org.checkerframework.checker.nullness.qual.KeyFor;
import org.checkerframework.dataflow.qual.Pure;

public class Issue2586 {

  void m1(Aux aux1, Aux aux2) {
    if (aux1.hasValue(Aux.MINIMUM_VALUE) && aux2.hasValue(Aux.MINIMUM_VALUE)) {
      // error: [keyfor:argument.type.incompatible] incompatible types in argument.
      int minA = aux1.getInt(Aux.MINIMUM_VALUE),
          minB = aux2.getInt(Aux.MINIMUM_VALUE);
    }
  }

  void m2(Aux aux1, Aux aux2) {
    if (aux1.hasValue(Aux.MINIMUM_VALUE) && aux2.hasValue(Aux.MINIMUM_VALUE)) {
      // warning: [nullness:unneeded.suppression] warning suppression "keyfor:argument.type.incompatible" is not used by NullnessChecker
      @SuppressWarnings("keyfor:argument.type.incompatible")
      int minA = aux1.getInt(Aux.MINIMUM_VALUE),
          minB = aux2.getInt(Aux.MINIMUM_VALUE);
    }
  }

  void m3(Aux aux1, Aux aux2) {
    if (aux1.hasValue("minvalue") && aux2.hasValue("minvalue")) {
      @SuppressWarnings("keyfor:argument.type.incompatible")
      int minA = aux1.getInt("minvalue"),
          minB = aux2.getInt("minvalue");
    }
  }

  void m5(Aux aux1, Aux aux2) {
    if (aux1.hasValue(Aux.MINIMUM_VALUE) && aux2.hasValue(Aux.MINIMUM_VALUE)) {
      int minA = aux1.getInt(Aux.MINIMUM_VALUE);
      @SuppressWarnings("keyfor:argument.type.incompatible")
      int minB = aux2.getInt(Aux.MINIMUM_VALUE);
    }
  }
}

class Aux {

  public Map<String, String> map = new HashMap<>();

  public static final String MINIMUM_VALUE = "minvalue";

  @Pure
  @EnsuresKeyForIf(result = true, expression = "#1", map = "map")
  public boolean hasValue(String key) {
    return map.containsKey(key);
  }

  @Pure
  public int getInt(@KeyFor("this.map") String key) {
    return 22;
  }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Issue2586.java reproducer and compile it using the javac command in the report, focusing on the Nullness Checker handling of the compound declarations in m1 and m2. The issue is resolved when the keyfor suppression can suppress the reported incompatibility without producing an unneeded-suppression warning, while the m3 and m5 variants continue to behave consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.