1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::ast;
use crate::shims::{to_offset, to_range};
use crate::ProgramInfo;
use libslide::*;
use tower_lsp::lsp_types::*;
use visit::StmtVisitor;
pub(crate) fn get_references(
position: Position,
include_declaration: bool,
program_info: &ProgramInfo,
) -> Option<Vec<Location>> {
let ProgramInfo { uri, source, .. } = program_info;
let references = get_kinded_references(position, program_info)?;
let references = references
.into_iter()
.filter_map(|rk| match rk {
ReferenceKind::Definition(_) if !include_declaration => None,
_ => Some(Location::new(uri.clone(), to_range(rk.span(), source))),
})
.collect();
Some(references)
}
pub enum ReferenceKind {
Definition(Span),
Usage(Span),
}
impl ReferenceKind {
pub fn span(&self) -> &Span {
match self {
Self::Definition(sp) => sp,
Self::Usage(sp) => sp,
}
}
}
pub(crate) fn get_kinded_references(
position: Position,
program_info: &ProgramInfo,
) -> Option<Vec<ReferenceKind>> {
let program = &program_info.original;
let position = to_offset(&position, &program_info.source);
let tightest_expr = ast::get_tightest_expr(position, &program)?;
let seeking = tightest_expr.get_var()?;
let mut reference_finder = ReferenceFinder {
seeking,
is_declaration: false,
refs: vec![],
};
reference_finder.visit_stmt_list(&program);
Some(reference_finder.refs)
}
struct ReferenceFinder {
seeking: InternedStr,
is_declaration: bool,
refs: Vec<ReferenceKind>,
}
impl<'a> StmtVisitor<'a> for ReferenceFinder {
fn visit_var(&mut self, var: &'a InternedStr, span: Span) {
if *var == self.seeking {
self.refs.push(match self.is_declaration {
true => ReferenceKind::Definition(span),
false => ReferenceKind::Usage(span),
});
}
}
fn visit_asgn(&mut self, asgn: &'a Assignment) {
fn visit_asgn_side(visitor: &mut ReferenceFinder, side: &RcExpr) {
visitor.is_declaration = side.is_var();
visit::descend_expr(visitor, side);
visitor.is_declaration = false;
}
visit_asgn_side(self, &asgn.lhs);
visit_asgn_side(self, &asgn.rhs);
}
}