diff options
Diffstat (limited to 'crates/ra_hir/src/code_model.rs')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 305 |
1 files changed, 144 insertions, 161 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 5690040a7..fd7776fb7 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub(crate) mod src; | 3 | pub(crate) mod src; |
4 | pub(crate) mod docs; | ||
5 | pub(crate) mod attrs; | ||
6 | 4 | ||
7 | use std::sync::Arc; | 5 | use std::sync::Arc; |
8 | 6 | ||
@@ -10,29 +8,30 @@ use hir_def::{ | |||
10 | adt::VariantData, | 8 | adt::VariantData, |
11 | body::scope::ExprScopes, | 9 | body::scope::ExprScopes, |
12 | builtin_type::BuiltinType, | 10 | builtin_type::BuiltinType, |
13 | nameres::per_ns::PerNs, | 11 | docs::Documentation, |
12 | per_ns::PerNs, | ||
14 | resolver::{HasResolver, TypeNs}, | 13 | resolver::{HasResolver, TypeNs}, |
15 | traits::TraitData, | 14 | type_ref::TypeRef, |
16 | type_ref::{Mutability, TypeRef}, | 15 | ContainerId, HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, |
17 | ContainerId, CrateModuleId, HasModule, ImplId, LocalEnumVariantId, LocalStructFieldId, Lookup, | 16 | LocalStructFieldId, Lookup, ModuleId, UnionId, |
18 | ModuleId, UnionId, | ||
19 | }; | 17 | }; |
20 | use hir_expand::{ | 18 | use hir_expand::{ |
21 | diagnostics::DiagnosticSink, | 19 | diagnostics::DiagnosticSink, |
22 | name::{self, AsName}, | 20 | name::{self, AsName}, |
21 | AstId, | ||
23 | }; | 22 | }; |
24 | use ra_db::{CrateId, Edition}; | 23 | use ra_db::{CrateId, Edition, FileId, FilePosition}; |
25 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 24 | use ra_syntax::{ast, AstNode, SyntaxNode}; |
26 | 25 | ||
27 | use crate::{ | 26 | use crate::{ |
28 | db::{AstDatabase, DefDatabase, HirDatabase}, | 27 | db::{DefDatabase, HirDatabase}, |
29 | expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, | 28 | expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, |
30 | ids::{ | 29 | ids::{ |
31 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 30 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
32 | TypeAliasId, | 31 | TypeAliasId, |
33 | }, | 32 | }, |
34 | ty::{InferenceResult, Namespace, TraitRef}, | 33 | ty::{InferenceResult, Namespace, TraitRef}, |
35 | Either, HasSource, ImportId, Name, Source, Ty, | 34 | Either, HasSource, Name, Source, Ty, |
36 | }; | 35 | }; |
37 | 36 | ||
38 | /// hir::Crate describes a single crate. It's the main interface with which | 37 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -80,6 +79,64 @@ impl Crate { | |||
80 | } | 79 | } |
81 | } | 80 | } |
82 | 81 | ||
82 | pub enum ModuleSource { | ||
83 | SourceFile(ast::SourceFile), | ||
84 | Module(ast::Module), | ||
85 | } | ||
86 | |||
87 | impl ModuleSource { | ||
88 | pub fn new( | ||
89 | db: &impl DefDatabase, | ||
90 | file_id: Option<FileId>, | ||
91 | decl_id: Option<AstId<ast::Module>>, | ||
92 | ) -> ModuleSource { | ||
93 | match (file_id, decl_id) { | ||
94 | (Some(file_id), _) => { | ||
95 | let source_file = db.parse(file_id).tree(); | ||
96 | ModuleSource::SourceFile(source_file) | ||
97 | } | ||
98 | (None, Some(item_id)) => { | ||
99 | let module = item_id.to_node(db); | ||
100 | assert!(module.item_list().is_some(), "expected inline module"); | ||
101 | ModuleSource::Module(module) | ||
102 | } | ||
103 | (None, None) => panic!(), | ||
104 | } | ||
105 | } | ||
106 | |||
107 | // FIXME: this methods do not belong here | ||
108 | pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource { | ||
109 | let parse = db.parse(position.file_id); | ||
110 | match &ra_syntax::algo::find_node_at_offset::<ast::Module>( | ||
111 | parse.tree().syntax(), | ||
112 | position.offset, | ||
113 | ) { | ||
114 | Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()), | ||
115 | _ => { | ||
116 | let source_file = parse.tree(); | ||
117 | ModuleSource::SourceFile(source_file) | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | pub fn from_child_node(db: &impl DefDatabase, child: Source<&SyntaxNode>) -> ModuleSource { | ||
123 | if let Some(m) = | ||
124 | child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) | ||
125 | { | ||
126 | ModuleSource::Module(m) | ||
127 | } else { | ||
128 | let file_id = child.file_id.original_file(db); | ||
129 | let source_file = db.parse(file_id).tree(); | ||
130 | ModuleSource::SourceFile(source_file) | ||
131 | } | ||
132 | } | ||
133 | |||
134 | pub fn from_file_id(db: &impl DefDatabase, file_id: FileId) -> ModuleSource { | ||
135 | let source_file = db.parse(file_id).tree(); | ||
136 | ModuleSource::SourceFile(source_file) | ||
137 | } | ||
138 | } | ||
139 | |||
83 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 140 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
84 | pub struct Module { | 141 | pub struct Module { |
85 | pub(crate) id: ModuleId, | 142 | pub(crate) id: ModuleId, |
@@ -111,10 +168,10 @@ impl_froms!( | |||
111 | BuiltinType | 168 | BuiltinType |
112 | ); | 169 | ); |
113 | 170 | ||
114 | pub use hir_def::ModuleSource; | 171 | pub use hir_def::attr::Attrs; |
115 | 172 | ||
116 | impl Module { | 173 | impl Module { |
117 | pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module { | 174 | pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { |
118 | Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } } | 175 | Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } } |
119 | } | 176 | } |
120 | 177 | ||
@@ -131,17 +188,6 @@ impl Module { | |||
131 | }) | 188 | }) |
132 | } | 189 | } |
133 | 190 | ||
134 | /// Returns the syntax of the last path segment corresponding to this import | ||
135 | pub fn import_source( | ||
136 | self, | ||
137 | db: &impl HirDatabase, | ||
138 | import: ImportId, | ||
139 | ) -> Either<ast::UseTree, ast::ExternCrateItem> { | ||
140 | let src = self.definition_source(db); | ||
141 | let (_, source_map) = db.raw_items_with_source_map(src.file_id); | ||
142 | source_map.get(&src.value, import) | ||
143 | } | ||
144 | |||
145 | /// Returns the crate this module is part of. | 191 | /// Returns the crate this module is part of. |
146 | pub fn krate(self) -> Crate { | 192 | pub fn krate(self) -> Crate { |
147 | Crate { crate_id: self.id.krate } | 193 | Crate { crate_id: self.id.krate } |
@@ -191,11 +237,13 @@ impl Module { | |||
191 | } | 237 | } |
192 | 238 | ||
193 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 239 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
194 | pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> { | 240 | pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<Import>)> { |
195 | db.crate_def_map(self.id.krate)[self.id.module_id] | 241 | db.crate_def_map(self.id.krate)[self.id.module_id] |
196 | .scope | 242 | .scope |
197 | .entries() | 243 | .entries() |
198 | .map(|(name, res)| (name.clone(), res.def.into(), res.import)) | 244 | .map(|(name, res)| { |
245 | (name.clone(), res.def.into(), res.import.map(|id| Import { parent: self, id })) | ||
246 | }) | ||
199 | .collect() | 247 | .collect() |
200 | } | 248 | } |
201 | 249 | ||
@@ -233,11 +281,16 @@ impl Module { | |||
233 | def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() | 281 | def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() |
234 | } | 282 | } |
235 | 283 | ||
236 | fn with_module_id(self, module_id: CrateModuleId) -> Module { | 284 | fn with_module_id(self, module_id: LocalModuleId) -> Module { |
237 | Module::new(self.krate(), module_id) | 285 | Module::new(self.krate(), module_id) |
238 | } | 286 | } |
239 | } | 287 | } |
240 | 288 | ||
289 | pub struct Import { | ||
290 | pub(crate) parent: Module, | ||
291 | pub(crate) id: LocalImportId, | ||
292 | } | ||
293 | |||
241 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 294 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
242 | pub struct StructField { | 295 | pub struct StructField { |
243 | pub(crate) parent: VariantDef, | 296 | pub(crate) parent: VariantDef, |
@@ -561,77 +614,6 @@ pub struct Function { | |||
561 | pub(crate) id: FunctionId, | 614 | pub(crate) id: FunctionId, |
562 | } | 615 | } |
563 | 616 | ||
564 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
565 | pub struct FnData { | ||
566 | pub(crate) name: Name, | ||
567 | pub(crate) params: Vec<TypeRef>, | ||
568 | pub(crate) ret_type: TypeRef, | ||
569 | /// True if the first param is `self`. This is relevant to decide whether this | ||
570 | /// can be called as a method. | ||
571 | pub(crate) has_self_param: bool, | ||
572 | } | ||
573 | |||
574 | impl FnData { | ||
575 | pub(crate) fn fn_data_query( | ||
576 | db: &(impl DefDatabase + AstDatabase), | ||
577 | func: Function, | ||
578 | ) -> Arc<FnData> { | ||
579 | let src = func.source(db); | ||
580 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | ||
581 | let mut params = Vec::new(); | ||
582 | let mut has_self_param = false; | ||
583 | if let Some(param_list) = src.value.param_list() { | ||
584 | if let Some(self_param) = param_list.self_param() { | ||
585 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | ||
586 | TypeRef::from_ast(type_ref) | ||
587 | } else { | ||
588 | let self_type = TypeRef::Path(name::SELF_TYPE.into()); | ||
589 | match self_param.kind() { | ||
590 | ast::SelfParamKind::Owned => self_type, | ||
591 | ast::SelfParamKind::Ref => { | ||
592 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
593 | } | ||
594 | ast::SelfParamKind::MutRef => { | ||
595 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
596 | } | ||
597 | } | ||
598 | }; | ||
599 | params.push(self_type); | ||
600 | has_self_param = true; | ||
601 | } | ||
602 | for param in param_list.params() { | ||
603 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | ||
604 | params.push(type_ref); | ||
605 | } | ||
606 | } | ||
607 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | ||
608 | TypeRef::from_ast(type_ref) | ||
609 | } else { | ||
610 | TypeRef::unit() | ||
611 | }; | ||
612 | |||
613 | let sig = FnData { name, params, ret_type, has_self_param }; | ||
614 | Arc::new(sig) | ||
615 | } | ||
616 | pub fn name(&self) -> &Name { | ||
617 | &self.name | ||
618 | } | ||
619 | |||
620 | pub fn params(&self) -> &[TypeRef] { | ||
621 | &self.params | ||
622 | } | ||
623 | |||
624 | pub fn ret_type(&self) -> &TypeRef { | ||
625 | &self.ret_type | ||
626 | } | ||
627 | |||
628 | /// True if the first arg is `self`. This is relevant to decide whether this | ||
629 | /// can be called as a method. | ||
630 | pub fn has_self_param(&self) -> bool { | ||
631 | self.has_self_param | ||
632 | } | ||
633 | } | ||
634 | |||
635 | impl Function { | 617 | impl Function { |
636 | pub fn module(self, db: &impl DefDatabase) -> Module { | 618 | pub fn module(self, db: &impl DefDatabase) -> Module { |
637 | self.id.lookup(db).module(db).into() | 619 | self.id.lookup(db).module(db).into() |
@@ -642,7 +624,15 @@ impl Function { | |||
642 | } | 624 | } |
643 | 625 | ||
644 | pub fn name(self, db: &impl HirDatabase) -> Name { | 626 | pub fn name(self, db: &impl HirDatabase) -> Name { |
645 | self.data(db).name.clone() | 627 | db.function_data(self.id).name.clone() |
628 | } | ||
629 | |||
630 | pub fn has_self_param(self, db: &impl HirDatabase) -> bool { | ||
631 | db.function_data(self.id).has_self_param | ||
632 | } | ||
633 | |||
634 | pub fn params(self, db: &impl HirDatabase) -> Vec<TypeRef> { | ||
635 | db.function_data(self.id).params.clone() | ||
646 | } | 636 | } |
647 | 637 | ||
648 | pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 638 | pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
@@ -657,10 +647,6 @@ impl Function { | |||
657 | db.type_for_def(self.into(), Namespace::Values) | 647 | db.type_for_def(self.into(), Namespace::Values) |
658 | } | 648 | } |
659 | 649 | ||
660 | pub fn data(self, db: &impl HirDatabase) -> Arc<FnData> { | ||
661 | db.fn_data(self) | ||
662 | } | ||
663 | |||
664 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 650 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
665 | db.infer(self.into()) | 651 | db.infer(self.into()) |
666 | } | 652 | } |
@@ -711,12 +697,8 @@ impl Const { | |||
711 | Some(self.module(db).krate()) | 697 | Some(self.module(db).krate()) |
712 | } | 698 | } |
713 | 699 | ||
714 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { | ||
715 | db.const_data(self) | ||
716 | } | ||
717 | |||
718 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | 700 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { |
719 | self.data(db).name().cloned() | 701 | db.const_data(self.id).name.clone() |
720 | } | 702 | } |
721 | 703 | ||
722 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 704 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
@@ -748,45 +730,6 @@ impl Const { | |||
748 | } | 730 | } |
749 | } | 731 | } |
750 | 732 | ||
751 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
752 | pub struct ConstData { | ||
753 | pub(crate) name: Option<Name>, | ||
754 | pub(crate) type_ref: TypeRef, | ||
755 | } | ||
756 | |||
757 | impl ConstData { | ||
758 | pub fn name(&self) -> Option<&Name> { | ||
759 | self.name.as_ref() | ||
760 | } | ||
761 | |||
762 | pub fn type_ref(&self) -> &TypeRef { | ||
763 | &self.type_ref | ||
764 | } | ||
765 | |||
766 | pub(crate) fn const_data_query( | ||
767 | db: &(impl DefDatabase + AstDatabase), | ||
768 | konst: Const, | ||
769 | ) -> Arc<ConstData> { | ||
770 | let node = konst.source(db).value; | ||
771 | const_data_for(&node) | ||
772 | } | ||
773 | |||
774 | pub(crate) fn static_data_query( | ||
775 | db: &(impl DefDatabase + AstDatabase), | ||
776 | konst: Static, | ||
777 | ) -> Arc<ConstData> { | ||
778 | let node = konst.source(db).value; | ||
779 | const_data_for(&node) | ||
780 | } | ||
781 | } | ||
782 | |||
783 | fn const_data_for<N: NameOwner + TypeAscriptionOwner>(node: &N) -> Arc<ConstData> { | ||
784 | let name = node.name().map(|n| n.as_name()); | ||
785 | let type_ref = TypeRef::from_ast_opt(node.ascribed_type()); | ||
786 | let sig = ConstData { name, type_ref }; | ||
787 | Arc::new(sig) | ||
788 | } | ||
789 | |||
790 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 733 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
791 | pub struct Static { | 734 | pub struct Static { |
792 | pub(crate) id: StaticId, | 735 | pub(crate) id: StaticId, |
@@ -801,10 +744,6 @@ impl Static { | |||
801 | Some(self.module(db).krate()) | 744 | Some(self.module(db).krate()) |
802 | } | 745 | } |
803 | 746 | ||
804 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { | ||
805 | db.static_data(self) | ||
806 | } | ||
807 | |||
808 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 747 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
809 | db.infer(self.into()) | 748 | db.infer(self.into()) |
810 | } | 749 | } |
@@ -821,11 +760,11 @@ impl Trait { | |||
821 | } | 760 | } |
822 | 761 | ||
823 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | 762 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { |
824 | self.trait_data(db).name.clone() | 763 | db.trait_data(self.id).name.clone() |
825 | } | 764 | } |
826 | 765 | ||
827 | pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> { | 766 | pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> { |
828 | self.trait_data(db).items.iter().map(|it| (*it).into()).collect() | 767 | db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect() |
829 | } | 768 | } |
830 | 769 | ||
831 | fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { | 770 | fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { |
@@ -871,7 +810,7 @@ impl Trait { | |||
871 | } | 810 | } |
872 | 811 | ||
873 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | 812 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { |
874 | let trait_data = self.trait_data(db); | 813 | let trait_data = db.trait_data(self.id); |
875 | let res = | 814 | let res = |
876 | trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?; | 815 | trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?; |
877 | Some(res) | 816 | Some(res) |
@@ -885,16 +824,12 @@ impl Trait { | |||
885 | self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) | 824 | self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) |
886 | } | 825 | } |
887 | 826 | ||
888 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | ||
889 | db.trait_data(self.id) | ||
890 | } | ||
891 | |||
892 | pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { | 827 | pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { |
893 | TraitRef::for_trait(db, self) | 828 | TraitRef::for_trait(db, self) |
894 | } | 829 | } |
895 | 830 | ||
896 | pub fn is_auto(self, db: &impl DefDatabase) -> bool { | 831 | pub fn is_auto(self, db: &impl DefDatabase) -> bool { |
897 | self.trait_data(db).auto | 832 | db.trait_data(self.id).auto |
898 | } | 833 | } |
899 | } | 834 | } |
900 | 835 | ||
@@ -937,7 +872,7 @@ impl TypeAlias { | |||
937 | } | 872 | } |
938 | 873 | ||
939 | pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { | 874 | pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { |
940 | db.type_alias_data(self).type_ref.clone() | 875 | db.type_alias_data(self.id).type_ref.clone() |
941 | } | 876 | } |
942 | 877 | ||
943 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | 878 | pub fn ty(self, db: &impl HirDatabase) -> Ty { |
@@ -945,7 +880,7 @@ impl TypeAlias { | |||
945 | } | 880 | } |
946 | 881 | ||
947 | pub fn name(self, db: &impl DefDatabase) -> Name { | 882 | pub fn name(self, db: &impl DefDatabase) -> Name { |
948 | db.type_alias_data(self).name.clone() | 883 | db.type_alias_data(self.id).name.clone() |
949 | } | 884 | } |
950 | } | 885 | } |
951 | 886 | ||
@@ -1110,3 +1045,51 @@ impl From<PerNs> for ScopeDef { | |||
1110 | .unwrap_or(ScopeDef::Unknown) | 1045 | .unwrap_or(ScopeDef::Unknown) |
1111 | } | 1046 | } |
1112 | } | 1047 | } |
1048 | |||
1049 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1050 | pub enum AttrDef { | ||
1051 | Module(Module), | ||
1052 | StructField(StructField), | ||
1053 | Adt(Adt), | ||
1054 | Function(Function), | ||
1055 | EnumVariant(EnumVariant), | ||
1056 | Static(Static), | ||
1057 | Const(Const), | ||
1058 | Trait(Trait), | ||
1059 | TypeAlias(TypeAlias), | ||
1060 | MacroDef(MacroDef), | ||
1061 | } | ||
1062 | |||
1063 | impl_froms!( | ||
1064 | AttrDef: Module, | ||
1065 | StructField, | ||
1066 | Adt(Struct, Enum, Union), | ||
1067 | EnumVariant, | ||
1068 | Static, | ||
1069 | Const, | ||
1070 | Function, | ||
1071 | Trait, | ||
1072 | TypeAlias, | ||
1073 | MacroDef | ||
1074 | ); | ||
1075 | |||
1076 | pub trait HasAttrs { | ||
1077 | fn attrs(self, db: &impl DefDatabase) -> Attrs; | ||
1078 | } | ||
1079 | |||
1080 | impl<T: Into<AttrDef>> HasAttrs for T { | ||
1081 | fn attrs(self, db: &impl DefDatabase) -> Attrs { | ||
1082 | let def: AttrDef = self.into(); | ||
1083 | db.attrs(def.into()) | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | pub trait Docs { | ||
1088 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>; | ||
1089 | } | ||
1090 | impl<T: Into<AttrDef> + Copy> Docs for T { | ||
1091 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
1092 | let def: AttrDef = (*self).into(); | ||
1093 | db.documentation(def.into()) | ||
1094 | } | ||
1095 | } | ||