diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-09-03 08:55:24 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-10-08 03:04:21 +0100 |
commit | c648884397bfdb779c447fa31964dc1fce94bd95 (patch) | |
tree | 276467ffe91360d31f285ce04bf16c0753c61a10 /crates | |
parent | 62b76e7004bc215a375e41bd204b2eab5acdf9c2 (diff) |
Differentiate method/tymethod by determining 'defaultness'
Currently a method only has defaultness if it is a provided trait
method, but this will change when specialisation is available and may
need to become a concept known to hir.
I opted to go for a 'fewest changes' approach given specialisation is
still under development.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/code_model.rs | 9 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 3 | ||||
-rw-r--r-- | crates/ide/src/doc_links.rs | 19 |
6 files changed, 30 insertions, 8 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 1dd6d73f3..0b24f247c 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -772,7 +772,14 @@ impl Function { | |||
772 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink) | 772 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink) |
773 | } | 773 | } |
774 | 774 | ||
775 | pub fn parent_def(self, db: &dyn HirDatabase) -> Option<MethodOwner> { | 775 | /// Whether this function declaration has a definition. |
776 | /// | ||
777 | /// This is false in the case of required (not provided) trait methods. | ||
778 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | ||
779 | db.function_data(self.id).has_body | ||
780 | } | ||
781 | |||
782 | pub fn method_owner(self, db: &dyn HirDatabase) -> Option<MethodOwner> { | ||
776 | match self.as_assoc_item(db).map(|assoc| assoc.container(db)) { | 783 | match self.as_assoc_item(db).map(|assoc| assoc.container(db)) { |
777 | Some(AssocItemContainer::Trait(t)) => Some(t.into()), | 784 | Some(AssocItemContainer::Trait(t)) => Some(t.into()), |
778 | Some(AssocItemContainer::ImplDef(imp)) => { | 785 | Some(AssocItemContainer::ImplDef(imp)) => { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 4094a76cb..687abe6ca 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -35,8 +35,8 @@ pub use crate::{ | |||
35 | code_model::{ | 35 | code_model::{ |
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, | 36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, |
37 | Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function, | 37 | Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function, |
38 | GenericDef, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, | 38 | GenericDef, HasVisibility, ImplDef, Local, MacroDef, MethodOwner, Module, ModuleDef, |
39 | Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, | 39 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, |
40 | }, | 40 | }, |
41 | has_source::HasSource, | 41 | has_source::HasSource, |
42 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, | 42 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 6190906da..ff1ef0df6 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -25,6 +25,7 @@ pub struct FunctionData { | |||
25 | /// True if the first param is `self`. This is relevant to decide whether this | 25 | /// True if the first param is `self`. This is relevant to decide whether this |
26 | /// can be called as a method. | 26 | /// can be called as a method. |
27 | pub has_self_param: bool, | 27 | pub has_self_param: bool, |
28 | pub has_body: bool, | ||
28 | pub is_unsafe: bool, | 29 | pub is_unsafe: bool, |
29 | pub is_varargs: bool, | 30 | pub is_varargs: bool, |
30 | pub visibility: RawVisibility, | 31 | pub visibility: RawVisibility, |
@@ -42,6 +43,7 @@ impl FunctionData { | |||
42 | ret_type: func.ret_type.clone(), | 43 | ret_type: func.ret_type.clone(), |
43 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), | 44 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), |
44 | has_self_param: func.has_self_param, | 45 | has_self_param: func.has_self_param, |
46 | has_body: func.has_body, | ||
45 | is_unsafe: func.is_unsafe, | 47 | is_unsafe: func.is_unsafe, |
46 | is_varargs: func.is_varargs, | 48 | is_varargs: func.is_varargs, |
47 | visibility: item_tree[func.visibility].clone(), | 49 | visibility: item_tree[func.visibility].clone(), |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 0fd91b9d0..8a1121bbd 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -505,6 +505,7 @@ pub struct Function { | |||
505 | pub visibility: RawVisibilityId, | 505 | pub visibility: RawVisibilityId, |
506 | pub generic_params: GenericParamsId, | 506 | pub generic_params: GenericParamsId, |
507 | pub has_self_param: bool, | 507 | pub has_self_param: bool, |
508 | pub has_body: bool, | ||
508 | pub is_unsafe: bool, | 509 | pub is_unsafe: bool, |
509 | pub params: Box<[TypeRef]>, | 510 | pub params: Box<[TypeRef]>, |
510 | pub is_varargs: bool, | 511 | pub is_varargs: bool, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 54814f141..3328639cf 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -330,12 +330,15 @@ impl Ctx { | |||
330 | ret_type | 330 | ret_type |
331 | }; | 331 | }; |
332 | 332 | ||
333 | let has_body = func.body().is_some(); | ||
334 | |||
333 | let ast_id = self.source_ast_id_map.ast_id(func); | 335 | let ast_id = self.source_ast_id_map.ast_id(func); |
334 | let mut res = Function { | 336 | let mut res = Function { |
335 | name, | 337 | name, |
336 | visibility, | 338 | visibility, |
337 | generic_params: GenericParamsId::EMPTY, | 339 | generic_params: GenericParamsId::EMPTY, |
338 | has_self_param, | 340 | has_self_param, |
341 | has_body, | ||
339 | is_unsafe: func.unsafe_token().is_some(), | 342 | is_unsafe: func.unsafe_token().is_some(), |
340 | params: params.into_boxed_slice(), | 343 | params: params.into_boxed_slice(), |
341 | is_varargs, | 344 | is_varargs, |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 512c42c4d..2f6c59c40 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -13,7 +13,7 @@ use ide_db::{defs::Definition, RootDatabase}; | |||
13 | 13 | ||
14 | use hir::{ | 14 | use hir::{ |
15 | db::{DefDatabase, HirDatabase}, | 15 | db::{DefDatabase, HirDatabase}, |
16 | Adt, AsName, AssocItem, Crate, Field, HasAttrs, ItemInNs, ModuleDef, | 16 | Adt, AsName, AssocItem, Crate, Field, HasAttrs, ItemInNs, MethodOwner, ModuleDef, |
17 | }; | 17 | }; |
18 | use ide_db::{ | 18 | use ide_db::{ |
19 | defs::{classify_name, classify_name_ref, Definition}, | 19 | defs::{classify_name, classify_name_ref, Definition}, |
@@ -117,7 +117,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
117 | let target_def: ModuleDef = match definition { | 117 | let target_def: ModuleDef = match definition { |
118 | Definition::ModuleDef(moddef) => match moddef { | 118 | Definition::ModuleDef(moddef) => match moddef { |
119 | ModuleDef::Function(f) => { | 119 | ModuleDef::Function(f) => { |
120 | f.parent_def(db).map(|mowner| mowner.into()).unwrap_or_else(|| f.clone().into()) | 120 | f.method_owner(db).map(|mowner| mowner.into()).unwrap_or_else(|| f.clone().into()) |
121 | } | 121 | } |
122 | moddef => moddef, | 122 | moddef => moddef, |
123 | }, | 123 | }, |
@@ -401,9 +401,18 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem) | |||
401 | Some(match field_or_assoc { | 401 | Some(match field_or_assoc { |
402 | FieldOrAssocItem::Field(field) => format!("#structfield.{}", field.name(db)), | 402 | FieldOrAssocItem::Field(field) => format!("#structfield.{}", field.name(db)), |
403 | FieldOrAssocItem::AssocItem(assoc) => match assoc { | 403 | FieldOrAssocItem::AssocItem(assoc) => match assoc { |
404 | // TODO: Rustdoc sometimes uses tymethod instead of method. This case needs to be investigated. | 404 | AssocItem::Function(function) => { |
405 | AssocItem::Function(function) => format!("#method.{}", function.name(db)), | 405 | let is_trait_method = |
406 | // TODO: This might be the old method for documenting associated constants, i32::MAX uses a separate page... | 406 | matches!(function.method_owner(db), Some(MethodOwner::Trait(..))); |
407 | // This distinction may get more complicated when specialisation is available. | ||
408 | // In particular this decision is made based on whether a method 'has defaultness'. | ||
409 | // Currently this is only the case for provided trait methods. | ||
410 | if is_trait_method && !function.has_body(db) { | ||
411 | format!("#tymethod.{}", function.name(db)) | ||
412 | } else { | ||
413 | format!("#method.{}", function.name(db)) | ||
414 | } | ||
415 | } | ||
407 | AssocItem::Const(constant) => format!("#associatedconstant.{}", constant.name(db)?), | 416 | AssocItem::Const(constant) => format!("#associatedconstant.{}", constant.name(db)?), |
408 | AssocItem::TypeAlias(ty) => format!("#associatedtype.{}", ty.name(db)), | 417 | AssocItem::TypeAlias(ty) => format!("#associatedtype.{}", ty.name(db)), |
409 | }, | 418 | }, |