typetools / typetools/checker-framework

Utilize `RegexChecker`'s `group.count.invalid` check in `NullnessChecker`

Open
#4,006 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Consider the following dummy code:

$ cat -n Dummy.java 
     1	import java.util.regex.Matcher;
     2	import java.util.regex.Pattern;
     3	import org.checkerframework.checker.nullness.qual.NonNull;
     4	
     5	final class Dummy {
     6	  private static final Pattern PATTERN = Pattern.compile("^.(.*).$");
     7	
     8	  String doSomethingOdd(String input) {
     9	    Matcher matcher = PATTERN.matcher(input);
    10	    if (!matcher.matches()) {
    11	      return "";
    12	    }
    13	
    14	    @NonNull String a = matcher.group(1);
    15	    @NonNull String b = matcher.group(2);
    16	    return a + b;
    17	  }
    18	}

Compiling this code using both the NullnessChecker and RegexChecker we get the following output:

$ javac \
    -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
    -processorpath ~/.m2/repository/org/checkerframework/checker/3.8.0/checker-3.8.0.jar \
    -cp ~/.m2/repository/org/checkerframework/checker-qual
/3.8.0/checker-qual-3.8.0.jar \
    -Awarns \
    -processor org.checkerframework.checker.nullness.NullnessChecker,org.checkerframework.checker.regex.RegexChecker \
    Dummy.java
Dummy.java:14: warning: [assignment.type.incompatible] incompatible types in assignment.
    @NonNull String a = matcher.group(1);
                                     ^
  found   : @Initialized @Nullable String
  required: @UnknownInitialization @NonNull String
Dummy.java:15: warning: [assignment.type.incompatible] incompatible types in assignment.
    @NonNull String b = matcher.group(2);
                                     ^
  found   : @Initialized @Nullable String
  required: @UnknownInitialization @NonNull String
Dummy.java:15: warning: [group.count.invalid] invalid groups parameter 2. Only 1 groups are guaranteed to exist for matcher.
    @NonNull String b = matcher.group(2);
                                      ^
3 warnings

As can be seen, the RegexChecker is smart enough to realize that matcher.group(1) is safe, while matcher.group(2) is not. On the other hand, the NullnessChecker flags also matcher.group(1) as problematic, while this call will not yield null.

Which leads me to the feature request: would be be possible to "somehow" share the RegexChecker analysis such that the NullnessChecker does not produce this false positive?

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 NullnessChecker and RegexChecker entry points, then trace how matcher.group(1) and matcher.group(2) are analyzed when both checkers run. Determine how the RegexChecker's group-count information could be shared without weakening the existing group.count.invalid diagnostic; done means group(1) no longer produces the nullness warning while group(2) remains rejected.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.