Skip to content

Commit 36c12d9

Browse files
authored
Merge pull request #266 from Shopify/at-more-constant-ref-tests
Index more constant references
2 parents 9f926ef + 3b3a7bd commit 36c12d9

File tree

2 files changed

+251
-3
lines changed

2 files changed

+251
-3
lines changed

rust/saturn/src/indexing/ruby_indexer.rs

Lines changed: 238 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,17 @@ impl Visit<'_> for RubyIndexer<'_> {
351351
self.local_graph.add_definition(fully_qualified_name, definition);
352352
self.local_graph.add_member(&previous_nesting_id, declaration_id, &name);
353353

354+
if let ruby_prism::Node::ConstantPathNode { .. } = node.constant_path() {
355+
let constant_path = node.constant_path().as_constant_path_node().unwrap();
356+
if let Some(parent) = constant_path.parent() {
357+
self.visit(&parent);
358+
}
359+
}
360+
361+
if let Some(superclass) = node.superclass() {
362+
self.visit(&superclass);
363+
}
364+
354365
if let Some(body) = node.body() {
355366
self.visit(&body);
356367
}
@@ -376,13 +387,35 @@ impl Visit<'_> for RubyIndexer<'_> {
376387
self.local_graph.add_definition(fully_qualified_name, definition);
377388
self.local_graph.add_member(&previous_nesting_id, declaration_id, &name);
378389

390+
if let ruby_prism::Node::ConstantPathNode { .. } = node.constant_path() {
391+
let constant_path = node.constant_path().as_constant_path_node().unwrap();
392+
if let Some(parent) = constant_path.parent() {
393+
self.visit(&parent);
394+
}
395+
}
396+
379397
if let Some(body) = node.body() {
380398
self.visit(&body);
381399
}
382400

383401
self.scope.leave();
384402
}
385403

404+
fn visit_constant_and_write_node(&mut self, node: &ruby_prism::ConstantAndWriteNode) {
405+
self.index_constant_reference(&node.name_loc());
406+
self.visit(&node.value());
407+
}
408+
409+
fn visit_constant_operator_write_node(&mut self, node: &ruby_prism::ConstantOperatorWriteNode) {
410+
self.index_constant_reference(&node.name_loc());
411+
self.visit(&node.value());
412+
}
413+
414+
fn visit_constant_or_write_node(&mut self, node: &ruby_prism::ConstantOrWriteNode) {
415+
self.index_constant_reference(&node.name_loc());
416+
self.visit(&node.value());
417+
}
418+
386419
fn visit_constant_write_node(&mut self, node: &ruby_prism::ConstantWriteNode) {
387420
let previous_nesting_id = self.scope.current_nesting_id().unwrap_or(*OBJECT_ID);
388421
let name_loc = node.name_loc();
@@ -406,6 +439,18 @@ impl Visit<'_> for RubyIndexer<'_> {
406439
self.visit(&node.value());
407440
}
408441

442+
fn visit_constant_path_and_write_node(&mut self, node: &ruby_prism::ConstantPathAndWriteNode) {
443+
self.visit_constant_path_node(&node.target());
444+
}
445+
446+
fn visit_constant_path_operator_write_node(&mut self, node: &ruby_prism::ConstantPathOperatorWriteNode) {
447+
self.visit_constant_path_node(&node.target());
448+
}
449+
450+
fn visit_constant_path_or_write_node(&mut self, node: &ruby_prism::ConstantPathOrWriteNode) {
451+
self.visit_constant_path_node(&node.target());
452+
}
453+
409454
fn visit_constant_path_write_node(&mut self, node: &ruby_prism::ConstantPathWriteNode) {
410455
let previous_nesting_id = self.scope.current_nesting_id().unwrap_or(*OBJECT_ID);
411456
let location = node.target().location();
@@ -426,6 +471,10 @@ impl Visit<'_> for RubyIndexer<'_> {
426471

427472
self.local_graph.add_definition(fully_qualified_name, definition);
428473
self.local_graph.add_member(&previous_nesting_id, declaration_id, &name);
474+
475+
if let Some(parent) = node.target().parent() {
476+
self.visit(&parent);
477+
}
429478
self.visit(&node.value());
430479
}
431480

@@ -434,6 +483,10 @@ impl Visit<'_> for RubyIndexer<'_> {
434483
}
435484

436485
fn visit_constant_path_node(&mut self, node: &ruby_prism::ConstantPathNode<'_>) {
486+
if let Some(parent) = node.parent() {
487+
self.visit(&parent);
488+
}
489+
437490
self.index_constant_reference(&node.location());
438491
}
439492

@@ -822,6 +875,16 @@ mod tests {
822875
};
823876
}
824877

878+
fn collect_constant_reference_names(graph: &Graph) -> Vec<&String> {
879+
graph
880+
.unresolved_references()
881+
.iter()
882+
.map(|r| match r {
883+
UnresolvedReference::Constant(constant) => graph.names().get(constant.name_id()).unwrap(),
884+
})
885+
.collect::<Vec<_>>()
886+
}
887+
825888
#[test]
826889
fn index_class_node() {
827890
let mut context = GraphTest::new();
@@ -1827,10 +1890,24 @@ mod tests {
18271890
});
18281891

18291892
let refs = context.graph.unresolved_references();
1830-
assert_eq!(refs.len(), 1);
1893+
assert_eq!(refs.len(), 2);
18311894

18321895
let reference = &refs[0];
18331896

1897+
match reference {
1898+
UnresolvedReference::Constant(unresolved) => {
1899+
assert_eq!(unresolved.name_id(), &NameId::from("Bar"));
1900+
assert_eq!(
1901+
unresolved.nesting().as_ref().unwrap().ids_as_vec(),
1902+
vec![DeclarationId::from("Foo"), DeclarationId::from("Foo::Bar::Baz")]
1903+
);
1904+
assert_eq!(unresolved.uri_id(), UriId::from("file:///foo.rb"));
1905+
assert_eq!(unresolved.offset(), &Offset::new(19, 22));
1906+
}
1907+
}
1908+
1909+
let reference = &refs[1];
1910+
18341911
match reference {
18351912
UnresolvedReference::Constant(unresolved) => {
18361913
assert_eq!(unresolved.name_id(), &NameId::from("String"));
@@ -1845,7 +1922,7 @@ mod tests {
18451922
}
18461923

18471924
#[test]
1848-
fn index_unresolved_constant_references() {
1925+
fn index_unresolved_constant_reference_context() {
18491926
let mut context = GraphTest::new();
18501927

18511928
context.index_uri("file:///foo.rb", {
@@ -1891,10 +1968,24 @@ mod tests {
18911968
});
18921969

18931970
let refs = context.graph.unresolved_references();
1894-
assert_eq!(refs.len(), 1);
1971+
assert_eq!(refs.len(), 2);
18951972

18961973
let reference = &refs[0];
18971974

1975+
match reference {
1976+
UnresolvedReference::Constant(unresolved) => {
1977+
assert_eq!(unresolved.name_id(), &NameId::from("Object"));
1978+
assert_eq!(
1979+
unresolved.nesting().as_ref().unwrap().ids_as_vec(),
1980+
vec![DeclarationId::from("Foo"), DeclarationId::from("Foo::Bar")]
1981+
);
1982+
assert_eq!(unresolved.uri_id(), UriId::from("file:///foo.rb"));
1983+
assert_eq!(unresolved.offset(), &Offset::new(27, 33));
1984+
}
1985+
}
1986+
1987+
let reference = &refs[1];
1988+
18981989
match reference {
18991990
UnresolvedReference::Constant(unresolved) => {
19001991
assert_eq!(unresolved.name_id(), &NameId::from("Object::String"));
@@ -1907,4 +1998,148 @@ mod tests {
19071998
}
19081999
}
19092000
}
2001+
2002+
#[test]
2003+
fn index_unresolved_constant_references() {
2004+
let mut context = GraphTest::new();
2005+
2006+
context.index_uri("file:///foo.rb", {
2007+
"
2008+
puts C1
2009+
puts C2::C3::C4
2010+
puts foo::C5
2011+
puts C6.foo
2012+
foo = C7
2013+
C8 << 42
2014+
C9 += 42
2015+
C10 ||= 42
2016+
C11 &&= 42
2017+
C12[C13]
2018+
C14::IGNORED1 = 42 # IGNORED1 is an assignment
2019+
C15::C16 << 42
2020+
C17::C18 += 42
2021+
C19::C20 ||= 42
2022+
C21::C22 &&= 42
2023+
puts \"#{C23}\"
2024+
2025+
::IGNORED2 = 42 # IGNORED2 is an assignment
2026+
puts \"IGNORED3\"
2027+
puts :IGNORED4
2028+
"
2029+
});
2030+
2031+
assert_eq!(
2032+
collect_constant_reference_names(&context.graph),
2033+
vec![
2034+
"C1",
2035+
"C2",
2036+
"C2::C3",
2037+
"C2::C3::C4",
2038+
"foo::C5",
2039+
"C6",
2040+
"C7",
2041+
"C8",
2042+
"C9",
2043+
"C10",
2044+
"C11",
2045+
"C12",
2046+
"C13",
2047+
"C14",
2048+
"C15",
2049+
"C15::C16",
2050+
"C17",
2051+
"C17::C18",
2052+
"C19",
2053+
"C19::C20",
2054+
"C21",
2055+
"C21::C22",
2056+
"C23"
2057+
]
2058+
);
2059+
}
2060+
2061+
#[test]
2062+
fn index_unresolved_constant_references_from_values() {
2063+
let mut context = GraphTest::new();
2064+
2065+
context.index_uri("file:///foo.rb", {
2066+
"
2067+
IGNORED1 = C1
2068+
IGNORED2 = [C2::C3]
2069+
C4 << C5
2070+
C6 += C7
2071+
C8 ||= C9
2072+
C10 &&= C11
2073+
C12[C13] = C14
2074+
"
2075+
});
2076+
2077+
assert_eq!(
2078+
collect_constant_reference_names(&context.graph),
2079+
vec![
2080+
"C1", "C2", "C2::C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13", "C14",
2081+
]
2082+
);
2083+
}
2084+
2085+
#[test]
2086+
fn index_unresolved_constant_references_for_classes() {
2087+
let mut context = GraphTest::new();
2088+
2089+
context.index_uri("file:///foo.rb", {
2090+
"
2091+
C1.new
2092+
2093+
class IGNORED < ::C2; end
2094+
class IGNORED < C3; end
2095+
class IGNORED < C4::C5; end
2096+
class IGNORED < ::C6::C7; end
2097+
2098+
class C8::IGNORED; end
2099+
class ::C9::IGNORED; end
2100+
class C10::C11::IGNORED; end
2101+
"
2102+
});
2103+
2104+
assert_eq!(
2105+
collect_constant_reference_names(&context.graph),
2106+
vec![
2107+
"C1", "C2", "C3", "C4", "C4::C5", "C6", "C6::C7", "C8", "C9", "C10", "C10::C11",
2108+
]
2109+
);
2110+
}
2111+
2112+
#[test]
2113+
fn index_unresolved_constant_references_for_modules() {
2114+
let mut context = GraphTest::new();
2115+
2116+
context.index_uri("file:///foo.rb", {
2117+
"
2118+
module X
2119+
include M1
2120+
include M2::M3
2121+
extend M4
2122+
extend M5::M6
2123+
prepend M7
2124+
prepend M8::M9
2125+
end
2126+
2127+
M10.include M11
2128+
M12.extend M13
2129+
M14.prepend M15
2130+
2131+
module M16::IGNORED; end
2132+
module ::M17::IGNORED; end
2133+
module M18::M19::IGNORED; end
2134+
"
2135+
});
2136+
2137+
assert_eq!(
2138+
collect_constant_reference_names(&context.graph),
2139+
vec![
2140+
"M1", "M2", "M2::M3", "M4", "M5", "M5::M6", "M7", "M8", "M8::M9", "M10", "M11", "M12", "M13", "M14",
2141+
"M15", "M16", "M17", "M18", "M18::M19",
2142+
]
2143+
);
2144+
}
19102145
}

rust/saturn/src/model/graph.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ impl Graph {
6363
&self.definitions
6464
}
6565

66+
// Returns an immutable reference to the names map
67+
#[must_use]
68+
pub fn names(&self) -> &IdentityHashMap<NameId, String> {
69+
&self.names
70+
}
71+
6672
// Returns an immutable reference to the URI pool map
6773
#[must_use]
6874
pub fn documents(&self) -> &IdentityHashMap<UriId, Document> {
@@ -770,6 +776,13 @@ mod tests {
770776
let const_ref = context.graph.unresolved_references.remove(0);
771777
assert!(context.graph.resolve_reference(&const_ref).is_none());
772778

779+
// ::Foo should be resolved to the Foo declaration
780+
let const_ref = context.graph.unresolved_references.remove(0);
781+
assert_eq!(
782+
context.graph.resolve_reference(&const_ref).unwrap().name(),
783+
String::from("Foo")
784+
);
785+
773786
// ::Foo::Bar should be resolved to the Foo::Bar declaration
774787
let const_ref = context.graph.unresolved_references.remove(0);
775788
assert_eq!(

0 commit comments

Comments
 (0)