intelligent ctags powered by tree-sitter and lexical scope-graphs

add html bin

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