aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/call_hierarchy.rs8
-rw-r--r--crates/ide/src/diagnostics/fixes.rs9
-rw-r--r--crates/ide/src/display/navigation_target.rs137
-rw-r--r--crates/ide/src/doc_links.rs1
-rw-r--r--crates/ide/src/goto_implementation.rs6
-rw-r--r--crates/ide/src/goto_type_definition.rs4
-rw-r--r--crates/ide/src/hover.rs74
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/references.rs16
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs1
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs13
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html4
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs4
-rw-r--r--crates/ide/src/view_hir.rs25
17 files changed, 214 insertions, 98 deletions
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f1544dbe0..bb28cca4d 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -36,4 +36,4 @@ completion = { path = "../completion", version = "0.0.0" }
36hir = { path = "../hir", version = "0.0.0" } 36hir = { path = "../hir", version = "0.0.0" }
37 37
38[dev-dependencies] 38[dev-dependencies]
39expect-test = "1.0" 39expect-test = "1.1"
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 60e0cd4ad..3c2d39f5d 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -8,7 +8,7 @@ use ide_db::RootDatabase;
8use syntax::{ast, match_ast, AstNode, TextRange}; 8use syntax::{ast, match_ast, AstNode, TextRange};
9 9
10use crate::{ 10use crate::{
11 display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, 11 display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
12}; 12};
13 13
14#[derive(Debug, Clone)] 14#[derive(Debug, Clone)]
@@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
61 match node { 61 match node {
62 ast::Fn(it) => { 62 ast::Fn(it) => {
63 let def = sema.to_def(&it)?; 63 let def = sema.to_def(&it)?;
64 Some(def.to_nav(sema.db)) 64 def.try_to_nav(sema.db)
65 }, 65 },
66 _ => None, 66 _ => None,
67 } 67 }
@@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
99 match callable.kind() { 99 match callable.kind() {
100 hir::CallableKind::Function(it) => { 100 hir::CallableKind::Function(it) => {
101 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.to_nav(db); 102 let nav = fn_def.try_to_nav(db)?;
103 Some(nav) 103 Some(nav)
104 } 104 }
105 _ => None, 105 _ => None,
@@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
107 } 107 }
108 FnCallNode::MethodCallExpr(expr) => { 108 FnCallNode::MethodCallExpr(expr) => {
109 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
110 Some(function.to_nav(db)) 110 function.try_to_nav(db)
111 } 111 }
112 } { 112 } {
113 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index d79f5c170..ec0f840e9 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -156,20 +156,23 @@ fn missing_record_expr_field_fix(
156 let record_fields = match VariantDef::from(def_id) { 156 let record_fields = match VariantDef::from(def_id) {
157 VariantDef::Struct(s) => { 157 VariantDef::Struct(s) => {
158 module = s.module(sema.db); 158 module = s.module(sema.db);
159 let source = s.source(sema.db); 159 #[allow(deprecated)]
160 let source = s.source(sema.db)?;
160 def_file_id = source.file_id; 161 def_file_id = source.file_id;
161 let fields = source.value.field_list()?; 162 let fields = source.value.field_list()?;
162 record_field_list(fields)? 163 record_field_list(fields)?
163 } 164 }
164 VariantDef::Union(u) => { 165 VariantDef::Union(u) => {
165 module = u.module(sema.db); 166 module = u.module(sema.db);
166 let source = u.source(sema.db); 167 #[allow(deprecated)]
168 let source = u.source(sema.db)?;
167 def_file_id = source.file_id; 169 def_file_id = source.file_id;
168 source.value.record_field_list()? 170 source.value.record_field_list()?
169 } 171 }
170 VariantDef::Variant(e) => { 172 VariantDef::Variant(e) => {
171 module = e.module(sema.db); 173 module = e.module(sema.db);
172 let source = e.source(sema.db); 174 #[allow(deprecated)]
175 let source = e.source(sema.db)?;
173 def_file_id = source.file_id; 176 def_file_id = source.file_id;
174 let fields = source.value.field_list()?; 177 let fields = source.value.field_list()?;
175 record_field_list(fields)? 178 record_field_list(fields)?
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 6431e7d6d..e24c78301 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -24,6 +24,7 @@ pub enum SymbolKind {
24 Impl, 24 Impl,
25 Field, 25 Field,
26 TypeParam, 26 TypeParam,
27 ConstParam,
27 LifetimeParam, 28 LifetimeParam,
28 ValueParam, 29 ValueParam,
29 SelfParam, 30 SelfParam,
@@ -209,40 +210,32 @@ impl ToNav for FileSymbol {
209impl TryToNav for Definition { 210impl TryToNav for Definition {
210 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 211 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
211 match self { 212 match self {
212 Definition::Macro(it) => { 213 Definition::Macro(it) => it.try_to_nav(db),
213 // FIXME: Currently proc-macro do not have ast-node, 214 Definition::Field(it) => it.try_to_nav(db),
214 // such that it does not have source
215 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
216 if it.is_proc_macro() {
217 return None;
218 }
219 Some(it.to_nav(db))
220 }
221 Definition::Field(it) => Some(it.to_nav(db)),
222 Definition::ModuleDef(it) => it.try_to_nav(db), 215 Definition::ModuleDef(it) => it.try_to_nav(db),
223 Definition::SelfType(it) => Some(it.to_nav(db)), 216 Definition::SelfType(it) => it.try_to_nav(db),
224 Definition::Local(it) => Some(it.to_nav(db)), 217 Definition::Local(it) => Some(it.to_nav(db)),
225 Definition::TypeParam(it) => Some(it.to_nav(db)), 218 Definition::TypeParam(it) => it.try_to_nav(db),
226 Definition::LifetimeParam(it) => Some(it.to_nav(db)), 219 Definition::LifetimeParam(it) => it.try_to_nav(db),
227 Definition::Label(it) => Some(it.to_nav(db)), 220 Definition::Label(it) => Some(it.to_nav(db)),
221 Definition::ConstParam(it) => it.try_to_nav(db),
228 } 222 }
229 } 223 }
230} 224}
231 225
232impl TryToNav for hir::ModuleDef { 226impl TryToNav for hir::ModuleDef {
233 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 227 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
234 let res = match self { 228 match self {
235 hir::ModuleDef::Module(it) => it.to_nav(db), 229 hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
236 hir::ModuleDef::Function(it) => it.to_nav(db), 230 hir::ModuleDef::Function(it) => it.try_to_nav(db),
237 hir::ModuleDef::Adt(it) => it.to_nav(db), 231 hir::ModuleDef::Adt(it) => it.try_to_nav(db),
238 hir::ModuleDef::Variant(it) => it.to_nav(db), 232 hir::ModuleDef::Variant(it) => it.try_to_nav(db),
239 hir::ModuleDef::Const(it) => it.to_nav(db), 233 hir::ModuleDef::Const(it) => it.try_to_nav(db),
240 hir::ModuleDef::Static(it) => it.to_nav(db), 234 hir::ModuleDef::Static(it) => it.try_to_nav(db),
241 hir::ModuleDef::Trait(it) => it.to_nav(db), 235 hir::ModuleDef::Trait(it) => it.try_to_nav(db),
242 hir::ModuleDef::TypeAlias(it) => it.to_nav(db), 236 hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
243 hir::ModuleDef::BuiltinType(_) => return None, 237 hir::ModuleDef::BuiltinType(_) => None,
244 }; 238 }
245 Some(res)
246 } 239 }
247} 240}
248 241
@@ -277,13 +270,13 @@ impl ToNavFromAst for hir::Trait {
277 const KIND: SymbolKind = SymbolKind::Trait; 270 const KIND: SymbolKind = SymbolKind::Trait;
278} 271}
279 272
280impl<D> ToNav for D 273impl<D> TryToNav for D
281where 274where
282 D: HasSource + ToNavFromAst + Copy + HasAttrs, 275 D: HasSource + ToNavFromAst + Copy + HasAttrs,
283 D::Ast: ast::NameOwner + ShortLabel, 276 D::Ast: ast::NameOwner + ShortLabel,
284{ 277{
285 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 278 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
286 let src = self.source(db); 279 let src = self.source(db)?;
287 let mut res = NavigationTarget::from_named( 280 let mut res = NavigationTarget::from_named(
288 db, 281 db,
289 src.as_ref().map(|it| it as &dyn ast::NameOwner), 282 src.as_ref().map(|it| it as &dyn ast::NameOwner),
@@ -291,7 +284,7 @@ where
291 ); 284 );
292 res.docs = self.docs(db); 285 res.docs = self.docs(db);
293 res.description = src.value.short_label(); 286 res.description = src.value.short_label();
294 res 287 Some(res)
295 } 288 }
296} 289}
297 290
@@ -310,9 +303,9 @@ impl ToNav for hir::Module {
310 } 303 }
311} 304}
312 305
313impl ToNav for hir::Impl { 306impl TryToNav for hir::Impl {
314 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 307 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
315 let src = self.source(db); 308 let src = self.source(db)?;
316 let derive_attr = self.is_builtin_derive(db); 309 let derive_attr = self.is_builtin_derive(db);
317 let frange = if let Some(item) = &derive_attr { 310 let frange = if let Some(item) = &derive_attr {
318 item.syntax().original_file_range(db) 311 item.syntax().original_file_range(db)
@@ -325,21 +318,21 @@ impl ToNav for hir::Impl {
325 src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) 318 src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
326 }; 319 };
327 320
328 NavigationTarget::from_syntax( 321 Some(NavigationTarget::from_syntax(
329 frange.file_id, 322 frange.file_id,
330 "impl".into(), 323 "impl".into(),
331 focus_range, 324 focus_range,
332 frange.range, 325 frange.range,
333 SymbolKind::Impl, 326 SymbolKind::Impl,
334 ) 327 ))
335 } 328 }
336} 329}
337 330
338impl ToNav for hir::Field { 331impl TryToNav for hir::Field {
339 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 332 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
340 let src = self.source(db); 333 let src = self.source(db)?;
341 334
342 match &src.value { 335 let field_source = match &src.value {
343 FieldSource::Named(it) => { 336 FieldSource::Named(it) => {
344 let mut res = 337 let mut res =
345 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); 338 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
@@ -357,13 +350,14 @@ impl ToNav for hir::Field {
357 SymbolKind::Field, 350 SymbolKind::Field,
358 ) 351 )
359 } 352 }
360 } 353 };
354 Some(field_source)
361 } 355 }
362} 356}
363 357
364impl ToNav for hir::MacroDef { 358impl TryToNav for hir::MacroDef {
365 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 359 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
366 let src = self.source(db); 360 let src = self.source(db)?;
367 log::debug!("nav target {:#?}", src.value.syntax()); 361 log::debug!("nav target {:#?}", src.value.syntax());
368 let mut res = NavigationTarget::from_named( 362 let mut res = NavigationTarget::from_named(
369 db, 363 db,
@@ -371,26 +365,26 @@ impl ToNav for hir::MacroDef {
371 SymbolKind::Macro, 365 SymbolKind::Macro,
372 ); 366 );
373 res.docs = self.docs(db); 367 res.docs = self.docs(db);
374 res 368 Some(res)
375 } 369 }
376} 370}
377 371
378impl ToNav for hir::Adt { 372impl TryToNav for hir::Adt {
379 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 373 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
380 match self { 374 match self {
381 hir::Adt::Struct(it) => it.to_nav(db), 375 hir::Adt::Struct(it) => it.try_to_nav(db),
382 hir::Adt::Union(it) => it.to_nav(db), 376 hir::Adt::Union(it) => it.try_to_nav(db),
383 hir::Adt::Enum(it) => it.to_nav(db), 377 hir::Adt::Enum(it) => it.try_to_nav(db),
384 } 378 }
385 } 379 }
386} 380}
387 381
388impl ToNav for hir::AssocItem { 382impl TryToNav for hir::AssocItem {
389 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 383 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
390 match self { 384 match self {
391 AssocItem::Function(it) => it.to_nav(db), 385 AssocItem::Function(it) => it.try_to_nav(db),
392 AssocItem::Const(it) => it.to_nav(db), 386 AssocItem::Const(it) => it.try_to_nav(db),
393 AssocItem::TypeAlias(it) => it.to_nav(db), 387 AssocItem::TypeAlias(it) => it.try_to_nav(db),
394 } 388 }
395 } 389 }
396} 390}
@@ -444,9 +438,9 @@ impl ToNav for hir::Label {
444 } 438 }
445} 439}
446 440
447impl ToNav for hir::TypeParam { 441impl TryToNav for hir::TypeParam {
448 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 442 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
449 let src = self.source(db); 443 let src = self.source(db)?;
450 let full_range = match &src.value { 444 let full_range = match &src.value {
451 Either::Left(it) => it.syntax().text_range(), 445 Either::Left(it) => it.syntax().text_range(),
452 Either::Right(it) => it.syntax().text_range(), 446 Either::Right(it) => it.syntax().text_range(),
@@ -455,7 +449,7 @@ impl ToNav for hir::TypeParam {
455 Either::Left(_) => None, 449 Either::Left(_) => None,
456 Either::Right(it) => it.name().map(|it| it.syntax().text_range()), 450 Either::Right(it) => it.name().map(|it| it.syntax().text_range()),
457 }; 451 };
458 NavigationTarget { 452 Some(NavigationTarget {
459 file_id: src.file_id.original_file(db), 453 file_id: src.file_id.original_file(db),
460 name: self.name(db).to_string().into(), 454 name: self.name(db).to_string().into(),
461 kind: Some(SymbolKind::TypeParam), 455 kind: Some(SymbolKind::TypeParam),
@@ -464,15 +458,15 @@ impl ToNav for hir::TypeParam {
464 container_name: None, 458 container_name: None,
465 description: None, 459 description: None,
466 docs: None, 460 docs: None,
467 } 461 })
468 } 462 }
469} 463}
470 464
471impl ToNav for hir::LifetimeParam { 465impl TryToNav for hir::LifetimeParam {
472 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 466 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
473 let src = self.source(db); 467 let src = self.source(db)?;
474 let full_range = src.value.syntax().text_range(); 468 let full_range = src.value.syntax().text_range();
475 NavigationTarget { 469 Some(NavigationTarget {
476 file_id: src.file_id.original_file(db), 470 file_id: src.file_id.original_file(db),
477 name: self.name(db).to_string().into(), 471 name: self.name(db).to_string().into(),
478 kind: Some(SymbolKind::LifetimeParam), 472 kind: Some(SymbolKind::LifetimeParam),
@@ -481,7 +475,24 @@ impl ToNav for hir::LifetimeParam {
481 container_name: None, 475 container_name: None,
482 description: None, 476 description: None,
483 docs: None, 477 docs: None,
484 } 478 })
479 }
480}
481
482impl TryToNav for hir::ConstParam {
483 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
484 let src = self.source(db)?;
485 let full_range = src.value.syntax().text_range();
486 Some(NavigationTarget {
487 file_id: src.file_id.original_file(db),
488 name: self.name(db).to_string().into(),
489 kind: Some(SymbolKind::ConstParam),
490 full_range,
491 focus_range: src.value.name().map(|n| n.syntax().text_range()),
492 container_name: None,
493 description: None,
494 docs: None,
495 })
485 } 496 }
486} 497}
487 498
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index e10516f43..367fac05e 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -193,6 +193,7 @@ fn rewrite_intra_doc_link(
193 Definition::SelfType(_) 193 Definition::SelfType(_)
194 | Definition::Local(_) 194 | Definition::Local(_)
195 | Definition::TypeParam(_) 195 | Definition::TypeParam(_)
196 | Definition::ConstParam(_)
196 | Definition::LifetimeParam(_) 197 | Definition::LifetimeParam(_)
197 | Definition::Label(_) => return None, 198 | Definition::Label(_) => return None,
198 }?; 199 }?;
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 6eac39639..da9378a97 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics};
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::{algo::find_node_at_offset, ast, AstNode}; 3use syntax::{algo::find_node_at_offset, ast, AstNode};
4 4
5use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 5use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
6 6
7// Feature: Go to Implementation 7// Feature: Go to Implementation
8// 8//
@@ -55,7 +55,7 @@ fn impls_for_def(
55 impls 55 impls
56 .into_iter() 56 .into_iter()
57 .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) 57 .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
58 .map(|imp| imp.to_nav(sema.db)) 58 .filter_map(|imp| imp.try_to_nav(sema.db))
59 .collect(), 59 .collect(),
60 ) 60 )
61} 61}
@@ -69,7 +69,7 @@ fn impls_for_trait(
69 69
70 let impls = Impl::for_trait(sema.db, krate, tr); 70 let impls = Impl::for_trait(sema.db, krate, tr);
71 71
72 Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect()) 72 Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
73} 73}
74 74
75#[cfg(test)] 75#[cfg(test)]
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index aba6bf5dc..7e84e06be 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1use ide_db::RootDatabase; 1use ide_db::RootDatabase;
2use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 2use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
3 3
4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 4use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
5 5
6// Feature: Go to Type Definition 6// Feature: Go to Type Definition
7// 7//
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition(
37 37
38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; 38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
39 39
40 let nav = adt_def.to_nav(db); 40 let nav = adt_def.try_to_nav(db)?;
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 73245fbe7..2737c900f 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset,
13use test_utils::mark; 13use test_utils::mark;
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, ShortLabel, ToNav, TryToNav}, 16 display::{macro_label, ShortLabel, TryToNav},
17 doc_links::{remove_links, rewrite_links}, 17 doc_links::{remove_links, rewrite_links},
18 markdown_remove::remove_markdown, 18 markdown_remove::remove_markdown,
19 markup::Markup, 19 markup::Markup,
@@ -109,6 +109,8 @@ pub(crate) fn hover(
109 match node { 109 match node {
110 ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), 110 ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)),
111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
112 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime)
113 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)),
112 _ => None, 114 _ => None,
113 } 115 }
114 }; 116 };
@@ -181,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
181 183
182 match def { 184 match def {
183 Definition::ModuleDef(it) => match it { 185 Definition::ModuleDef(it) => match it {
184 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), 186 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)),
185 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), 187 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)),
186 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), 188 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
187 ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), 189 ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
188 _ => None, 190 _ => None,
189 }, 191 },
190 _ => None, 192 _ => None,
@@ -204,7 +206,8 @@ fn runnable_action(
204 _ => None, 206 _ => None,
205 }, 207 },
206 ModuleDef::Function(it) => { 208 ModuleDef::Function(it) => {
207 let src = it.source(sema.db); 209 #[allow(deprecated)]
210 let src = it.source(sema.db)?;
208 if src.file_id != file_id.into() { 211 if src.file_id != file_id.into() {
209 mark::hit!(hover_macro_generated_struct_fn_doc_comment); 212 mark::hit!(hover_macro_generated_struct_fn_doc_comment);
210 mark::hit!(hover_macro_generated_struct_fn_doc_attr); 213 mark::hit!(hover_macro_generated_struct_fn_doc_attr);
@@ -324,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
324 let mod_path = definition_mod_path(db, &def); 327 let mod_path = definition_mod_path(db, &def);
325 return match def { 328 return match def {
326 Definition::Macro(it) => { 329 Definition::Macro(it) => {
327 // FIXME: Currently proc-macro do not have ast-node, 330 let label = macro_label(&it.source(db)?.value);
328 // such that it does not have source
329 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
330 if it.is_proc_macro() {
331 return None;
332 }
333 let label = macro_label(&it.source(db).value);
334 from_def_source_labeled(db, it, Some(label), mod_path) 331 from_def_source_labeled(db, it, Some(label), mod_path)
335 } 332 }
336 Definition::Field(def) => { 333 Definition::Field(def) => {
337 let src = def.source(db).value; 334 #[allow(deprecated)]
335 let src = def.source(db)?.value;
338 if let FieldSource::Named(it) = src { 336 if let FieldSource::Named(it) = src {
339 from_def_source_labeled(db, def, it.short_label(), mod_path) 337 from_def_source_labeled(db, def, it.short_label(), mod_path)
340 } else { 338 } else {
@@ -360,9 +358,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
360 ModuleDef::Static(it) => from_def_source(db, it, mod_path), 358 ModuleDef::Static(it) => from_def_source(db, it, mod_path),
361 ModuleDef::Trait(it) => from_def_source(db, it, mod_path), 359 ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
362 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), 360 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
363 ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), 361 ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)),
364 }, 362 },
365 Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), 363 Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))),
366 Definition::SelfType(impl_def) => { 364 Definition::SelfType(impl_def) => {
367 impl_def.target_ty(db).as_adt().and_then(|adt| match adt { 365 impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
368 Adt::Struct(it) => from_def_source(db, it, mod_path), 366 Adt::Struct(it) => from_def_source(db, it, mod_path),
@@ -370,7 +368,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
370 Adt::Enum(it) => from_def_source(db, it, mod_path), 368 Adt::Enum(it) => from_def_source(db, it, mod_path),
371 }) 369 })
372 } 370 }
373 Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { 371 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
372 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
373 Definition::TypeParam(_) | Definition::ConstParam(_) => {
374 // FIXME: Hover for generic param 374 // FIXME: Hover for generic param
375 None 375 None
376 } 376 }
@@ -381,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
381 D: HasSource<Ast = A> + HasAttrs + Copy, 381 D: HasSource<Ast = A> + HasAttrs + Copy,
382 A: ShortLabel, 382 A: ShortLabel,
383 { 383 {
384 let short_label = def.source(db).value.short_label(); 384 #[allow(deprecated)]
385 let short_label = def.source(db)?.value.short_label();
385 from_def_source_labeled(db, def, short_label, mod_path) 386 from_def_source_labeled(db, def, short_label, mod_path)
386 } 387 }
387 388
@@ -403,7 +404,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
403 return tokens.max_by_key(priority); 404 return tokens.max_by_key(priority);
404 fn priority(n: &SyntaxToken) -> usize { 405 fn priority(n: &SyntaxToken) -> usize {
405 match n.kind() { 406 match n.kind() {
406 IDENT | INT_NUMBER => 3, 407 IDENT | INT_NUMBER | LIFETIME_IDENT => 3,
407 T!['('] | T![')'] => 2, 408 T!['('] | T![')'] => 2,
408 kind if kind.is_trivia() => 0, 409 kind if kind.is_trivia() => 0,
409 _ => 1, 410 _ => 1,
@@ -1169,7 +1170,10 @@ fn f() { fo<|>o!(); }
1169 r#"struct TS(String, i32<|>);"#, 1170 r#"struct TS(String, i32<|>);"#,
1170 expect![[r#" 1171 expect![[r#"
1171 *i32* 1172 *i32*
1173
1174 ```rust
1172 i32 1175 i32
1176 ```
1173 "#]], 1177 "#]],
1174 ) 1178 )
1175 } 1179 }
@@ -3221,4 +3225,36 @@ fn no_hover() {
3221"#, 3225"#,
3222 ); 3226 );
3223 } 3227 }
3228
3229 #[test]
3230 fn hover_label() {
3231 check(
3232 r#"
3233fn foo() {
3234 'label<|>: loop {}
3235}
3236"#,
3237 expect![[r#"
3238 *'label*
3239
3240 ```rust
3241 'label
3242 ```
3243 "#]],
3244 );
3245 }
3246
3247 #[test]
3248 fn hover_lifetime() {
3249 check(
3250 r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#,
3251 expect![[r#"
3252 *'lifetime*
3253
3254 ```rust
3255 'lifetime
3256 ```
3257 "#]],
3258 );
3259 }
3224} 3260}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b3331f03f..a450794f3 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -31,6 +31,7 @@ mod folding_ranges;
31mod goto_definition; 31mod goto_definition;
32mod goto_implementation; 32mod goto_implementation;
33mod goto_type_definition; 33mod goto_type_definition;
34mod view_hir;
34mod hover; 35mod hover;
35mod inlay_hints; 36mod inlay_hints;
36mod join_lines; 37mod join_lines;
@@ -271,6 +272,10 @@ impl Analysis {
271 self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) 272 self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range))
272 } 273 }
273 274
275 pub fn view_hir(&self, position: FilePosition) -> Cancelable<String> {
276 self.with_db(|db| view_hir::view_hir(&db, position))
277 }
278
274 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { 279 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
275 self.with_db(|db| expand_macro::expand_macro(db, position)) 280 self.with_db(|db| expand_macro::expand_macro(db, position))
276 } 281 }
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 21b2d7ca1..fa58fc319 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1144,4 +1144,20 @@ fn foo<'a>() -> &'a () {
1144 "#]], 1144 "#]],
1145 ); 1145 );
1146 } 1146 }
1147
1148 #[test]
1149 fn test_find_const_param() {
1150 check(
1151 r#"
1152fn foo<const FOO<|>: usize>() -> usize {
1153 FOO
1154}
1155"#,
1156 expect![[r#"
1157 FOO ConstParam FileId(0) 7..23 13..16 Other
1158
1159 FileId(0) 42..45 Other
1160 "#]],
1161 );
1162 }
1147} 1163}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 891183266..c893afc7c 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -230,7 +230,7 @@ impl TestAttr {
230 230
231const RUSTDOC_FENCE: &str = "```"; 231const RUSTDOC_FENCE: &str = "```";
232const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 232const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
233 &["", "rust", "should_panic", "edition2015", "edition2018"]; 233 &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
234 234
235fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { 235fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
236 attrs.docs().map_or(false, |doc| { 236 attrs.docs().map_or(false, |doc| {
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 5ad96581b..ba0085244 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -819,6 +819,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
819 }, 819 },
820 Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), 820 Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl),
821 Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), 821 Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam),
822 Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam),
822 Definition::Local(local) => { 823 Definition::Local(local) => {
823 let tag = if local.is_param(db) { 824 let tag = if local.is_param(db) {
824 HighlightTag::Symbol(SymbolKind::ValueParam) 825 HighlightTag::Symbol(SymbolKind::ValueParam)
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
index 9eb184c74..6cbd683c6 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/injection.rs
@@ -54,8 +54,17 @@ pub(super) fn highlight_injection(
54type RangesMap = BTreeMap<TextSize, TextSize>; 54type RangesMap = BTreeMap<TextSize, TextSize>;
55 55
56const RUSTDOC_FENCE: &'static str = "```"; 56const RUSTDOC_FENCE: &'static str = "```";
57const RUSTDOC_FENCE_TOKENS: &[&'static str] = 57const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
58 &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; 58 "",
59 "rust",
60 "should_panic",
61 "ignore",
62 "no_run",
63 "compile_fail",
64 "edition2015",
65 "edition2018",
66 "edition2021",
67];
59 68
60/// Extracts Rust code from documentation comments as well as a mapping from 69/// Extracts Rust code from documentation comments as well as a mapping from
61/// the extracted source code back to the original source ranges. 70/// the extracted source code back to the original source ranges.
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 2a6cc0cab..8b8867079 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -77,6 +77,7 @@ impl HighlightTag {
77 SymbolKind::Function => "function", 77 SymbolKind::Function => "function",
78 SymbolKind::TypeAlias => "type_alias", 78 SymbolKind::TypeAlias => "type_alias",
79 SymbolKind::TypeParam => "type_param", 79 SymbolKind::TypeParam => "type_param",
80 SymbolKind::ConstParam => "const_param",
80 SymbolKind::LifetimeParam => "lifetime", 81 SymbolKind::LifetimeParam => "lifetime",
81 SymbolKind::Macro => "macro", 82 SymbolKind::Macro => "macro",
82 SymbolKind::Local => "variable", 83 SymbolKind::Local => "variable",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 72ff9dd40..02270b077 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -118,6 +118,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> 118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span>
119<span class="punctuation">}</span> 119<span class="punctuation">}</span>
120 120
121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="punctuation">{</span>
122 <span class="const_param">FOO</span>
123<span class="punctuation">}</span>
124
121<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> 125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span>
122<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> 126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span>
123 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> 127 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index e0df0d2b5..30b5b648e 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -91,6 +91,10 @@ fn never() -> ! {
91 loop {} 91 loop {}
92} 92}
93 93
94fn const_param<const FOO: usize>() -> usize {
95 FOO
96}
97
94use ops::Fn; 98use ops::Fn;
95fn baz<F: Fn() -> ()>(f: F) { 99fn baz<F: Fn() -> ()>(f: F) {
96 f() 100 f()
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs
new file mode 100644
index 000000000..cfcfb7cfb
--- /dev/null
+++ b/crates/ide/src/view_hir.rs
@@ -0,0 +1,25 @@
1use hir::{Function, Semantics};
2use ide_db::base_db::FilePosition;
3use ide_db::RootDatabase;
4use syntax::{algo::find_node_at_offset, ast, AstNode};
5
6// Feature: View Hir
7//
8// |===
9// | Editor | Action Name
10//
11// | VS Code | **Rust Analyzer: View Hir**
12// |===
13pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
14 body_hir(db, position).unwrap_or("Not inside a function body".to_string())
15}
16
17fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
18 let sema = Semantics::new(db);
19 let source_file = sema.parse(position.file_id);
20
21 let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?;
22
23 let function: Function = sema.to_def(&function)?;
24 Some(function.debug_hir(db))
25}