Skip to content

Commit 397b34f

Browse files
committed
refactor(parsing): LanguageBehavior drops resolve_method_call
- `LanguageBehavior::resolve_method_call` and its `resolve_instance_method` helper are removed; `ResolveStage` absorbed static/self/instance-receiver resolution into its tiered ladder and no caller remained - `method_call.rs`'s module doc reflects the current pipeline: `MethodCall` is data attached as relationship metadata by the PARSE stage; `ResolveStage::resolve_one` (super-call, static-call, and scope-ladder + receiver-gate arms) does the resolving; `LanguageBehavior` only answers language-specific questions (separators, self aliases, `is_receiver_compat`)
1 parent f9f3bcd commit 397b34f

2 files changed

Lines changed: 14 additions & 171 deletions

File tree

‎src/parsing/language_behavior.rs‎

Lines changed: 2 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,13 @@
5757
//! 3. Register both in `ParserFactory`
5858
//! 4. (Future) Register in the language registry for auto-discovery
5959
60-
use crate::parsing::MethodCall;
6160
use crate::parsing::paths::{strip_extension, strip_source_root};
6261
use crate::parsing::resolution::{
6362
GenericInheritanceResolver, GenericResolutionContext, ImportBinding, ImportOrigin,
6463
InheritanceResolver, PipelineSymbolCache, ResolutionScope, ScopeLevel,
6564
};
6665
use crate::relationship::RelationKind;
67-
use crate::storage::DocumentIndex;
6866
use crate::{FileId, Symbol, SymbolId, SymbolKind, Visibility};
69-
use std::collections::HashMap;
7067
use std::path::{Path, PathBuf};
7168
use 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.

‎src/parsing/method_call.rs‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,23 @@
99
//! ```text
1010
//! Parser
1111
//! ├─ find_variable_types() ──┐
12-
//! └─ find_method_calls() ────┼─→ MethodCallResolver (per file)
13-
//! │ - variable_types: HashMap<String, String>
14-
//! │ - method_calls: Vec<MethodCall>
15-
//! │
12+
//! └─ find_method_calls() ────┼─→ MethodCall records (receiver, static flag,
13+
//! │ caller range) attached as relationship
14+
//! │ metadata by the PARSE stage
1615
//! ↓
17-
//! LanguageBehavior::resolve_method_call()
16+
//! ResolveStage::resolve_one()
17+
//! ├─ super()-receiver calls → resolve_super_call()
18+
//! ├─ qualified static calls → resolve_static_call()
19+
//! └─ everything else → scope ladder + receiver gates
20+
//! (is_receiver_compat / is_instance_type_compatible)
1821
//! ```
1922
//!
2023
//! # Separation of Concerns
2124
//!
22-
//! - `MethodCallResolver` - owns DATA (variable types, method calls)
23-
//! - `LanguageBehavior` - owns LOGIC (language-specific resolution)
24-
//! - Indexer - orchestrates WHEN to call what
25+
//! - `MethodCall` - owns DATA (receiver, static flag, call site)
26+
//! - `ResolveStage` - owns resolution (tiers, receiver gates, disambiguation)
27+
//! - `LanguageBehavior` - answers language questions the stage asks
28+
//! (separators, self aliases, receiver compatibility)
2529
2630
use crate::Range;
2731
use std::collections::HashMap;

0 commit comments

Comments
 (0)