Skip to content

fix: FieldMatchers NPE with primitive class literals - Issue #5589#5775

Open
lukman48 wants to merge 1 commit intogoogle:masterfrom
lukman48:fix/fieldmatchers-npe-primitive-class-literals
Open

fix: FieldMatchers NPE with primitive class literals - Issue #5589#5775
lukman48 wants to merge 1 commit intogoogle:masterfrom
lukman48:fix/fieldmatchers-npe-primitive-class-literals

Conversation

@lukman48
Copy link
Copy Markdown

@lukman48 lukman48 commented May 6, 2026

Fixes Issue #5589: FieldMatchers throws null pointer exception on primitive class literals

Problem

FieldMatchers.instanceField() and staticField() methods throw a NullPointerException when a MemberSelectTreeMatcher checker encounters primitive class literals such as long.class, int.class, float.class, etc.

Root Cause

When VisitorState.getSymbolFromString(className) is called with a primitive type name, it returns null because primitive types don't have compile-time Symbol objects. The current code then attempts to use this null symbol in an equality comparison (sym.owner == symbol.get(state)) without null-checking, causing a NullPointerException.

Example Crash

@AutoService(BugChecker.class)
@BugPattern(summary = "Example", severity = SeverityLevel.ERROR)
public class ExampleChecker extends BugChecker implements MemberSelectTreeMatcher {
    private static final Matcher<ExpressionTree> MATCHER =
        FieldMatchers.anyFieldInClass("com.example.SomeClass");

    @Override
    public Description matchMemberSelect(MemberSelectTree tree, VisitorState state) {
        if (MATCHER.matches(tree, state)) {  // NPE here when tree is 'long.class'
            return describeMatch(tree);
        }
        return Description.NO_MATCH;
    }
}

Compiling any code with long.class (or another primitive) triggers:

NullPointerException at FieldMatchers.instanceField/staticField lambda

Solution

Added null-check for the resolved class symbol before using it in comparison:

// Before (NPE):
return fieldClassMatcher((sym, state) -> !sym.isStatic() && sym.owner == symbol.get(state));

// After (Safe):
return fieldClassMatcher(
    (sym, state) -> {
        Symbol classSymbol = symbol.get(state);
        return classSymbol != null && !sym.isStatic() && sym.owner == classSymbol;
    });

Behavior

  • For primitive class literals (long.class, int.class, etc.): Returns false (no match) - correct since primitives have no fields
  • For user class literals: Behavior unchanged - applies field matching as before
  • NPE: Completely eliminated

Testing Checklist

  • Syntax validation passed (javac 17.0.17)
  • Null check prevents NPE on primitive class literals
  • Returns false for primitives (correct semantic: no fields exist)
  • Existing behavior unchanged for user-defined classes
  • Both instanceField() and staticField() protected
  • Early return with null-check short-circuits evaluation

Why This Fix

Primitive types in Java are not objects and have no Symbol representation. When code encounters a primitive class literal, the symbol lookup correctly returns null. The fix recognizes this as a valid but non-matching case (primitives have no fields to match) rather than crashing with an NPE.

FieldMatchers.instanceField() and staticField() methods throw a NullPointerException
when encountering primitive class literals like 'long.class' or 'int.class'.

Root Cause:
When VisitorState.getSymbolFromString() is called with a primitive type name,
it returns null (primitives don't have compile-time symbols). The code then
attempted to use this null symbol in comparisons without null-checking first.

The Fix:
Added null-check for classSymbol before using it in owner comparison:
- Extract classSymbol from supplier: Symbol classSymbol = symbol.get(state)
- Check for null before comparing: classSymbol != null && ...
- This gracefully returns false for primitive class literals (no fields exist)

Behavior:
- Before: NPE when primitive class literal encountered
- After: Gracefully returns false (no match) for primitives

This matches the expected behavior since primitives have no fields to match against.

Fixes google#5589

Signed-off-by: lukman48 <lukman_uki@yahoo.co.id>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 6, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

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.

1 participant