Skip to content

Commit 52bd050

Browse files
authored
Merge pull request #282 from Shopify/at-ref-ids
Use unique IDs for unresolved references
2 parents 02f59c2 + 451ca9b commit 52bd050

File tree

4 files changed

+113
-31
lines changed

4 files changed

+113
-31
lines changed

rust/saturn/src/indexing/ruby_indexer.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -980,9 +980,27 @@ mod tests {
980980
};
981981
}
982982

983+
fn collect_unresolved_references(graph: &Graph) -> Vec<&UnresolvedReference> {
984+
let mut unresolved_references = graph.unresolved_references().values().collect::<Vec<_>>();
985+
986+
unresolved_references.sort_by_key(|r| match r {
987+
UnresolvedReference::Constant(constant) => (
988+
graph.documents().get(&constant.uri_id()).unwrap().uri().to_string(),
989+
constant.offset().start(),
990+
graph.names().get(constant.name_id()).unwrap(),
991+
),
992+
UnresolvedReference::Method(method) => (
993+
graph.documents().get(&method.uri_id()).unwrap().uri().to_string(),
994+
method.offset().start(),
995+
graph.names().get(method.name_id()).unwrap(),
996+
),
997+
});
998+
999+
unresolved_references
1000+
}
1001+
9831002
fn collect_constant_reference_names(graph: &Graph) -> Vec<&String> {
984-
graph
985-
.unresolved_references()
1003+
collect_unresolved_references(graph)
9861004
.iter()
9871005
.filter_map(|r| match r {
9881006
UnresolvedReference::Constant(constant) => Some(graph.names().get(constant.name_id()).unwrap()),
@@ -992,8 +1010,7 @@ mod tests {
9921010
}
9931011

9941012
fn collect_method_reference_names(graph: &Graph) -> Vec<&String> {
995-
graph
996-
.unresolved_references()
1013+
collect_unresolved_references(graph)
9971014
.iter()
9981015
.filter_map(|r| match r {
9991016
UnresolvedReference::Constant(_) => None,
@@ -2037,7 +2054,7 @@ mod tests {
20372054
"
20382055
});
20392056

2040-
let refs = context.graph.unresolved_references();
2057+
let refs = context.graph.unresolved_references().values().collect::<Vec<_>>();
20412058
assert_eq!(refs.len(), 2);
20422059

20432060
let reference = &refs[0];
@@ -2089,7 +2106,7 @@ mod tests {
20892106
"
20902107
});
20912108

2092-
let refs = context.graph.unresolved_references();
2109+
let refs = context.graph.unresolved_references().values().collect::<Vec<_>>();
20932110
assert_eq!(refs.len(), 1);
20942111

20952112
let reference = &refs[0];
@@ -2124,7 +2141,7 @@ mod tests {
21242141
"
21252142
});
21262143

2127-
let refs = context.graph.unresolved_references();
2144+
let refs = context.graph.unresolved_references().values().collect::<Vec<_>>();
21282145
assert_eq!(refs.len(), 2);
21292146

21302147
let reference = &refs[0];
@@ -2350,7 +2367,7 @@ mod tests {
23502367
collect_method_reference_names(&context.graph),
23512368
vec![
23522369
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10", "m11", "m12", "m13", "m14", "m15", "m16",
2353-
"m17", "m18", "m19", "m20", "m21", "m22", "m23", "m24", "m25", "m26", "m27", "!", "m28", "m29", "m30",
2370+
"m17", "m18", "m19", "m20", "m21", "m22", "m23", "m24", "m25", "m26", "!", "m27", "m28", "m29", "m30",
23542371
"m31", "m32", "m33", "m34", "m35", "m36", "[]", "m37", "m38", "m39", "m40", "m41", "m42", "m43", "m44",
23552372
"m45", "m46", "m47", "m48", "m49", "m50"
23562373
]
@@ -2488,7 +2505,7 @@ mod tests {
24882505

24892506
assert_eq!(
24902507
collect_method_reference_names(&context.graph),
2491-
vec!["x", ">", "<=>", "y"]
2508+
vec!["x", "<=>", ">", "y"]
24922509
);
24932510
}
24942511

@@ -2504,7 +2521,7 @@ mod tests {
25042521

25052522
assert_eq!(
25062523
collect_method_reference_names(&context.graph),
2507-
vec!["x", ">=", "<=>", "y"]
2524+
vec!["x", "<=>", ">=", "y"]
25082525
);
25092526
}
25102527

rust/saturn/src/model/graph.rs

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::model::declaration::Declaration;
44
use crate::model::definitions::Definition;
55
use crate::model::document::Document;
66
use crate::model::identity_maps::IdentityHashMap;
7-
use crate::model::ids::{DeclarationId, DefinitionId, NameId, UriId};
7+
use crate::model::ids::{DeclarationId, DefinitionId, NameId, ReferenceId, UriId};
88
use crate::model::integrity::IntegrityChecker;
99
use crate::model::references::{ResolvedReference, UnresolvedReference};
1010
use crate::stats;
@@ -28,8 +28,8 @@ pub struct Graph {
2828
definitions: IdentityHashMap<DefinitionId, Definition>,
2929
// Map of unqualified names
3030
names: IdentityHashMap<NameId, String>,
31-
// List of references that still need to be resolved
32-
unresolved_references: Vec<UnresolvedReference>,
31+
// Map of references that still need to be resolved
32+
unresolved_references: IdentityHashMap<ReferenceId, UnresolvedReference>,
3333
db: Db,
3434
}
3535

@@ -47,7 +47,7 @@ impl Graph {
4747
definitions: IdentityHashMap::default(),
4848
documents: IdentityHashMap::default(),
4949
names: IdentityHashMap::default(),
50-
unresolved_references: Vec::new(),
50+
unresolved_references: IdentityHashMap::default(),
5151
db: Db::new(),
5252
}
5353
}
@@ -76,9 +76,9 @@ impl Graph {
7676
&self.documents
7777
}
7878

79-
// Returns an immutable reference to the list of unresolved references
79+
// Returns an immutable reference to the unresolved references map
8080
#[must_use]
81-
pub fn unresolved_references(&self) -> &Vec<UnresolvedReference> {
81+
pub fn unresolved_references(&self) -> &IdentityHashMap<ReferenceId, UnresolvedReference> {
8282
&self.unresolved_references
8383
}
8484

@@ -182,8 +182,10 @@ impl Graph {
182182
}
183183

184184
// Register an unresolved reference to something (e.g.: constant, method, variable), which has to be resolved later
185-
pub fn add_unresolved_reference(&mut self, reference: UnresolvedReference) {
186-
self.unresolved_references.push(reference);
185+
pub fn add_unresolved_reference(&mut self, reference: UnresolvedReference) -> ReferenceId {
186+
let reference_id = reference.id();
187+
self.unresolved_references.insert(reference_id, reference);
188+
reference_id
187189
}
188190

189191
/// Attempts to resolve a reference against the graph. Returns the fully qualified declaration ID that the reference
@@ -469,7 +471,7 @@ impl Graph {
469471
self.definitions = IdentityHashMap::default();
470472
self.documents = IdentityHashMap::default();
471473
self.names = IdentityHashMap::default();
472-
self.unresolved_references = Vec::new();
474+
self.unresolved_references = IdentityHashMap::default();
473475
}
474476

475477
#[allow(clippy::cast_precision_loss)]
@@ -539,7 +541,7 @@ impl Graph {
539541
pub fn resolve_references(&mut self) {
540542
let unresolved = std::mem::take(&mut self.unresolved_references);
541543

542-
for reference in unresolved {
544+
for (id, reference) in unresolved {
543545
match &reference {
544546
UnresolvedReference::Constant(_) => {
545547
if let Some(declaration) = self.resolve_reference(&reference) {
@@ -562,12 +564,12 @@ impl Graph {
562564
}
563565
} else {
564566
// Keep unresolved references
565-
self.unresolved_references.push(reference);
567+
self.unresolved_references.insert(id, reference);
566568
}
567569
}
568570
UnresolvedReference::Method(_) => {
569571
// TODO: Implement method reference resolution
570-
self.unresolved_references.push(reference);
572+
self.unresolved_references.insert(id, reference);
571573
}
572574
}
573575
}
@@ -594,7 +596,7 @@ impl Graph {
594596
// Count unresolved references by type
595597
let mut unresolved_constants = 0;
596598
let mut unresolved_methods = 0;
597-
for reference in &self.unresolved_references {
599+
for reference in self.unresolved_references.values() {
598600
match reference {
599601
UnresolvedReference::Constant(_) => unresolved_constants += 1,
600602
UnresolvedReference::Method(_) => unresolved_methods += 1,
@@ -705,7 +707,7 @@ mod tests {
705707
let constant = $context
706708
.graph
707709
.unresolved_references
708-
.iter()
710+
.values()
709711
.filter_map(|r| {
710712
if let UnresolvedReference::Constant(c) = r {
711713
Some(c)
@@ -975,6 +977,14 @@ mod tests {
975977
fn resolving_constants() {
976978
let mut context = GraphTest::new();
977979

980+
context.index_uri("file:///bar.rb", {
981+
r"
982+
class Bar
983+
::Foo::Bar # should be resolved to Foo::Bar from file:///foo.rb
984+
end
985+
"
986+
});
987+
978988
context.index_uri("file:///foo.rb", {
979989
r"
980990
module Foo
@@ -992,12 +1002,31 @@ mod tests {
9921002
"
9931003
});
9941004

995-
context.index_uri("file:///bar.rb", {
996-
r"
997-
class Bar
998-
::Foo::Bar # should be resolved to Foo::Bar from file:///foo.rb
999-
end
1000-
"
1005+
let mut unresolved_references = context.graph.unresolved_references().values().collect::<Vec<_>>();
1006+
1007+
unresolved_references.sort_by_key(|r| match r {
1008+
UnresolvedReference::Constant(constant) => (
1009+
context
1010+
.graph
1011+
.documents()
1012+
.get(&constant.uri_id())
1013+
.unwrap()
1014+
.uri()
1015+
.to_string(),
1016+
constant.offset().start(),
1017+
constant.offset().end(),
1018+
),
1019+
UnresolvedReference::Method(method) => (
1020+
context
1021+
.graph
1022+
.documents()
1023+
.get(&method.uri_id())
1024+
.unwrap()
1025+
.uri()
1026+
.to_string(),
1027+
method.offset().start(),
1028+
method.offset().end(),
1029+
),
10011030
});
10021031

10031032
context.graph.resolve_references();

rust/saturn/src/model/ids.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ pub struct NameMarker;
2929
///
3030
/// In here, the `NameId` for `Bar` is just the hashed `Bar` string, not `Foo::Bar`
3131
pub type NameId = Id<NameMarker>;
32+
33+
#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
34+
pub struct ReferenceMarker;
35+
/// `ReferenceId` represents the ID of a reference occurrence in a file.
36+
/// It is built from the reference kind, `uri_id` and the reference `offset`.
37+
pub type ReferenceId = Id<ReferenceMarker>;

rust/saturn/src/model/references.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
indexing::scope::Nesting,
3-
model::ids::{NameId, UriId},
3+
model::ids::{NameId, ReferenceId, UriId},
44
offset::Offset,
55
};
66
use serde::{Deserialize, Serialize};
@@ -65,6 +65,36 @@ pub enum ResolvedReference {
6565
Method(Box<MethodReference>),
6666
}
6767

68+
impl UnresolvedReference {
69+
#[must_use]
70+
pub fn id(&self) -> ReferenceId {
71+
match self {
72+
UnresolvedReference::Constant(constant) => {
73+
// C:<uri_id>:<start>-<end>
74+
let key = format!(
75+
"C:{}:{}:{}-{}",
76+
constant.name_id(),
77+
constant.uri_id(),
78+
constant.offset().start(),
79+
constant.offset().end()
80+
);
81+
ReferenceId::from(&key)
82+
}
83+
UnresolvedReference::Method(method) => {
84+
// M:<uri_id>:<start>-<end>
85+
let key = format!(
86+
"M:{}:{}:{}-{}",
87+
method.name_id(),
88+
method.uri_id(),
89+
method.offset().start(),
90+
method.offset().end()
91+
);
92+
ReferenceId::from(&key)
93+
}
94+
}
95+
}
96+
}
97+
6898
impl ConstantReference {
6999
#[must_use]
70100
pub fn new(name_id: NameId, nesting: Option<Arc<Nesting>>, uri_id: UriId, offset: Offset) -> Self {

0 commit comments

Comments
 (0)