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