aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/display/navigation_target.rs52
-rw-r--r--crates/ide/src/hover.rs16
-rw-r--r--crates/ide/src/runnables.rs18
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
3use either::Either; 3use either::Either;
4use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource}; 4use hir::{
5 AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirFileId, InFile, ModuleSource,
6};
5use ide_db::base_db::{FileId, SourceDatabase}; 7use ide_db::base_db::{FileId, SourceDatabase};
6use ide_db::{defs::Definition, RootDatabase}; 8use ide_db::{defs::Definition, RootDatabase};
7use syntax::{ 9use 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
49pub(crate) trait ToNav { 51pub(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
215impl<D> ToNav for D 217impl<D> ToNav for D
216where 218where
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
377pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 379pub(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#"
3432fn 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};
6use ide_db::RootDatabase; 6use ide_db::RootDatabase;
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ 8use 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 = "```";
240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
241 &["", "rust", "should_panic", "edition2015", "edition2018"]; 241 &["", "rust", "should_panic", "edition2015", "edition2018"];
242 242
243fn has_runnable_doc_test(def: &dyn DocCommentsOwner) -> bool { 243fn 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