aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/hover.rs
blob: c3825f6ea8ffb4af4a7f8af8ffd3ca1369e5f1b2 (plain)
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
use ra_db::{Cancelable, SyntaxDatabase};
use ra_syntax::{ast, AstNode};

use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange};

pub(crate) fn hover(
    db: &RootDatabase,
    position: FilePosition,
) -> Cancelable<Option<RangeInfo<String>>> {
    let mut res = Vec::new();
    let range = if let Some(rr) = db.approximately_resolve_symbol(position)? {
        for nav in rr.resolves_to {
            res.extend(db.doc_text_for(nav)?)
        }
        rr.reference_range
    } else {
        let file = db.source_file(position.file_id);
        let expr: ast::Expr = ctry!(ra_editor::find_node_at_offset(
            file.syntax(),
            position.offset
        ));
        let frange = FileRange {
            file_id: position.file_id,
            range: expr.syntax().range(),
        };
        res.extend(db.type_of(frange)?);
        expr.syntax().range()
    };
    if res.is_empty() {
        return Ok(None);
    }
    let res = RangeInfo::new(range, res.join("\n\n---\n"));
    Ok(Some(res))
}

#[cfg(test)]
mod tests {
    use ra_syntax::TextRange;

    use crate::mock_analysis::single_file_with_position;

    #[test]
    fn hover_shows_type_of_an_expression() {
        let (analysis, position) = single_file_with_position(
            "
            pub fn foo() -> u32 { 1 }

            fn main() {
                let foo_test = foo()<|>;
            }
        ",
        );
        let hover = analysis.hover(position).unwrap().unwrap();
        assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into()));
        assert_eq!(hover.info, "u32");
    }
}