Skip to content

PHP extractor misses scoped_call_expression (static method calls) #232

Description

@erhanurgun

Summary

The PHP extractor wires up function_call_expression and member_call_expression into calls edges, but it never visits scoped_call_expression. That means static method calls like Helper::format() or Foo::make() do not produce any graph edges, so code that relies on helper classes or static factories shows up with weaker coupling than it actually has.

Current behavior

Minimal reproducer:

<?php

namespace App\Support;

class StringHelper
{
    public static function slugify(string $text): string
    {
        return strtolower($text);
    }
}

class SlugGenerator
{
    public function make(string $title): string
    {
        return StringHelper::slugify($title);
    }
}

Running extract_php() on this file returns both classes, the static method and the non-static method, and the usual contains and method edges. No edge connects SlugGenerator or its .make() method to StringHelper, even though the body of make() obviously uses it.

Expected behavior

The calling function or method should be linked to the class that owns the static method, with a relation label that keeps it distinct from instance-level calls. For example uses_static makes the intent obvious without polluting calls, which currently means "invoked a callable through () or ->".

Proposed solution

Extend LanguageConfig with an optional static_call_types frozenset and populate it in _PHP_CONFIG with scoped_call_expression. In the walk_calls dispatcher, handle the new node type by reading its class reference (via the scope field with a positional name fallback, since tree-sitter-php has exposed the class name under different field names across versions) and adding a uses_static edge when the class resolves in label_to_nid.

The change is additive. Languages that do not set static_call_types see no behavioral difference. I already have a ready patch with tests.

Notes

This is one of a small family of missing-edge issues in the PHP extractor. A separate issue (and PR) exists for class_constant_access_expression, and I am planning one more for scoped_property_access_expression. They all share the same shape, so the fixes are self-contained and reviewable in isolation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions