aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/semantics.rs19
-rw-r--r--crates/ra_hir/src/source_analyzer.rs51
-rw-r--r--crates/ra_hir_ty/Cargo.toml6
-rw-r--r--crates/ra_hir_ty/src/lib.rs14
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs10
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs31
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs57
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs30
-rw-r--r--crates/ra_ide/src/hover.rs17
-rw-r--r--crates/ra_ide/src/references/rename.rs211
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs33
-rw-r--r--crates/ra_parser/src/lib.rs2
-rw-r--r--crates/ra_parser/src/parser.rs2
-rw-r--r--crates/ra_syntax/src/syntax_node.rs2
-rw-r--r--crates/ra_tt/src/buffer.rs4
15 files changed, 429 insertions, 60 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 515e5eb17..7c1f79f27 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -23,7 +23,7 @@ use crate::{
23 db::HirDatabase, 23 db::HirDatabase,
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, 27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, 28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
29}; 29};
@@ -451,6 +451,23 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
451 pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> { 451 pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> {
452 resolve_hir_path(self.db, &self.resolver, path) 452 resolve_hir_path(self.db, &self.resolver, path)
453 } 453 }
454
455 /// Resolves a path where we know it is a qualifier of another path.
456 ///
457 /// For example, if we have:
458 /// ```
459 /// mod my {
460 /// pub mod foo {
461 /// struct Bar;
462 /// }
463 ///
464 /// pub fn foo() {}
465 /// }
466 /// ```
467 /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
468 pub fn resolve_hir_path_qualifier(&self, path: &Path) -> Option<PathResolution> {
469 resolve_hir_path_qualifier(self.db, &self.resolver, path)
470 }
454} 471}
455 472
456// FIXME: Change `HasSource` trait to work with `Semantics` and remove this? 473// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index c862a4f48..4b509f07c 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -226,6 +226,17 @@ impl SourceAnalyzer {
226 // This must be a normal source file rather than macro file. 226 // This must be a normal source file rather than macro file.
227 let hir_path = 227 let hir_path =
228 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; 228 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
229
230 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
231 // trying to resolve foo::bar.
232 if let Some(outer_path) = path.syntax().parent().and_then(ast::Path::cast) {
233 if let Some(qualifier) = outer_path.qualifier() {
234 if path == &qualifier {
235 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
236 }
237 }
238 }
239
229 resolve_hir_path(db, &self.resolver, &hir_path) 240 resolve_hir_path(db, &self.resolver, &hir_path)
230 } 241 }
231 242
@@ -404,6 +415,7 @@ pub(crate) fn resolve_hir_path(
404 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), 415 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
405 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), 416 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
406 }); 417 });
418
407 let body_owner = resolver.body_owner(); 419 let body_owner = resolver.body_owner();
408 let values = 420 let values =
409 resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { 421 resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
@@ -426,9 +438,48 @@ pub(crate) fn resolve_hir_path(
426 .resolve_module_path_in_items(db.upcast(), path.mod_path()) 438 .resolve_module_path_in_items(db.upcast(), path.mod_path())
427 .take_types() 439 .take_types()
428 .map(|it| PathResolution::Def(it.into())); 440 .map(|it| PathResolution::Def(it.into()));
441
429 types.or(values).or(items).or_else(|| { 442 types.or(values).or(items).or_else(|| {
430 resolver 443 resolver
431 .resolve_path_as_macro(db.upcast(), path.mod_path()) 444 .resolve_path_as_macro(db.upcast(), path.mod_path())
432 .map(|def| PathResolution::Macro(def.into())) 445 .map(|def| PathResolution::Macro(def.into()))
433 }) 446 })
434} 447}
448
449/// Resolves a path where we know it is a qualifier of another path.
450///
451/// For example, if we have:
452/// ```
453/// mod my {
454/// pub mod foo {
455/// struct Bar;
456/// }
457///
458/// pub fn foo() {}
459/// }
460/// ```
461/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
462pub(crate) fn resolve_hir_path_qualifier(
463 db: &dyn HirDatabase,
464 resolver: &Resolver,
465 path: &crate::Path,
466) -> Option<PathResolution> {
467 let items = resolver
468 .resolve_module_path_in_items(db.upcast(), path.mod_path())
469 .take_types()
470 .map(|it| PathResolution::Def(it.into()));
471
472 if items.is_some() {
473 return items;
474 }
475
476 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
477 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
478 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
479 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()),
480 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
481 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
482 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
483 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
484 })
485}
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 65db6d1b0..5fc0ec5e3 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,9 +27,9 @@ test_utils = { path = "../test_utils" }
27 27
28scoped-tls = "1" 28scoped-tls = "1"
29 29
30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35insta = "0.16.0" 35insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index ccc4348f4..daea02f88 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -808,15 +808,13 @@ impl Ty {
808 } 808 }
809 } 809 }
810 810
811 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 811 /// If this is a `dyn Trait`, returns that trait.
812 pub fn inherent_trait(&self) -> Option<TraitId> { 812 pub fn dyn_trait(&self) -> Option<TraitId> {
813 match self { 813 match self {
814 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 814 Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred {
815 predicates.iter().find_map(|pred| match pred { 815 GenericPredicate::Implemented(tr) => Some(tr.trait_),
816 GenericPredicate::Implemented(tr) => Some(tr.trait_), 816 _ => None,
817 _ => None, 817 }),
818 })
819 }
820 _ => None, 818 _ => None,
821 } 819 }
822 } 820 }
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 657284fd0..0851e16a8 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -408,8 +408,9 @@ fn iterate_trait_method_candidates<T>(
408 receiver_ty: Option<&Canonical<Ty>>, 408 receiver_ty: Option<&Canonical<Ty>>,
409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
410) -> Option<T> { 410) -> Option<T> {
411 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 411 // if ty is `dyn Trait`, the trait doesn't need to be in scope
412 let inherent_trait = self_ty.value.inherent_trait().into_iter(); 412 let inherent_trait =
413 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
413 let env_traits = if let Ty::Placeholder(_) = self_ty.value { 414 let env_traits = if let Ty::Placeholder(_) = self_ty.value {
414 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 415 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
415 env.trait_predicates_for_self_ty(&self_ty.value) 416 env.trait_predicates_for_self_ty(&self_ty.value)
@@ -601,11 +602,6 @@ pub fn implements_trait(
601 krate: CrateId, 602 krate: CrateId,
602 trait_: TraitId, 603 trait_: TraitId,
603) -> bool { 604) -> bool {
604 if ty.value.inherent_trait() == Some(trait_) {
605 // FIXME this is a bit of a hack, since Chalk should say the same thing
606 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
607 return true;
608 }
609 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 605 let goal = generic_implements_goal(db, env, trait_, ty.clone());
610 let solution = db.trait_solve(krate, goal); 606 let solution = db.trait_solve(krate, goal);
611 607
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 67f964ab5..9c2c9e1d2 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1096,3 +1096,34 @@ fn test() { (S {}).method()<|>; }
1096 ); 1096 );
1097 assert_eq!(t, "()"); 1097 assert_eq!(t, "()");
1098} 1098}
1099
1100#[test]
1101fn dyn_trait_super_trait_not_in_scope() {
1102 assert_snapshot!(
1103 infer(r#"
1104mod m {
1105 pub trait SuperTrait {
1106 fn foo(&self) -> u32 { 0 }
1107 }
1108}
1109trait Trait: m::SuperTrait {}
1110
1111struct S;
1112impl m::SuperTrait for S {}
1113impl Trait for S {}
1114
1115fn test(d: &dyn Trait) {
1116 d.foo();
1117}
1118"#),
1119 @r###"
1120 52..56 'self': &Self
1121 65..70 '{ 0 }': u32
1122 67..68 '0': u32
1123 177..178 'd': &dyn Trait
1124 192..208 '{ ...o(); }': ()
1125 198..199 'd': &dyn Trait
1126 198..205 'd.foo()': u32
1127 "###
1128 );
1129}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 1ccb7c3b4..5870618a0 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -182,7 +182,10 @@ impl chalk_ir::interner::Interner for Interner {
182 Arc::new(goal) 182 Arc::new(goal)
183 } 183 }
184 184
185 fn intern_goals(&self, data: impl IntoIterator<Item = Goal<Self>>) -> Self::InternedGoals { 185 fn intern_goals<E>(
186 &self,
187 data: impl IntoIterator<Item = Result<Goal<Self>, E>>,
188 ) -> Result<Self::InternedGoals, E> {
186 data.into_iter().collect() 189 data.into_iter().collect()
187 } 190 }
188 191
@@ -222,10 +225,10 @@ impl chalk_ir::interner::Interner for Interner {
222 clause 225 clause
223 } 226 }
224 227
225 fn intern_program_clauses( 228 fn intern_program_clauses<E>(
226 &self, 229 &self,
227 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>, 230 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
228 ) -> Arc<[chalk_ir::ProgramClause<Self>]> { 231 ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> {
229 data.into_iter().collect() 232 data.into_iter().collect()
230 } 233 }
231 234
@@ -236,10 +239,10 @@ impl chalk_ir::interner::Interner for Interner {
236 &clauses 239 &clauses
237 } 240 }
238 241
239 fn intern_quantified_where_clauses( 242 fn intern_quantified_where_clauses<E>(
240 &self, 243 &self,
241 data: impl IntoIterator<Item = chalk_ir::QuantifiedWhereClause<Self>>, 244 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
242 ) -> Self::InternedQuantifiedWhereClauses { 245 ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
243 data.into_iter().collect() 246 data.into_iter().collect()
244 } 247 }
245 248
@@ -250,10 +253,10 @@ impl chalk_ir::interner::Interner for Interner {
250 clauses 253 clauses
251 } 254 }
252 255
253 fn intern_parameter_kinds( 256 fn intern_parameter_kinds<E>(
254 &self, 257 &self,
255 data: impl IntoIterator<Item = chalk_ir::ParameterKind<()>>, 258 data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>,
256 ) -> Self::InternedParameterKinds { 259 ) -> Result<Self::InternedParameterKinds, E> {
257 data.into_iter().collect() 260 data.into_iter().collect()
258 } 261 }
259 262
@@ -264,10 +267,10 @@ impl chalk_ir::interner::Interner for Interner {
264 &parameter_kinds 267 &parameter_kinds
265 } 268 }
266 269
267 fn intern_canonical_var_kinds( 270 fn intern_canonical_var_kinds<E>(
268 &self, 271 &self,
269 data: impl IntoIterator<Item = chalk_ir::ParameterKind<UniverseIndex>>, 272 data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<UniverseIndex>, E>>,
270 ) -> Self::InternedCanonicalVarKinds { 273 ) -> Result<Self::InternedCanonicalVarKinds, E> {
271 data.into_iter().collect() 274 data.into_iter().collect()
272 } 275 }
273 276
@@ -460,6 +463,14 @@ impl ToChalk for TypeCtor {
460 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), 463 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
461 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 464 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
462 TypeName::OpaqueType(_) => unreachable!(), 465 TypeName::OpaqueType(_) => unreachable!(),
466
467 TypeName::Scalar(_) => unreachable!(),
468 TypeName::Tuple(_) => unreachable!(),
469 TypeName::Raw(_) => unreachable!(),
470 TypeName::Slice => unreachable!(),
471 TypeName::Ref(_) => unreachable!(),
472 TypeName::Str => unreachable!(),
473
463 TypeName::Error => { 474 TypeName::Error => {
464 // this should not be reached, since we don't represent TypeName::Error with TypeCtor 475 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
465 unreachable!() 476 unreachable!()
@@ -862,12 +873,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
862 // We don't do coherence checking (yet) 873 // We don't do coherence checking (yet)
863 unimplemented!() 874 unimplemented!()
864 } 875 }
865 fn as_struct_id(&self, id: &TypeName<Interner>) -> Option<StructId> {
866 match id {
867 TypeName::Struct(struct_id) => Some(*struct_id),
868 _ => None,
869 }
870 }
871 fn interner(&self) -> &Interner { 876 fn interner(&self) -> &Interner {
872 &Interner 877 &Interner
873 } 878 }
@@ -892,6 +897,20 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
892 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> { 897 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> {
893 unimplemented!() 898 unimplemented!()
894 } 899 }
900
901 fn force_impl_for(
902 &self,
903 _well_known: chalk_rust_ir::WellKnownTrait,
904 _ty: &chalk_ir::TyData<Interner>,
905 ) -> Option<bool> {
906 // this method is mostly for rustc
907 None
908 }
909
910 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
911 // FIXME: implement actual object safety
912 true
913 }
895} 914}
896 915
897pub(crate) fn program_clauses_for_chalk_env_query( 916pub(crate) fn program_clauses_for_chalk_env_query(
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index 7fcd22525..db7430454 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -20,7 +20,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
20 let scope = ctx.scope(); 20 let scope = ctx.scope();
21 let context_module = scope.module(); 21 let context_module = scope.module();
22 22
23 let res = match scope.resolve_hir_path(&path) { 23 let res = match scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 24 Some(res) => res,
25 None => return, 25 None => return,
26 }; 26 };
@@ -226,6 +226,34 @@ mod tests {
226 } 226 }
227 227
228 #[test] 228 #[test]
229 fn completes_mod_with_same_name_as_function() {
230 assert_debug_snapshot!(
231 do_reference_completion(
232 r"
233 use self::my::<|>;
234
235 mod my {
236 pub struct Bar;
237 }
238
239 fn my() {}
240 "
241 ),
242 @r###"
243 [
244 CompletionItem {
245 label: "Bar",
246 source_range: 31..31,
247 delete: 31..31,
248 insert: "Bar",
249 kind: Struct,
250 },
251 ]
252 "###
253 );
254 }
255
256 #[test]
229 fn path_visibility() { 257 fn path_visibility() {
230 assert_debug_snapshot!( 258 assert_debug_snapshot!(
231 do_reference_completion( 259 do_reference_completion(
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 06d4f1c63..befa977c7 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -921,4 +921,21 @@ fn func(foo: i32) { if true { <|>foo; }; }
921 &["unsafe trait foo"], 921 &["unsafe trait foo"],
922 ); 922 );
923 } 923 }
924
925 #[test]
926 fn test_hover_mod_with_same_name_as_function() {
927 check_hover_result(
928 "
929 //- /lib.rs
930 use self::m<|>y::Bar;
931
932 mod my {
933 pub struct Bar;
934 }
935
936 fn my() {}
937 ",
938 &["mod my"],
939 );
940 }
924} 941}
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 2cbb82c1a..410dae75c 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -4,14 +4,16 @@ use hir::{ModuleSource, Semantics};
4use ra_db::{RelativePath, RelativePathBuf, SourceDatabaseExt}; 4use ra_db::{RelativePath, RelativePathBuf, SourceDatabaseExt};
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
7 algo::find_node_at_offset, ast, lex_single_valid_syntax_kind, AstNode, SyntaxKind, SyntaxNode, 7 algo::find_node_at_offset, ast, ast::TypeAscriptionOwner, lex_single_valid_syntax_kind,
8 AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
8}; 9};
9use ra_text_edit::TextEdit; 10use ra_text_edit::TextEdit;
11use std::convert::TryInto;
10use test_utils::tested_by; 12use test_utils::tested_by;
11 13
12use crate::{ 14use crate::{
13 references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, 15 references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind,
14 SourceChange, SourceFileEdit, TextRange, 16 SourceChange, SourceFileEdit, TextRange, TextSize,
15}; 17};
16 18
17pub(crate) fn rename( 19pub(crate) fn rename(
@@ -21,17 +23,21 @@ pub(crate) fn rename(
21) -> Option<RangeInfo<SourceChange>> { 23) -> Option<RangeInfo<SourceChange>> {
22 match lex_single_valid_syntax_kind(new_name)? { 24 match lex_single_valid_syntax_kind(new_name)? {
23 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), 25 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
26 SyntaxKind::SELF_KW => return rename_to_self(db, position),
24 _ => return None, 27 _ => return None,
25 } 28 }
26 29
27 let sema = Semantics::new(db); 30 let sema = Semantics::new(db);
28 let source_file = sema.parse(position.file_id); 31 let source_file = sema.parse(position.file_id);
29 if let Some((ast_name, ast_module)) = 32 let syntax = source_file.syntax();
30 find_name_and_module_at_offset(source_file.syntax(), position) 33 if let Some((ast_name, ast_module)) = find_name_and_module_at_offset(syntax, position) {
31 {
32 let range = ast_name.syntax().text_range(); 34 let range = ast_name.syntax().text_range();
33 rename_mod(&sema, &ast_name, &ast_module, position, new_name) 35 rename_mod(&sema, &ast_name, &ast_module, position, new_name)
34 .map(|info| RangeInfo::new(range, info)) 36 .map(|info| RangeInfo::new(range, info))
37 } else if let Some(self_token) =
38 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
39 {
40 rename_self_to_param(db, position, self_token, new_name)
35 } else { 41 } else {
36 rename_reference(sema.db, position, new_name) 42 rename_reference(sema.db, position, new_name)
37 } 43 }
@@ -125,6 +131,112 @@ fn rename_mod(
125 Some(SourceChange::from_edits("Rename", source_file_edits, file_system_edits)) 131 Some(SourceChange::from_edits("Rename", source_file_edits, file_system_edits))
126} 132}
127 133
134fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> {
135 let sema = Semantics::new(db);
136 let source_file = sema.parse(position.file_id);
137 let syn = source_file.syntax();
138
139 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?;
140 let params = fn_def.param_list()?;
141 if params.self_param().is_some() {
142 return None; // method already has self param
143 }
144 let first_param = params.params().next()?;
145 let mutable = match first_param.ascribed_type() {
146 Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(),
147 _ => return None, // not renaming other types
148 };
149
150 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
151
152 let param_range = first_param.syntax().text_range();
153 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
154 .into_iter()
155 .partition(|reference| param_range.intersect(reference.file_range.range).is_some());
156
157 if param_ref.is_empty() {
158 return None;
159 }
160
161 let mut edits = usages
162 .into_iter()
163 .map(|reference| source_edit_from_reference(reference, "self"))
164 .collect::<Vec<_>>();
165
166 edits.push(SourceFileEdit {
167 file_id: position.file_id,
168 edit: TextEdit::replace(
169 param_range,
170 String::from(if mutable { "&mut self" } else { "&self" }),
171 ),
172 });
173
174 Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits)))
175}
176
177fn text_edit_from_self_param(
178 syn: &SyntaxNode,
179 self_param: &ast::SelfParam,
180 new_name: &str,
181) -> Option<TextEdit> {
182 fn target_type_name(impl_def: &ast::ImplDef) -> Option<String> {
183 if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() {
184 return Some(p.path()?.segment()?.name_ref()?.text().to_string());
185 }
186 None
187 }
188
189 let impl_def =
190 find_node_at_offset::<ast::ImplDef>(syn, self_param.syntax().text_range().start())?;
191 let type_name = target_type_name(&impl_def)?;
192
193 let mut replacement_text = String::from(new_name);
194 replacement_text.push_str(": ");
195 replacement_text.push_str(self_param.mut_token().map_or("&", |_| "&mut "));
196 replacement_text.push_str(type_name.as_str());
197
198 Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
199}
200
201fn rename_self_to_param(
202 db: &RootDatabase,
203 position: FilePosition,
204 self_token: SyntaxToken,
205 new_name: &str,
206) -> Option<RangeInfo<SourceChange>> {
207 let sema = Semantics::new(db);
208 let source_file = sema.parse(position.file_id);
209 let syn = source_file.syntax();
210
211 let text = db.file_text(position.file_id);
212 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?;
213 let search_range = fn_def.syntax().text_range();
214
215 let mut edits: Vec<SourceFileEdit> = vec![];
216
217 for (idx, _) in text.match_indices("self") {
218 let offset: TextSize = idx.try_into().unwrap();
219 if !search_range.contains_inclusive(offset) {
220 continue;
221 }
222 if let Some(ref usage) =
223 syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
224 {
225 let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
226 text_edit_from_self_param(syn, self_param, new_name)?
227 } else {
228 TextEdit::replace(usage.text_range(), String::from(new_name))
229 };
230 edits.push(SourceFileEdit { file_id: position.file_id, edit });
231 }
232 }
233
234 let range = ast::SelfParam::cast(self_token.parent())
235 .map_or(self_token.text_range(), |p| p.syntax().text_range());
236
237 Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits)))
238}
239
128fn rename_reference( 240fn rename_reference(
129 db: &RootDatabase, 241 db: &RootDatabase,
130 position: FilePosition, 242 position: FilePosition,
@@ -774,6 +886,95 @@ mod tests {
774 ); 886 );
775 } 887 }
776 888
889 #[test]
890 fn test_parameter_to_self() {
891 test_rename(
892 r#"
893 struct Foo {
894 i: i32,
895 }
896
897 impl Foo {
898 fn f(foo<|>: &mut Foo) -> i32 {
899 foo.i
900 }
901 }
902 "#,
903 "self",
904 r#"
905 struct Foo {
906 i: i32,
907 }
908
909 impl Foo {
910 fn f(&mut self) -> i32 {
911 self.i
912 }
913 }
914 "#,
915 );
916 }
917
918 #[test]
919 fn test_self_to_parameter() {
920 test_rename(
921 r#"
922 struct Foo {
923 i: i32,
924 }
925
926 impl Foo {
927 fn f(&mut <|>self) -> i32 {
928 self.i
929 }
930 }
931 "#,
932 "foo",
933 r#"
934 struct Foo {
935 i: i32,
936 }
937
938 impl Foo {
939 fn f(foo: &mut Foo) -> i32 {
940 foo.i
941 }
942 }
943 "#,
944 );
945 }
946
947 #[test]
948 fn test_self_in_path_to_parameter() {
949 test_rename(
950 r#"
951 struct Foo {
952 i: i32,
953 }
954
955 impl Foo {
956 fn f(&self) -> i32 {
957 let self_var = 1;
958 self<|>.i
959 }
960 }
961 "#,
962 "foo",
963 r#"
964 struct Foo {
965 i: i32,
966 }
967
968 impl Foo {
969 fn f(foo: &Foo) -> i32 {
970 let self_var = 1;
971 foo.i
972 }
973 }
974 "#,
975 );
976 }
977
777 fn test_rename(text: &str, new_name: &str, expected: &str) { 978 fn test_rename(text: &str, new_name: &str, expected: &str) {
778 let (analysis, position) = single_file_with_position(text); 979 let (analysis, position) = single_file_with_position(text);
779 let source_change = analysis.rename(position, new_name).unwrap(); 980 let source_change = analysis.rename(position, new_name).unwrap();
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index 4b173edd3..7c9bb4d00 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -1,4 +1,4 @@
1//! Transcraber takes a template, like `fn $ident() {}`, a set of bindings like 1//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
2//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` 2//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
3 3
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
@@ -53,7 +53,8 @@ impl Bindings {
53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { 53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> {
54 assert!(template.delimiter == None); 54 assert!(template.delimiter == None);
55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; 55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
56 expand_subtree(&mut ctx, template) 56 let mut arena: Vec<tt::TokenTree> = Vec::new();
57 expand_subtree(&mut ctx, template, &mut arena)
57} 58}
58 59
59#[derive(Debug)] 60#[derive(Debug)]
@@ -73,8 +74,13 @@ struct ExpandCtx<'a> {
73 nesting: Vec<NestingState>, 74 nesting: Vec<NestingState>,
74} 75}
75 76
76fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> ExpandResult<tt::Subtree> { 77fn expand_subtree(
77 let mut buf: Vec<tt::TokenTree> = Vec::new(); 78 ctx: &mut ExpandCtx,
79 template: &tt::Subtree,
80 arena: &mut Vec<tt::TokenTree>,
81) -> ExpandResult<tt::Subtree> {
82 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
83 let start_elements = arena.len();
78 let mut err = None; 84 let mut err = None;
79 for op in parse_template(template) { 85 for op in parse_template(template) {
80 let op = match op { 86 let op = match op {
@@ -85,25 +91,27 @@ fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> ExpandResult<t
85 } 91 }
86 }; 92 };
87 match op { 93 match op {
88 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => buf.push(tt.clone()), 94 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()),
89 Op::TokenTree(tt::TokenTree::Subtree(tt)) => { 95 Op::TokenTree(tt::TokenTree::Subtree(tt)) => {
90 let ExpandResult(tt, e) = expand_subtree(ctx, tt); 96 let ExpandResult(tt, e) = expand_subtree(ctx, tt, arena);
91 err = err.or(e); 97 err = err.or(e);
92 buf.push(tt.into()); 98 arena.push(tt.into());
93 } 99 }
94 Op::Var { name, kind: _ } => { 100 Op::Var { name, kind: _ } => {
95 let ExpandResult(fragment, e) = expand_var(ctx, name); 101 let ExpandResult(fragment, e) = expand_var(ctx, name);
96 err = err.or(e); 102 err = err.or(e);
97 push_fragment(&mut buf, fragment); 103 push_fragment(arena, fragment);
98 } 104 }
99 Op::Repeat { subtree, kind, separator } => { 105 Op::Repeat { subtree, kind, separator } => {
100 let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator); 106 let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator, arena);
101 err = err.or(e); 107 err = err.or(e);
102 push_fragment(&mut buf, fragment) 108 push_fragment(arena, fragment)
103 } 109 }
104 } 110 }
105 } 111 }
106 ExpandResult(tt::Subtree { delimiter: template.delimiter, token_trees: buf }, err) 112 // drain the elements added in this instance of expand_subtree
113 let tts = arena.drain(start_elements..arena.len()).collect();
114 ExpandResult(tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err)
107} 115}
108 116
109fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { 117fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
@@ -155,6 +163,7 @@ fn expand_repeat(
155 template: &tt::Subtree, 163 template: &tt::Subtree,
156 kind: RepeatKind, 164 kind: RepeatKind,
157 separator: Option<Separator>, 165 separator: Option<Separator>,
166 arena: &mut Vec<tt::TokenTree>,
158) -> ExpandResult<Fragment> { 167) -> ExpandResult<Fragment> {
159 let mut buf: Vec<tt::TokenTree> = Vec::new(); 168 let mut buf: Vec<tt::TokenTree> = Vec::new();
160 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); 169 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
@@ -165,7 +174,7 @@ fn expand_repeat(
165 let mut counter = 0; 174 let mut counter = 0;
166 175
167 loop { 176 loop {
168 let ExpandResult(mut t, e) = expand_subtree(ctx, template); 177 let ExpandResult(mut t, e) = expand_subtree(ctx, template, arena);
169 let nesting_state = ctx.nesting.last_mut().unwrap(); 178 let nesting_state = ctx.nesting.last_mut().unwrap();
170 if nesting_state.at_end || !nesting_state.hit { 179 if nesting_state.at_end || !nesting_state.hit {
171 break; 180 break;
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index e08ad4dae..eeb8ad66b 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -25,7 +25,7 @@ pub(crate) use token_set::TokenSet;
25pub use syntax_kind::SyntaxKind; 25pub use syntax_kind::SyntaxKind;
26 26
27#[derive(Debug, Clone, PartialEq, Eq, Hash)] 27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct ParseError(pub String); 28pub struct ParseError(pub Box<String>);
29 29
30/// `TokenSource` abstracts the source of the tokens parser operates on. 30/// `TokenSource` abstracts the source of the tokens parser operates on.
31/// 31///
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index faa63d53f..4f59b0a23 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -192,7 +192,7 @@ impl<'t> Parser<'t> {
192 /// structured errors with spans and notes, like rustc 192 /// structured errors with spans and notes, like rustc
193 /// does. 193 /// does.
194 pub(crate) fn error<T: Into<String>>(&mut self, message: T) { 194 pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
195 let msg = ParseError(message.into()); 195 let msg = ParseError(Box::new(message.into()));
196 self.push_event(Event::Error { msg }) 196 self.push_event(Event::Error { msg })
197 } 197 }
198 198
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index f9d379abf..e566af7e8 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -70,6 +70,6 @@ impl SyntaxTreeBuilder {
70 } 70 }
71 71
72 pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextSize) { 72 pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextSize) {
73 self.errors.push(SyntaxError::new_at_offset(error.0, text_pos)) 73 self.errors.push(SyntaxError::new_at_offset(*error.0, text_pos))
74 } 74 }
75} 75}
diff --git a/crates/ra_tt/src/buffer.rs b/crates/ra_tt/src/buffer.rs
index 14b3f707d..5967f44cd 100644
--- a/crates/ra_tt/src/buffer.rs
+++ b/crates/ra_tt/src/buffer.rs
@@ -42,7 +42,9 @@ impl<'t> TokenBuffer<'t> {
42 buffers: &mut Vec<Box<[Entry<'t>]>>, 42 buffers: &mut Vec<Box<[Entry<'t>]>>,
43 next: Option<EntryPtr>, 43 next: Option<EntryPtr>,
44 ) -> usize { 44 ) -> usize {
45 let mut entries = vec![]; 45 // Must contain everything in tokens and then the Entry::End
46 let start_capacity = tokens.len() + 1;
47 let mut entries = Vec::with_capacity(start_capacity);
46 let mut children = vec![]; 48 let mut children = vec![];
47 49
48 for (idx, tt) in tokens.iter().enumerate() { 50 for (idx, tt) in tokens.iter().enumerate() {