diff options
-rw-r--r-- | crates/hir/src/attrs.rs | 6 | ||||
-rw-r--r-- | crates/hir_def/src/resolver.rs | 13 | ||||
-rw-r--r-- | crates/ide/src/doc_links.rs | 23 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 29 | ||||
-rw-r--r-- | crates/project_model/src/build_data.rs | 6 |
5 files changed, 71 insertions, 6 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 99fb65bac..9e6a3e155 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | use hir_def::{ | 2 | use hir_def::{ |
3 | attr::{Attrs, Documentation}, | 3 | attr::{Attrs, Documentation}, |
4 | path::ModPath, | 4 | path::ModPath, |
5 | per_ns::PerNs, | ||
5 | resolver::HasResolver, | 6 | resolver::HasResolver, |
6 | AttrDefId, GenericParamId, ModuleDefId, | 7 | AttrDefId, GenericParamId, ModuleDefId, |
7 | }; | 8 | }; |
@@ -112,6 +113,11 @@ fn resolve_doc_path( | |||
112 | let path = ast::Path::parse(link).ok()?; | 113 | let path = ast::Path::parse(link).ok()?; |
113 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); | 114 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); |
114 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); | 115 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); |
116 | if resolved == PerNs::none() { | ||
117 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { | ||
118 | return Some(ModuleDefId::TraitId(trait_id)); | ||
119 | }; | ||
120 | } | ||
115 | let def = match ns { | 121 | let def = match ns { |
116 | Some(Namespace::Types) => resolved.take_types()?, | 122 | Some(Namespace::Types) => resolved.take_types()?, |
117 | Some(Namespace::Values) => resolved.take_values()?, | 123 | Some(Namespace::Values) => resolved.take_values()?, |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index d48029b7d..b2f577649 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -146,6 +146,19 @@ impl Resolver { | |||
146 | self.resolve_module_path(db, path, BuiltinShadowMode::Module) | 146 | self.resolve_module_path(db, path, BuiltinShadowMode::Module) |
147 | } | 147 | } |
148 | 148 | ||
149 | pub fn resolve_module_path_in_trait_items( | ||
150 | &self, | ||
151 | db: &dyn DefDatabase, | ||
152 | path: &ModPath, | ||
153 | ) -> Option<TraitId> { | ||
154 | let (item_map, module) = self.module_scope()?; | ||
155 | let (module_res, ..) = item_map.resolve_path(db, module, &path, BuiltinShadowMode::Module); | ||
156 | match module_res.take_types()? { | ||
157 | ModuleDefId::TraitId(it) => Some(it), | ||
158 | _ => None, | ||
159 | } | ||
160 | } | ||
161 | |||
149 | pub fn resolve_path_in_type_ns( | 162 | pub fn resolve_path_in_type_ns( |
150 | &self, | 163 | &self, |
151 | db: &dyn DefDatabase, | 164 | db: &dyn DefDatabase, |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 1f08d7810..730e0dd0a 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -221,14 +221,31 @@ fn rewrite_intra_doc_link( | |||
221 | }?; | 221 | }?; |
222 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
223 | let canonical_path = resolved.canonical_path(db)?; | 223 | let canonical_path = resolved.canonical_path(db)?; |
224 | let new_target = get_doc_url(db, &krate)? | 224 | let mut new_url = get_doc_url(db, &krate)? |
225 | .join(&format!("{}/", krate.display_name(db)?)) | 225 | .join(&format!("{}/", krate.display_name(db)?)) |
226 | .ok()? | 226 | .ok()? |
227 | .join(&canonical_path.replace("::", "/")) | 227 | .join(&canonical_path.replace("::", "/")) |
228 | .ok()? | 228 | .ok()? |
229 | .join(&get_symbol_filename(db, &resolved)?) | 229 | .join(&get_symbol_filename(db, &resolved)?) |
230 | .ok()? | 230 | .ok()?; |
231 | .into_string(); | 231 | |
232 | if let ModuleDef::Trait(t) = resolved { | ||
233 | let items = t.items(db); | ||
234 | if let Some(field_or_assoc_item) = items.iter().find_map(|assoc_item| { | ||
235 | if let Some(name) = assoc_item.name(db) { | ||
236 | if link.to_string() == format!("{}::{}", canonical_path, name) { | ||
237 | return Some(FieldOrAssocItem::AssocItem(*assoc_item)); | ||
238 | } | ||
239 | } | ||
240 | None | ||
241 | }) { | ||
242 | if let Some(fragment) = get_symbol_fragment(db, &field_or_assoc_item) { | ||
243 | new_url = new_url.join(&fragment).ok()?; | ||
244 | } | ||
245 | }; | ||
246 | } | ||
247 | |||
248 | let new_target = new_url.into_string(); | ||
232 | let new_title = strip_prefixes_suffixes(title); | 249 | let new_title = strip_prefixes_suffixes(title); |
233 | Some((new_target, new_title.to_string())) | 250 | Some((new_target, new_title.to_string())) |
234 | } | 251 | } |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index ec1631486..d47a4cb0f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1826,6 +1826,35 @@ pub struct B$0ar | |||
1826 | "#]], | 1826 | "#]], |
1827 | ); | 1827 | ); |
1828 | } | 1828 | } |
1829 | #[test] | ||
1830 | fn test_hover_intra_link_reference_to_trait_method() { | ||
1831 | check( | ||
1832 | r#" | ||
1833 | pub trait Foo { | ||
1834 | fn buzz() -> usize; | ||
1835 | } | ||
1836 | /// [Foo][buzz] | ||
1837 | /// | ||
1838 | /// [buzz]: Foo::buzz | ||
1839 | pub struct B$0ar | ||
1840 | "#, | ||
1841 | expect![[r#" | ||
1842 | *Bar* | ||
1843 | |||
1844 | ```rust | ||
1845 | test | ||
1846 | ``` | ||
1847 | |||
1848 | ```rust | ||
1849 | pub struct Bar | ||
1850 | ``` | ||
1851 | |||
1852 | --- | ||
1853 | |||
1854 | [Foo](https://docs.rs/test/*/test/trait.Foo.html#tymethod.buzz) | ||
1855 | "#]], | ||
1856 | ); | ||
1857 | } | ||
1829 | 1858 | ||
1830 | #[test] | 1859 | #[test] |
1831 | fn test_hover_external_url() { | 1860 | fn test_hover_external_url() { |
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index 82fcf23ad..cf32995e0 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -10,7 +10,7 @@ use std::{ | |||
10 | use anyhow::Result; | 10 | use anyhow::Result; |
11 | use cargo_metadata::{BuildScript, Message, Package, PackageId}; | 11 | use cargo_metadata::{BuildScript, Message, Package, PackageId}; |
12 | use itertools::Itertools; | 12 | use itertools::Itertools; |
13 | use paths::AbsPathBuf; | 13 | use paths::{AbsPath, AbsPathBuf}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
15 | use stdx::JodChild; | 15 | use stdx::JodChild; |
16 | 16 | ||
@@ -37,14 +37,14 @@ pub struct BuildData { | |||
37 | 37 | ||
38 | impl BuildDataMap { | 38 | impl BuildDataMap { |
39 | pub(crate) fn new( | 39 | pub(crate) fn new( |
40 | cargo_toml: &Path, | 40 | cargo_toml: &AbsPath, |
41 | cargo_features: &CargoConfig, | 41 | cargo_features: &CargoConfig, |
42 | packages: &Vec<Package>, | 42 | packages: &Vec<Package>, |
43 | progress: &dyn Fn(String), | 43 | progress: &dyn Fn(String), |
44 | ) -> Result<BuildDataMap> { | 44 | ) -> Result<BuildDataMap> { |
45 | let mut cmd = Command::new(toolchain::cargo()); | 45 | let mut cmd = Command::new(toolchain::cargo()); |
46 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) | 46 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) |
47 | .arg(cargo_toml); | 47 | .arg(cargo_toml.as_ref()); |
48 | 48 | ||
49 | // --all-targets includes tests, benches and examples in addition to the | 49 | // --all-targets includes tests, benches and examples in addition to the |
50 | // default lib and bins. This is an independent concept from the --targets | 50 | // default lib and bins. This is an independent concept from the --targets |