+17
-1
Cargo.lock
+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
+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
+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
src/debug.rs
+10
src/languages/go.tsg
+10
src/languages/go.tsg
+6
-1410
src/lib.rs
+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
+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
+2
-1
src/stag.tsg
src/languages/rust.tsg
+12
-28
src/stdlib.rs
+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
}