Skip to content

Commit 39084db

Browse files
committed
Find inherited methods
1 parent a05a09b commit 39084db

1 file changed

Lines changed: 143 additions & 3 deletions

File tree

rust/rubydex/src/query.rs

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,10 +531,9 @@ pub fn dealias_method(graph: &Graph, alias: &MethodAliasDefinition) -> Vec<Deali
531531
},
532532
};
533533

534-
let owner_decl = graph.declarations().get(&owner_id).unwrap();
535-
let ns = owner_decl.as_namespace().unwrap();
534+
let method_decl_id = find_member_in_ancestors(graph, owner_id, *alias.old_name_str_id());
536535

537-
let Some(&method_decl_id) = ns.member(alias.old_name_str_id()) else {
536+
let Some(method_decl_id) = method_decl_id else {
538537
return vec![];
539538
};
540539
let method_decl = graph.declarations().get(&method_decl_id).unwrap();
@@ -551,6 +550,31 @@ pub fn dealias_method(graph: &Graph, alias: &MethodAliasDefinition) -> Vec<Deali
551550
.collect()
552551
}
553552

553+
/// Searches for a member by `StringId` in the given namespace and its ancestor chain.
554+
#[must_use]
555+
pub fn find_member_in_ancestors(
556+
graph: &Graph,
557+
namespace_id: DeclarationId,
558+
str_id: StringId,
559+
) -> Option<DeclarationId> {
560+
let ns = graph.declarations().get(&namespace_id)?.as_namespace()?;
561+
562+
if let Some(&decl_id) = ns.member(&str_id) {
563+
return Some(decl_id);
564+
}
565+
566+
for ancestor in ns.ancestors() {
567+
if let Ancestor::Complete(ancestor_id) = ancestor {
568+
let ancestor_ns = graph.declarations().get(ancestor_id)?.as_namespace()?;
569+
if let Some(&decl_id) = ancestor_ns.member(&str_id) {
570+
return Some(decl_id);
571+
}
572+
}
573+
}
574+
575+
None
576+
}
577+
554578
#[cfg(test)]
555579
mod tests {
556580
use std::str::FromStr;
@@ -1893,6 +1917,122 @@ mod tests {
18931917
);
18941918
}
18951919

1920+
#[test]
1921+
fn dealias_method_inherited() {
1922+
let mut context = GraphTest::new();
1923+
context.index_uri("file:///foo.rb", "
1924+
class Parent
1925+
def foo(a); end
1926+
end
1927+
class Child < Parent
1928+
alias bar foo
1929+
end
1930+
");
1931+
context.resolve();
1932+
1933+
let alias = get_method_alias_def(context.graph(), "Child#bar()");
1934+
let results = dealias_method(context.graph(), alias);
1935+
assert_eq!(results.len(), 1);
1936+
assert!(matches!(results[0], DealiasMethodResult::Method(_)));
1937+
}
1938+
1939+
#[test]
1940+
fn find_member_in_ancestors_direct() {
1941+
let mut context = GraphTest::new();
1942+
context.index_uri("file:///foo.rb", "
1943+
class Foo
1944+
def bar; end
1945+
end
1946+
");
1947+
context.resolve();
1948+
1949+
let result = find_member_in_ancestors(
1950+
context.graph(),
1951+
DeclarationId::from("Foo"),
1952+
StringId::from("bar()"),
1953+
);
1954+
assert_eq!(result, Some(DeclarationId::from("Foo#bar()")));
1955+
}
1956+
1957+
#[test]
1958+
fn find_member_in_ancestors_inherited() {
1959+
let mut context = GraphTest::new();
1960+
context.index_uri("file:///foo.rb", "
1961+
class Parent
1962+
def foo; end
1963+
end
1964+
class Child < Parent
1965+
end
1966+
");
1967+
context.resolve();
1968+
1969+
let result = find_member_in_ancestors(
1970+
context.graph(),
1971+
DeclarationId::from("Child"),
1972+
StringId::from("foo()"),
1973+
);
1974+
assert_eq!(result, Some(DeclarationId::from("Parent#foo()")));
1975+
}
1976+
1977+
#[test]
1978+
fn find_member_in_ancestors_overridden() {
1979+
let mut context = GraphTest::new();
1980+
context.index_uri("file:///foo.rb", "
1981+
class Parent
1982+
def foo; end
1983+
end
1984+
class Child < Parent
1985+
def foo; end
1986+
end
1987+
");
1988+
context.resolve();
1989+
1990+
let result = find_member_in_ancestors(
1991+
context.graph(),
1992+
DeclarationId::from("Child"),
1993+
StringId::from("foo()"),
1994+
);
1995+
assert_eq!(result, Some(DeclarationId::from("Child#foo()")));
1996+
}
1997+
1998+
#[test]
1999+
fn find_member_in_ancestors_not_found() {
2000+
let mut context = GraphTest::new();
2001+
context.index_uri("file:///foo.rb", "
2002+
class Foo
2003+
end
2004+
");
2005+
context.resolve();
2006+
2007+
let result = find_member_in_ancestors(
2008+
context.graph(),
2009+
DeclarationId::from("Foo"),
2010+
StringId::from("nonexistent()"),
2011+
);
2012+
assert_eq!(result, None);
2013+
}
2014+
2015+
#[test]
2016+
fn find_member_in_ancestors_via_module() {
2017+
let mut context = GraphTest::new();
2018+
context.index_uri("file:///foo.rb", "
2019+
module Greetable
2020+
def greet; end
2021+
end
2022+
class Foo
2023+
include Greetable
2024+
end
2025+
");
2026+
context.resolve();
2027+
2028+
let result = find_member_in_ancestors(
2029+
context.graph(),
2030+
DeclarationId::from("Foo"),
2031+
StringId::from("greet()"),
2032+
);
2033+
assert_eq!(result, Some(DeclarationId::from("Greetable#greet()")));
2034+
}
2035+
18962036
#[test]
18972037
fn method_call_completion_excludes_keywords() {
18982038
let mut context = GraphTest::new();

0 commit comments

Comments
 (0)