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.
Summary
The PHP extractor wires up
function_call_expressionandmember_call_expressionintocallsedges, but it never visitsscoped_call_expression. That means static method calls likeHelper::format()orFoo::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:
Running
extract_php()on this file returns both classes, the static method and the non-static method, and the usualcontainsandmethodedges. No edge connectsSlugGeneratoror its.make()method toStringHelper, even though the body ofmake()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 exampleuses_staticmakes the intent obvious without pollutingcalls, which currently means "invoked a callable through()or->".Proposed solution
Extend
LanguageConfigwith an optionalstatic_call_typesfrozenset and populate it in_PHP_CONFIGwithscoped_call_expression. In thewalk_callsdispatcher, handle the new node type by reading its class reference (via thescopefield with a positional name fallback, since tree-sitter-php has exposed the class name under different field names across versions) and adding auses_staticedge when the class resolves inlabel_to_nid.The change is additive. Languages that do not set
static_call_typessee 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 forscoped_property_access_expression. They all share the same shape, so the fixes are self-contained and reviewable in isolation.