5757//! 3. Register both in `ParserFactory`
5858//! 4. (Future) Register in the language registry for auto-discovery
5959
60- use crate :: parsing:: MethodCall ;
6160use crate :: parsing:: paths:: { strip_extension, strip_source_root} ;
6261use crate :: parsing:: resolution:: {
6362 GenericInheritanceResolver , GenericResolutionContext , ImportBinding , ImportOrigin ,
6463 InheritanceResolver , PipelineSymbolCache , ResolutionScope , ScopeLevel ,
6564} ;
6665use crate :: relationship:: RelationKind ;
67- use crate :: storage:: DocumentIndex ;
6866use crate :: { FileId , Symbol , SymbolId , SymbolKind , Visibility } ;
69- use std:: collections:: HashMap ;
7067use std:: path:: { Path , PathBuf } ;
7168use tree_sitter:: Language ;
7269
@@ -330,8 +327,8 @@ pub trait LanguageBehavior: Send + Sync {
330327 None
331328 }
332329
333- /// Receiver tokens that route an instance call to the Self-call arm of
334- /// `resolve_method_call` .
330+ /// Receiver tokens the resolve stage treats as the calling instance
331+ /// (self-form receivers pass the receiver gate without type inference) .
335332 ///
336333 /// Default `&["self"]` matches Rust/Python/Swift. Per-language overrides:
337334 /// PHP `&["$this"]`, Python `&["self", "cls"]`, JS/TS/Java/Kotlin/C++ `&["this"]`.
@@ -354,164 +351,6 @@ pub trait LanguageBehavior: Send + Sync {
354351 None
355352 }
356353
357- /// Resolve an instance method call to its symbol ID
358- ///
359- /// Given a type name and method name, find the symbol ID for the method.
360- /// Uses the resolution context for import-aware type lookup, then queries
361- /// the Defines relationship to find the method.
362- ///
363- /// # Arguments
364- /// * `type_name` - The resolved type name (e.g., "Calculator")
365- /// * `method_name` - The method being called (e.g., "add")
366- /// * `context` - Resolution context with import information
367- /// * `document_index` - For querying relationships
368- ///
369- /// # Returns
370- /// The SymbolId of the method if found, None otherwise
371- fn resolve_instance_method (
372- & self ,
373- type_name : & str ,
374- method_name : & str ,
375- context : & dyn ResolutionScope ,
376- document_index : & DocumentIndex ,
377- ) -> Option < SymbolId > {
378- // Step 1: Resolve type using context (import-aware)
379- let type_id = match context. resolve ( type_name) {
380- Some ( id) => {
381- tracing:: debug!( "[resolve_instance_method] resolved type '{type_name}' to {id:?}" ) ;
382- id
383- }
384- None => {
385- tracing:: debug!( "[resolve_instance_method] failed to resolve type '{type_name}'" ) ;
386- return None ;
387- }
388- } ;
389-
390- // Step 2: Find method via Defines relationship from that specific type
391- let defined_symbols =
392- match document_index. get_relationships_from ( type_id, RelationKind :: Defines ) {
393- Ok ( rels) => {
394- tracing:: debug!(
395- "[resolve_instance_method] found {} Defines relationships from {type_id:?}" ,
396- rels. len( )
397- ) ;
398- rels
399- }
400- Err ( e) => {
401- tracing:: debug!(
402- "[resolve_instance_method] error getting Defines from {type_id:?}: {e}"
403- ) ;
404- return None ;
405- }
406- } ;
407-
408- // Step 3: Find the method with matching name
409- for ( _, to_id, _) in defined_symbols {
410- if let Ok ( Some ( symbol) ) = document_index. find_symbol_by_id ( to_id) {
411- tracing:: debug!(
412- "[resolve_instance_method] checking defined symbol: '{}' vs '{method_name}'" ,
413- symbol. name. as_ref( )
414- ) ;
415- if symbol. name . as_ref ( ) == method_name {
416- tracing:: debug!(
417- "[resolve_instance_method] found method '{method_name}' at {to_id:?}"
418- ) ;
419- return Some ( to_id) ;
420- }
421- }
422- }
423-
424- tracing:: debug!(
425- "[resolve_instance_method] method '{method_name}' not found in type '{type_name}'"
426- ) ;
427- None
428- }
429-
430- /// Resolve a method call to its symbol ID
431- ///
432- /// This is the unified API for resolving all types of method calls:
433- /// - Static calls: `Type::method()` - resolved via context with qualified name
434- /// - Instance calls: `receiver.method()` - type looked up, then Defines relationship queried
435- /// - Self calls: `self.method()` - resolved via current type context
436- ///
437- /// # Arguments
438- /// * `method_call` - The structured method call information
439- /// * `receiver_types` - Map of variable names to their types (e.g., "calc" -> "Calculator")
440- /// * `context` - Resolution context with import information
441- /// * `document_index` - For querying symbols and relationships
442- ///
443- /// # Returns
444- /// The SymbolId of the resolved method, or None if unresolved
445- fn resolve_method_call (
446- & self ,
447- method_call : & MethodCall ,
448- receiver_types : & HashMap < String , String > ,
449- context : & dyn ResolutionScope ,
450- document_index : & DocumentIndex ,
451- ) -> Option < SymbolId > {
452- let method_name = & method_call. method_name ;
453-
454- match ( & method_call. receiver , method_call. is_static ) {
455- // Static call: Type::method()
456- // Use module_separator for resolution (:: for Rust, . for most others)
457- ( Some ( type_name) , true ) => {
458- let qualified = format ! ( "{type_name}{}{method_name}" , self . module_separator( ) ) ;
459- tracing:: debug!( "[resolve_method_call] static call: {qualified}" ) ;
460- context. resolve ( & qualified)
461- }
462-
463- // Instance call: receiver.method()
464- ( Some ( receiver) , false )
465- if !self . self_receiver_aliases ( ) . contains ( & receiver. as_str ( ) ) =>
466- {
467- // Look up the receiver's type
468- let type_name = match receiver_types. get ( receiver) {
469- Some ( t) => t,
470- None => {
471- tracing:: debug!(
472- "[resolve_method_call] no type found for receiver '{receiver}'"
473- ) ;
474- return None ;
475- }
476- } ;
477-
478- tracing:: debug!(
479- "[resolve_method_call] instance call: {receiver}.{method_name} (type: {type_name})"
480- ) ;
481-
482- // Use resolve_instance_method to find via Defines relationship
483- self . resolve_instance_method ( type_name, method_name, context, document_index)
484- }
485-
486- // Self call: self.method() / $this->method() / this.method() / cls.method() per language.
487- ( Some ( receiver) , false )
488- if self . self_receiver_aliases ( ) . contains ( & receiver. as_str ( ) ) =>
489- {
490- // For self calls, try to resolve via context which should have current type info
491- let self_method = format ! ( "self.{method_name}" ) ;
492- tracing:: debug!(
493- "[resolve_method_call] self call (receiver={receiver}): {self_method}"
494- ) ;
495- context. resolve ( & self_method) . or_else ( || {
496- // Fallback: just try the method name
497- context. resolve ( method_name)
498- } )
499- }
500-
501- // Plain function call (no receiver)
502- ( None , _) => {
503- tracing:: debug!( "[resolve_method_call] plain function call: {method_name}" ) ;
504- context. resolve ( method_name)
505- }
506-
507- // Catch-all (shouldn't happen)
508- _ => {
509- tracing:: debug!( "[resolve_method_call] unhandled case: {:?}" , method_call) ;
510- None
511- }
512- }
513- }
514-
515354 /// Get the inheritance relationship name for this language
516355 ///
517356 /// Returns "implements" for languages with interfaces, "extends" for inheritance.
0 commit comments