]> git.lizzy.rs Git - rust.git/blob - crates/hir/src/has_source.rs
dd7c0c57067c27e9ab3d5df0157563ed2e464496
[rust.git] / crates / hir / src / has_source.rs
1 //! Provides set of implementation for hir's objects that allows get back location in file.
2
3 use either::Either;
4 use hir_def::{
5     nameres::{ModuleOrigin, ModuleSource},
6     src::{HasChildSource, HasSource as _},
7     Lookup, VariantId,
8 };
9 use hir_expand::InFile;
10 use syntax::ast;
11
12 use crate::{
13     db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
14     MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
15 };
16
17 pub trait HasSource {
18     type Ast;
19     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
20 }
21
22 /// NB: Module is !HasSource, because it has two source nodes at the same time:
23 /// definition and declaration.
24 impl Module {
25     /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
26     pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
27         let def_map = db.crate_def_map(self.id.krate);
28         def_map[self.id.local_id].definition_source(db.upcast())
29     }
30
31     pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
32         let def_map = db.crate_def_map(self.id.krate);
33         match def_map[self.id.local_id].origin {
34             ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
35             _ => false,
36         }
37     }
38
39     /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
40     /// `None` for the crate root.
41     pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
42         let def_map = db.crate_def_map(self.id.krate);
43         def_map[self.id.local_id].declaration_source(db.upcast())
44     }
45 }
46
47 impl HasSource for Field {
48     type Ast = FieldSource;
49     fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
50         let var = VariantId::from(self.parent);
51         let src = var.child_source(db.upcast());
52         src.map(|it| match it[self.id].clone() {
53             Either::Left(it) => FieldSource::Pos(it),
54             Either::Right(it) => FieldSource::Named(it),
55         })
56     }
57 }
58 impl HasSource for Struct {
59     type Ast = ast::Struct;
60     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
61         self.id.lookup(db.upcast()).source(db.upcast())
62     }
63 }
64 impl HasSource for Union {
65     type Ast = ast::Union;
66     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
67         self.id.lookup(db.upcast()).source(db.upcast())
68     }
69 }
70 impl HasSource for Enum {
71     type Ast = ast::Enum;
72     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
73         self.id.lookup(db.upcast()).source(db.upcast())
74     }
75 }
76 impl HasSource for Variant {
77     type Ast = ast::Variant;
78     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
79         self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
80     }
81 }
82 impl HasSource for Function {
83     type Ast = ast::Fn;
84     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
85         self.id.lookup(db.upcast()).source(db.upcast())
86     }
87 }
88 impl HasSource for Const {
89     type Ast = ast::Const;
90     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
91         self.id.lookup(db.upcast()).source(db.upcast())
92     }
93 }
94 impl HasSource for Static {
95     type Ast = ast::Static;
96     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
97         self.id.lookup(db.upcast()).source(db.upcast())
98     }
99 }
100 impl HasSource for Trait {
101     type Ast = ast::Trait;
102     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
103         self.id.lookup(db.upcast()).source(db.upcast())
104     }
105 }
106 impl HasSource for TypeAlias {
107     type Ast = ast::TypeAlias;
108     fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
109         self.id.lookup(db.upcast()).source(db.upcast())
110     }
111 }
112 impl HasSource for MacroDef {
113     type Ast = ast::Macro;
114     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> {
115         InFile {
116             file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
117             value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
118         }
119     }
120 }
121 impl HasSource for Impl {
122     type Ast = ast::Impl;
123     fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
124         self.id.lookup(db.upcast()).source(db.upcast())
125     }
126 }
127
128 impl HasSource for TypeParam {
129     type Ast = Either<ast::Trait, ast::TypeParam>;
130     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
131         let child_source = self.id.parent.child_source(db.upcast());
132         child_source.map(|it| it[self.id.local_id].clone())
133     }
134 }
135
136 impl HasSource for LifetimeParam {
137     type Ast = ast::LifetimeParam;
138     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
139         let child_source = self.id.parent.child_source(db.upcast());
140         child_source.map(|it| it[self.id.local_id].clone())
141     }
142 }
143
144 impl HasSource for ConstParam {
145     type Ast = ast::ConstParam;
146     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
147         let child_source = self.id.parent.child_source(db.upcast());
148         child_source.map(|it| it[self.id.local_id].clone())
149     }
150 }