aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/impls.rs
blob: 750a869f256fa9cc02e5669ec5094d91bb7a716e (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
84
85
86
//! Defines hir-level representation of impls.
//!
//! The handling is similar, but is not quite the same as for other items,
//! because `impl`s don't have names.

use std::sync::Arc;

use hir_expand::AstId;
use ra_syntax::ast;

use crate::{
    db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstLoc, ContainerId,
    FunctionLoc, ImplId, Intern, TypeAliasLoc,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplData {
    target_trait: Option<TypeRef>,
    target_type: TypeRef,
    items: Vec<AssocItemId>,
    negative: bool,
}

impl ImplData {
    pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> {
        let src = id.source(db);
        let items = db.ast_id_map(src.file_id);

        let target_trait = src.value.target_trait().map(TypeRef::from_ast);
        let target_type = TypeRef::from_ast_opt(src.value.target_type());
        let negative = src.value.is_negative();

        let items = if let Some(item_list) = src.value.item_list() {
            item_list
                .impl_items()
                .map(|item_node| match item_node {
                    ast::ImplItem::FnDef(it) => {
                        let def = FunctionLoc {
                            container: ContainerId::ImplId(id),
                            ast_id: AstId::new(src.file_id, items.ast_id(&it)),
                        }
                        .intern(db);
                        def.into()
                    }
                    ast::ImplItem::ConstDef(it) => {
                        let def = ConstLoc {
                            container: ContainerId::ImplId(id),
                            ast_id: AstId::new(src.file_id, items.ast_id(&it)),
                        }
                        .intern(db);
                        def.into()
                    }
                    ast::ImplItem::TypeAliasDef(it) => {
                        let def = TypeAliasLoc {
                            container: ContainerId::ImplId(id),
                            ast_id: AstId::new(src.file_id, items.ast_id(&it)),
                        }
                        .intern(db);
                        def.into()
                    }
                })
                .collect()
        } else {
            Vec::new()
        };

        let res = ImplData { target_trait, target_type, items, negative };
        Arc::new(res)
    }

    pub fn target_trait(&self) -> Option<&TypeRef> {
        self.target_trait.as_ref()
    }

    pub fn target_type(&self) -> &TypeRef {
        &self.target_type
    }

    pub fn items(&self) -> &[AssocItemId] {
        &self.items
    }

    pub fn is_negative(&self) -> bool {
        self.negative
    }
}