aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/code_model
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/code_model')
-rw-r--r--crates/ra_hir/src/code_model/attrs.rs92
-rw-r--r--crates/ra_hir/src/code_model/docs.rs97
-rw-r--r--crates/ra_hir/src/code_model/src.rs138
3 files changed, 47 insertions, 280 deletions
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs
deleted file mode 100644
index 9e304217c..000000000
--- a/crates/ra_hir/src/code_model/attrs.rs
+++ /dev/null
@@ -1,92 +0,0 @@
1//! FIXME: write short doc here
2
3use crate::{
4 db::{AstDatabase, DefDatabase, HirDatabase},
5 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
6 Struct, StructField, Trait, TypeAlias, Union,
7};
8use hir_def::attr::Attr;
9use hir_expand::hygiene::Hygiene;
10use ra_syntax::ast;
11use std::sync::Arc;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum AttrDef {
15 Module(Module),
16 StructField(StructField),
17 Adt(Adt),
18 Function(Function),
19 EnumVariant(EnumVariant),
20 Static(Static),
21 Const(Const),
22 Trait(Trait),
23 TypeAlias(TypeAlias),
24 MacroDef(MacroDef),
25}
26
27impl_froms!(
28 AttrDef: Module,
29 StructField,
30 Adt(Struct, Enum, Union),
31 EnumVariant,
32 Static,
33 Const,
34 Function,
35 Trait,
36 TypeAlias,
37 MacroDef
38);
39
40pub trait Attrs {
41 fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>>;
42}
43
44pub(crate) fn attributes_query(
45 db: &(impl DefDatabase + AstDatabase),
46 def: AttrDef,
47) -> Option<Arc<[Attr]>> {
48 match def {
49 AttrDef::Module(it) => {
50 let src = it.declaration_source(db)?;
51 let hygiene = Hygiene::new(db, src.file_id);
52 Attr::from_attrs_owner(&src.value, &hygiene)
53 }
54 AttrDef::StructField(it) => match it.source(db).value {
55 FieldSource::Named(named) => {
56 let src = it.source(db);
57 let hygiene = Hygiene::new(db, src.file_id);
58 Attr::from_attrs_owner(&named, &hygiene)
59 }
60 FieldSource::Pos(..) => None,
61 },
62 AttrDef::Adt(it) => match it {
63 Adt::Struct(it) => attrs_from_ast(it, db),
64 Adt::Enum(it) => attrs_from_ast(it, db),
65 Adt::Union(it) => attrs_from_ast(it, db),
66 },
67 AttrDef::EnumVariant(it) => attrs_from_ast(it, db),
68 AttrDef::Static(it) => attrs_from_ast(it, db),
69 AttrDef::Const(it) => attrs_from_ast(it, db),
70 AttrDef::Function(it) => attrs_from_ast(it, db),
71 AttrDef::Trait(it) => attrs_from_ast(it, db),
72 AttrDef::TypeAlias(it) => attrs_from_ast(it, db),
73 AttrDef::MacroDef(it) => attrs_from_ast(it, db),
74 }
75}
76
77fn attrs_from_ast<T, D>(node: T, db: &D) -> Option<Arc<[Attr]>>
78where
79 T: HasSource,
80 T::Ast: ast::AttrsOwner,
81 D: DefDatabase + AstDatabase,
82{
83 let src = node.source(db);
84 let hygiene = Hygiene::new(db, src.file_id);
85 Attr::from_attrs_owner(&src.value, &hygiene)
86}
87
88impl<T: Into<AttrDef> + Copy> Attrs for T {
89 fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>> {
90 db.attrs((*self).into())
91 }
92}
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs
deleted file mode 100644
index e40efef34..000000000
--- a/crates/ra_hir/src/code_model/docs.rs
+++ /dev/null
@@ -1,97 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use ra_syntax::ast;
6
7use crate::{
8 db::{AstDatabase, DefDatabase, HirDatabase},
9 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
10 Struct, StructField, Trait, TypeAlias, Union,
11};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum DocDef {
15 Module(Module),
16 StructField(StructField),
17 Adt(Adt),
18 EnumVariant(EnumVariant),
19 Static(Static),
20 Const(Const),
21 Function(Function),
22 Trait(Trait),
23 TypeAlias(TypeAlias),
24 MacroDef(MacroDef),
25}
26
27impl_froms!(
28 DocDef: Module,
29 StructField,
30 Adt(Struct, Enum, Union),
31 EnumVariant,
32 Static,
33 Const,
34 Function,
35 Trait,
36 TypeAlias,
37 MacroDef
38);
39
40/// Holds documentation
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Documentation(Arc<str>);
43
44impl Documentation {
45 fn new(s: &str) -> Documentation {
46 Documentation(s.into())
47 }
48
49 pub fn as_str(&self) -> &str {
50 &*self.0
51 }
52}
53
54impl Into<String> for Documentation {
55 fn into(self) -> String {
56 self.as_str().to_owned()
57 }
58}
59
60pub trait Docs {
61 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>;
62}
63
64pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
65 node.doc_comment_text().map(|it| Documentation::new(&it))
66}
67
68pub(crate) fn documentation_query(
69 db: &(impl DefDatabase + AstDatabase),
70 def: DocDef,
71) -> Option<Documentation> {
72 match def {
73 DocDef::Module(it) => docs_from_ast(&it.declaration_source(db)?.value),
74 DocDef::StructField(it) => match it.source(db).value {
75 FieldSource::Named(named) => docs_from_ast(&named),
76 FieldSource::Pos(..) => None,
77 },
78 DocDef::Adt(it) => match it {
79 Adt::Struct(it) => docs_from_ast(&it.source(db).value),
80 Adt::Enum(it) => docs_from_ast(&it.source(db).value),
81 Adt::Union(it) => docs_from_ast(&it.source(db).value),
82 },
83 DocDef::EnumVariant(it) => docs_from_ast(&it.source(db).value),
84 DocDef::Static(it) => docs_from_ast(&it.source(db).value),
85 DocDef::Const(it) => docs_from_ast(&it.source(db).value),
86 DocDef::Function(it) => docs_from_ast(&it.source(db).value),
87 DocDef::Trait(it) => docs_from_ast(&it.source(db).value),
88 DocDef::TypeAlias(it) => docs_from_ast(&it.source(db).value),
89 DocDef::MacroDef(it) => docs_from_ast(&it.source(db).value),
90 }
91}
92
93impl<T: Into<DocDef> + Copy> Docs for T {
94 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
95 db.documentation((*self).into())
96 }
97}
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 4aa427de4..a4e317c20 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,172 +1,128 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{HasSource as _, Lookup}; 3use hir_def::{AstItemDef, HasChildSource, HasSource as _, Lookup, VariantId};
4use ra_syntax::ast::{self, AstNode}; 4use hir_expand::either::Either;
5use ra_syntax::ast;
5 6
6use crate::{ 7use crate::{
7 db::{AstDatabase, DefDatabase, HirDatabase}, 8 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef,
8 ids::AstItemDef, 9 Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
9 Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module,
10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
11}; 10};
12 11
13pub use hir_expand::Source; 12pub use hir_expand::Source;
14 13
15pub trait HasSource { 14pub trait HasSource {
16 type Ast; 15 type Ast;
17 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 16 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast>;
18} 17}
19 18
20/// NB: Module is !HasSource, because it has two source nodes at the same time: 19/// NB: Module is !HasSource, because it has two source nodes at the same time:
21/// definition and declaration. 20/// definition and declaration.
22impl Module { 21impl Module {
23 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 22 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
24 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> { 23 pub fn definition_source(self, db: &impl DefDatabase) -> Source<ModuleSource> {
25 let def_map = db.crate_def_map(self.id.krate); 24 let def_map = db.crate_def_map(self.id.krate);
26 let decl_id = def_map[self.id.module_id].declaration; 25 let src = def_map[self.id.module_id].definition_source(db);
27 let file_id = def_map[self.id.module_id].definition; 26 src.map(|it| match it {
28 let value = ModuleSource::new(db, file_id, decl_id); 27 Either::A(it) => ModuleSource::SourceFile(it),
29 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); 28 Either::B(it) => ModuleSource::Module(it),
30 Source { file_id, value } 29 })
31 } 30 }
32 31
33 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
34 /// `None` for the crate root. 33 /// `None` for the crate root.
35 pub fn declaration_source( 34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
36 self,
37 db: &(impl DefDatabase + AstDatabase),
38 ) -> Option<Source<ast::Module>> {
39 let def_map = db.crate_def_map(self.id.krate); 35 let def_map = db.crate_def_map(self.id.krate);
40 let decl = def_map[self.id.module_id].declaration?; 36 def_map[self.id.module_id].declaration_source(db)
41 let value = decl.to_node(db);
42 Some(Source { file_id: decl.file_id(), value })
43 } 37 }
44} 38}
45 39
46impl HasSource for StructField { 40impl HasSource for StructField {
47 type Ast = FieldSource; 41 type Ast = FieldSource;
48 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> { 42 fn source(self, db: &impl DefDatabase) -> Source<FieldSource> {
49 let var_data = self.parent.variant_data(db); 43 let var = VariantId::from(self.parent);
50 let fields = var_data.fields().unwrap(); 44 let src = var.child_source(db);
51 let ss; 45 src.map(|it| match it[self.id].clone() {
52 let es; 46 Either::A(it) => FieldSource::Pos(it),
53 let (file_id, struct_kind) = match self.parent { 47 Either::B(it) => FieldSource::Named(it),
54 VariantDef::Struct(s) => { 48 })
55 ss = s.source(db);
56 (ss.file_id, ss.value.kind())
57 }
58 VariantDef::EnumVariant(e) => {
59 es = e.source(db);
60 (es.file_id, es.value.kind())
61 }
62 };
63
64 let field_sources = match struct_kind {
65 ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(),
66 ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(),
67 ast::StructKind::Unit => Vec::new(),
68 };
69 let value = field_sources
70 .into_iter()
71 .zip(fields.iter())
72 .find(|(_syntax, (id, _))| *id == self.id)
73 .unwrap()
74 .0;
75 Source { file_id, value }
76 } 49 }
77} 50}
78impl HasSource for Struct { 51impl HasSource for Struct {
79 type Ast = ast::StructDef; 52 type Ast = ast::StructDef;
80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 53 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
81 self.id.0.source(db) 54 self.id.0.source(db)
82 } 55 }
83} 56}
84impl HasSource for Union { 57impl HasSource for Union {
85 type Ast = ast::StructDef; 58 type Ast = ast::StructDef;
86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 59 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
87 self.id.0.source(db) 60 self.id.0.source(db)
88 } 61 }
89} 62}
90impl HasSource for Enum { 63impl HasSource for Enum {
91 type Ast = ast::EnumDef; 64 type Ast = ast::EnumDef;
92 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumDef> { 65 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumDef> {
93 self.id.source(db) 66 self.id.source(db)
94 } 67 }
95} 68}
96impl HasSource for EnumVariant { 69impl HasSource for EnumVariant {
97 type Ast = ast::EnumVariant; 70 type Ast = ast::EnumVariant;
98 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumVariant> { 71 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumVariant> {
99 let enum_data = db.enum_data(self.parent.id); 72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
100 let src = self.parent.id.source(db);
101 let value = src
102 .value
103 .variant_list()
104 .into_iter()
105 .flat_map(|it| it.variants())
106 .zip(enum_data.variants.iter())
107 .find(|(_syntax, (id, _))| *id == self.id)
108 .unwrap()
109 .0;
110 Source { file_id: src.file_id, value }
111 } 73 }
112} 74}
113impl HasSource for Function { 75impl HasSource for Function {
114 type Ast = ast::FnDef; 76 type Ast = ast::FnDef;
115 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::FnDef> { 77 fn source(self, db: &impl DefDatabase) -> Source<ast::FnDef> {
116 self.id.lookup(db).source(db) 78 self.id.lookup(db).source(db)
117 } 79 }
118} 80}
119impl HasSource for Const { 81impl HasSource for Const {
120 type Ast = ast::ConstDef; 82 type Ast = ast::ConstDef;
121 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ConstDef> { 83 fn source(self, db: &impl DefDatabase) -> Source<ast::ConstDef> {
122 self.id.lookup(db).source(db) 84 self.id.lookup(db).source(db)
123 } 85 }
124} 86}
125impl HasSource for Static { 87impl HasSource for Static {
126 type Ast = ast::StaticDef; 88 type Ast = ast::StaticDef;
127 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StaticDef> { 89 fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
128 self.id.source(db) 90 self.id.lookup(db).source(db)
129 } 91 }
130} 92}
131impl HasSource for Trait { 93impl HasSource for Trait {
132 type Ast = ast::TraitDef; 94 type Ast = ast::TraitDef;
133 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TraitDef> { 95 fn source(self, db: &impl DefDatabase) -> Source<ast::TraitDef> {
134 self.id.source(db) 96 self.id.source(db)
135 } 97 }
136} 98}
137impl HasSource for TypeAlias { 99impl HasSource for TypeAlias {
138 type Ast = ast::TypeAliasDef; 100 type Ast = ast::TypeAliasDef;
139 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TypeAliasDef> { 101 fn source(self, db: &impl DefDatabase) -> Source<ast::TypeAliasDef> {
140 self.id.lookup(db).source(db) 102 self.id.lookup(db).source(db)
141 } 103 }
142} 104}
143impl HasSource for MacroDef { 105impl HasSource for MacroDef {
144 type Ast = ast::MacroCall; 106 type Ast = ast::MacroCall;
145 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { 107 fn source(self, db: &impl DefDatabase) -> Source<ast::MacroCall> {
146 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) } 108 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) }
147 } 109 }
148} 110}
149 111impl HasSource for ImplBlock {
150pub trait HasBodySource: HasBody + HasSource 112 type Ast = ast::ImplBlock;
151where 113 fn source(self, db: &impl DefDatabase) -> Source<ast::ImplBlock> {
152 Self::Ast: AstNode, 114 self.id.source(db)
153{
154 fn expr_source(
155 self,
156 db: &impl HirDatabase,
157 expr_id: crate::expr::ExprId,
158 ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> {
159 let source_map = self.body_source_map(db);
160 let source_ptr = source_map.expr_syntax(expr_id)?;
161 let root = source_ptr.file_syntax(db);
162 let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root)));
163 Some(source)
164 } 115 }
165} 116}
117impl HasSource for Import {
118 type Ast = Either<ast::UseTree, ast::ExternCrateItem>;
166 119
167impl<T> HasBodySource for T 120 /// Returns the syntax of the last path segment corresponding to this import
168where 121 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast> {
169 T: HasBody + HasSource, 122 let src = self.parent.definition_source(db);
170 T::Ast: AstNode, 123 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
171{ 124 let root = db.parse_or_expand(src.file_id).unwrap();
125 let ptr = source_map.get(self.id);
126 src.with_value(ptr.map(|it| it.to_node(&root), |it| it.to_node(&root)))
127 }
172} 128}