Skip to content

Java interface-to-implementation edge synthesis incorrectly matches overloaded methods #2663

Closed

Description

@hxj1225

Java indexing produces incorrect interface-to-implementation edges for overloaded methods. The method signatures in nodes are correct, but the synthesized calls edges connect each interface overload to both implementation overloads.
Example
The following simplified example illustrates the pattern observed in an existing project:
import java.util.List;

interface ExampleService {
    Object putTairValue(String tairKey);

    Object putTairValue(List<String> tairKey, double count);
}
class ExampleServiceImpl implements ExampleService {
    @Override
    public Object putTairValue(String tairKey) {
        return null;
    }

    @Override
    public Object putTairValue(List<String> tairKey, double count) {
        return null;
    }
}

Steps to reproduce

  1. Index a Java project containing the interface and implementation above.
  2. Inspect the method signatures in nodes.
  3. Inspect the synthesized interface-to-implementation edges between these methods.

Actual behavior
In the affected project, the native graph contains all four combinations:

Interface method parameters	Implementation method parameters	Result
String	String	Correct
String	List<String>, double	Incorrect
List<String>, double	String	Incorrect
List<String>, double	List<String>, double	Correct

The incorrect edges have these attributes:

{
  "kind": "calls",
  "provenance": "heuristic"
}

Their metadata includes:

{
  "synthesizedBy": "interface-impl",
  "via": "putTairValue"
}

These are synthesized implementation relationships, not actual calls between the methods.
Expected behavior
Only two interface-to-implementation edges should exist:

ExampleService.putTairValue(String)
  → ExampleServiceImpl.putTairValue(String)

ExampleService.putTairValue(List<String>, double)
  → ExampleServiceImpl.putTairValue(List<String>, double)

Overload matching should consider parameter signatures and Java override rules, rather than method names alone.
Impact
The extra edges introduce false call paths and make downstream call-chain analysis and visualization misleading.
Investigation
The native database already stores distinct, correct parameter signatures for all four method nodes. This points to an issue in interface-to-implementation edge synthesis rather than method extraction.
The observed cross-product suggests name-based matching, although the exact implementation cause still needs confirmation.

Activity

  1. colbymchenry commented on Oct 23, 2026

    @colbymchenry
    Owner

    Thanks for the clear report and the example. You were right that the stored signatures were already correct: the override pass paired overloads by name alone.

    #2820 is merged to main. Each overload of an interface or base-class method now links only to the implementation methods with the same parameters, in Java, Kotlin, C# and Scala, so your two putTairValue overloads each get exactly one edge. On real projects such as guava and hadoop that removed over 3,000 wrong override links, and it restored about 230 correct ones that a per-class limit had been cutting off.

    It ships in the next release; re-index after upgrading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions