Skip to content

Java: a call on a receiver whose declared type is outside the repo binds to a same-named method on the enclosing class (self-edges included) #1961

Description

@inth3shadows

On main (ba3c21e), when a Java call's receiver has a declared type outside the repo and several same-named methods exist in the repo, request.getHeaders() resolves by name to AhcWSRequest::getHeaders. The declared type (StandaloneAhcWSRequest) is ignored.

import play.libs.ws.ahc.StandaloneAhcWSRequest;
public class AhcWSRequest {
  private StandaloneAhcWSRequest request;
  public Map<String,String> getHeaders() { return request.getHeaders(); }                         // L5
  public Map<String,String> getHeadersParam(StandaloneAhcWSRequest request) { return request.getHeaders(); } // L8
}
// plus: class Other { Map<String,String> getHeaders() {...} }

Stored calls edges (all resolvedBy: instance-method):

AhcWSRequest::getHeaders      → AhcWSRequest::getHeaders   L5  (self-edge)
AhcWSRequest::getHeadersParam → AhcWSRequest::getHeaders   L8

Neither call is in the source: both receivers are StandaloneAhcWSRequest, which the repo doesn't define. var locals and this.request behave the same way. (codegraph callees getHeaders hides the self-edge, so it only shows up in the database.)

Cause: in matchMethodCall, Strategy 3 (src/resolution/name-matcher.ts) scores same-named methods by word overlap between the receiver name and the candidate's qualified name. request overlaps AhcWSRequest, and the same-language bonus brings the score to 2, which meets the threshold. It has no check against the caller itself (unlike the n.id !== ref.fromNodeId filters elsewhere in the file), and it doesn't consult a declared receiver type that names something outside the repo.

Suggested fix: exclude ref.fromNodeId from Strategy 3's candidates. Separately, when the receiver's declared type is known and isn't a project type, decline instead of name-matching. The first is a one-line guard. The second is the real fix for the false edges.

Found by @danusha2345 while verifying #1935 on playframework (AhcWSRequest.getHeaders). The same behavior is on main, so #1935 doesn't introduce it.

Activity

  1. danusha2345 commented on Sep 26, 2026

    @danusha2345
    Contributor

    #1942 covers this. It types Java receivers from their declared field, parameter and local (var) types, and when that type isn't a project type the call gets no edge instead of a name match. #1939 separately keeps a delegating call off its own enclosing method.

    Checked on the fixture from this issue (AhcWSRequest with a field, a parameter and a var local of type StandaloneAhcWSRequest, plus Other.getHeaders):

    build calls edges
    main (d0996a2) AhcWSRequest::getHeaders → AhcWSRequest::getHeaders (L5, self-edge), AhcWSRequest::getHeadersParam → AhcWSRequest::getHeaders (L6)
    #1939 only the L6 edge remains
    #1942 (35a787b) none
  2. inth3shadows commented on Sep 26, 2026

    @inth3shadows
    ContributorAuthor

    Thanks @danusha2345, I missed #1942 and #1939 when I filed this; my duplicate check only looked at issues.

    Confirmed on #1942's head (35a787b) with the fixture above, plus a this.request variant:

    build calls edges
    without #1942 getHeaders → getHeaders (L5, self-edge), getHeadersThis → getHeaders (L6), getHeadersParam → getHeaders (L8)
    #1942 (35a787b) none

    Closing as a duplicate of #1942.

  3. inth3shadows commented on Sep 27, 2026

    @inth3shadows
    ContributorAuthor

    Closing as a duplicate of #1942, which fixes this and is the preferred fix.

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