diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/display/navigation_target.rs | 52 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 16 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 18 |
3 files changed, 53 insertions, 33 deletions
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 4790d648a..234f80a3a 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -1,11 +1,13 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource}; | 4 | use hir::{ |
5 | AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirFileId, InFile, ModuleSource, | ||
6 | }; | ||
5 | use ide_db::base_db::{FileId, SourceDatabase}; | 7 | use ide_db::base_db::{FileId, SourceDatabase}; |
6 | use ide_db::{defs::Definition, RootDatabase}; | 8 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use syntax::{ | 9 | use syntax::{ |
8 | ast::{self, DocCommentsOwner, NameOwner}, | 10 | ast::{self, NameOwner}, |
9 | match_ast, AstNode, SmolStr, | 11 | match_ast, AstNode, SmolStr, |
10 | SyntaxKind::{self, IDENT_PAT, TYPE_PARAM}, | 12 | SyntaxKind::{self, IDENT_PAT, TYPE_PARAM}, |
11 | TextRange, | 13 | TextRange, |
@@ -43,7 +45,7 @@ pub struct NavigationTarget { | |||
43 | pub kind: SyntaxKind, | 45 | pub kind: SyntaxKind, |
44 | pub container_name: Option<SmolStr>, | 46 | pub container_name: Option<SmolStr>, |
45 | pub description: Option<String>, | 47 | pub description: Option<String>, |
46 | pub docs: Option<String>, | 48 | pub docs: Option<Documentation>, |
47 | } | 49 | } |
48 | 50 | ||
49 | pub(crate) trait ToNav { | 51 | pub(crate) trait ToNav { |
@@ -71,7 +73,7 @@ impl NavigationTarget { | |||
71 | frange.range, | 73 | frange.range, |
72 | src.value.syntax().kind(), | 74 | src.value.syntax().kind(), |
73 | ); | 75 | ); |
74 | res.docs = src.value.doc_comment_text(); | 76 | res.docs = module.attrs(db).docs(); |
75 | res.description = src.value.short_label(); | 77 | res.description = src.value.short_label(); |
76 | return res; | 78 | return res; |
77 | } | 79 | } |
@@ -214,14 +216,14 @@ impl ToNavFromAst for hir::Trait {} | |||
214 | 216 | ||
215 | impl<D> ToNav for D | 217 | impl<D> ToNav for D |
216 | where | 218 | where |
217 | D: HasSource + ToNavFromAst + Copy, | 219 | D: HasSource + ToNavFromAst + Copy + HasAttrs, |
218 | D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 220 | D::Ast: ast::NameOwner + ShortLabel, |
219 | { | 221 | { |
220 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 222 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
221 | let src = self.source(db); | 223 | let src = self.source(db); |
222 | let mut res = | 224 | let mut res = |
223 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); | 225 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
224 | res.docs = src.value.doc_comment_text(); | 226 | res.docs = self.docs(db); |
225 | res.description = src.value.short_label(); | 227 | res.description = src.value.short_label(); |
226 | res | 228 | res |
227 | } | 229 | } |
@@ -274,7 +276,7 @@ impl ToNav for hir::Field { | |||
274 | match &src.value { | 276 | match &src.value { |
275 | FieldSource::Named(it) => { | 277 | FieldSource::Named(it) => { |
276 | let mut res = NavigationTarget::from_named(db, src.with_value(it)); | 278 | let mut res = NavigationTarget::from_named(db, src.with_value(it)); |
277 | res.docs = it.doc_comment_text(); | 279 | res.docs = self.docs(db); |
278 | res.description = it.short_label(); | 280 | res.description = it.short_label(); |
279 | res | 281 | res |
280 | } | 282 | } |
@@ -298,7 +300,7 @@ impl ToNav for hir::MacroDef { | |||
298 | log::debug!("nav target {:#?}", src.value.syntax()); | 300 | log::debug!("nav target {:#?}", src.value.syntax()); |
299 | let mut res = | 301 | let mut res = |
300 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); | 302 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
301 | res.docs = src.value.doc_comment_text(); | 303 | res.docs = self.docs(db); |
302 | res | 304 | res |
303 | } | 305 | } |
304 | } | 306 | } |
@@ -374,26 +376,28 @@ impl ToNav for hir::TypeParam { | |||
374 | } | 376 | } |
375 | } | 377 | } |
376 | 378 | ||
377 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { | 379 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<Documentation> { |
378 | let parse = db.parse(symbol.file_id); | 380 | let parse = db.parse(symbol.file_id); |
379 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 381 | let node = symbol.ptr.to_node(parse.tree().syntax()); |
382 | let file_id = HirFileId::from(symbol.file_id); | ||
380 | 383 | ||
381 | match_ast! { | 384 | let it = match_ast! { |
382 | match node { | 385 | match node { |
383 | ast::Fn(it) => it.doc_comment_text(), | 386 | ast::Fn(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
384 | ast::Struct(it) => it.doc_comment_text(), | 387 | ast::Struct(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
385 | ast::Enum(it) => it.doc_comment_text(), | 388 | ast::Enum(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
386 | ast::Trait(it) => it.doc_comment_text(), | 389 | ast::Trait(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
387 | ast::Module(it) => it.doc_comment_text(), | 390 | ast::Module(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
388 | ast::TypeAlias(it) => it.doc_comment_text(), | 391 | ast::TypeAlias(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
389 | ast::Const(it) => it.doc_comment_text(), | 392 | ast::Const(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
390 | ast::Static(it) => it.doc_comment_text(), | 393 | ast::Static(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
391 | ast::RecordField(it) => it.doc_comment_text(), | 394 | ast::RecordField(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
392 | ast::Variant(it) => it.doc_comment_text(), | 395 | ast::Variant(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
393 | ast::MacroCall(it) => it.doc_comment_text(), | 396 | ast::MacroCall(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), |
394 | _ => None, | 397 | _ => return None, |
395 | } | 398 | } |
396 | } | 399 | }; |
400 | it.docs() | ||
397 | } | 401 | } |
398 | 402 | ||
399 | /// Get a description of a symbol. | 403 | /// Get a description of a symbol. |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index cf04c3de0..ab017d2ad 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -139,6 +139,11 @@ pub(crate) fn hover( | |||
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | if token.kind() == syntax::SyntaxKind::COMMENT { | ||
143 | // don't highlight the entire parent node on comment hover | ||
144 | return None; | ||
145 | } | ||
146 | |||
142 | let node = token.ancestors().find(|n| { | 147 | let node = token.ancestors().find(|n| { |
143 | ast::Expr::can_cast(n.kind()) | 148 | ast::Expr::can_cast(n.kind()) |
144 | || ast::Pat::can_cast(n.kind()) | 149 | || ast::Pat::can_cast(n.kind()) |
@@ -3419,4 +3424,15 @@ mod Foo<|> { | |||
3419 | "#]], | 3424 | "#]], |
3420 | ); | 3425 | ); |
3421 | } | 3426 | } |
3427 | |||
3428 | #[test] | ||
3429 | fn hover_comments_dont_highlight_parent() { | ||
3430 | check_hover_no_result( | ||
3431 | r#" | ||
3432 | fn no_hover() { | ||
3433 | // no<|>hover | ||
3434 | } | ||
3435 | "#, | ||
3436 | ); | ||
3437 | } | ||
3422 | } | 3438 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index e15411777..646f63704 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -6,7 +6,7 @@ use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; | |||
6 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, | 9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | 12 | ||
@@ -118,6 +118,7 @@ fn runnable_fn( | |||
118 | ) -> Option<Runnable> { | 118 | ) -> Option<Runnable> { |
119 | let name_string = fn_def.name()?.text().to_string(); | 119 | let name_string = fn_def.name()?.text().to_string(); |
120 | 120 | ||
121 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); | ||
121 | let kind = if name_string == "main" { | 122 | let kind = if name_string == "main" { |
122 | RunnableKind::Bin | 123 | RunnableKind::Bin |
123 | } else { | 124 | } else { |
@@ -162,14 +163,13 @@ fn runnable_fn( | |||
162 | RunnableKind::Test { test_id, attr } | 163 | RunnableKind::Test { test_id, attr } |
163 | } else if fn_def.has_atom_attr("bench") { | 164 | } else if fn_def.has_atom_attr("bench") { |
164 | RunnableKind::Bench { test_id } | 165 | RunnableKind::Bench { test_id } |
165 | } else if has_runnable_doc_test(&fn_def) { | 166 | } else if has_runnable_doc_test(&attrs) { |
166 | RunnableKind::DocTest { test_id } | 167 | RunnableKind::DocTest { test_id } |
167 | } else { | 168 | } else { |
168 | return None; | 169 | return None; |
169 | } | 170 | } |
170 | }; | 171 | }; |
171 | 172 | ||
172 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); | ||
173 | let cfg = attrs.cfg(); | 173 | let cfg = attrs.cfg(); |
174 | 174 | ||
175 | let nav = if let RunnableKind::DocTest { .. } = kind { | 175 | let nav = if let RunnableKind::DocTest { .. } = kind { |
@@ -189,13 +189,13 @@ fn runnable_struct( | |||
189 | struct_def: ast::Struct, | 189 | struct_def: ast::Struct, |
190 | file_id: FileId, | 190 | file_id: FileId, |
191 | ) -> Option<Runnable> { | 191 | ) -> Option<Runnable> { |
192 | if !has_runnable_doc_test(&struct_def) { | ||
193 | return None; | ||
194 | } | ||
195 | let name_string = struct_def.name()?.text().to_string(); | 192 | let name_string = struct_def.name()?.text().to_string(); |
196 | 193 | ||
197 | let attrs = | 194 | let attrs = |
198 | Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def)); | 195 | Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def)); |
196 | if !has_runnable_doc_test(&attrs) { | ||
197 | return None; | ||
198 | } | ||
199 | let cfg = attrs.cfg(); | 199 | let cfg = attrs.cfg(); |
200 | 200 | ||
201 | let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) { | 201 | let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) { |
@@ -240,11 +240,11 @@ const RUSTDOC_FENCE: &str = "```"; | |||
240 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 240 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
241 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 241 | &["", "rust", "should_panic", "edition2015", "edition2018"]; |
242 | 242 | ||
243 | fn has_runnable_doc_test(def: &dyn DocCommentsOwner) -> bool { | 243 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { |
244 | def.doc_comment_text().map_or(false, |comments_text| { | 244 | attrs.docs().map_or(false, |doc| { |
245 | let mut in_code_block = false; | 245 | let mut in_code_block = false; |
246 | 246 | ||
247 | for line in comments_text.lines() { | 247 | for line in String::from(doc).lines() { |
248 | if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) { | 248 | if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) { |
249 | in_code_block = !in_code_block; | 249 | in_code_block = !in_code_block; |
250 | 250 | ||