1use petgraph::{graph::NodeIndex, visit::EdgeRef, Direction, Graph};
2use serde::{Deserialize, Serialize};
3use tree_sitter_graph::{
4 ast::File, functions::Functions, ExecutionConfig, Identifier, NoCancellation, Variables,
5};
6
7use crate::{
8 error::{ConfigError, StagError},
9 stdlib,
10 text_range::{self, TextRange},
11};
12
13#[derive(Default)]
14pub struct StagBuilder<'a> {
15 language: Option<tree_sitter::Language>,
16 stag_file: Option<&'a str>,
17 filename: Option<&'a str>,
18 source: Option<&'a str>,
19}
20
21impl<'a> StagBuilder<'a> {
22 pub fn with_language(&mut self, language: tree_sitter::Language) -> &mut Self {
23 self.language = Some(language);
24 self
25 }
26
27 pub fn with_stag_file(&mut self, stag_file: &'a str) -> &mut Self {
28 self.stag_file = Some(stag_file);
29 self
30 }
31
32 pub fn with_source(&mut self, source: &'a str) -> &mut Self {
33 self.source = Some(source);
34 self
35 }
36
37 pub fn with_file_name(&mut self, filename: &'a str) -> &mut Self {
38 self.filename = Some(filename);
39 self
40 }
41
42 pub fn execute(&self) -> Result<ScopeGraph, StagError> {
43 let mut parser = tree_sitter::Parser::new();
44 let language = self.language.clone().ok_or(ConfigError::MissingLanguage)?;
45 parser.set_language(&language)?;
46
47 let file = File::from_str(
48 language,
49 self.stag_file.ok_or(ConfigError::MissingStagSource)?,
50 )
51 .map_err(ConfigError::from)?;
52
53 let mut functions = Functions::stdlib();
54 functions.add(Identifier::from("scope"), stdlib::ScopeShorthand);
55 functions.add(Identifier::from("def"), stdlib::DefShorthand);
56 functions.add(Identifier::from("ref"), stdlib::RefShortHand);
57 functions.add(Identifier::from("cover"), stdlib::CoverRanges);
58 functions.add(Identifier::from("range"), stdlib::NodeRange);
59 let globals = Variables::new();
60 let config = ExecutionConfig::new(&functions, &globals);
61
62 let src = self.source.ok_or(ConfigError::MissingSource)?;
63 let tree = parser.parse(src.as_bytes(), None).unwrap();
64 let graph = file
65 .execute(&tree, &src, &config, &NoCancellation)
66 .map_err(ConfigError::from)?;
67
68 let mut sg = ScopeGraph::new(tree.root_node().range().into());
69 sg = build_scope_graph(graph, sg);
70 Ok(sg)
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
75pub struct LocalDef {
76 pub range: TextRange,
77 pub text: String,
78 pub symbol: Option<String>,
79}
80
81impl LocalDef {
82 /// Initialize a new definition
83 pub fn new(range: TextRange, text: String, symbol: Option<String>) -> Self {
84 Self {
85 range,
86 text,
87 symbol,
88 }
89 }
90
91 pub fn name<'a>(&self, buffer: &'a [u8]) -> &'a [u8] {
92 &buffer[self.range.start.byte..self.range.end.byte]
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
97pub struct LocalImport {
98 pub range: TextRange,
99 pub text: String,
100}
101
102impl LocalImport {
103 /// Initialize a new import
104 pub fn new(range: TextRange, text: String) -> Self {
105 Self { range, text }
106 }
107
108 pub fn name<'a>(&self, buffer: &'a [u8]) -> &'a [u8] {
109 &buffer[self.range.start.byte..self.range.end.byte]
110 }
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Reference {
115 pub range: TextRange,
116 pub text: String,
117 pub symbol: Option<String>,
118}
119
120impl Reference {
121 /// Initialize a new reference
122 pub fn new(range: TextRange, text: String, symbol: Option<String>) -> Self {
123 Self {
124 range,
125 text,
126 symbol,
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
132pub struct LocalScope {
133 pub range: TextRange,
134}
135
136impl LocalScope {
137 pub fn new(range: TextRange) -> Self {
138 Self { range }
139 }
140}
141
142pub struct ScopeStack<'a> {
143 pub scope_graph: &'a ScopeGraph,
144 pub start: Option<NodeIndex<u32>>,
145}
146
147impl<'a> Iterator for ScopeStack<'a> {
148 type Item = NodeIndex<u32>;
149 fn next(&mut self) -> Option<Self::Item> {
150 if let Some(start) = self.start {
151 let parent = self
152 .scope_graph
153 .graph
154 .edges_directed(start, Direction::Outgoing)
155 .find(|edge| *edge.weight() == EdgeKind::ScopeToScope)
156 .map(|edge| edge.target());
157 let original = start;
158 self.start = parent;
159 Some(original)
160 } else {
161 None
162 }
163 }
164}
165
166/// A node in the ScopeGraph
167#[derive(Serialize, Deserialize, Debug, Clone)]
168pub struct Node {
169 kind: NodeKind,
170 metadata: Metadata,
171}
172
173impl Node {
174 pub fn new(kind: NodeKind) -> Self {
175 Self {
176 kind,
177 metadata: Default::default(),
178 }
179 }
180
181 pub fn scope(s: LocalScope) -> Self {
182 Self::new(NodeKind::Scope(s))
183 }
184
185 pub fn local_def(d: LocalDef) -> Self {
186 Self::new(NodeKind::Def(d))
187 }
188
189 pub fn reference(r: Reference) -> Self {
190 Self::new(NodeKind::Ref(r))
191 }
192
193 pub fn import(i: LocalImport) -> Self {
194 Self::new(NodeKind::Import(i))
195 }
196
197 /// Produce the range spanned by this node
198 pub fn range(&self) -> TextRange {
199 match &self.kind {
200 NodeKind::Scope(l) => l.range,
201 NodeKind::Def(d) => d.range,
202 NodeKind::Ref(r) => r.range,
203 NodeKind::Import(i) => i.range,
204 }
205 }
206}
207
208#[derive(Serialize, Deserialize, Default, Debug, Clone)]
209struct Metadata {}
210
211/// The kind of a lexical node in the ScopeGraph
212#[derive(Serialize, Deserialize, Debug, Clone)]
213pub enum NodeKind {
214 /// A scope node
215 Scope(LocalScope),
216
217 /// A definition node
218 Def(LocalDef),
219
220 /// An import node
221 Import(LocalImport),
222
223 /// A reference node
224 Ref(Reference),
225}
226
227/// Describes the relation between two nodes in the ScopeGraph
228#[derive(Serialize, Deserialize, PartialEq, Eq, Copy, Clone, Debug)]
229pub enum EdgeKind {
230 /// The edge weight from a nested scope to its parent scope
231 ScopeToScope,
232
233 /// The edge weight from a definition to its definition scope
234 DefToScope,
235
236 /// The edge weight from an import to its definition scope
237 ImportToScope,
238
239 /// The edge weight from a reference to its definition
240 RefToDef,
241
242 /// The edge weight from a reference to its import
243 RefToImport,
244}
245
246/// A graph representation of scopes and names in a single syntax tree
247#[derive(Debug, Serialize, Deserialize, Clone)]
248pub struct ScopeGraph {
249 /// The raw graph
250 pub graph: Graph<Node, EdgeKind>,
251
252 // Graphs do not have the concept of a `root`, but lexical scopes follow the syntax
253 // tree, and as a result, have a "root" node. The root_idx points to a scope node that
254 // encompasses the entire file: the file-global scope.
255 root_idx: NodeIndex,
256}
257
258impl ScopeGraph {
259 pub fn new(range: TextRange) -> Self {
260 let mut graph = Graph::new();
261 let root_idx = graph.add_node(Node::scope(LocalScope::new(range)));
262 Self { graph, root_idx }
263 }
264
265 pub fn get_node(&self, node_idx: NodeIndex) -> Option<&Node> {
266 self.graph.node_weight(node_idx)
267 }
268
269 /// Insert a local scope into the scope-graph
270 fn insert_local_scope(&mut self, new: LocalScope) -> Option<NodeIndex> {
271 if let Some(parent_scope) = self.scope_by_range(new.range, self.root_idx) {
272 let new_scope = Node::scope(new);
273 let new_idx = self.graph.add_node(new_scope);
274 self.graph
275 .add_edge(new_idx, parent_scope, EdgeKind::ScopeToScope);
276 Some(new_idx)
277 } else {
278 None
279 }
280 }
281
282 /// Insert a def into the scope-graph
283 fn insert_local_def(&mut self, new: LocalDef) {
284 if let Some(defining_scope) = self.scope_by_range(new.range, self.root_idx) {
285 let new_def = Node::local_def(new);
286 let new_idx = self.graph.add_node(new_def);
287 self.graph
288 .add_edge(new_idx, defining_scope, EdgeKind::DefToScope);
289 }
290 }
291
292 /// Insert a def into the scope-graph, at the root scope
293 #[allow(unused)]
294 fn insert_global_def(&mut self, new: LocalDef) {
295 let new_def = Node::local_def(new);
296 let new_idx = self.graph.add_node(new_def);
297 self.graph
298 .add_edge(new_idx, self.root_idx, EdgeKind::DefToScope);
299 }
300
301 /// Insert an import into the scope-graph
302 fn insert_local_import(&mut self, new: LocalImport) {
303 if let Some(defining_scope) = self.scope_by_range(new.range, self.root_idx) {
304 let new_imp = Node::import(new);
305 let new_idx = self.graph.add_node(new_imp);
306 self.graph
307 .add_edge(new_idx, defining_scope, EdgeKind::ImportToScope);
308 }
309 }
310
311 /// Insert a ref into the scope-graph
312 fn insert_ref(&mut self, new: Reference) {
313 let mut possible_defs = vec![];
314 let mut possible_imports = vec![];
315 if let Some(local_scope_idx) = self.scope_by_range(new.range, self.root_idx) {
316 // traverse the scopes from the current-scope to the root-scope
317 for scope in self.scope_stack(local_scope_idx) {
318 // find candidate definitions in each scope
319 for local_def in self
320 .graph
321 .edges_directed(scope, Direction::Incoming)
322 .filter(|edge| *edge.weight() == EdgeKind::DefToScope)
323 .map(|edge| edge.source())
324 {
325 if let NodeKind::Def(def) = &self.graph[local_def].kind {
326 if new.text == def.text {
327 match (def.symbol.as_ref(), new.symbol.as_ref()) {
328 // both contain symbols, but they don't belong to the same namepspace
329 (Some(d), Some(r)) if d != r => {}
330
331 // in all other cases, form an edge from the ref to def.
332 // an empty symbol belongs to all namespaces:
333 // * (None, None)
334 // * (None, Some(_))
335 // * (Some(_), None)
336 // * (Some(_), Some(_)) if def.namespace == ref.namespace
337 _ => {
338 possible_defs.push(local_def);
339 }
340 };
341 }
342 }
343 }
344
345 // find candidate imports in each scope
346 for local_import in self
347 .graph
348 .edges_directed(scope, Direction::Incoming)
349 .filter(|edge| *edge.weight() == EdgeKind::ImportToScope)
350 .map(|edge| edge.source())
351 {
352 if let NodeKind::Import(import) = &self.graph[local_import].kind {
353 if new.text == import.text {
354 possible_imports.push(local_import);
355 }
356 }
357 }
358 }
359 }
360
361 if !possible_defs.is_empty() || !possible_imports.is_empty() {
362 let new_ref = Node::reference(new);
363 let ref_idx = self.graph.add_node(new_ref);
364 for def_idx in possible_defs {
365 self.graph.add_edge(ref_idx, def_idx, EdgeKind::RefToDef);
366 }
367 for imp_idx in possible_imports {
368 self.graph.add_edge(ref_idx, imp_idx, EdgeKind::RefToImport);
369 }
370 }
371 }
372
373 fn scope_stack(&self, start: NodeIndex) -> ScopeStack<'_> {
374 ScopeStack {
375 scope_graph: self,
376 start: Some(start),
377 }
378 }
379
380 // The smallest scope that encompasses `range`. Start at `start` and narrow down if possible.
381 fn scope_by_range(&self, range: TextRange, start: NodeIndex) -> Option<NodeIndex> {
382 let target_range = self.graph[start].range();
383 if target_range.contains(&range) {
384 let mut child_scopes = self
385 .graph
386 .edges_directed(start, Direction::Incoming)
387 .filter(|edge| *edge.weight() == EdgeKind::ScopeToScope)
388 .map(|edge| edge.source())
389 .collect::<Vec<_>>();
390
391 child_scopes.sort_by_key(|s| self.graph[*s].range());
392 let target_child_scope = child_scopes.binary_search_by(|x| {
393 if self.graph[*x].range().contains(&range) {
394 std::cmp::Ordering::Equal
395 } else {
396 self.graph[*x].range().cmp(&range)
397 }
398 });
399
400 if let Some(t) = target_child_scope
401 .ok()
402 .and_then(|idx| child_scopes.get(idx))
403 .and_then(|s| self.scope_by_range(range, *s))
404 {
405 return Some(t);
406 } else {
407 return Some(start);
408 }
409 }
410 None
411 }
412
413 /// Produce a list of interesting ranges: ranges of defs and refs
414 pub fn hoverable_ranges(&self) -> Box<dyn Iterator<Item = TextRange> + '_> {
415 let iterator =
416 self.graph
417 .node_indices()
418 .filter_map(|node_idx| match &self.graph[node_idx].kind {
419 NodeKind::Scope(_) => None,
420 NodeKind::Def(d) => Some(d.range),
421 NodeKind::Ref(r) => Some(r.range),
422 NodeKind::Import(i) => Some(i.range),
423 });
424 Box::new(iterator)
425 }
426
427 /// Produce possible definitions for a reference
428 pub fn definitions(
429 &self,
430 reference_node: NodeIndex,
431 ) -> Box<dyn Iterator<Item = NodeIndex> + '_> {
432 let iterator = self
433 .graph
434 .edges_directed(reference_node, Direction::Outgoing)
435 .filter(|edge| *edge.weight() == EdgeKind::RefToDef)
436 .map(|edge| edge.target());
437 Box::new(iterator)
438 }
439
440 /// Produce possible imports for a reference
441 pub fn imports(&self, reference_node: NodeIndex) -> Box<dyn Iterator<Item = NodeIndex> + '_> {
442 let iterator = self
443 .graph
444 .edges_directed(reference_node, Direction::Outgoing)
445 .filter(|edge| *edge.weight() == EdgeKind::RefToImport)
446 .map(|edge| edge.target());
447 Box::new(iterator)
448 }
449
450 /// Produce possible references for a definition/import node
451 pub fn references(
452 &self,
453 definition_node: NodeIndex,
454 ) -> Box<dyn Iterator<Item = NodeIndex> + '_> {
455 let iterator = self
456 .graph
457 .edges_directed(definition_node, Direction::Incoming)
458 .filter(|edge| {
459 *edge.weight() == EdgeKind::RefToDef || *edge.weight() == EdgeKind::RefToImport
460 })
461 .map(|edge| edge.source());
462 Box::new(iterator)
463 }
464
465 pub fn node_by_range(&self, start_byte: usize, end_byte: usize) -> Option<NodeIndex> {
466 self.graph
467 .node_indices()
468 .filter(|&idx| self.is_definition(idx) || self.is_reference(idx) || self.is_import(idx))
469 .find(|&idx| {
470 let node = self.graph[idx].range();
471 start_byte >= node.start.byte && end_byte <= node.end.byte
472 })
473 }
474
475 pub fn node_by_position(&self, line: usize, column: usize) -> Option<NodeIndex> {
476 self.graph
477 .node_indices()
478 .filter(|&idx| self.is_definition(idx) || self.is_reference(idx))
479 .find(|&idx| {
480 let node = self.graph[idx].range();
481 node.start.line == line
482 && node.end.line == line
483 && node.start.column <= column
484 && node.end.column >= column
485 })
486 }
487
488 #[cfg(test)]
489 pub fn find_node_by_name(&self, src: &[u8], name: &[u8]) -> Option<NodeIndex> {
490 self.graph.node_indices().find(|idx| {
491 matches!(
492 &self.graph[*idx].kind,
493 NodeKind::Def(d) if d.name(src) == name)
494 })
495 }
496
497 #[cfg(test)]
498 pub fn debug(&self, src: &[u8]) -> crate::debug::ScopeDebug {
499 let graph = &self.graph;
500 let start = self.root_idx;
501 crate::debug::ScopeDebug::new(graph, start, src)
502 }
503
504 pub fn is_definition(&self, node_idx: NodeIndex) -> bool {
505 matches!(self.graph[node_idx].kind, NodeKind::Def(_))
506 }
507
508 pub fn is_reference(&self, node_idx: NodeIndex) -> bool {
509 matches!(self.graph[node_idx].kind, NodeKind::Ref(_))
510 }
511
512 pub fn is_scope(&self, node_idx: NodeIndex) -> bool {
513 matches!(self.graph[node_idx].kind, NodeKind::Scope(_))
514 }
515
516 pub fn is_import(&self, node_idx: NodeIndex) -> bool {
517 matches!(self.graph[node_idx].kind, NodeKind::Import(_))
518 }
519}
520
521fn build_scope_graph(
522 tsg: tree_sitter_graph::graph::Graph,
523 mut scope_graph: ScopeGraph,
524) -> ScopeGraph {
525 let nodes = tsg.iter_nodes().collect::<Vec<_>>();
526 for node in nodes
527 .iter()
528 .map(|node_ref| &tsg[*node_ref])
529 .filter(|node| is_scope(node))
530 {
531 let range =
532 text_range::value_to_range(node.attributes.get(&Identifier::from("range")).unwrap());
533 let scope = LocalScope::new(range.into());
534 scope_graph.insert_local_scope(scope);
535 }
536
537 for node in nodes
538 .iter()
539 .map(|node_ref| &tsg[*node_ref])
540 .filter(|node| is_import(node))
541 {
542 let range =
543 text_range::value_to_range(node.attributes.get(&Identifier::from("range")).unwrap());
544 let text = node
545 .attributes
546 .get(&Identifier::from("text"))
547 .and_then(|id| id.clone().into_string().ok())
548 .expect("import without text");
549 let import = LocalImport::new(range.into(), text);
550 scope_graph.insert_local_import(import);
551 }
552
553 for node in nodes
554 .iter()
555 .map(|node_ref| &tsg[*node_ref])
556 .filter(|node| is_def(node))
557 {
558 let range =
559 text_range::value_to_range(node.attributes.get(&Identifier::from("range")).unwrap());
560 let symbol = node
561 .attributes
562 .get(&Identifier::from("symbol"))
563 .and_then(|id| id.clone().into_string().ok());
564 let text = node
565 .attributes
566 .get(&Identifier::from("text"))
567 .and_then(|id| id.clone().into_string().ok())
568 .expect("def without text");
569 let local_def = LocalDef::new(range.into(), text, symbol);
570
571 // TODO: fix scoping here
572 scope_graph.insert_local_def(local_def);
573 }
574
575 for node in nodes
576 .iter()
577 .map(|node_ref| &tsg[*node_ref])
578 .filter(|node| is_ref(node))
579 {
580 let range =
581 text_range::value_to_range(node.attributes.get(&Identifier::from("range")).unwrap());
582 let symbol = node
583 .attributes
584 .get(&Identifier::from("symbol"))
585 .and_then(|id| id.clone().into_string().ok());
586 let text = node
587 .attributes
588 .get(&Identifier::from("text"))
589 .and_then(|id| id.clone().into_string().ok())
590 .expect("ref without text");
591 let ref_ = Reference::new(range.into(), text, symbol);
592
593 scope_graph.insert_ref(ref_);
594 }
595
596 scope_graph
597}
598
599fn is_string_attr(node: &tree_sitter_graph::graph::GraphNode, key: &str, value: &str) -> bool {
600 matches!(node.attributes.get(&Identifier::from(key)).and_then(|v| v.as_str().ok()), Some(v) if v == value)
601}
602
603fn is_scope(node: &tree_sitter_graph::graph::GraphNode) -> bool {
604 is_string_attr(node, "kind", "scope")
605}
606
607fn is_import(node: &tree_sitter_graph::graph::GraphNode) -> bool {
608 is_string_attr(node, "kind", "import")
609}
610
611fn is_def(node: &tree_sitter_graph::graph::GraphNode) -> bool {
612 is_string_attr(node, "kind", "def")
613}
614
615fn is_ref(node: &tree_sitter_graph::graph::GraphNode) -> bool {
616 is_string_attr(node, "kind", "ref")
617}
618
619#[cfg(test)]
620mod tests {
621 use super::*;
622 use expect_test::{expect, Expect};
623
624 fn counts(src: &str) -> (usize, usize, usize, usize) {
625 let sg = build_graph(src);
626 let nodes = sg.graph.node_weights();
627
628 nodes.fold((0, 0, 0, 0), |(s, d, r, i), node| match node.kind {
629 NodeKind::Scope(_) => (s + 1, d, r, i),
630 NodeKind::Def(_) => (s, d + 1, r, i),
631 NodeKind::Ref(_) => (s, d, r + 1, i),
632 NodeKind::Import(_) => (s, d, r, i + 1),
633 })
634 }
635
636 pub fn test_scopes(src: &str, expected: Expect) {
637 let graph = build_graph(src);
638 let observed = graph.debug(src.as_bytes());
639 expected.assert_debug_eq(&observed)
640 }
641
642 pub fn build_graph(src: &str) -> ScopeGraph {
643 StagBuilder::default()
644 .with_source(src)
645 .with_stag_file(crate::RUST)
646 .with_language(tree_sitter_rust::LANGUAGE.into())
647 .execute()
648 .unwrap()
649 }
650
651 #[test]
652 fn declare_const_and_static() {
653 let src = r#"
654 const a: () = ();
655 static b: () = ();
656 "#;
657
658 let (_, def_count, _, _) = counts(src);
659
660 // a, b
661 assert_eq!(def_count, 2);
662 }
663
664 #[test]
665 fn declare_let_statement() {
666 let src = r#"
667 fn main() {
668 let a = ();
669 let (b, c) = ();
670 let S { d, e } = ();
671 let S { field: f, g } = ();
672 let S { h, .. } = ();
673 let S { i, field: _ } = ();
674 }
675 "#;
676 let (_, def_count, _, _) = counts(src);
677
678 // main, a, b, c, d, e, f, g, h, i
679 assert_eq!(def_count, 10);
680 }
681
682 #[test]
683 fn declare_function_params() {
684 let src = r#"
685 fn f1(a: T) {}
686 fn f2(b: T, c: T) {}
687 fn f3((d, e): (T, U)) {}
688 fn f4(S {f, g}: S) {}
689 fn f5(S {h, ..}: S) {}
690 fn f6(S { field: i }: S) {}
691 "#;
692 let (_, def_count, _, _) = counts(src);
693
694 // f1, f2, f3, f4, f5, f6, a, b, c, d, e, f, g, h, i
695 assert_eq!(def_count, 15);
696 }
697
698 #[test]
699 fn declare_closure_params() {
700 let src = r#"
701 fn main() {
702 let _ = |x| {};
703 let _ = |x, y| {};
704 let _ = |x: ()| {};
705 let _ = |(x, y): ()| {};
706 }
707 "#;
708 let (_, def_count, _, _) = counts(src);
709
710 // main,
711 // x,
712 // x, y,
713 // x,
714 // x, y
715 assert_eq!(def_count, 7);
716 }
717
718 #[test]
719 fn declare_labels() {
720 let src = r#"
721 fn main() {
722 'loop: loop {};
723 'loop: for _ in () {}
724 'loop: while true {}
725 }
726 "#;
727 let (_, def_count, _, _) = counts(src);
728
729 // main, 'loop x3
730 assert_eq!(def_count, 4);
731 }
732
733 #[test]
734 fn declare_types() {
735 let src = r#"
736 struct One {
737 two: T,
738 three: T,
739 }
740
741 enum Four {
742 Five,
743 Six(T),
744 Seven {
745 eight: T
746 }
747 }
748
749 union Nine {}
750
751 type Ten = ();
752 "#;
753 let (_, def_count, _, _) = counts(src);
754
755 assert_eq!(def_count, 10);
756 }
757
758 #[test]
759 fn declare_namespaces() {
760 let src = r#"
761 mod one {}
762 pub mod two {}
763 mod three {
764 mod four {}
765 }
766 "#;
767 let (_, def_count, _, _) = counts(src);
768
769 assert_eq!(def_count, 4);
770 }
771
772 #[test]
773 fn declare_let_expr() {
774 let src = r#"
775 if let a = () {}
776 if let Some(a) = () {}
777
778 while let a = () {}
779 while let Some(a) = () {}
780 "#;
781 let (_, def_count, _, _) = counts(src);
782
783 assert_eq!(def_count, 4);
784 }
785
786 #[test]
787 fn refer_unary_expr() {
788 let src = r#"
789 fn main() {
790 let a = 2;
791 !a;
792 -a;
793 *a;
794 }
795 "#;
796 let (_, _, ref_count, _) = counts(src);
797
798 assert_eq!(ref_count, 3);
799 }
800
801 #[test]
802 fn refer_binary_expr() {
803 let src = r#"
804 fn main() {
805 let a = 2;
806 let b = 3;
807 a + b;
808 a >> b;
809 }
810 "#;
811 let (_, _, ref_count, _) = counts(src);
812
813 assert_eq!(ref_count, 4);
814 }
815
816 #[test]
817 fn refer_control_flow() {
818 let src = r#"
819 fn main() {
820 let a = 2;
821
822 // 1
823 if a {}
824
825 // 2
826 if _ {} else if a {}
827
828 // 3
829 while a {
830 // 4
831 break a;
832 }
833
834 // 5
835 a?;
836
837 // 6
838 return a;
839
840 // 7
841 a.await;
842
843 // 8
844 yield a;
845 }
846 "#;
847 let (_, _, ref_count, _) = counts(src);
848
849 assert_eq!(ref_count, 8);
850 }
851
852 #[test]
853 fn refer_assignment() {
854 let src = r#"
855 fn main() {
856 let mut a = 2;
857 a += 2;
858 a = 2;
859 a *= 2;
860 }
861 "#;
862 let (_, _, ref_count, _) = counts(src);
863
864 assert_eq!(ref_count, 3);
865 }
866
867 #[test]
868 fn refer_struct_expr() {
869 let src = r#"
870 fn main() {
871 let a = 2;
872 let b = 2;
873 S { a, b };
874 S { ..a };
875 S { field: a, b };
876 }
877 "#;
878 let (_, _, ref_count, _) = counts(src);
879
880 assert_eq!(ref_count, 5);
881 }
882
883 #[test]
884 fn refer_dot() {
885 let src = r#"
886 fn main() {
887 let a = S {};
888
889 a.b;
890 a.foo();
891 }
892 "#;
893 let (_, _, ref_count, _) = counts(src);
894
895 assert_eq!(ref_count, 2);
896 }
897
898 #[test]
899 fn refer_arguments() {
900 let src = r#"
901 fn main() {
902 let a = 2;
903 let b = 3;
904 foo(a, b);
905 }
906 "#;
907 let (_, _, ref_count, _) = counts(src);
908
909 assert_eq!(ref_count, 2);
910 }
911
912 #[test]
913 fn function_params() {
914 test_scopes(
915 r#"
916 fn foo(t: T, u: U) -> R {}
917 "#,
918 expect![[r#"
919 scope {
920 definitions: [
921 foo {
922 context: "fn §foo§(t: T, u: U) -> R {}",
923 },
924 ],
925 child scopes: [
926 scope {
927 definitions: [
928 t {
929 context: "fn foo(§t§: T, u: U) -> R {}",
930 },
931 u {
932 context: "fn foo(t: T, §u§: U) -> R {}",
933 },
934 ],
935 child scopes: [],
936 },
937 scope {
938 definitions: [],
939 child scopes: [],
940 },
941 ],
942 }
943 "#]],
944 );
945 }
946
947 #[test]
948 fn use_statements() {
949 test_scopes(
950 r#"
951 mod intelligence;
952
953 use bleep;
954 use super::test_utils;
955 use intelligence::language as lang;
956 use crate::text_range::{TextRange, Point};
957 "#,
958 expect![[r#"
959 scope {
960 definitions: [
961 intelligence {
962 context: "mod §intelligence§;",
963 referenced in (1): [
964 `use §intelligence§::language as lang;`,
965 ],
966 },
967 bleep {
968 context: "use §bleep§;",
969 },
970 test_utils {
971 context: "use super::§test_utils§;",
972 },
973 lang {
974 context: "use intelligence::language as §lang§;",
975 },
976 TextRange {
977 context: "use crate::text_range::{§TextRange§, Point};",
978 },
979 Point {
980 context: "use crate::text_range::{TextRange, §Point§};",
981 },
982 ],
983 child scopes: [],
984 }
985 "#]],
986 )
987 }
988
989 #[test]
990 fn lifetimes() {
991 test_scopes(
992 r#"
993 impl<'a, T> Trait for Struct<'a, T> {
994 fn foo<'b>(&'a self) -> &'b T { }
995 }
996 "#,
997 expect![[r#"
998 scope {
999 definitions: [],
1000 child scopes: [
1001 scope {
1002 definitions: [
1003 'a {
1004 context: "impl<§'a§, T> Trait for Struct<'a, T> {",
1005 referenced in (2): [
1006 `impl<'a, T> Trait for Struct<§'a§, T> {`,
1007 `fn foo<'b>(&§'a§ self) -> &'b T { }`,
1008 ],
1009 },
1010 T {
1011 context: "impl<'a, §T§> Trait for Struct<'a, T> {",
1012 referenced in (2): [
1013 `impl<'a, T> Trait for Struct<'a, §T§> {`,
1014 `fn foo<'b>(&'a self) -> &'b §T§ { }`,
1015 ],
1016 },
1017 ],
1018 child scopes: [
1019 scope {
1020 definitions: [
1021 foo {
1022 context: "fn §foo§<'b>(&'a self) -> &'b T { }",
1023 },
1024 ],
1025 child scopes: [
1026 scope {
1027 definitions: [
1028 'b {
1029 context: "fn foo<§'b§>(&'a self) -> &'b T { }",
1030 referenced in (1): [
1031 `fn foo<'b>(&'a self) -> &§'b§ T { }`,
1032 ],
1033 },
1034 self {
1035 context: "fn foo<'b>(&'a §self§) -> &'b T { }",
1036 },
1037 ],
1038 child scopes: [],
1039 },
1040 scope {
1041 definitions: [],
1042 child scopes: [],
1043 },
1044 ],
1045 },
1046 ],
1047 },
1048 ],
1049 }
1050 "#]],
1051 )
1052 }
1053
1054 #[test]
1055 fn generics_and_traits() {
1056 test_scopes(
1057 r#"
1058 trait Foo {}
1059
1060 fn foo<'a, 'b, T, U: Foo<T> + 'a>(t: T, u: U)
1061 where T: Foo + 'b,
1062 { }
1063 "#,
1064 expect![[r#"
1065 scope {
1066 definitions: [
1067 Foo {
1068 context: "trait §Foo§ {}",
1069 referenced in (2): [
1070 `fn foo<'a, 'b, T, U: §Foo§<T> + 'a>(t: T, u: U)`,
1071 `where T: §Foo§ + 'b,`,
1072 ],
1073 },
1074 foo {
1075 context: "fn §foo§<'a, 'b, T, U: Foo<T> + 'a>(t: T, u: U)",
1076 },
1077 ],
1078 child scopes: [
1079 scope {
1080 definitions: [],
1081 child scopes: [
1082 scope {
1083 definitions: [],
1084 child scopes: [
1085 scope {
1086 definitions: [],
1087 child scopes: [],
1088 },
1089 ],
1090 },
1091 ],
1092 },
1093 scope {
1094 definitions: [
1095 'a {
1096 context: "fn foo<§'a§, 'b, T, U: Foo<T> + 'a>(t: T, u: U)",
1097 referenced in (1): [
1098 `fn foo<'a, 'b, T, U: Foo<T> + §'a§>(t: T, u: U)`,
1099 ],
1100 },
1101 'b {
1102 context: "fn foo<'a, §'b§, T, U: Foo<T> + 'a>(t: T, u: U)",
1103 referenced in (1): [
1104 `where T: Foo + §'b§,`,
1105 ],
1106 },
1107 T {
1108 context: "fn foo<'a, 'b, §T§, U: Foo<T> + 'a>(t: T, u: U)",
1109 referenced in (3): [
1110 `fn foo<'a, 'b, T, U: Foo<§T§> + 'a>(t: T, u: U)`,
1111 `fn foo<'a, 'b, T, U: Foo<T> + 'a>(t: §T§, u: U)`,
1112 `where §T§: Foo + 'b,`,
1113 ],
1114 },
1115 U {
1116 context: "fn foo<'a, 'b, T, §U§: Foo<T> + 'a>(t: T, u: U)",
1117 referenced in (1): [
1118 `fn foo<'a, 'b, T, U: Foo<T> + 'a>(t: T, u: §U§)`,
1119 ],
1120 },
1121 t {
1122 context: "fn foo<'a, 'b, T, U: Foo<T> + 'a>(§t§: T, u: U)",
1123 },
1124 u {
1125 context: "fn foo<'a, 'b, T, U: Foo<T> + 'a>(t: T, §u§: U)",
1126 },
1127 ],
1128 child scopes: [],
1129 },
1130 scope {
1131 definitions: [],
1132 child scopes: [],
1133 },
1134 ],
1135 }
1136 "#]],
1137 )
1138 }
1139
1140 #[test]
1141 fn type_constructors() {
1142 test_scopes(
1143 r#"
1144 struct Highlight {}
1145
1146 enum Direction { Incoming, Outgoing }
1147
1148 fn foo() -> Highlight {
1149 Highlight { }
1150 }
1151
1152 fn bar() -> Direction {
1153 Direction::Incoming
1154 }
1155 "#,
1156 expect![[r#"
1157 scope {
1158 definitions: [
1159 Highlight {
1160 context: "struct §Highlight§ {}",
1161 referenced in (2): [
1162 `fn foo() -> §Highlight§ {`,
1163 `§Highlight§ { }`,
1164 ],
1165 },
1166 Direction {
1167 context: "enum §Direction§ { Incoming, Outgoing }",
1168 referenced in (2): [
1169 `fn bar() -> §Direction§ {`,
1170 `§Direction§::Incoming`,
1171 ],
1172 },
1173 foo {
1174 context: "fn §foo§() -> Highlight {",
1175 },
1176 bar {
1177 context: "fn §bar§() -> Direction {",
1178 },
1179 ],
1180 child scopes: [
1181 scope {
1182 definitions: [],
1183 child scopes: [
1184 scope {
1185 definitions: [],
1186 child scopes: [],
1187 },
1188 ],
1189 },
1190 scope {
1191 definitions: [],
1192 child scopes: [
1193 scope {
1194 definitions: [
1195 Incoming {
1196 context: "enum Direction { §Incoming§, Outgoing }",
1197 },
1198 Outgoing {
1199 context: "enum Direction { Incoming, §Outgoing§ }",
1200 },
1201 ],
1202 child scopes: [],
1203 },
1204 ],
1205 },
1206 scope {
1207 definitions: [],
1208 child scopes: [],
1209 },
1210 scope {
1211 definitions: [],
1212 child scopes: [],
1213 },
1214 scope {
1215 definitions: [],
1216 child scopes: [],
1217 },
1218 scope {
1219 definitions: [],
1220 child scopes: [],
1221 },
1222 ],
1223 }
1224 "#]],
1225 )
1226 }
1227
1228 #[test]
1229 fn macros() {
1230 test_scopes(
1231 r#"
1232 fn main() {
1233 let (a, b, c) = ();
1234 // top-level tokens
1235 assert_eq!(a, b + c);
1236
1237 // nested tokens
1238 println!("{}", if a { b } then { c });
1239 }
1240 "#,
1241 expect![[r#"
1242 scope {
1243 definitions: [
1244 main {
1245 context: "fn §main§() {",
1246 },
1247 ],
1248 child scopes: [
1249 scope {
1250 definitions: [],
1251 child scopes: [],
1252 },
1253 scope {
1254 definitions: [
1255 a {
1256 context: "let (§a§, b, c) = ();",
1257 referenced in (2): [
1258 `assert_eq!(§a§, b + c);`,
1259 `println!("{}", if §a§ { b } then { c });`,
1260 ],
1261 },
1262 b {
1263 context: "let (a, §b§, c) = ();",
1264 referenced in (2): [
1265 `assert_eq!(a, §b§ + c);`,
1266 `println!("{}", if a { §b§ } then { c });`,
1267 ],
1268 },
1269 c {
1270 context: "let (a, b, §c§) = ();",
1271 referenced in (2): [
1272 `assert_eq!(a, b + §c§);`,
1273 `println!("{}", if a { b } then { §c§ });`,
1274 ],
1275 },
1276 ],
1277 child scopes: [],
1278 },
1279 ],
1280 }
1281 "#]],
1282 )
1283 }
1284
1285 // Self::method and self.method can be raised as references
1286 #[test]
1287 fn handle_self_type_and_var() {
1288 test_scopes(
1289 r#"
1290 struct MyStruct {}
1291
1292 impl MyStruct {
1293 fn foo() {
1294 Self::foo()
1295 }
1296
1297 fn bar(&self) {
1298 self.bar()
1299 }
1300 }
1301 "#,
1302 expect![[r#"
1303 scope {
1304 definitions: [
1305 MyStruct {
1306 context: "struct §MyStruct§ {}",
1307 referenced in (1): [
1308 `impl §MyStruct§ {`,
1309 ],
1310 },
1311 ],
1312 child scopes: [
1313 scope {
1314 definitions: [],
1315 child scopes: [
1316 scope {
1317 definitions: [],
1318 child scopes: [],
1319 },
1320 ],
1321 },
1322 scope {
1323 definitions: [],
1324 child scopes: [
1325 scope {
1326 definitions: [
1327 foo {
1328 context: "fn §foo§() {",
1329 referenced in (1): [
1330 `Self::§foo§()`,
1331 ],
1332 },
1333 bar {
1334 context: "fn §bar§(&self) {",
1335 referenced in (1): [
1336 `self.§bar§()`,
1337 ],
1338 },
1339 ],
1340 child scopes: [
1341 scope {
1342 definitions: [],
1343 child scopes: [],
1344 },
1345 scope {
1346 definitions: [],
1347 child scopes: [],
1348 },
1349 scope {
1350 definitions: [
1351 self {
1352 context: "fn bar(&§self§) {",
1353 },
1354 ],
1355 child scopes: [],
1356 },
1357 scope {
1358 definitions: [],
1359 child scopes: [],
1360 },
1361 ],
1362 },
1363 ],
1364 },
1365 ],
1366 }
1367 "#]],
1368 )
1369 }
1370
1371 #[test]
1372 fn let_else_1_65_support() {
1373 test_scopes(
1374 r#"
1375 fn main() {
1376 let a = 3;
1377 if let b = a
1378 && let c = b
1379 && let d = c {
1380 d
1381 } else {
1382 return;
1383 }
1384 }
1385 "#,
1386 expect![[r#"
1387 scope {
1388 definitions: [
1389 main {
1390 context: "fn §main§() {",
1391 },
1392 ],
1393 child scopes: [
1394 scope {
1395 definitions: [],
1396 child scopes: [],
1397 },
1398 scope {
1399 definitions: [
1400 a {
1401 context: "let §a§ = 3;",
1402 referenced in (1): [
1403 `if let b = §a§`,
1404 ],
1405 },
1406 ],
1407 child scopes: [
1408 scope {
1409 definitions: [
1410 b {
1411 context: "if let §b§ = a",
1412 referenced in (1): [
1413 `&& let c = §b§`,
1414 ],
1415 },
1416 c {
1417 context: "&& let §c§ = b",
1418 referenced in (1): [
1419 `&& let d = §c§ {`,
1420 ],
1421 },
1422 d {
1423 context: "&& let §d§ = c {",
1424 },
1425 ],
1426 child scopes: [],
1427 },
1428 scope {
1429 definitions: [],
1430 child scopes: [],
1431 },
1432 scope {
1433 definitions: [],
1434 child scopes: [],
1435 },
1436 ],
1437 },
1438 ],
1439 }
1440 "#]],
1441 )
1442 }
1443}