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);
    }
}