aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/hir/src/code_model.rs39
-rw-r--r--crates/hir/src/from_id.rs6
-rw-r--r--crates/hir/src/has_source.rs6
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/semantics.rs6
-rw-r--r--crates/hir_def/src/attr.rs2
-rw-r--r--crates/hir_def/src/lib.rs30
-rw-r--r--crates/hir_ty/src/diagnostics.rs15
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs103
-rw-r--r--crates/ide/src/display/navigation_target.rs65
-rw-r--r--crates/ide/src/doc_links.rs7
-rw-r--r--crates/ide/src/goto_definition.rs57
-rw-r--r--crates/ide/src/goto_implementation.rs6
-rw-r--r--crates/ide/src/hover.rs4
-rw-r--r--crates/ide/src/lib.rs7
-rw-r--r--crates/ide/src/references.rs91
-rw-r--r--crates/ide/src/references/rename.rs104
-rw-r--r--crates/ide/src/runnables.rs203
-rw-r--r--crates/ide/src/syntax_highlighting.rs1
-rw-r--r--crates/ide_db/src/defs.rs61
-rw-r--r--crates/ide_db/src/search.rs63
-rw-r--r--crates/ide_db/src/symbol_index.rs3
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/caps.rs3
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs5
-rw-r--r--editors/code/package-lock.json71
-rw-r--r--editors/code/package.json6
29 files changed, 650 insertions, 324 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4476d188b..31a850797 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -844,9 +844,9 @@ dependencies = [
844 844
845[[package]] 845[[package]]
846name = "lsp-types" 846name = "lsp-types"
847version = "0.85.0" 847version = "0.86.0"
848source = "registry+https://github.com/rust-lang/crates.io-index" 848source = "registry+https://github.com/rust-lang/crates.io-index"
849checksum = "857650f3e83fb62f89d15410414e0ed7d0735445020da398d37f65d20a5423b9" 849checksum = "f2a5c40d566f2704dac30859bca152217583fc94fd5b178d8baba915e1abd382"
850dependencies = [ 850dependencies = [
851 "base64", 851 "base64",
852 "bitflags", 852 "bitflags",
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 9bfcd215a..f17734e41 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -267,7 +267,12 @@ impl ModuleDef {
267 _ => return, 267 _ => return,
268 }; 268 };
269 269
270 hir_ty::diagnostics::validate_module_item(db, id, sink) 270 let module = match self.module(db) {
271 Some(it) => it,
272 None => return,
273 };
274
275 hir_ty::diagnostics::validate_module_item(db, module.id.krate, id, sink)
271 } 276 }
272} 277}
273 278
@@ -397,9 +402,9 @@ impl Module {
397 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() 402 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
398 } 403 }
399 404
400 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<ImplDef> { 405 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
401 let def_map = db.crate_def_map(self.id.krate); 406 let def_map = db.crate_def_map(self.id.krate);
402 def_map[self.id.local_id].scope.impls().map(ImplDef::from).collect() 407 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
403 } 408 }
404 409
405 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module { 410 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
@@ -780,8 +785,9 @@ impl Function {
780 } 785 }
781 786
782 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 787 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
788 let krate = self.module(db).id.krate;
783 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); 789 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink);
784 hir_ty::diagnostics::validate_module_item(db, self.id.into(), sink); 790 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
785 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 791 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
786 } 792 }
787 793
@@ -1001,7 +1007,7 @@ pub enum AssocItem {
1001} 1007}
1002pub enum AssocItemContainer { 1008pub enum AssocItemContainer {
1003 Trait(Trait), 1009 Trait(Trait),
1004 ImplDef(ImplDef), 1010 Impl(Impl),
1005} 1011}
1006pub trait AsAssocItem { 1012pub trait AsAssocItem {
1007 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>; 1013 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
@@ -1058,7 +1064,7 @@ impl AssocItem {
1058 }; 1064 };
1059 match container { 1065 match container {
1060 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), 1066 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
1061 AssocContainerId::ImplId(id) => AssocItemContainer::ImplDef(id.into()), 1067 AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
1062 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), 1068 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
1063 } 1069 }
1064 } 1070 }
@@ -1080,7 +1086,7 @@ pub enum GenericDef {
1080 Adt(Adt), 1086 Adt(Adt),
1081 Trait(Trait), 1087 Trait(Trait),
1082 TypeAlias(TypeAlias), 1088 TypeAlias(TypeAlias),
1083 ImplDef(ImplDef), 1089 Impl(Impl),
1084 // enum variants cannot have generics themselves, but their parent enums 1090 // enum variants cannot have generics themselves, but their parent enums
1085 // can, and this makes some code easier to write 1091 // can, and this makes some code easier to write
1086 EnumVariant(EnumVariant), 1092 EnumVariant(EnumVariant),
@@ -1092,7 +1098,7 @@ impl_from!(
1092 Adt(Struct, Enum, Union), 1098 Adt(Struct, Enum, Union),
1093 Trait, 1099 Trait,
1094 TypeAlias, 1100 TypeAlias,
1095 ImplDef, 1101 Impl,
1096 EnumVariant, 1102 EnumVariant,
1097 Const 1103 Const
1098 for GenericDef 1104 for GenericDef
@@ -1262,30 +1268,28 @@ impl LifetimeParam {
1262 1268
1263// FIXME: rename from `ImplDef` to `Impl` 1269// FIXME: rename from `ImplDef` to `Impl`
1264#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1270#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1265pub struct ImplDef { 1271pub struct Impl {
1266 pub(crate) id: ImplId, 1272 pub(crate) id: ImplId,
1267} 1273}
1268 1274
1269impl ImplDef { 1275impl Impl {
1270 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> { 1276 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
1271 let inherent = db.inherent_impls_in_crate(krate.id); 1277 let inherent = db.inherent_impls_in_crate(krate.id);
1272 let trait_ = db.trait_impls_in_crate(krate.id); 1278 let trait_ = db.trait_impls_in_crate(krate.id);
1273 1279
1274 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() 1280 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1275 } 1281 }
1276 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> { 1282 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> {
1277 let impls = db.trait_impls_in_crate(krate.id); 1283 let impls = db.trait_impls_in_crate(krate.id);
1278 impls.for_trait(trait_.id).map(Self::from).collect() 1284 impls.for_trait(trait_.id).map(Self::from).collect()
1279 } 1285 }
1280 1286
1287 // FIXME: the return type is wrong. This should be a hir version of
1288 // `TraitRef` (ie, resolved `TypeRef`).
1281 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1289 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1282 db.impl_data(self.id).target_trait.clone() 1290 db.impl_data(self.id).target_trait.clone()
1283 } 1291 }
1284 1292
1285 pub fn target_type(self, db: &dyn HirDatabase) -> TypeRef {
1286 db.impl_data(self.id).target_type.clone()
1287 }
1288
1289 pub fn target_ty(self, db: &dyn HirDatabase) -> Type { 1293 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1290 let impl_data = db.impl_data(self.id); 1294 let impl_data = db.impl_data(self.id);
1291 let resolver = self.id.resolver(db.upcast()); 1295 let resolver = self.id.resolver(db.upcast());
@@ -1319,6 +1323,7 @@ impl ImplDef {
1319 let item = src.file_id.is_builtin_derive(db.upcast())?; 1323 let item = src.file_id.is_builtin_derive(db.upcast())?;
1320 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); 1324 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
1321 1325
1326 // FIXME: handle `cfg_attr`
1322 let attr = item 1327 let attr = item
1323 .value 1328 .value
1324 .attrs() 1329 .attrs()
@@ -1898,7 +1903,7 @@ pub enum ScopeDef {
1898 ModuleDef(ModuleDef), 1903 ModuleDef(ModuleDef),
1899 MacroDef(MacroDef), 1904 MacroDef(MacroDef),
1900 GenericParam(TypeParam), 1905 GenericParam(TypeParam),
1901 ImplSelfType(ImplDef), 1906 ImplSelfType(Impl),
1902 AdtSelfType(Adt), 1907 AdtSelfType(Adt),
1903 Local(Local), 1908 Local(Local),
1904 Unknown, 1909 Unknown,
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index dd3fcfe4a..8d0f84508 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -39,7 +39,7 @@ from_id![
39 (hir_def::StaticId, crate::Static), 39 (hir_def::StaticId, crate::Static),
40 (hir_def::ConstId, crate::Const), 40 (hir_def::ConstId, crate::Const),
41 (hir_def::FunctionId, crate::Function), 41 (hir_def::FunctionId, crate::Function),
42 (hir_def::ImplId, crate::ImplDef), 42 (hir_def::ImplId, crate::Impl),
43 (hir_def::TypeParamId, crate::TypeParam), 43 (hir_def::TypeParamId, crate::TypeParam),
44 (hir_def::LifetimeParamId, crate::LifetimeParam), 44 (hir_def::LifetimeParamId, crate::LifetimeParam),
45 (hir_expand::MacroDefId, crate::MacroDef) 45 (hir_expand::MacroDefId, crate::MacroDef)
@@ -146,7 +146,7 @@ impl From<GenericDef> for GenericDefId {
146 GenericDef::Adt(it) => GenericDefId::AdtId(it.into()), 146 GenericDef::Adt(it) => GenericDefId::AdtId(it.into()),
147 GenericDef::Trait(it) => GenericDefId::TraitId(it.id), 147 GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
148 GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), 148 GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
149 GenericDef::ImplDef(it) => GenericDefId::ImplId(it.id), 149 GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
150 GenericDef::EnumVariant(it) => { 150 GenericDef::EnumVariant(it) => {
151 GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id }) 151 GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
152 } 152 }
@@ -162,7 +162,7 @@ impl From<GenericDefId> for GenericDef {
162 GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), 162 GenericDefId::AdtId(it) => GenericDef::Adt(it.into()),
163 GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), 163 GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
164 GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), 164 GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
165 GenericDefId::ImplId(it) => GenericDef::ImplDef(it.into()), 165 GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
166 GenericDefId::EnumVariantId(it) => { 166 GenericDefId::EnumVariantId(it) => {
167 GenericDef::EnumVariant(EnumVariant { parent: it.parent.into(), id: it.local_id }) 167 GenericDef::EnumVariant(EnumVariant { parent: it.parent.into(), id: it.local_id })
168 } 168 }
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 11ae63c31..c5b81b252 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -10,8 +10,8 @@ use hir_expand::InFile;
10use syntax::ast; 10use syntax::ast;
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, 13 db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, Impl, LifetimeParam,
14 LifetimeParam, MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, 14 MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union,
15}; 15};
16 16
17pub trait HasSource { 17pub trait HasSource {
@@ -118,7 +118,7 @@ impl HasSource for MacroDef {
118 } 118 }
119 } 119 }
120} 120}
121impl HasSource for ImplDef { 121impl HasSource for Impl {
122 type Ast = ast::Impl; 122 type Ast = ast::Impl;
123 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { 123 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
124 self.id.lookup(db.upcast()).source(db.upcast()) 124 self.id.lookup(db.upcast()).source(db.upcast())
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0f399a2c6..3f4f8d8e4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,7 +35,7 @@ pub use crate::{
35 code_model::{ 35 code_model::{
36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, 36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
37 Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function, 37 Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function,
38 GenericDef, HasVisibility, ImplDef, LifetimeParam, Local, MacroDef, Module, ModuleDef, 38 GenericDef, HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module, ModuleDef,
39 ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, 39 ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef,
40 }, 40 },
41 has_source::HasSource, 41 has_source::HasSource,
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index ee2074602..83ec91f58 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -25,7 +25,7 @@ use crate::{
25 diagnostics::Diagnostic, 25 diagnostics::Diagnostic,
26 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 26 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
27 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 27 source_analyzer::{resolve_hir_path, SourceAnalyzer},
28 AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, LifetimeParam, Local, 28 AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, LifetimeParam, Local,
29 MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, 29 MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
30 VariantDef, 30 VariantDef,
31}; 31};
@@ -38,7 +38,7 @@ pub enum PathResolution {
38 Local(Local), 38 Local(Local),
39 /// A generic parameter 39 /// A generic parameter
40 TypeParam(TypeParam), 40 TypeParam(TypeParam),
41 SelfType(ImplDef), 41 SelfType(Impl),
42 Macro(MacroDef), 42 Macro(MacroDef),
43 AssocItem(AssocItem), 43 AssocItem(AssocItem),
44} 44}
@@ -708,7 +708,7 @@ to_def_impls![
708 (crate::Enum, ast::Enum, enum_to_def), 708 (crate::Enum, ast::Enum, enum_to_def),
709 (crate::Union, ast::Union, union_to_def), 709 (crate::Union, ast::Union, union_to_def),
710 (crate::Trait, ast::Trait, trait_to_def), 710 (crate::Trait, ast::Trait, trait_to_def),
711 (crate::ImplDef, ast::Impl, impl_to_def), 711 (crate::Impl, ast::Impl, impl_to_def),
712 (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), 712 (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
713 (crate::Const, ast::Const, const_to_def), 713 (crate::Const, ast::Const, const_to_def),
714 (crate::Static, ast::Static, static_to_def), 714 (crate::Static, ast::Static, static_to_def),
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index c64b78445..45313f335 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -104,7 +104,7 @@ impl Attrs {
104 } 104 }
105 } 105 }
106 106
107 pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { 107 fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
108 let hygiene = Hygiene::new(db.upcast(), owner.file_id); 108 let hygiene = Hygiene::new(db.upcast(), owner.file_id);
109 Attrs::new(owner.value, &hygiene) 109 Attrs::new(owner.value, &hygiene)
110 } 110 }
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 7e2199a9c..ba09a9126 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -425,6 +425,16 @@ impl HasModule for AdtId {
425 } 425 }
426} 426}
427 427
428impl HasModule for VariantId {
429 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
430 match self {
431 VariantId::EnumVariantId(it) => it.parent.lookup(db).container.module(db),
432 VariantId::StructId(it) => it.lookup(db).container.module(db),
433 VariantId::UnionId(it) => it.lookup(db).container.module(db),
434 }
435 }
436}
437
428impl HasModule for DefWithBodyId { 438impl HasModule for DefWithBodyId {
429 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 439 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
430 match self { 440 match self {
@@ -465,6 +475,26 @@ impl HasModule for StaticLoc {
465 } 475 }
466} 476}
467 477
478impl AttrDefId {
479 pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
480 match self {
481 AttrDefId::ModuleId(it) => it.krate,
482 AttrDefId::FieldId(it) => it.parent.module(db).krate,
483 AttrDefId::AdtId(it) => it.module(db).krate,
484 AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
485 AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db).krate,
486 AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
487 AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
488 AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate,
489 AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
490 AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate,
491 // FIXME: `MacroDefId` should store the defining module, then this can implement
492 // `HasModule`
493 AttrDefId::MacroDefId(it) => it.krate,
494 }
495 }
496}
497
468/// A helper trait for converting to MacroCallId 498/// A helper trait for converting to MacroCallId
469pub trait AsMacroCall { 499pub trait AsMacroCall {
470 fn as_call_id( 500 fn as_call_id(
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 1c72f766e..14e18f5a1 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -6,6 +6,7 @@ mod decl_check;
6 6
7use std::{any::Any, fmt}; 7use std::{any::Any, fmt};
8 8
9use base_db::CrateId;
9use hir_def::{DefWithBodyId, ModuleDefId}; 10use hir_def::{DefWithBodyId, ModuleDefId};
10use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; 11use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
11use hir_expand::{name::Name, HirFileId, InFile}; 12use hir_expand::{name::Name, HirFileId, InFile};
@@ -18,12 +19,13 @@ pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern
18 19
19pub fn validate_module_item( 20pub fn validate_module_item(
20 db: &dyn HirDatabase, 21 db: &dyn HirDatabase,
22 krate: CrateId,
21 owner: ModuleDefId, 23 owner: ModuleDefId,
22 sink: &mut DiagnosticSink<'_>, 24 sink: &mut DiagnosticSink<'_>,
23) { 25) {
24 let _p = profile::span("validate_module_item"); 26 let _p = profile::span("validate_module_item");
25 let mut validator = decl_check::DeclValidator::new(owner, sink); 27 let mut validator = decl_check::DeclValidator::new(db, krate, sink);
26 validator.validate_item(db); 28 validator.validate_item(owner);
27} 29}
28 30
29pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { 31pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
@@ -407,7 +409,7 @@ mod tests {
407 for (module_id, _) in crate_def_map.modules.iter() { 409 for (module_id, _) in crate_def_map.modules.iter() {
408 for decl in crate_def_map[module_id].scope.declarations() { 410 for decl in crate_def_map[module_id].scope.declarations() {
409 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); 411 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
410 validate_module_item(self, decl, &mut sink); 412 validate_module_item(self, krate, decl, &mut sink);
411 413
412 if let ModuleDefId::FunctionId(f) = decl { 414 if let ModuleDefId::FunctionId(f) = decl {
413 fns.push(f) 415 fns.push(f)
@@ -419,7 +421,12 @@ mod tests {
419 for item in impl_data.items.iter() { 421 for item in impl_data.items.iter() {
420 if let AssocItemId::FunctionId(f) = item { 422 if let AssocItemId::FunctionId(f) = item {
421 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); 423 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
422 validate_module_item(self, ModuleDefId::FunctionId(*f), &mut sink); 424 validate_module_item(
425 self,
426 krate,
427 ModuleDefId::FunctionId(*f),
428 &mut sink,
429 );
423 fns.push(*f) 430 fns.push(*f)
424 } 431 }
425 } 432 }
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 25587e116..eaeb6899f 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -12,6 +12,7 @@
12 12
13mod case_conv; 13mod case_conv;
14 14
15use base_db::CrateId;
15use hir_def::{ 16use hir_def::{
16 adt::VariantData, 17 adt::VariantData,
17 expr::{Pat, PatId}, 18 expr::{Pat, PatId},
@@ -40,7 +41,8 @@ mod allow {
40} 41}
41 42
42pub(super) struct DeclValidator<'a, 'b: 'a> { 43pub(super) struct DeclValidator<'a, 'b: 'a> {
43 owner: ModuleDefId, 44 db: &'a dyn HirDatabase,
45 krate: CrateId,
44 sink: &'a mut DiagnosticSink<'b>, 46 sink: &'a mut DiagnosticSink<'b>,
45} 47}
46 48
@@ -53,26 +55,27 @@ struct Replacement {
53 55
54impl<'a, 'b> DeclValidator<'a, 'b> { 56impl<'a, 'b> DeclValidator<'a, 'b> {
55 pub(super) fn new( 57 pub(super) fn new(
56 owner: ModuleDefId, 58 db: &'a dyn HirDatabase,
59 krate: CrateId,
57 sink: &'a mut DiagnosticSink<'b>, 60 sink: &'a mut DiagnosticSink<'b>,
58 ) -> DeclValidator<'a, 'b> { 61 ) -> DeclValidator<'a, 'b> {
59 DeclValidator { owner, sink } 62 DeclValidator { db, krate, sink }
60 } 63 }
61 64
62 pub(super) fn validate_item(&mut self, db: &dyn HirDatabase) { 65 pub(super) fn validate_item(&mut self, item: ModuleDefId) {
63 match self.owner { 66 match item {
64 ModuleDefId::FunctionId(func) => self.validate_func(db, func), 67 ModuleDefId::FunctionId(func) => self.validate_func(func),
65 ModuleDefId::AdtId(adt) => self.validate_adt(db, adt), 68 ModuleDefId::AdtId(adt) => self.validate_adt(adt),
66 ModuleDefId::ConstId(const_id) => self.validate_const(db, const_id), 69 ModuleDefId::ConstId(const_id) => self.validate_const(const_id),
67 ModuleDefId::StaticId(static_id) => self.validate_static(db, static_id), 70 ModuleDefId::StaticId(static_id) => self.validate_static(static_id),
68 _ => return, 71 _ => return,
69 } 72 }
70 } 73 }
71 74
72 fn validate_adt(&mut self, db: &dyn HirDatabase, adt: AdtId) { 75 fn validate_adt(&mut self, adt: AdtId) {
73 match adt { 76 match adt {
74 AdtId::StructId(struct_id) => self.validate_struct(db, struct_id), 77 AdtId::StructId(struct_id) => self.validate_struct(struct_id),
75 AdtId::EnumId(enum_id) => self.validate_enum(db, enum_id), 78 AdtId::EnumId(enum_id) => self.validate_enum(enum_id),
76 AdtId::UnionId(_) => { 79 AdtId::UnionId(_) => {
77 // Unions aren't yet supported by this validator. 80 // Unions aren't yet supported by this validator.
78 } 81 }
@@ -82,27 +85,27 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
82 /// Checks whether not following the convention is allowed for this item. 85 /// Checks whether not following the convention is allowed for this item.
83 /// 86 ///
84 /// Currently this method doesn't check parent attributes. 87 /// Currently this method doesn't check parent attributes.
85 fn allowed(&self, db: &dyn HirDatabase, id: AttrDefId, allow_name: &str) -> bool { 88 fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool {
86 db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name)) 89 self.db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name))
87 } 90 }
88 91
89 fn validate_func(&mut self, db: &dyn HirDatabase, func: FunctionId) { 92 fn validate_func(&mut self, func: FunctionId) {
90 let data = db.function_data(func); 93 let data = self.db.function_data(func);
91 if data.is_extern { 94 if data.is_extern {
92 mark::hit!(extern_func_incorrect_case_ignored); 95 mark::hit!(extern_func_incorrect_case_ignored);
93 return; 96 return;
94 } 97 }
95 98
96 let body = db.body(func.into()); 99 let body = self.db.body(func.into());
97 100
98 // Recursively validate inner scope items, such as static variables and constants. 101 // Recursively validate inner scope items, such as static variables and constants.
99 for (item_id, _) in body.item_scope.values() { 102 for (item_id, _) in body.item_scope.values() {
100 let mut validator = DeclValidator::new(item_id, self.sink); 103 let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
101 validator.validate_item(db); 104 validator.validate_item(item_id);
102 } 105 }
103 106
104 // Check whether non-snake case identifiers are allowed for this function. 107 // Check whether non-snake case identifiers are allowed for this function.
105 if self.allowed(db, func.into(), allow::NON_SNAKE_CASE) { 108 if self.allowed(func.into(), allow::NON_SNAKE_CASE) {
106 return; 109 return;
107 } 110 }
108 111
@@ -169,11 +172,10 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
169 // If there is at least one element to spawn a warning on, go to the source map and generate a warning. 172 // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
170 self.create_incorrect_case_diagnostic_for_func( 173 self.create_incorrect_case_diagnostic_for_func(
171 func, 174 func,
172 db,
173 fn_name_replacement, 175 fn_name_replacement,
174 fn_param_replacements, 176 fn_param_replacements,
175 ); 177 );
176 self.create_incorrect_case_diagnostic_for_variables(func, db, pats_replacements); 178 self.create_incorrect_case_diagnostic_for_variables(func, pats_replacements);
177 } 179 }
178 180
179 /// Given the information about incorrect names in the function declaration, looks up into the source code 181 /// Given the information about incorrect names in the function declaration, looks up into the source code
@@ -181,7 +183,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
181 fn create_incorrect_case_diagnostic_for_func( 183 fn create_incorrect_case_diagnostic_for_func(
182 &mut self, 184 &mut self,
183 func: FunctionId, 185 func: FunctionId,
184 db: &dyn HirDatabase,
185 fn_name_replacement: Option<Replacement>, 186 fn_name_replacement: Option<Replacement>,
186 fn_param_replacements: Vec<Replacement>, 187 fn_param_replacements: Vec<Replacement>,
187 ) { 188 ) {
@@ -190,8 +191,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
190 return; 191 return;
191 } 192 }
192 193
193 let fn_loc = func.lookup(db.upcast()); 194 let fn_loc = func.lookup(self.db.upcast());
194 let fn_src = fn_loc.source(db.upcast()); 195 let fn_src = fn_loc.source(self.db.upcast());
195 196
196 // Diagnostic for function name. 197 // Diagnostic for function name.
197 if let Some(replacement) = fn_name_replacement { 198 if let Some(replacement) = fn_name_replacement {
@@ -282,7 +283,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
282 fn create_incorrect_case_diagnostic_for_variables( 283 fn create_incorrect_case_diagnostic_for_variables(
283 &mut self, 284 &mut self,
284 func: FunctionId, 285 func: FunctionId,
285 db: &dyn HirDatabase,
286 pats_replacements: Vec<(PatId, Replacement)>, 286 pats_replacements: Vec<(PatId, Replacement)>,
287 ) { 287 ) {
288 // XXX: only look at source_map if we do have missing fields 288 // XXX: only look at source_map if we do have missing fields
@@ -290,12 +290,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
290 return; 290 return;
291 } 291 }
292 292
293 let (_, source_map) = db.body_with_source_map(func.into()); 293 let (_, source_map) = self.db.body_with_source_map(func.into());
294 294
295 for (id, replacement) in pats_replacements { 295 for (id, replacement) in pats_replacements {
296 if let Ok(source_ptr) = source_map.pat_syntax(id) { 296 if let Ok(source_ptr) = source_map.pat_syntax(id) {
297 if let Some(expr) = source_ptr.value.as_ref().left() { 297 if let Some(expr) = source_ptr.value.as_ref().left() {
298 let root = source_ptr.file_syntax(db.upcast()); 298 let root = source_ptr.file_syntax(self.db.upcast());
299 if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { 299 if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) {
300 let parent = match ident_pat.syntax().parent() { 300 let parent = match ident_pat.syntax().parent() {
301 Some(parent) => parent, 301 Some(parent) => parent,
@@ -333,12 +333,11 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
333 } 333 }
334 } 334 }
335 335
336 fn validate_struct(&mut self, db: &dyn HirDatabase, struct_id: StructId) { 336 fn validate_struct(&mut self, struct_id: StructId) {
337 let data = db.struct_data(struct_id); 337 let data = self.db.struct_data(struct_id);
338 338
339 let non_camel_case_allowed = 339 let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES);
340 self.allowed(db, struct_id.into(), allow::NON_CAMEL_CASE_TYPES); 340 let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE);
341 let non_snake_case_allowed = self.allowed(db, struct_id.into(), allow::NON_SNAKE_CASE);
342 341
343 // Check the structure name. 342 // Check the structure name.
344 let struct_name = data.name.to_string(); 343 let struct_name = data.name.to_string();
@@ -379,7 +378,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
379 // If there is at least one element to spawn a warning on, go to the source map and generate a warning. 378 // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
380 self.create_incorrect_case_diagnostic_for_struct( 379 self.create_incorrect_case_diagnostic_for_struct(
381 struct_id, 380 struct_id,
382 db,
383 struct_name_replacement, 381 struct_name_replacement,
384 struct_fields_replacements, 382 struct_fields_replacements,
385 ); 383 );
@@ -390,7 +388,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
390 fn create_incorrect_case_diagnostic_for_struct( 388 fn create_incorrect_case_diagnostic_for_struct(
391 &mut self, 389 &mut self,
392 struct_id: StructId, 390 struct_id: StructId,
393 db: &dyn HirDatabase,
394 struct_name_replacement: Option<Replacement>, 391 struct_name_replacement: Option<Replacement>,
395 struct_fields_replacements: Vec<Replacement>, 392 struct_fields_replacements: Vec<Replacement>,
396 ) { 393 ) {
@@ -399,8 +396,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
399 return; 396 return;
400 } 397 }
401 398
402 let struct_loc = struct_id.lookup(db.upcast()); 399 let struct_loc = struct_id.lookup(self.db.upcast());
403 let struct_src = struct_loc.source(db.upcast()); 400 let struct_src = struct_loc.source(self.db.upcast());
404 401
405 if let Some(replacement) = struct_name_replacement { 402 if let Some(replacement) = struct_name_replacement {
406 let ast_ptr = match struct_src.value.name() { 403 let ast_ptr = match struct_src.value.name() {
@@ -473,11 +470,11 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
473 } 470 }
474 } 471 }
475 472
476 fn validate_enum(&mut self, db: &dyn HirDatabase, enum_id: EnumId) { 473 fn validate_enum(&mut self, enum_id: EnumId) {
477 let data = db.enum_data(enum_id); 474 let data = self.db.enum_data(enum_id);
478 475
479 // Check whether non-camel case names are allowed for this enum. 476 // Check whether non-camel case names are allowed for this enum.
480 if self.allowed(db, enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { 477 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) {
481 return; 478 return;
482 } 479 }
483 480
@@ -512,7 +509,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
512 // If there is at least one element to spawn a warning on, go to the source map and generate a warning. 509 // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
513 self.create_incorrect_case_diagnostic_for_enum( 510 self.create_incorrect_case_diagnostic_for_enum(
514 enum_id, 511 enum_id,
515 db,
516 enum_name_replacement, 512 enum_name_replacement,
517 enum_fields_replacements, 513 enum_fields_replacements,
518 ) 514 )
@@ -523,7 +519,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
523 fn create_incorrect_case_diagnostic_for_enum( 519 fn create_incorrect_case_diagnostic_for_enum(
524 &mut self, 520 &mut self,
525 enum_id: EnumId, 521 enum_id: EnumId,
526 db: &dyn HirDatabase,
527 enum_name_replacement: Option<Replacement>, 522 enum_name_replacement: Option<Replacement>,
528 enum_variants_replacements: Vec<Replacement>, 523 enum_variants_replacements: Vec<Replacement>,
529 ) { 524 ) {
@@ -532,8 +527,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
532 return; 527 return;
533 } 528 }
534 529
535 let enum_loc = enum_id.lookup(db.upcast()); 530 let enum_loc = enum_id.lookup(self.db.upcast());
536 let enum_src = enum_loc.source(db.upcast()); 531 let enum_src = enum_loc.source(self.db.upcast());
537 532
538 if let Some(replacement) = enum_name_replacement { 533 if let Some(replacement) = enum_name_replacement {
539 let ast_ptr = match enum_src.value.name() { 534 let ast_ptr = match enum_src.value.name() {
@@ -608,10 +603,10 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
608 } 603 }
609 } 604 }
610 605
611 fn validate_const(&mut self, db: &dyn HirDatabase, const_id: ConstId) { 606 fn validate_const(&mut self, const_id: ConstId) {
612 let data = db.const_data(const_id); 607 let data = self.db.const_data(const_id);
613 608
614 if self.allowed(db, const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 609 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) {
615 return; 610 return;
616 } 611 }
617 612
@@ -632,8 +627,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
632 return; 627 return;
633 }; 628 };
634 629
635 let const_loc = const_id.lookup(db.upcast()); 630 let const_loc = const_id.lookup(self.db.upcast());
636 let const_src = const_loc.source(db.upcast()); 631 let const_src = const_loc.source(self.db.upcast());
637 632
638 let ast_ptr = match const_src.value.name() { 633 let ast_ptr = match const_src.value.name() {
639 Some(name) => name, 634 Some(name) => name,
@@ -652,14 +647,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
652 self.sink.push(diagnostic); 647 self.sink.push(diagnostic);
653 } 648 }
654 649
655 fn validate_static(&mut self, db: &dyn HirDatabase, static_id: StaticId) { 650 fn validate_static(&mut self, static_id: StaticId) {
656 let data = db.static_data(static_id); 651 let data = self.db.static_data(static_id);
657 if data.is_extern { 652 if data.is_extern {
658 mark::hit!(extern_static_incorrect_case_ignored); 653 mark::hit!(extern_static_incorrect_case_ignored);
659 return; 654 return;
660 } 655 }
661 656
662 if self.allowed(db, static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 657 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) {
663 return; 658 return;
664 } 659 }
665 660
@@ -680,8 +675,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
680 return; 675 return;
681 }; 676 };
682 677
683 let static_loc = static_id.lookup(db.upcast()); 678 let static_loc = static_id.lookup(self.db.upcast());
684 let static_src = static_loc.source(db.upcast()); 679 let static_src = static_loc.source(self.db.upcast());
685 680
686 let ast_ptr = match static_src.value.name() { 681 let ast_ptr = match static_src.value.name() {
687 Some(name) => name, 682 Some(name) => name,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 234f80a3a..522607cb7 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -1,15 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use either::Either; 3use either::Either;
4use hir::{ 4use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource};
5 AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirFileId, InFile, ModuleSource,
6};
7use ide_db::base_db::{FileId, SourceDatabase}; 5use ide_db::base_db::{FileId, SourceDatabase};
8use ide_db::{defs::Definition, RootDatabase}; 6use ide_db::{defs::Definition, RootDatabase};
9use syntax::{ 7use syntax::{
10 ast::{self, NameOwner}, 8 ast::{self, NameOwner},
11 match_ast, AstNode, SmolStr, 9 match_ast, AstNode, SmolStr,
12 SyntaxKind::{self, IDENT_PAT, TYPE_PARAM}, 10 SyntaxKind::{self, IDENT_PAT, LIFETIME_PARAM, TYPE_PARAM},
13 TextRange, 11 TextRange,
14}; 12};
15 13
@@ -119,25 +117,6 @@ impl NavigationTarget {
119 ) 117 )
120 } 118 }
121 119
122 /// Allows `NavigationTarget` to be created from a `DocCommentsOwner` and a `NameOwner`
123 pub(crate) fn from_doc_commented(
124 db: &RootDatabase,
125 named: InFile<&dyn ast::NameOwner>,
126 node: InFile<&dyn ast::DocCommentsOwner>,
127 ) -> NavigationTarget {
128 let name =
129 named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
130 let frange = node.map(|it| it.syntax()).original_file_range(db);
131
132 NavigationTarget::from_syntax(
133 frange.file_id,
134 name,
135 None,
136 frange.range,
137 node.value.syntax().kind(),
138 )
139 }
140
141 fn from_syntax( 120 fn from_syntax(
142 file_id: FileId, 121 file_id: FileId,
143 name: SmolStr, 122 name: SmolStr,
@@ -168,7 +147,7 @@ impl ToNav for FileSymbol {
168 focus_range: self.name_range, 147 focus_range: self.name_range,
169 container_name: self.container_name.clone(), 148 container_name: self.container_name.clone(),
170 description: description_from_symbol(db, self), 149 description: description_from_symbol(db, self),
171 docs: docs_from_symbol(db, self), 150 docs: None,
172 } 151 }
173 } 152 }
174} 153}
@@ -182,6 +161,7 @@ impl TryToNav for Definition {
182 Definition::SelfType(it) => Some(it.to_nav(db)), 161 Definition::SelfType(it) => Some(it.to_nav(db)),
183 Definition::Local(it) => Some(it.to_nav(db)), 162 Definition::Local(it) => Some(it.to_nav(db)),
184 Definition::TypeParam(it) => Some(it.to_nav(db)), 163 Definition::TypeParam(it) => Some(it.to_nav(db)),
164 Definition::LifetimeParam(it) => Some(it.to_nav(db)),
185 } 165 }
186 } 166 }
187} 167}
@@ -244,7 +224,7 @@ impl ToNav for hir::Module {
244 } 224 }
245} 225}
246 226
247impl ToNav for hir::ImplDef { 227impl ToNav for hir::Impl {
248 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 228 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
249 let src = self.source(db); 229 let src = self.source(db);
250 let derive_attr = self.is_builtin_derive(db); 230 let derive_attr = self.is_builtin_derive(db);
@@ -376,28 +356,21 @@ impl ToNav for hir::TypeParam {
376 } 356 }
377} 357}
378 358
379pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<Documentation> { 359impl ToNav for hir::LifetimeParam {
380 let parse = db.parse(symbol.file_id); 360 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
381 let node = symbol.ptr.to_node(parse.tree().syntax()); 361 let src = self.source(db);
382 let file_id = HirFileId::from(symbol.file_id); 362 let full_range = src.value.syntax().text_range();
383 363 NavigationTarget {
384 let it = match_ast! { 364 file_id: src.file_id.original_file(db),
385 match node { 365 name: self.name(db).to_string().into(),
386 ast::Fn(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 366 kind: LIFETIME_PARAM,
387 ast::Struct(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 367 full_range,
388 ast::Enum(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 368 focus_range: Some(full_range),
389 ast::Trait(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 369 container_name: None,
390 ast::Module(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 370 description: None,
391 ast::TypeAlias(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)), 371 docs: None,
392 ast::Const(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
393 ast::Static(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
394 ast::RecordField(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
395 ast::Variant(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
396 ast::MacroCall(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
397 _ => return None,
398 } 372 }
399 }; 373 }
400 it.docs()
401} 374}
402 375
403/// Get a description of a symbol. 376/// Get a description of a symbol.
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 10263537a..79c081cac 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -112,7 +112,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
112 .as_assoc_item(db) 112 .as_assoc_item(db)
113 .and_then(|assoc| match assoc.container(db) { 113 .and_then(|assoc| match assoc.container(db) {
114 AssocItemContainer::Trait(t) => Some(t.into()), 114 AssocItemContainer::Trait(t) => Some(t.into()),
115 AssocItemContainer::ImplDef(impld) => { 115 AssocItemContainer::Impl(impld) => {
116 impld.target_ty(db).as_adt().map(|adt| adt.into()) 116 impld.target_ty(db).as_adt().map(|adt| adt.into())
117 } 117 }
118 }) 118 })
@@ -190,7 +190,10 @@ fn rewrite_intra_doc_link(
190 }, 190 },
191 Definition::Macro(it) => it.resolve_doc_path(db, link, ns), 191 Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
192 Definition::Field(it) => it.resolve_doc_path(db, link, ns), 192 Definition::Field(it) => it.resolve_doc_path(db, link, ns),
193 Definition::SelfType(_) | Definition::Local(_) | Definition::TypeParam(_) => return None, 193 Definition::SelfType(_)
194 | Definition::Local(_)
195 | Definition::TypeParam(_)
196 | Definition::LifetimeParam(_) => return None,
194 }?; 197 }?;
195 let krate = resolved.module(db)?.krate(); 198 let krate = resolved.module(db)?.krate();
196 let canonical_path = resolved.canonical_path(db)?; 199 let canonical_path = resolved.canonical_path(db)?;
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index b9810457f..173509b08 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,3 +1,4 @@
1use either::Either;
1use hir::Semantics; 2use hir::Semantics;
2use ide_db::{ 3use ide_db::{
3 base_db::FileId, 4 base_db::FileId,
@@ -33,7 +34,7 @@ pub(crate) fn goto_definition(
33 let nav_targets = match_ast! { 34 let nav_targets = match_ast! {
34 match parent { 35 match parent {
35 ast::NameRef(name_ref) => { 36 ast::NameRef(name_ref) => {
36 reference_definition(&sema, &name_ref).to_vec() 37 reference_definition(&sema, Either::Right(&name_ref)).to_vec()
37 }, 38 },
38 ast::Name(name) => { 39 ast::Name(name) => {
39 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); 40 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
@@ -53,6 +54,13 @@ pub(crate) fn goto_definition(
53 let self_param = func.param_list()?.self_param()?; 54 let self_param = func.param_list()?.self_param()?;
54 vec![self_to_nav_target(self_param, position.file_id)?] 55 vec![self_to_nav_target(self_param, position.file_id)?]
55 }, 56 },
57 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
58 let def = name_class.referenced_or_defined(sema.db);
59 let nav = def.try_to_nav(sema.db)?;
60 vec![nav]
61 } else {
62 reference_definition(&sema, Either::Left(&lt)).to_vec()
63 },
56 _ => return None, 64 _ => return None,
57 } 65 }
58 }; 66 };
@@ -64,7 +72,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
64 return tokens.max_by_key(priority); 72 return tokens.max_by_key(priority);
65 fn priority(n: &SyntaxToken) -> usize { 73 fn priority(n: &SyntaxToken) -> usize {
66 match n.kind() { 74 match n.kind() {
67 IDENT | INT_NUMBER | T![self] => 2, 75 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2,
68 kind if kind.is_trivia() => 0, 76 kind if kind.is_trivia() => 0,
69 _ => 1, 77 _ => 1,
70 } 78 }
@@ -102,9 +110,12 @@ impl ReferenceResult {
102 110
103pub(crate) fn reference_definition( 111pub(crate) fn reference_definition(
104 sema: &Semantics<RootDatabase>, 112 sema: &Semantics<RootDatabase>,
105 name_ref: &ast::NameRef, 113 name_ref: Either<&ast::Lifetime, &ast::NameRef>,
106) -> ReferenceResult { 114) -> ReferenceResult {
107 let name_kind = NameRefClass::classify(sema, name_ref); 115 let name_kind = name_ref.either(
116 |lifetime| NameRefClass::classify_lifetime(sema, lifetime),
117 |name_ref| NameRefClass::classify(sema, name_ref),
118 );
108 if let Some(def) = name_kind { 119 if let Some(def) = name_kind {
109 let def = def.referenced(sema.db); 120 let def = def.referenced(sema.db);
110 return match def.try_to_nav(sema.db) { 121 return match def.try_to_nav(sema.db) {
@@ -114,10 +125,9 @@ pub(crate) fn reference_definition(
114 } 125 }
115 126
116 // Fallback index based approach: 127 // Fallback index based approach:
117 let navs = symbol_index::index_resolve(sema.db, name_ref) 128 let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text);
118 .into_iter() 129 let navs =
119 .map(|s| s.to_nav(sema.db)) 130 symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect();
120 .collect();
121 ReferenceResult::Approximate(navs) 131 ReferenceResult::Approximate(navs)
122} 132}
123 133
@@ -1036,4 +1046,35 @@ impl Foo {
1036}"#, 1046}"#,
1037 ) 1047 )
1038 } 1048 }
1049
1050 #[test]
1051 fn goto_lifetime_param_on_decl() {
1052 check(
1053 r#"
1054fn foo<'foobar<|>>(_: &'foobar ()) {
1055 //^^^^^^^
1056}"#,
1057 )
1058 }
1059
1060 #[test]
1061 fn goto_lifetime_param_decl() {
1062 check(
1063 r#"
1064fn foo<'foobar>(_: &'foobar<|> ()) {
1065 //^^^^^^^
1066}"#,
1067 )
1068 }
1069
1070 #[test]
1071 fn goto_lifetime_param_decl_nested() {
1072 check(
1073 r#"
1074fn foo<'foobar>(_: &'foobar ()) {
1075 fn foo<'foobar>(_: &'foobar<|> ()) {}
1076 //^^^^^^^
1077}"#,
1078 )
1079 }
1039} 1080}
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 68c628d31..6eac39639 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -1,4 +1,4 @@
1use hir::{Crate, ImplDef, Semantics}; 1use 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
@@ -49,7 +49,7 @@ fn impls_for_def(
49 ast::AdtDef::Union(def) => sema.to_def(def)?.ty(sema.db), 49 ast::AdtDef::Union(def) => sema.to_def(def)?.ty(sema.db),
50 }; 50 };
51 51
52 let impls = ImplDef::all_in_crate(sema.db, krate); 52 let impls = Impl::all_in_crate(sema.db, krate);
53 53
54 Some( 54 Some(
55 impls 55 impls
@@ -67,7 +67,7 @@ fn impls_for_trait(
67) -> Option<Vec<NavigationTarget>> { 67) -> Option<Vec<NavigationTarget>> {
68 let tr = sema.to_def(node)?; 68 let tr = sema.to_def(node)?;
69 69
70 let impls = ImplDef::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().map(|imp| imp.to_nav(sema.db)).collect())
73} 73}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index ab017d2ad..e82aad6d5 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -295,7 +295,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
295 Definition::ModuleDef(md) => match md { 295 Definition::ModuleDef(md) => match md {
296 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { 296 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
297 AssocItemContainer::Trait(t) => Some(t.name(db)), 297 AssocItemContainer::Trait(t) => Some(t.name(db)),
298 AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), 298 AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
299 }, 299 },
300 ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)), 300 ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)),
301 _ => None, 301 _ => None,
@@ -364,7 +364,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
364 Adt::Enum(it) => from_def_source(db, it, mod_path), 364 Adt::Enum(it) => from_def_source(db, it, mod_path),
365 }) 365 })
366 } 366 }
367 Definition::TypeParam(_) => { 367 Definition::TypeParam(_) | Definition::LifetimeParam(_) => {
368 // FIXME: Hover for generic param 368 // FIXME: Hover for generic param
369 None 369 None
370 } 370 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 71068cac2..c5c652cda 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -528,6 +528,13 @@ impl Analysis {
528 self.with_db(|db| references::rename::rename(db, position, new_name)) 528 self.with_db(|db| references::rename::rename(db, position, new_name))
529 } 529 }
530 530
531 pub fn prepare_rename(
532 &self,
533 position: FilePosition,
534 ) -> Cancelable<Result<RangeInfo<()>, RenameError>> {
535 self.with_db(|db| references::rename::prepare_rename(db, position))
536 }
537
531 pub fn structural_search_replace( 538 pub fn structural_search_replace(
532 &self, 539 &self,
533 query: &str, 540 query: &str,
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 675957fff..98190a86b 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -130,6 +130,8 @@ pub(crate) fn find_all_refs(
130 kind = ReferenceKind::FieldShorthandForLocal; 130 kind = ReferenceKind::FieldShorthandForLocal;
131 } 131 }
132 } 132 }
133 } else if let Definition::LifetimeParam(_) = def {
134 kind = ReferenceKind::Lifetime;
133 }; 135 };
134 136
135 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 137 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
@@ -148,11 +150,29 @@ fn find_name(
148 let range = name.syntax().text_range(); 150 let range = name.syntax().text_range();
149 return Some(RangeInfo::new(range, def)); 151 return Some(RangeInfo::new(range, def));
150 } 152 }
151 let name_ref = 153
152 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; 154 let (text_range, def) = if let Some(lifetime) =
153 let def = NameRefClass::classify(sema, &name_ref)?.referenced(sema.db); 155 sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset)
154 let range = name_ref.syntax().text_range(); 156 {
155 Some(RangeInfo::new(range, def)) 157 if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime)
158 .map(|class| NameRefClass::referenced(class, sema.db))
159 {
160 (lifetime.syntax().text_range(), def)
161 } else {
162 (
163 lifetime.syntax().text_range(),
164 NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db),
165 )
166 }
167 } else {
168 let name_ref =
169 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
170 (
171 name_ref.syntax().text_range(),
172 NameRefClass::classify(sema, &name_ref)?.referenced(sema.db),
173 )
174 };
175 Some(RangeInfo::new(text_range, def))
156} 176}
157 177
158fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { 178fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> {
@@ -1005,4 +1025,65 @@ impl Foo {
1005 } 1025 }
1006 expect.assert_eq(&actual) 1026 expect.assert_eq(&actual)
1007 } 1027 }
1028
1029 #[test]
1030 fn test_find_lifetimes_function() {
1031 check(
1032 r#"
1033trait Foo<'a> {}
1034impl<'a> Foo<'a> for &'a () {}
1035fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> {
1036 fn bar<'a>(_: &'a ()) {}
1037 x
1038}
1039"#,
1040 expect![[r#"
1041 'a LIFETIME_PARAM FileId(0) 55..57 55..57 Lifetime
1042
1043 FileId(0) 63..65 Lifetime
1044 FileId(0) 71..73 Lifetime
1045 FileId(0) 82..84 Lifetime
1046 FileId(0) 95..97 Lifetime
1047 FileId(0) 106..108 Lifetime
1048 "#]],
1049 );
1050 }
1051
1052 #[test]
1053 fn test_find_lifetimes_type_alias() {
1054 check(
1055 r#"
1056type Foo<'a, T> where T: 'a<|> = &'a T;
1057"#,
1058 expect![[r#"
1059 'a LIFETIME_PARAM FileId(0) 9..11 9..11 Lifetime
1060
1061 FileId(0) 25..27 Lifetime
1062 FileId(0) 31..33 Lifetime
1063 "#]],
1064 );
1065 }
1066
1067 #[test]
1068 fn test_find_lifetimes_trait_impl() {
1069 check(
1070 r#"
1071trait Foo<'a> {
1072 fn foo() -> &'a ();
1073}
1074impl<'a> Foo<'a> for &'a () {
1075 fn foo() -> &'a<|> () {
1076 unimplemented!()
1077 }
1078}
1079"#,
1080 expect![[r#"
1081 'a LIFETIME_PARAM FileId(0) 47..49 47..49 Lifetime
1082
1083 FileId(0) 55..57 Lifetime
1084 FileId(0) 64..66 Lifetime
1085 FileId(0) 89..91 Lifetime
1086 "#]],
1087 );
1088 }
1008} 1089}
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 44081f210..56e923841 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -35,6 +35,29 @@ impl fmt::Display for RenameError {
35 35
36impl Error for RenameError {} 36impl Error for RenameError {}
37 37
38pub(crate) fn prepare_rename(
39 db: &RootDatabase,
40 position: FilePosition,
41) -> Result<RangeInfo<()>, RenameError> {
42 let sema = Semantics::new(db);
43 let source_file = sema.parse(position.file_id);
44 let syntax = source_file.syntax();
45 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
46 rename_mod(&sema, position, module, "dummy")
47 } else if let Some(self_token) =
48 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
49 {
50 rename_self_to_param(&sema, position, self_token, "dummy")
51 } else {
52 let range = match find_all_refs(&sema, position, None) {
53 Some(RangeInfo { range, .. }) => range,
54 None => return Err(RenameError("No references found at position".to_string())),
55 };
56 Ok(RangeInfo::new(range, SourceChange::from(vec![])))
57 }
58 .map(|info| RangeInfo::new(info.range, ()))
59}
60
38pub(crate) fn rename( 61pub(crate) fn rename(
39 db: &RootDatabase, 62 db: &RootDatabase,
40 position: FilePosition, 63 position: FilePosition,
@@ -49,11 +72,18 @@ pub(crate) fn rename_with_semantics(
49 position: FilePosition, 72 position: FilePosition,
50 new_name: &str, 73 new_name: &str,
51) -> Result<RangeInfo<SourceChange>, RenameError> { 74) -> Result<RangeInfo<SourceChange>, RenameError> {
52 match lex_single_syntax_kind(new_name) { 75 let is_lifetime_name = match lex_single_syntax_kind(new_name) {
53 Some(res) => match res { 76 Some(res) => match res {
54 (SyntaxKind::IDENT, _) => (), 77 (SyntaxKind::IDENT, _) => false,
55 (SyntaxKind::UNDERSCORE, _) => (), 78 (SyntaxKind::UNDERSCORE, _) => false,
56 (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position), 79 (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position),
80 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true,
81 (SyntaxKind::LIFETIME_IDENT, _) => {
82 return Err(RenameError(format!(
83 "Invalid name `{0}`: Cannot rename lifetime to {0}",
84 new_name
85 )))
86 }
57 (_, Some(syntax_error)) => { 87 (_, Some(syntax_error)) => {
58 return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error))) 88 return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error)))
59 } 89 }
@@ -62,18 +92,21 @@ pub(crate) fn rename_with_semantics(
62 } 92 }
63 }, 93 },
64 None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))), 94 None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))),
65 } 95 };
66 96
67 let source_file = sema.parse(position.file_id); 97 let source_file = sema.parse(position.file_id);
68 let syntax = source_file.syntax(); 98 let syntax = source_file.syntax();
69 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 99 // this is here to prevent lifetime renames from happening on modules and self
100 if is_lifetime_name {
101 rename_reference(&sema, position, new_name, is_lifetime_name)
102 } else if let Some(module) = find_module_at_offset(&sema, position, syntax) {
70 rename_mod(&sema, position, module, new_name) 103 rename_mod(&sema, position, module, new_name)
71 } else if let Some(self_token) = 104 } else if let Some(self_token) =
72 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 105 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
73 { 106 {
74 rename_self_to_param(&sema, position, self_token, new_name) 107 rename_self_to_param(&sema, position, self_token, new_name)
75 } else { 108 } else {
76 rename_reference(&sema, position, new_name) 109 rename_reference(&sema, position, new_name, is_lifetime_name)
77 } 110 }
78} 111}
79 112
@@ -355,12 +388,26 @@ fn rename_reference(
355 sema: &Semantics<RootDatabase>, 388 sema: &Semantics<RootDatabase>,
356 position: FilePosition, 389 position: FilePosition,
357 new_name: &str, 390 new_name: &str,
391 is_lifetime_name: bool,
358) -> Result<RangeInfo<SourceChange>, RenameError> { 392) -> Result<RangeInfo<SourceChange>, RenameError> {
359 let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { 393 let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) {
360 Some(range_info) => range_info, 394 Some(range_info) => range_info,
361 None => return Err(RenameError("No references found at position".to_string())), 395 None => return Err(RenameError("No references found at position".to_string())),
362 }; 396 };
363 397
398 match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) {
399 (true, false) => {
400 return Err(RenameError(format!(
401 "Invalid name `{}`: not a lifetime identifier",
402 new_name
403 )))
404 }
405 (false, true) => {
406 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name)))
407 }
408 _ => (),
409 }
410
364 let edit = refs 411 let edit = refs
365 .into_iter() 412 .into_iter()
366 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 413 .map(|reference| source_edit_from_reference(sema, reference, new_name))
@@ -465,6 +512,24 @@ mod tests {
465 } 512 }
466 513
467 #[test] 514 #[test]
515 fn test_rename_to_invalid_identifier_lifetime() {
516 check(
517 "'foo",
518 r#"fn main() { let i<|> = 1; }"#,
519 "error: Invalid name `'foo`: not an identifier",
520 );
521 }
522
523 #[test]
524 fn test_rename_to_invalid_identifier_lifetime2() {
525 check(
526 "foo",
527 r#"fn main<'a>(_: &'a<|> ()) {}"#,
528 "error: Invalid name `foo`: not a lifetime identifier",
529 );
530 }
531
532 #[test]
468 fn test_rename_for_local() { 533 fn test_rename_for_local() {
469 check( 534 check(
470 "k", 535 "k",
@@ -1396,4 +1461,31 @@ fn foo(Foo { i: bar }: foo) -> i32 {
1396"#, 1461"#,
1397 ) 1462 )
1398 } 1463 }
1464
1465 #[test]
1466 fn test_rename_lifetimes() {
1467 check(
1468 "'yeeee",
1469 r#"
1470trait Foo<'a> {
1471 fn foo() -> &'a ();
1472}
1473impl<'a> Foo<'a> for &'a () {
1474 fn foo() -> &'a<|> () {
1475 unimplemented!()
1476 }
1477}
1478"#,
1479 r#"
1480trait Foo<'a> {
1481 fn foo() -> &'a ();
1482}
1483impl<'yeeee> Foo<'yeeee> for &'yeeee () {
1484 fn foo() -> &'yeeee () {
1485 unimplemented!()
1486 }
1487}
1488"#,
1489 )
1490 }
1399} 1491}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 646f63704..2f465c195 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -2,7 +2,7 @@ use std::fmt;
2 2
3use assists::utils::test_related_attribute; 3use assists::utils::test_related_attribute;
4use cfg::CfgExpr; 4use cfg::CfgExpr;
5use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; 5use hir::{AsAssocItem, HasAttrs, InFile, Semantics};
6use ide_db::RootDatabase; 6use ide_db::RootDatabase;
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ 8use syntax::{
@@ -10,7 +10,10 @@ use syntax::{
10 match_ast, SyntaxNode, 10 match_ast, SyntaxNode,
11}; 11};
12 12
13use crate::{display::ToNav, FileId, NavigationTarget}; 13use crate::{
14 display::{ToNav, TryToNav},
15 FileId, NavigationTarget,
16};
14 17
15#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
16pub struct Runnable { 19pub struct Runnable {
@@ -101,124 +104,109 @@ pub(crate) fn runnable(
101 item: SyntaxNode, 104 item: SyntaxNode,
102 file_id: FileId, 105 file_id: FileId,
103) -> Option<Runnable> { 106) -> Option<Runnable> {
104 match_ast! { 107 let runnable_item = match_ast! {
105 match item { 108 match (item.clone()) {
106 ast::Struct(it) => runnable_struct(sema, it, file_id),
107 ast::Fn(it) => runnable_fn(sema, it, file_id), 109 ast::Fn(it) => runnable_fn(sema, it, file_id),
108 ast::Module(it) => runnable_mod(sema, it, file_id), 110 ast::Module(it) => runnable_mod(sema, it),
109 _ => None, 111 _ => None,
110 } 112 }
111 } 113 };
114 runnable_item.or_else(|| runnable_doctest(sema, item))
112} 115}
113 116
114fn runnable_fn( 117fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) -> Option<Runnable> {
115 sema: &Semantics<RootDatabase>, 118 let def = sema.to_def(&func)?;
116 fn_def: ast::Fn, 119 let name_string = func.name()?.text().to_string();
117 file_id: FileId,
118) -> Option<Runnable> {
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));
122 let kind = if name_string == "main" { 121 let kind = if name_string == "main" {
123 RunnableKind::Bin 122 RunnableKind::Bin
124 } else { 123 } else {
125 let test_id = match sema.to_def(&fn_def).map(|def| def.module(sema.db)) { 124 let canonical_path = sema.to_def(&func).and_then(|def| {
126 Some(module) => { 125 let def: hir::ModuleDef = def.into();
127 let def = sema.to_def(&fn_def)?; 126 def.canonical_path(sema.db)
128 let impl_trait_name = def.as_assoc_item(sema.db).and_then(|assoc_item| { 127 });
129 match assoc_item.container(sema.db) { 128 let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string));
130 hir::AssocItemContainer::Trait(trait_item) => { 129
131 Some(trait_item.name(sema.db).to_string()) 130 if test_related_attribute(&func).is_some() {
132 } 131 let attr = TestAttr::from_fn(&func);
133 hir::AssocItemContainer::ImplDef(impl_def) => impl_def
134 .target_ty(sema.db)
135 .as_adt()
136 .map(|adt| adt.name(sema.db).to_string()),
137 }
138 });
139
140 let path_iter = module
141 .path_to_root(sema.db)
142 .into_iter()
143 .rev()
144 .filter_map(|it| it.name(sema.db))
145 .map(|name| name.to_string());
146
147 let path = if let Some(impl_trait_name) = impl_trait_name {
148 path_iter
149 .chain(std::iter::once(impl_trait_name))
150 .chain(std::iter::once(name_string))
151 .join("::")
152 } else {
153 path_iter.chain(std::iter::once(name_string)).join("::")
154 };
155
156 TestId::Path(path)
157 }
158 None => TestId::Name(name_string),
159 };
160
161 if test_related_attribute(&fn_def).is_some() {
162 let attr = TestAttr::from_fn(&fn_def);
163 RunnableKind::Test { test_id, attr } 132 RunnableKind::Test { test_id, attr }
164 } else if fn_def.has_atom_attr("bench") { 133 } else if func.has_atom_attr("bench") {
165 RunnableKind::Bench { test_id } 134 RunnableKind::Bench { test_id }
166 } else if has_runnable_doc_test(&attrs) {
167 RunnableKind::DocTest { test_id }
168 } else { 135 } else {
169 return None; 136 return None;
170 } 137 }
171 }; 138 };
172 139
173 let cfg = attrs.cfg(); 140 let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &func));
174 141 let cfg = def.attrs(sema.db).cfg();
175 let nav = if let RunnableKind::DocTest { .. } = kind {
176 NavigationTarget::from_doc_commented(
177 sema.db,
178 InFile::new(file_id.into(), &fn_def),
179 InFile::new(file_id.into(), &fn_def),
180 )
181 } else {
182 NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def))
183 };
184 Some(Runnable { nav, kind, cfg }) 142 Some(Runnable { nav, kind, cfg })
185} 143}
186 144
187fn runnable_struct( 145fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> {
188 sema: &Semantics<RootDatabase>, 146 match_ast! {
189 struct_def: ast::Struct, 147 match item {
190 file_id: FileId, 148 ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
191) -> Option<Runnable> { 149 ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
192 let name_string = struct_def.name()?.text().to_string(); 150 ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
151 ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
152 ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
153 ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
154 ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
155 ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()),
156 _ => None,
157 }
158 }
159}
193 160
194 let attrs = 161fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> {
195 Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def)); 162 let attrs = match def {
163 hir::ModuleDef::Module(it) => it.attrs(sema.db),
164 hir::ModuleDef::Function(it) => it.attrs(sema.db),
165 hir::ModuleDef::Adt(it) => it.attrs(sema.db),
166 hir::ModuleDef::EnumVariant(it) => it.attrs(sema.db),
167 hir::ModuleDef::Const(it) => it.attrs(sema.db),
168 hir::ModuleDef::Static(it) => it.attrs(sema.db),
169 hir::ModuleDef::Trait(it) => it.attrs(sema.db),
170 hir::ModuleDef::TypeAlias(it) => it.attrs(sema.db),
171 hir::ModuleDef::BuiltinType(_) => return None,
172 };
196 if !has_runnable_doc_test(&attrs) { 173 if !has_runnable_doc_test(&attrs) {
197 return None; 174 return None;
198 } 175 }
199 let cfg = attrs.cfg(); 176 let def_name = def.name(sema.db).map(|it| it.to_string());
200 177 let test_id = def
201 let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) { 178 .canonical_path(sema.db)
202 Some(module) => { 179 // This probably belongs to canonical path?
203 let path_iter = module 180 .map(|path| {
204 .path_to_root(sema.db) 181 let assoc_def = match def {
205 .into_iter() 182 hir::ModuleDef::Function(it) => it.as_assoc_item(sema.db),
206 .rev() 183 hir::ModuleDef::Const(it) => it.as_assoc_item(sema.db),
207 .filter_map(|it| it.name(sema.db)) 184 hir::ModuleDef::TypeAlias(it) => it.as_assoc_item(sema.db),
208 .map(|name| name.to_string()); 185 _ => None,
209 let path = path_iter.chain(std::iter::once(name_string)).join("::"); 186 };
210 187 // FIXME: this also looks very wrong
211 TestId::Path(path) 188 if let Some(assoc_def) = assoc_def {
212 } 189 if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) {
213 None => TestId::Name(name_string), 190 if let Some(adt) = imp.target_ty(sema.db).as_adt() {
214 }; 191 let name = adt.name(sema.db).to_string();
215 192 let idx = path.rfind(':').unwrap_or(0);
216 let nav = NavigationTarget::from_doc_commented( 193 let (prefix, suffix) = path.split_at(idx);
217 sema.db, 194 return format!("{}{}::{}", prefix, name, suffix);
218 InFile::new(file_id.into(), &struct_def), 195 }
219 InFile::new(file_id.into(), &struct_def), 196 }
220 ); 197 }
221 Some(Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg }) 198 path
199 })
200 .map(TestId::Path)
201 .or_else(|| def_name.clone().map(TestId::Name))?;
202
203 let mut nav = def.try_to_nav(sema.db)?;
204 nav.focus_range = None;
205 nav.description = None;
206 nav.docs = None;
207 nav.kind = syntax::SyntaxKind::COMMENT;
208 let res = Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg: attrs.cfg() };
209 Some(res)
222} 210}
223 211
224#[derive(Debug, Copy, Clone)] 212#[derive(Debug, Copy, Clone)]
@@ -262,11 +250,7 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
262 }) 250 })
263} 251}
264 252
265fn runnable_mod( 253fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
266 sema: &Semantics<RootDatabase>,
267 module: ast::Module,
268 file_id: FileId,
269) -> Option<Runnable> {
270 if !has_test_function_or_multiple_test_submodules(&module) { 254 if !has_test_function_or_multiple_test_submodules(&module) {
271 return None; 255 return None;
272 } 256 }
@@ -279,7 +263,8 @@ fn runnable_mod(
279 .filter_map(|it| it.name(sema.db)) 263 .filter_map(|it| it.name(sema.db))
280 .join("::"); 264 .join("::");
281 265
282 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); 266 let def = sema.to_def(&module)?;
267 let attrs = def.attrs(sema.db);
283 let cfg = attrs.cfg(); 268 let cfg = attrs.cfg();
284 let nav = module_def.to_nav(sema.db); 269 let nav = module_def.to_nav(sema.db);
285 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) 270 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
@@ -319,7 +304,7 @@ mod tests {
319 304
320 use crate::fixture; 305 use crate::fixture;
321 306
322 use super::{RunnableAction, BENCH, BIN, DOCTEST, TEST}; 307 use super::*;
323 308
324 fn check( 309 fn check(
325 ra_fixture: &str, 310 ra_fixture: &str,
@@ -548,7 +533,7 @@ struct StructWithRunnable(String);
548 full_range: 15..74, 533 full_range: 15..74,
549 focus_range: None, 534 focus_range: None,
550 name: "should_have_runnable", 535 name: "should_have_runnable",
551 kind: FN, 536 kind: COMMENT,
552 container_name: None, 537 container_name: None,
553 description: None, 538 description: None,
554 docs: None, 539 docs: None,
@@ -568,7 +553,7 @@ struct StructWithRunnable(String);
568 full_range: 76..148, 553 full_range: 76..148,
569 focus_range: None, 554 focus_range: None,
570 name: "should_have_runnable_1", 555 name: "should_have_runnable_1",
571 kind: FN, 556 kind: COMMENT,
572 container_name: None, 557 container_name: None,
573 description: None, 558 description: None,
574 docs: None, 559 docs: None,
@@ -588,7 +573,7 @@ struct StructWithRunnable(String);
588 full_range: 150..254, 573 full_range: 150..254,
589 focus_range: None, 574 focus_range: None,
590 name: "should_have_runnable_2", 575 name: "should_have_runnable_2",
591 kind: FN, 576 kind: COMMENT,
592 container_name: None, 577 container_name: None,
593 description: None, 578 description: None,
594 docs: None, 579 docs: None,
@@ -608,7 +593,7 @@ struct StructWithRunnable(String);
608 full_range: 756..821, 593 full_range: 756..821,
609 focus_range: None, 594 focus_range: None,
610 name: "StructWithRunnable", 595 name: "StructWithRunnable",
611 kind: STRUCT, 596 kind: COMMENT,
612 container_name: None, 597 container_name: None,
613 description: None, 598 description: None,
614 docs: None, 599 docs: None,
@@ -670,7 +655,7 @@ impl Data {
670 full_range: 44..98, 655 full_range: 44..98,
671 focus_range: None, 656 focus_range: None,
672 name: "foo", 657 name: "foo",
673 kind: FN, 658 kind: COMMENT,
674 container_name: None, 659 container_name: None,
675 description: None, 660 description: None,
676 docs: None, 661 docs: None,
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 990b0f7d9..488969f1a 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -806,6 +806,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
806 } 806 }
807 return h; 807 return h;
808 } 808 }
809 Definition::LifetimeParam(_) => HighlightTag::Lifetime,
809 } 810 }
810 .into() 811 .into()
811} 812}
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d4a774261..bd2afc887 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -6,12 +6,12 @@
6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). 6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7 7
8use hir::{ 8use hir::{
9 db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, 9 db::HirDatabase, Crate, Field, HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module,
10 Name, PathResolution, Semantics, TypeParam, Visibility, 10 ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
11}; 11};
12use syntax::{ 12use syntax::{
13 ast::{self, AstNode}, 13 ast::{self, AstNode},
14 match_ast, SyntaxNode, 14 match_ast, SyntaxKind, SyntaxNode,
15}; 15};
16 16
17use crate::RootDatabase; 17use crate::RootDatabase;
@@ -22,9 +22,11 @@ pub enum Definition {
22 Macro(MacroDef), 22 Macro(MacroDef),
23 Field(Field), 23 Field(Field),
24 ModuleDef(ModuleDef), 24 ModuleDef(ModuleDef),
25 SelfType(ImplDef), 25 SelfType(Impl),
26 Local(Local), 26 Local(Local),
27 TypeParam(TypeParam), 27 TypeParam(TypeParam),
28 LifetimeParam(LifetimeParam),
29 // FIXME: Label
28} 30}
29 31
30impl Definition { 32impl Definition {
@@ -36,6 +38,7 @@ impl Definition {
36 Definition::SelfType(it) => Some(it.module(db)), 38 Definition::SelfType(it) => Some(it.module(db)),
37 Definition::Local(it) => Some(it.module(db)), 39 Definition::Local(it) => Some(it.module(db)),
38 Definition::TypeParam(it) => Some(it.module(db)), 40 Definition::TypeParam(it) => Some(it.module(db)),
41 Definition::LifetimeParam(it) => Some(it.module(db)),
39 } 42 }
40 } 43 }
41 44
@@ -47,6 +50,7 @@ impl Definition {
47 Definition::SelfType(_) => None, 50 Definition::SelfType(_) => None,
48 Definition::Local(_) => None, 51 Definition::Local(_) => None,
49 Definition::TypeParam(_) => None, 52 Definition::TypeParam(_) => None,
53 Definition::LifetimeParam(_) => None,
50 } 54 }
51 } 55 }
52 56
@@ -72,6 +76,7 @@ impl Definition {
72 Definition::SelfType(_) => return None, 76 Definition::SelfType(_) => return None,
73 Definition::Local(it) => it.name(db)?, 77 Definition::Local(it) => it.name(db)?,
74 Definition::TypeParam(it) => it.name(db), 78 Definition::TypeParam(it) => it.name(db),
79 Definition::LifetimeParam(it) => it.name(db),
75 }; 80 };
76 Some(name) 81 Some(name)
77 } 82 }
@@ -229,6 +234,25 @@ impl NameClass {
229 } 234 }
230 } 235 }
231 } 236 }
237
238 pub fn classify_lifetime(
239 sema: &Semantics<RootDatabase>,
240 lifetime: &ast::Lifetime,
241 ) -> Option<NameClass> {
242 let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
243 let parent = lifetime.syntax().parent()?;
244
245 match_ast! {
246 match parent {
247 ast::LifetimeParam(it) => {
248 let def = sema.to_def(&it)?;
249 Some(NameClass::Definition(Definition::LifetimeParam(def)))
250 },
251 ast::Label(_it) => None,
252 _ => None,
253 }
254 }
255 }
232} 256}
233 257
234#[derive(Debug)] 258#[derive(Debug)]
@@ -338,6 +362,35 @@ impl NameRefClass {
338 let resolved = sema.resolve_extern_crate(&extern_crate)?; 362 let resolved = sema.resolve_extern_crate(&extern_crate)?;
339 Some(NameRefClass::ExternCrate(resolved)) 363 Some(NameRefClass::ExternCrate(resolved))
340 } 364 }
365
366 pub fn classify_lifetime(
367 sema: &Semantics<RootDatabase>,
368 lifetime: &ast::Lifetime,
369 ) -> Option<NameRefClass> {
370 let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
371 let parent = lifetime.syntax().parent()?;
372 match parent.kind() {
373 SyntaxKind::LIFETIME_ARG
374 | SyntaxKind::SELF_PARAM
375 | SyntaxKind::TYPE_BOUND
376 | SyntaxKind::WHERE_PRED
377 | SyntaxKind::REF_TYPE => sema
378 .resolve_lifetime_param(lifetime)
379 .map(Definition::LifetimeParam)
380 .map(NameRefClass::Definition),
381 // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
382 // if our lifetime is in a LifetimeParam without being the constrained lifetime
383 _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
384 != Some(lifetime) =>
385 {
386 sema.resolve_lifetime_param(lifetime)
387 .map(Definition::LifetimeParam)
388 .map(NameRefClass::Definition)
389 }
390 SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => None,
391 _ => None,
392 }
393 }
341} 394}
342 395
343impl From<PathResolution> for Definition { 396impl From<PathResolution> for Definition {
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 3936c7390..525c8a41f 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -33,6 +33,7 @@ pub enum ReferenceKind {
33 RecordFieldExprOrPat, 33 RecordFieldExprOrPat,
34 SelfKw, 34 SelfKw,
35 EnumLiteral, 35 EnumLiteral,
36 Lifetime,
36 Other, 37 Other,
37} 38}
38 39
@@ -129,6 +130,25 @@ impl Definition {
129 return SearchScope::new(res); 130 return SearchScope::new(res);
130 } 131 }
131 132
133 if let Definition::LifetimeParam(param) = self {
134 let range = match param.parent(db) {
135 hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(),
136 hir::GenericDef::Adt(it) => match it {
137 hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(),
138 hir::Adt::Union(it) => it.source(db).value.syntax().text_range(),
139 hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(),
140 },
141 hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(),
142 hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(),
143 hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(),
144 hir::GenericDef::EnumVariant(it) => it.source(db).value.syntax().text_range(),
145 hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(),
146 };
147 let mut res = FxHashMap::default();
148 res.insert(file_id, Some(range));
149 return SearchScope::new(res);
150 }
151
132 let vis = self.visibility(db); 152 let vis = self.visibility(db);
133 153
134 if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { 154 if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) {
@@ -255,25 +275,42 @@ impl<'a> FindUsages<'a> {
255 continue; 275 continue;
256 } 276 }
257 277
258 match sema.find_node_at_offset_with_descend(&tree, offset) { 278 if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) {
259 Some(name_ref) => { 279 if self.found_name_ref(&name_ref, sink) {
260 if self.found_name_ref(&name_ref, sink) { 280 return;
261 return; 281 }
262 } 282 } else if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) {
283 if self.found_name(&name, sink) {
284 return;
285 }
286 } else if let Some(lifetime) = sema.find_node_at_offset_with_descend(&tree, offset)
287 {
288 if self.found_lifetime(&lifetime, sink) {
289 return;
263 } 290 }
264 None => match sema.find_node_at_offset_with_descend(&tree, offset) {
265 Some(name) => {
266 if self.found_name(&name, sink) {
267 return;
268 }
269 }
270 None => {}
271 },
272 } 291 }
273 } 292 }
274 } 293 }
275 } 294 }
276 295
296 fn found_lifetime(
297 &self,
298 lifetime: &ast::Lifetime,
299 sink: &mut dyn FnMut(Reference) -> bool,
300 ) -> bool {
301 match NameRefClass::classify_lifetime(self.sema, lifetime) {
302 Some(NameRefClass::Definition(def)) if &def == self.def => {
303 let reference = Reference {
304 file_range: self.sema.original_range(lifetime.syntax()),
305 kind: ReferenceKind::Lifetime,
306 access: None,
307 };
308 sink(reference)
309 }
310 _ => false, // not a usage
311 }
312 }
313
277 fn found_name_ref( 314 fn found_name_ref(
278 &self, 315 &self,
279 name_ref: &ast::NameRef, 316 name_ref: &ast::NameRef,
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 121063aea..ca455fa03 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -209,8 +209,7 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil
209 query.search(&buf) 209 query.search(&buf)
210} 210}
211 211
212pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { 212pub fn index_resolve(db: &RootDatabase, name: &SmolStr) -> Vec<FileSymbol> {
213 let name = name_ref.text();
214 let mut query = Query::new(name.to_string()); 213 let mut query = Query::new(name.to_string());
215 query.exact(); 214 query.exact();
216 query.limit(4); 215 query.limit(4);
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 039976e4b..0b4d3f4eb 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -21,7 +21,7 @@ env_logger = { version = "0.8.1", default-features = false }
21itertools = "0.9.0" 21itertools = "0.9.0"
22jod-thread = "0.1.0" 22jod-thread = "0.1.0"
23log = "0.4.8" 23log = "0.4.8"
24lsp-types = { version = "0.85.0", features = ["proposed"] } 24lsp-types = { version = "0.86.0", features = ["proposed"] }
25parking_lot = "0.11.0" 25parking_lot = "0.11.0"
26pico-args = "0.3.1" 26pico-args = "0.3.1"
27oorandom = "11.1.2" 27oorandom = "11.1.2"
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 5e4c22bc5..de5eb93b5 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -64,7 +64,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
64 prepare_provider: Some(true), 64 prepare_provider: Some(true),
65 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, 65 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
66 })), 66 })),
67 on_type_rename_provider: None, 67 linked_editing_range_provider: None,
68 document_link_provider: None, 68 document_link_provider: None,
69 color_provider: None, 69 color_provider: None,
70 execute_command_provider: None, 70 execute_command_provider: None,
@@ -83,6 +83,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
83 } 83 }
84 .into(), 84 .into(),
85 ), 85 ),
86 moniker_provider: None,
86 experimental: Some(json!({ 87 experimental: Some(json!({
87 "joinLines": true, 88 "joinLines": true,
88 "ssr": true, 89 "ssr": true,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 94e2bfa1b..af226c109 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -733,7 +733,7 @@ pub(crate) fn handle_prepare_rename(
733 let _p = profile::span("handle_prepare_rename"); 733 let _p = profile::span("handle_prepare_rename");
734 let position = from_proto::file_position(&snap, params)?; 734 let position = from_proto::file_position(&snap, params)?;
735 735
736 let change = snap.analysis.rename(position, "dummy")??; 736 let change = snap.analysis.prepare_rename(position)??;
737 let line_index = snap.analysis.file_line_index(position.file_id)?; 737 let line_index = snap.analysis.file_line_index(position.file_id)?;
738 let range = to_proto::range(&line_index, change.range); 738 let range = to_proto::range(&line_index, change.range);
739 Ok(Some(PrepareRenameResponse::Range(range))) 739 Ok(Some(PrepareRenameResponse::Range(range)))
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 715f8927a..72f77a016 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -633,7 +633,7 @@ pub(crate) fn resource_op(
633 lsp_types::ResourceOp::Create(lsp_types::CreateFile { 633 lsp_types::ResourceOp::Create(lsp_types::CreateFile {
634 uri, 634 uri,
635 options: None, 635 options: None,
636 annotation: None, 636 annotation_id: None,
637 }) 637 })
638 } 638 }
639 FileSystemEdit::MoveFile { src, dst } => { 639 FileSystemEdit::MoveFile { src, dst } => {
@@ -643,7 +643,7 @@ pub(crate) fn resource_op(
643 old_uri, 643 old_uri,
644 new_uri, 644 new_uri,
645 options: None, 645 options: None,
646 annotation: None, 646 annotation_id: None,
647 }) 647 })
648 } 648 }
649 } 649 }
@@ -708,6 +708,7 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
708 .collect(), 708 .collect(),
709 ) 709 )
710 }), 710 }),
711 change_annotations: None,
711 } 712 }
712 } 713 }
713} 714}
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e83b116a7..2d717e366 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -195,9 +195,9 @@
195 } 195 }
196 }, 196 },
197 "@types/vscode": { 197 "@types/vscode": {
198 "version": "1.51.0", 198 "version": "1.52.0",
199 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.51.0.tgz", 199 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz",
200 "integrity": "sha512-C/jZ35OT5k/rsJyAK8mS1kM++vMcm89oSWegkzxRCvHllIq0cToZAkIDs6eCY4SKrvik3nrhELizyLcM0onbQA==", 200 "integrity": "sha512-Kt3bvWzAvvF/WH9YEcrCICDp0Z7aHhJGhLJ1BxeyNP6yRjonWqWnAIh35/pXAjswAnWOABrYlF7SwXR9+1nnLA==",
201 "dev": true 201 "dev": true
202 }, 202 },
203 "@typescript-eslint/eslint-plugin": { 203 "@typescript-eslint/eslint-plugin": {
@@ -455,8 +455,7 @@
455 "balanced-match": { 455 "balanced-match": {
456 "version": "1.0.0", 456 "version": "1.0.0",
457 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 457 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
458 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 458 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
459 "dev": true
460 }, 459 },
461 "binary-extensions": { 460 "binary-extensions": {
462 "version": "2.1.0", 461 "version": "2.1.0",
@@ -474,7 +473,6 @@
474 "version": "1.1.11", 473 "version": "1.1.11",
475 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 474 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
476 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 475 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
477 "dev": true,
478 "requires": { 476 "requires": {
479 "balanced-match": "^1.0.0", 477 "balanced-match": "^1.0.0",
480 "concat-map": "0.0.1" 478 "concat-map": "0.0.1"
@@ -673,8 +671,7 @@
673 "concat-map": { 671 "concat-map": {
674 "version": "0.0.1", 672 "version": "0.0.1",
675 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 673 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
676 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 674 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
677 "dev": true
678 }, 675 },
679 "cross-spawn": { 676 "cross-spawn": {
680 "version": "7.0.3", 677 "version": "7.0.3",
@@ -1622,7 +1619,6 @@
1622 "version": "3.0.4", 1619 "version": "3.0.4",
1623 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1620 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1624 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1621 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1625 "dev": true,
1626 "requires": { 1622 "requires": {
1627 "brace-expansion": "^1.1.7" 1623 "brace-expansion": "^1.1.7"
1628 } 1624 }
@@ -2021,9 +2017,27 @@
2021 "dev": true 2017 "dev": true
2022 }, 2018 },
2023 "semver": { 2019 "semver": {
2024 "version": "6.3.0", 2020 "version": "7.3.4",
2025 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2021 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
2026 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 2022 "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
2023 "requires": {
2024 "lru-cache": "^6.0.0"
2025 },
2026 "dependencies": {
2027 "lru-cache": {
2028 "version": "6.0.0",
2029 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
2030 "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
2031 "requires": {
2032 "yallist": "^4.0.0"
2033 }
2034 },
2035 "yallist": {
2036 "version": "4.0.0",
2037 "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
2038 "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
2039 }
2040 }
2027 }, 2041 },
2028 "serialize-javascript": { 2042 "serialize-javascript": {
2029 "version": "5.0.1", 2043 "version": "5.0.1",
@@ -2350,32 +2364,33 @@
2350 } 2364 }
2351 }, 2365 },
2352 "vscode-jsonrpc": { 2366 "vscode-jsonrpc": {
2353 "version": "6.0.0-next.7", 2367 "version": "6.0.0",
2354 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0-next.7.tgz", 2368 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz",
2355 "integrity": "sha512-1nG+6cuTtpzmXe7yYfO9GCkYlyV6Ai+jDnwidHiT2T7zhc+bJM+VTtc0T/CdTlDyTNTqIcCj0V1nD4TcVjJ7Ug==" 2369 "integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg=="
2356 }, 2370 },
2357 "vscode-languageclient": { 2371 "vscode-languageclient": {
2358 "version": "7.0.0-next.14", 2372 "version": "7.0.0",
2359 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0-next.14.tgz", 2373 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz",
2360 "integrity": "sha512-QUccfXK2F6AXXRFR8QJCaIz7N2BhJK6ok8E1aO8LHq2IBU33+5hTSJBXs7nEqrqZ/cY2VlDDbMWtMvCxz+/y1w==", 2374 "integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==",
2361 "requires": { 2375 "requires": {
2362 "semver": "^6.3.0", 2376 "minimatch": "^3.0.4",
2363 "vscode-languageserver-protocol": "3.16.0-next.11" 2377 "semver": "^7.3.4",
2378 "vscode-languageserver-protocol": "3.16.0"
2364 } 2379 }
2365 }, 2380 },
2366 "vscode-languageserver-protocol": { 2381 "vscode-languageserver-protocol": {
2367 "version": "3.16.0-next.11", 2382 "version": "3.16.0",
2368 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0-next.11.tgz", 2383 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz",
2369 "integrity": "sha512-31FmupmSmfznuMuGp7qN6h3d/hKUbexbvcwTvrUE/igqRlzFU542s8MtGICx1ERbVuDOLGp96W2Z92qbUbmBPA==", 2384 "integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==",
2370 "requires": { 2385 "requires": {
2371 "vscode-jsonrpc": "6.0.0-next.7", 2386 "vscode-jsonrpc": "6.0.0",
2372 "vscode-languageserver-types": "3.16.0-next.5" 2387 "vscode-languageserver-types": "3.16.0"
2373 } 2388 }
2374 }, 2389 },
2375 "vscode-languageserver-types": { 2390 "vscode-languageserver-types": {
2376 "version": "3.16.0-next.5", 2391 "version": "3.16.0",
2377 "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.5.tgz", 2392 "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
2378 "integrity": "sha512-lf8Y1XXMtF1r2oDDAmJe+drizNXkybSRXAQQk5dPy2rYJsY9SPXYNO074L3THu9zNYepzV5fRJZUPo/V/TLBRQ==" 2393 "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
2379 }, 2394 },
2380 "vscode-test": { 2395 "vscode-test": {
2381 "version": "1.4.1", 2396 "version": "1.4.1",
diff --git a/editors/code/package.json b/editors/code/package.json
index 160a62e46..ad01fea7b 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -21,7 +21,7 @@
21 "Programming Languages" 21 "Programming Languages"
22 ], 22 ],
23 "engines": { 23 "engines": {
24 "vscode": "^1.51.0" 24 "vscode": "^1.52.0"
25 }, 25 },
26 "enableProposedApi": true, 26 "enableProposedApi": true,
27 "scripts": { 27 "scripts": {
@@ -36,7 +36,7 @@
36 }, 36 },
37 "dependencies": { 37 "dependencies": {
38 "node-fetch": "^2.6.1", 38 "node-fetch": "^2.6.1",
39 "vscode-languageclient": "7.0.0-next.14" 39 "vscode-languageclient": "7.0.0"
40 }, 40 },
41 "devDependencies": { 41 "devDependencies": {
42 "@rollup/plugin-commonjs": "^17.0.0", 42 "@rollup/plugin-commonjs": "^17.0.0",
@@ -45,7 +45,7 @@
45 "@types/mocha": "^8.0.4", 45 "@types/mocha": "^8.0.4",
46 "@types/node": "~12.12.6", 46 "@types/node": "~12.12.6",
47 "@types/node-fetch": "^2.5.7", 47 "@types/node-fetch": "^2.5.7",
48 "@types/vscode": "^1.51.0", 48 "@types/vscode": "^1.52.0",
49 "@typescript-eslint/eslint-plugin": "^4.9.0", 49 "@typescript-eslint/eslint-plugin": "^4.9.0",
50 "@typescript-eslint/parser": "^4.9.0", 50 "@typescript-eslint/parser": "^4.9.0",
51 "eslint": "^7.15.0", 51 "eslint": "^7.15.0",