diff options
Diffstat (limited to 'crates/hir/src/code_model.rs')
-rw-r--r-- | crates/hir/src/code_model.rs | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 3d92d0c0d..9395efe4f 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -20,7 +20,7 @@ use hir_def::{ | |||
20 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
21 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, | 21 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, |
22 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, | 22 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, |
23 | TraitId, TypeAliasId, TypeParamId, UnionId, | 23 | TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, |
24 | }; | 24 | }; |
25 | use hir_expand::{ | 25 | use hir_expand::{ |
26 | diagnostics::DiagnosticSink, | 26 | diagnostics::DiagnosticSink, |
@@ -39,10 +39,12 @@ use syntax::{ | |||
39 | ast::{self, AttrsOwner, NameOwner}, | 39 | ast::{self, AttrsOwner, NameOwner}, |
40 | AstNode, SmolStr, | 40 | AstNode, SmolStr, |
41 | }; | 41 | }; |
42 | use tt::{Ident, Leaf, Literal, TokenTree}; | ||
42 | 43 | ||
43 | use crate::{ | 44 | use crate::{ |
44 | db::{DefDatabase, HirDatabase}, | 45 | db::{DefDatabase, HirDatabase}, |
45 | has_source::HasSource, | 46 | has_source::HasSource, |
47 | link_rewrite::Resolvable, | ||
46 | HirDisplay, InFile, Name, | 48 | HirDisplay, InFile, Name, |
47 | }; | 49 | }; |
48 | 50 | ||
@@ -122,6 +124,33 @@ impl Crate { | |||
122 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | 124 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { |
123 | db.crate_graph().iter().map(|id| Crate { id }).collect() | 125 | db.crate_graph().iter().map(|id| Crate { id }).collect() |
124 | } | 126 | } |
127 | |||
128 | /// Try to get the root URL of the documentation of a crate. | ||
129 | pub fn get_doc_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { | ||
130 | // Look for #![doc(html_root_url = "...")] | ||
131 | let attrs = db.attrs(AttrDef::from(self.root_module(db)).into()); | ||
132 | let doc_attr_q = attrs.by_key("doc"); | ||
133 | |||
134 | let doc_url = if doc_attr_q.exists() { | ||
135 | doc_attr_q.tt_values().map(|tt| { | ||
136 | let name = tt.token_trees.iter() | ||
137 | .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) | ||
138 | .skip(2) | ||
139 | .next(); | ||
140 | |||
141 | match name { | ||
142 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | ||
143 | _ => None | ||
144 | } | ||
145 | }).flat_map(|t| t).next().map(|s| s.to_string()) | ||
146 | } else { | ||
147 | None | ||
148 | }; | ||
149 | |||
150 | doc_url | ||
151 | .map(|s| s.trim_matches('"').trim_end_matches("/").to_owned() + "/") | ||
152 | .map(|s| s.to_string()) | ||
153 | } | ||
125 | } | 154 | } |
126 | 155 | ||
127 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -198,7 +227,6 @@ impl ModuleDef { | |||
198 | ModuleDef::Function(it) => Some(it.name(db)), | 227 | ModuleDef::Function(it) => Some(it.name(db)), |
199 | ModuleDef::EnumVariant(it) => Some(it.name(db)), | 228 | ModuleDef::EnumVariant(it) => Some(it.name(db)), |
200 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | 229 | ModuleDef::TypeAlias(it) => Some(it.name(db)), |
201 | |||
202 | ModuleDef::Module(it) => it.name(db), | 230 | ModuleDef::Module(it) => it.name(db), |
203 | ModuleDef::Const(it) => it.name(db), | 231 | ModuleDef::Const(it) => it.name(db), |
204 | ModuleDef::Static(it) => it.name(db), | 232 | ModuleDef::Static(it) => it.name(db), |
@@ -206,6 +234,23 @@ impl ModuleDef { | |||
206 | ModuleDef::BuiltinType(it) => Some(it.as_name()), | 234 | ModuleDef::BuiltinType(it) => Some(it.as_name()), |
207 | } | 235 | } |
208 | } | 236 | } |
237 | |||
238 | pub fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
239 | Some(match self { | ||
240 | ModuleDef::Module(m) => ModuleId::from(m.clone()).resolver(db), | ||
241 | ModuleDef::Function(f) => FunctionId::from(f.clone()).resolver(db), | ||
242 | ModuleDef::Adt(adt) => AdtId::from(adt.clone()).resolver(db), | ||
243 | ModuleDef::EnumVariant(ev) => { | ||
244 | GenericDefId::from(GenericDef::from(ev.clone())).resolver(db) | ||
245 | } | ||
246 | ModuleDef::Const(c) => GenericDefId::from(GenericDef::from(c.clone())).resolver(db), | ||
247 | ModuleDef::Static(s) => StaticId::from(s.clone()).resolver(db), | ||
248 | ModuleDef::Trait(t) => TraitId::from(t.clone()).resolver(db), | ||
249 | ModuleDef::TypeAlias(t) => ModuleId::from(t.module(db)).resolver(db), | ||
250 | // FIXME: This should be a resolver relative to `std/core` | ||
251 | ModuleDef::BuiltinType(_t) => None?, | ||
252 | }) | ||
253 | } | ||
209 | } | 254 | } |
210 | 255 | ||
211 | pub use hir_def::{ | 256 | pub use hir_def::{ |
@@ -1771,3 +1816,76 @@ pub trait HasVisibility { | |||
1771 | vis.is_visible_from(db.upcast(), module.id) | 1816 | vis.is_visible_from(db.upcast(), module.id) |
1772 | } | 1817 | } |
1773 | } | 1818 | } |
1819 | |||
1820 | impl Resolvable for ModuleDef { | ||
1821 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1822 | Some(match self { | ||
1823 | ModuleDef::Module(m) => ModuleId::from(m.clone()).resolver(db), | ||
1824 | ModuleDef::Function(f) => FunctionId::from(f.clone()).resolver(db), | ||
1825 | ModuleDef::Adt(adt) => AdtId::from(adt.clone()).resolver(db), | ||
1826 | ModuleDef::EnumVariant(ev) => { | ||
1827 | GenericDefId::from(GenericDef::from(ev.clone())).resolver(db) | ||
1828 | } | ||
1829 | ModuleDef::Const(c) => GenericDefId::from(GenericDef::from(c.clone())).resolver(db), | ||
1830 | ModuleDef::Static(s) => StaticId::from(s.clone()).resolver(db), | ||
1831 | ModuleDef::Trait(t) => TraitId::from(t.clone()).resolver(db), | ||
1832 | ModuleDef::TypeAlias(t) => ModuleId::from(t.module(db)).resolver(db), | ||
1833 | // FIXME: This should be a resolver relative to `std/core` | ||
1834 | ModuleDef::BuiltinType(_t) => None?, | ||
1835 | }) | ||
1836 | } | ||
1837 | |||
1838 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1839 | Some(self) | ||
1840 | } | ||
1841 | } | ||
1842 | |||
1843 | impl Resolvable for TypeParam { | ||
1844 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1845 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1846 | } | ||
1847 | |||
1848 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1849 | None | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | impl Resolvable for MacroDef { | ||
1854 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1855 | Some(Into::<ModuleId>::into(self.module(db)?).resolver(db)) | ||
1856 | } | ||
1857 | |||
1858 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1859 | None | ||
1860 | } | ||
1861 | } | ||
1862 | |||
1863 | impl Resolvable for Field { | ||
1864 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1865 | Some(Into::<VariantId>::into(Into::<VariantDef>::into(self.parent_def(db))).resolver(db)) | ||
1866 | } | ||
1867 | |||
1868 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1869 | None | ||
1870 | } | ||
1871 | } | ||
1872 | |||
1873 | impl Resolvable for ImplDef { | ||
1874 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1875 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1876 | } | ||
1877 | |||
1878 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1879 | None | ||
1880 | } | ||
1881 | } | ||
1882 | |||
1883 | impl Resolvable for Local { | ||
1884 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1885 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1886 | } | ||
1887 | |||
1888 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1889 | None | ||
1890 | } | ||
1891 | } | ||