Skip to content

Method.overrides(_) returns false for lambda synthetic methods when the target functional interface is unresolved (buildMode: none) #22085

Description

@jesuistombe

Summary

When a CodeQL Java database is built with buildMode: none and a lambda expression targets a method from a third-party library not on the classpath, the lambda's synthetic public method is not modelled as overriding the functional interface's abstract method. m.overrides(_) returns false for it, making it an unexpected match for any query that uses not m.overrides(_) to exclude interface implementations.


Environment

  • CodeQL CLI: 2.25.6
  • Language: Java
  • Build mode: none

Minimal reproduction

Directory layout:

lambda-override-bug/
├── qlpack.yml
├── LambdaNotOverride.ql
├── src/
│   └── Example.java          ← source root for CodeQL
└── stub/
    └── com/example/
        └── ThirdParty.java   ← only needed for the control case

Note: The stub must be outside src/ so that buildMode:none does not extract it. If it were inside src/, CodeQL would resolve com.example.ThirdParty from source and the bug would not reproduce.

qlpack.yml

name: lambda-bug-repro
version: 0.0.1
dependencies:
  codeql/java-all: "*"

src/Example.java

class Example {
    // Lambda targeting an unresolved third-party type.
    void useThirdParty(com.example.ThirdParty obj) {
        obj.onSuccess(result -> System.out.println(result));
    }

    // Lambda targeting a JDK type (always resolved — control).
    void useJdk() {
        java.util.stream.Stream.of("x").filter(s -> !s.isEmpty());
    }
}

stub/com/example/ThirdParty.java

package com.example;
import java.util.function.Consumer;

public class ThirdParty {
    public void onSuccess(Consumer<String> consumer) {}
}

LambdaNotOverride.ql

import java

from Method m
where
  m.fromSource() and
  m.isPublic() and
  m.getDeclaringType() instanceof AnonymousClass and
  not m.overrides(_)
select m, "Lambda synthetic method not modelled as override: " + m.getDeclaringType()

Steps to reproduce

cd lambda-override-bug
codeql pack install

# Bug: build without the stub (com.example.ThirdParty is unresolved)
codeql database create db-none --language=java --build-mode=none --source-root=src --overwrite
codeql query run --database db-none -- LambdaNotOverride.ql
# → 1 result: the lambda in useThirdParty() is returned

# Control: compile with the stub so ThirdParty resolves correctly
javac stub/com/example/ThirdParty.java -d stub-classes
mkdir -p classes
codeql database create db-compiled \
  --language=java \
  --command="javac -cp $(pwd)/stub-classes $(pwd)/src/Example.java -d $(pwd)/classes" \
  --source-root=src --overwrite
codeql query run --database db-compiled -- LambdaNotOverride.ql
# → 0 results

Actual vs expected behaviour

Scenario useThirdParty lambda overrides(_) useJdk lambda overrides(_)
buildMode:none, ThirdParty unresolved false true
Compiled, ThirdParty resolved via stub true true

When the functional interface type cannot be resolved, CodeQL creates an anonymous class extending <TypeAccess of ErrorType>. With no known parent type, no override link is established and the synthetic public method leaks through guards like not m.overrides(_).


Impact

Any query that uses not m.overrides(_) to restrict results to non-overriding methods will produce false positives on lambda expressions in buildMode:none databases containing calls into third-party libraries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    awaiting-responseThe CodeQL team is awaiting further input or clarification from the original reporter of this issue.questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions