aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/navigation_target.rs
blob: eaf46fd01e8155779785a5d92f57a11b846bc17d (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
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
use ra_db::{FileId, LocalSyntaxPtr, Cancelable};
use ra_syntax::{SyntaxNode, AstNode};
use hir::{Name, Def, ModuleSource};

use crate::{
    NavigationTarget,
    FileSymbol,
    db::RootDatabase,
};

impl NavigationTarget {
    pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            range: symbol.ptr.range(),
            ptr: Some(symbol.ptr.clone()),
        }
    }

    // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
    pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
        Ok(match def {
            Def::Struct(s) => {
                let (file_id, node) = s.source(db)?;
                Some(NavigationTarget::from_syntax(
                    s.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Enum(e) => {
                let (file_id, node) = e.source(db)?;
                Some(NavigationTarget::from_syntax(
                    e.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::EnumVariant(ev) => {
                let (file_id, node) = ev.source(db)?;
                Some(NavigationTarget::from_syntax(
                    ev.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Function(f) => {
                let (file_id, node) = f.source(db)?;
                let name = f.signature(db).name().clone();
                Some(NavigationTarget::from_syntax(
                    Some(name),
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Module(m) => {
                let (file_id, source) = m.definition_source(db)?;
                let name = m.name(db)?;
                match source {
                    ModuleSource::SourceFile(node) => {
                        Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
                    }
                    ModuleSource::Module(node) => {
                        Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
                    }
                }
            }
            Def::Item => None,
        })
    }

    fn from_syntax(name: Option<Name>, file_id: FileId, node: &SyntaxNode) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name: name.map(|n| n.to_string().into()).unwrap_or("".into()),
            kind: node.kind(),
            range: node.range(),
            ptr: Some(LocalSyntaxPtr::new(node)),
        }
    }
}