|
7 | 7 |
|
8 | 8 | use arrayvec::ArrayVec;
|
9 | 9 | use hir::{
|
10 |
| - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, DocLinkDef, |
11 |
| - ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, |
12 |
| - Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, |
13 |
| - TypeAlias, Variant, Visibility, |
| 10 | + Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, |
| 11 | + DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam, |
| 12 | + HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, |
| 13 | + Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, VariantDef, Visibility, |
14 | 14 | };
|
15 |
| -use stdx::impl_from; |
| 15 | +use stdx::{format_to, impl_from}; |
16 | 16 | use syntax::{
|
17 | 17 | ast::{self, AstNode},
|
18 | 18 | match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
|
19 | 19 | };
|
20 | 20 |
|
| 21 | +use crate::documentation::{Documentation, HasDocs}; |
| 22 | +use crate::famous_defs::FamousDefs; |
21 | 23 | use crate::RootDatabase;
|
22 | 24 |
|
23 | 25 | // FIXME: a more precise name would probably be `Symbol`?
|
@@ -83,6 +85,13 @@ impl Definition {
|
83 | 85 | Some(module)
|
84 | 86 | }
|
85 | 87 |
|
| 88 | + pub fn enclosing_definition(&self, db: &RootDatabase) -> Option<Definition> { |
| 89 | + match self { |
| 90 | + Definition::Local(it) => it.parent(db).try_into().ok(), |
| 91 | + _ => None, |
| 92 | + } |
| 93 | + } |
| 94 | + |
86 | 95 | pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
|
87 | 96 | let vis = match self {
|
88 | 97 | Definition::Field(sf) => sf.visibility(db),
|
@@ -134,6 +143,125 @@ impl Definition {
|
134 | 143 | };
|
135 | 144 | Some(name)
|
136 | 145 | }
|
| 146 | + |
| 147 | + pub fn docs( |
| 148 | + &self, |
| 149 | + db: &RootDatabase, |
| 150 | + famous_defs: Option<&FamousDefs<'_, '_>>, |
| 151 | + ) -> Option<Documentation> { |
| 152 | + let docs = match self { |
| 153 | + Definition::Macro(it) => it.docs(db), |
| 154 | + Definition::Field(it) => it.docs(db), |
| 155 | + Definition::Module(it) => it.docs(db), |
| 156 | + Definition::Function(it) => it.docs(db), |
| 157 | + Definition::Adt(it) => it.docs(db), |
| 158 | + Definition::Variant(it) => it.docs(db), |
| 159 | + Definition::Const(it) => it.docs(db), |
| 160 | + Definition::Static(it) => it.docs(db), |
| 161 | + Definition::Trait(it) => it.docs(db), |
| 162 | + Definition::TraitAlias(it) => it.docs(db), |
| 163 | + Definition::TypeAlias(it) => it.docs(db), |
| 164 | + Definition::BuiltinType(it) => { |
| 165 | + famous_defs.and_then(|fd| { |
| 166 | + // std exposes prim_{} modules with docstrings on the root to document the builtins |
| 167 | + let primitive_mod = format!("prim_{}", it.name().display(fd.0.db)); |
| 168 | + let doc_owner = find_std_module(fd, &primitive_mod)?; |
| 169 | + doc_owner.docs(fd.0.db) |
| 170 | + }) |
| 171 | + } |
| 172 | + Definition::Local(_) => None, |
| 173 | + Definition::SelfType(impl_def) => { |
| 174 | + impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))? |
| 175 | + } |
| 176 | + Definition::GenericParam(_) => None, |
| 177 | + Definition::Label(_) => None, |
| 178 | + Definition::ExternCrateDecl(it) => it.docs(db), |
| 179 | + |
| 180 | + Definition::BuiltinAttr(it) => { |
| 181 | + let name = it.name(db); |
| 182 | + let AttributeTemplate { word, list, name_value_str } = it.template(db)?; |
| 183 | + let mut docs = "Valid forms are:".to_owned(); |
| 184 | + if word { |
| 185 | + format_to!(docs, "\n - #\\[{}]", name); |
| 186 | + } |
| 187 | + if let Some(list) = list { |
| 188 | + format_to!(docs, "\n - #\\[{}({})]", name, list); |
| 189 | + } |
| 190 | + if let Some(name_value_str) = name_value_str { |
| 191 | + format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str); |
| 192 | + } |
| 193 | + Some(Documentation::new(docs.replace('*', "\\*"))) |
| 194 | + } |
| 195 | + Definition::ToolModule(_) => None, |
| 196 | + Definition::DeriveHelper(_) => None, |
| 197 | + }; |
| 198 | + |
| 199 | + docs.or_else(|| { |
| 200 | + // docs are missing, for assoc items of trait impls try to fall back to the docs of the |
| 201 | + // original item of the trait |
| 202 | + let assoc = self.as_assoc_item(db)?; |
| 203 | + let trait_ = assoc.containing_trait_impl(db)?; |
| 204 | + let name = Some(assoc.name(db)?); |
| 205 | + let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; |
| 206 | + item.docs(db) |
| 207 | + }) |
| 208 | + } |
| 209 | + |
| 210 | + pub fn label(&self, db: &RootDatabase) -> Option<String> { |
| 211 | + let label = match *self { |
| 212 | + Definition::Macro(it) => it.display(db).to_string(), |
| 213 | + Definition::Field(it) => it.display(db).to_string(), |
| 214 | + Definition::Module(it) => it.display(db).to_string(), |
| 215 | + Definition::Function(it) => it.display(db).to_string(), |
| 216 | + Definition::Adt(it) => it.display(db).to_string(), |
| 217 | + Definition::Variant(it) => it.display(db).to_string(), |
| 218 | + Definition::Const(it) => it.display(db).to_string(), |
| 219 | + Definition::Static(it) => it.display(db).to_string(), |
| 220 | + Definition::Trait(it) => it.display(db).to_string(), |
| 221 | + Definition::TraitAlias(it) => it.display(db).to_string(), |
| 222 | + Definition::TypeAlias(it) => it.display(db).to_string(), |
| 223 | + Definition::BuiltinType(it) => it.name().display(db).to_string(), |
| 224 | + Definition::Local(it) => { |
| 225 | + let ty = it.ty(db); |
| 226 | + let ty = ty.display_truncated(db, None); |
| 227 | + let is_mut = if it.is_mut(db) { "mut " } else { "" }; |
| 228 | + let desc = match it.primary_source(db).into_ident_pat() { |
| 229 | + Some(ident) => { |
| 230 | + let name = it.name(db); |
| 231 | + let let_kw = if ident.syntax().parent().map_or(false, |p| { |
| 232 | + p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR |
| 233 | + }) { |
| 234 | + "let " |
| 235 | + } else { |
| 236 | + "" |
| 237 | + }; |
| 238 | + format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) |
| 239 | + } |
| 240 | + None => format!("{is_mut}self: {ty}"), |
| 241 | + }; |
| 242 | + desc |
| 243 | + } |
| 244 | + Definition::SelfType(impl_def) => { |
| 245 | + impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? |
| 246 | + } |
| 247 | + Definition::GenericParam(it) => it.display(db).to_string(), |
| 248 | + Definition::Label(it) => it.name(db).display(db).to_string(), |
| 249 | + Definition::ExternCrateDecl(it) => it.display(db).to_string(), |
| 250 | + Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)), |
| 251 | + Definition::ToolModule(it) => it.name(db).to_string(), |
| 252 | + Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), |
| 253 | + }; |
| 254 | + Some(label) |
| 255 | + } |
| 256 | +} |
| 257 | + |
| 258 | +fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> { |
| 259 | + let db = famous_defs.0.db; |
| 260 | + let std_crate = famous_defs.std()?; |
| 261 | + let std_root_module = std_crate.root_module(); |
| 262 | + std_root_module.children(db).find(|module| { |
| 263 | + module.name(db).map_or(false, |module| module.display(db).to_string() == name) |
| 264 | + }) |
137 | 265 | }
|
138 | 266 |
|
139 | 267 | // FIXME: IdentClass as a name no longer fits
|
@@ -662,3 +790,22 @@ impl From<DocLinkDef> for Definition {
|
662 | 790 | }
|
663 | 791 | }
|
664 | 792 | }
|
| 793 | + |
| 794 | +impl From<VariantDef> for Definition { |
| 795 | + fn from(def: VariantDef) -> Self { |
| 796 | + ModuleDef::from(def).into() |
| 797 | + } |
| 798 | +} |
| 799 | + |
| 800 | +impl TryFrom<DefWithBody> for Definition { |
| 801 | + type Error = (); |
| 802 | + fn try_from(def: DefWithBody) -> Result<Self, Self::Error> { |
| 803 | + match def { |
| 804 | + DefWithBody::Function(it) => Ok(it.into()), |
| 805 | + DefWithBody::Static(it) => Ok(it.into()), |
| 806 | + DefWithBody::Const(it) => Ok(it.into()), |
| 807 | + DefWithBody::Variant(it) => Ok(it.into()), |
| 808 | + DefWithBody::InTypeConst(_) => Err(()), |
| 809 | + } |
| 810 | + } |
| 811 | +} |
0 commit comments