intelligent ctags powered by tree-sitter and lexical scope-graphs
at main 48 kB view raw
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}