diff options
Diffstat (limited to 'crates')
58 files changed, 904 insertions, 335 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 42856f0ca..45558c448 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -37,7 +37,6 @@ pub struct SubstituteTypeParams<'a> { | |||
37 | impl<'a> SubstituteTypeParams<'a> { | 37 | impl<'a> SubstituteTypeParams<'a> { |
38 | pub fn for_trait_impl( | 38 | pub fn for_trait_impl( |
39 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 39 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
40 | db: &'a RootDatabase, | ||
41 | // FIXME: there's implicit invariant that `trait_` and `source_scope` match... | 40 | // FIXME: there's implicit invariant that `trait_` and `source_scope` match... |
42 | trait_: hir::Trait, | 41 | trait_: hir::Trait, |
43 | impl_def: ast::ImplDef, | 42 | impl_def: ast::ImplDef, |
@@ -45,7 +44,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
45 | let substs = get_syntactic_substs(impl_def).unwrap_or_default(); | 44 | let substs = get_syntactic_substs(impl_def).unwrap_or_default(); |
46 | let generic_def: hir::GenericDef = trait_.into(); | 45 | let generic_def: hir::GenericDef = trait_.into(); |
47 | let substs_by_param: FxHashMap<_, _> = generic_def | 46 | let substs_by_param: FxHashMap<_, _> = generic_def |
48 | .params(db) | 47 | .params(source_scope.db) |
49 | .into_iter() | 48 | .into_iter() |
50 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky | 49 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky |
51 | .skip(1) | 50 | .skip(1) |
@@ -104,7 +103,6 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> { | |||
104 | pub struct QualifyPaths<'a> { | 103 | pub struct QualifyPaths<'a> { |
105 | target_scope: &'a SemanticsScope<'a, RootDatabase>, | 104 | target_scope: &'a SemanticsScope<'a, RootDatabase>, |
106 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 105 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
107 | db: &'a RootDatabase, | ||
108 | previous: Box<dyn AstTransform<'a> + 'a>, | 106 | previous: Box<dyn AstTransform<'a> + 'a>, |
109 | } | 107 | } |
110 | 108 | ||
@@ -112,9 +110,8 @@ impl<'a> QualifyPaths<'a> { | |||
112 | pub fn new( | 110 | pub fn new( |
113 | target_scope: &'a SemanticsScope<'a, RootDatabase>, | 111 | target_scope: &'a SemanticsScope<'a, RootDatabase>, |
114 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 112 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
115 | db: &'a RootDatabase, | ||
116 | ) -> Self { | 113 | ) -> Self { |
117 | Self { target_scope, source_scope, db, previous: Box::new(NullTransformer) } | 114 | Self { target_scope, source_scope, previous: Box::new(NullTransformer) } |
118 | } | 115 | } |
119 | 116 | ||
120 | fn get_substitution_inner( | 117 | fn get_substitution_inner( |
@@ -132,7 +129,7 @@ impl<'a> QualifyPaths<'a> { | |||
132 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 129 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
133 | match resolution { | 130 | match resolution { |
134 | PathResolution::Def(def) => { | 131 | PathResolution::Def(def) => { |
135 | let found_path = from.find_use_path(self.db, def)?; | 132 | let found_path = from.find_use_path(self.source_scope.db, def)?; |
136 | let mut path = path_to_ast(found_path); | 133 | let mut path = path_to_ast(found_path); |
137 | 134 | ||
138 | let type_args = p | 135 | let type_args = p |
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 639180d37..e5920b6f6 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -142,8 +142,8 @@ fn add_missing_impl_members_inner( | |||
142 | let n_existing_items = impl_item_list.impl_items().count(); | 142 | let n_existing_items = impl_item_list.impl_items().count(); |
143 | let source_scope = sema.scope_for_def(trait_); | 143 | let source_scope = sema.scope_for_def(trait_); |
144 | let target_scope = sema.scope(impl_item_list.syntax()); | 144 | let target_scope = sema.scope(impl_item_list.syntax()); |
145 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope, sema.db) | 145 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) |
146 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, sema.db, trait_, impl_node)); | 146 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node)); |
147 | let items = missing_items | 147 | let items = missing_items |
148 | .into_iter() | 148 | .into_iter() |
149 | .map(|it| ast_transform::apply(&*ast_transform, it)) | 149 | .map(|it| ast_transform::apply(&*ast_transform, it)) |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index e5d8c639d..97cf90ae4 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use hir::{db::HirDatabase, Adt, HasSource, Semantics}; | 5 | use hir::{Adt, HasSource, Semantics}; |
6 | use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; | 6 | use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -88,11 +88,7 @@ fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option< | |||
88 | }) | 88 | }) |
89 | } | 89 | } |
90 | 90 | ||
91 | fn build_pat( | 91 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { |
92 | db: &impl HirDatabase, | ||
93 | module: hir::Module, | ||
94 | var: hir::EnumVariant, | ||
95 | ) -> Option<ast::Pat> { | ||
96 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | 92 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); |
97 | 93 | ||
98 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 94 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 50a15f978..62fadcddd 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -235,7 +235,7 @@ mod helpers { | |||
235 | (Some(assist), ExpectedResult::Target(target)) => { | 235 | (Some(assist), ExpectedResult::Target(target)) => { |
236 | let action = assist.0[0].action.clone().unwrap(); | 236 | let action = assist.0[0].action.clone().unwrap(); |
237 | let range = action.target.expect("expected target on action"); | 237 | let range = action.target.expect("expected target on action"); |
238 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 238 | assert_eq_text!(&before[range], target); |
239 | } | 239 | } |
240 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 240 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
241 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { | 241 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 266c4cff3..42193b492 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -11,6 +11,7 @@ doctest = false | |||
11 | log = "0.4.8" | 11 | log = "0.4.8" |
12 | rustc-hash = "1.1.0" | 12 | rustc-hash = "1.1.0" |
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | arrayvec = "0.5.1" | ||
14 | 15 | ||
15 | itertools = "0.8.2" | 16 | itertools = "0.8.2" |
16 | 17 | ||
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 41d4e2ed3..ff041150b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use arrayvec::ArrayVec; | ||
4 | use either::Either; | 5 | use either::Either; |
5 | use hir_def::{ | 6 | use hir_def::{ |
6 | adt::StructKind, | 7 | adt::StructKind, |
@@ -226,7 +227,9 @@ impl Module { | |||
226 | Some((name, def)) | 227 | Some((name, def)) |
227 | } | 228 | } |
228 | }) | 229 | }) |
229 | .map(|(name, def)| (name.clone(), def.into())) | 230 | .flat_map(|(name, def)| { |
231 | ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) | ||
232 | }) | ||
230 | .collect() | 233 | .collect() |
231 | } | 234 | } |
232 | 235 | ||
@@ -308,7 +311,11 @@ impl StructField { | |||
308 | self.parent.variant_data(db).fields()[self.id].name.clone() | 311 | self.parent.variant_data(db).fields()[self.id].name.clone() |
309 | } | 312 | } |
310 | 313 | ||
311 | pub fn ty(&self, db: &impl HirDatabase) -> Type { | 314 | /// Returns the type as in the signature of the struct (i.e., with |
315 | /// placeholder types for type parameters). This is good for showing | ||
316 | /// signature help, but not so good to actually get the type of the field | ||
317 | /// when you actually have a variable of the struct. | ||
318 | pub fn signature_ty(&self, db: &impl HirDatabase) -> Type { | ||
312 | let var_id = self.parent.into(); | 319 | let var_id = self.parent.into(); |
313 | let generic_def_id: GenericDefId = match self.parent { | 320 | let generic_def_id: GenericDefId = match self.parent { |
314 | VariantDef::Struct(it) => it.id.into(), | 321 | VariantDef::Struct(it) => it.id.into(), |
@@ -482,6 +489,10 @@ impl Adt { | |||
482 | let subst = db.generic_defaults(self.into()); | 489 | let subst = db.generic_defaults(self.into()); |
483 | subst.iter().any(|ty| ty == &Ty::Unknown) | 490 | subst.iter().any(|ty| ty == &Ty::Unknown) |
484 | } | 491 | } |
492 | |||
493 | /// Turns this ADT into a type. Any type parameters of the ADT will be | ||
494 | /// turned into unknown types, which is good for e.g. finding the most | ||
495 | /// general set of completions, but will not look very nice when printed. | ||
485 | pub fn ty(self, db: &impl HirDatabase) -> Type { | 496 | pub fn ty(self, db: &impl HirDatabase) -> Type { |
486 | let id = AdtId::from(self); | 497 | let id = AdtId::from(self); |
487 | Type::from_def(db, id.module(db).krate, id) | 498 | Type::from_def(db, id.module(db).krate, id) |
@@ -1028,7 +1039,7 @@ impl Type { | |||
1028 | krate: CrateId, | 1039 | krate: CrateId, |
1029 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | 1040 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, |
1030 | ) -> Type { | 1041 | ) -> Type { |
1031 | let substs = Substs::type_params(db, def); | 1042 | let substs = Substs::build_for_def(db, def).fill_with_unknown().build(); |
1032 | let ty = db.ty(def.into()).subst(&substs); | 1043 | let ty = db.ty(def.into()).subst(&substs); |
1033 | Type::new(db, krate, def, ty) | 1044 | Type::new(db, krate, def, ty) |
1034 | } | 1045 | } |
@@ -1288,15 +1299,36 @@ pub enum ScopeDef { | |||
1288 | Unknown, | 1299 | Unknown, |
1289 | } | 1300 | } |
1290 | 1301 | ||
1291 | impl From<PerNs> for ScopeDef { | 1302 | impl ScopeDef { |
1292 | fn from(def: PerNs) -> Self { | 1303 | pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> { |
1293 | def.take_types() | 1304 | let mut items = ArrayVec::new(); |
1294 | .or_else(|| def.take_values()) | 1305 | |
1295 | .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into())) | 1306 | match (def.take_types(), def.take_values()) { |
1296 | .or_else(|| { | 1307 | (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), |
1297 | def.take_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into())) | 1308 | (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), |
1298 | }) | 1309 | (Some(m1), Some(m2)) => { |
1299 | .unwrap_or(ScopeDef::Unknown) | 1310 | // Some items, like unit structs and enum variants, are |
1311 | // returned as both a type and a value. Here we want | ||
1312 | // to de-duplicate them. | ||
1313 | if m1 != m2 { | ||
1314 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
1315 | items.push(ScopeDef::ModuleDef(m2.into())); | ||
1316 | } else { | ||
1317 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
1318 | } | ||
1319 | } | ||
1320 | (None, None) => {} | ||
1321 | }; | ||
1322 | |||
1323 | if let Some(macro_def_id) = def.take_macros() { | ||
1324 | items.push(ScopeDef::MacroDef(macro_def_id.into())); | ||
1325 | } | ||
1326 | |||
1327 | if items.is_empty() { | ||
1328 | items.push(ScopeDef::Unknown); | ||
1329 | } | ||
1330 | |||
1331 | items | ||
1300 | } | 1332 | } |
1301 | } | 1333 | } |
1302 | 1334 | ||
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 3782a9984..788bb3eb7 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -344,7 +344,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | |||
344 | 344 | ||
345 | resolver.process_all_names(self.db, &mut |name, def| { | 345 | resolver.process_all_names(self.db, &mut |name, def| { |
346 | let def = match def { | 346 | let def = match def { |
347 | resolver::ScopeDef::PerNs(it) => it.into(), | 347 | resolver::ScopeDef::PerNs(it) => { |
348 | let items = ScopeDef::all_items(it); | ||
349 | for item in items { | ||
350 | f(name.clone(), item); | ||
351 | } | ||
352 | return; | ||
353 | } | ||
348 | resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), | 354 | resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), |
349 | resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), | 355 | resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), |
350 | resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), | 356 | resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 57ba45b45..2bc405a59 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -47,13 +47,19 @@ impl Expander { | |||
47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( | 47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
48 | &mut self, | 48 | &mut self, |
49 | db: &DB, | 49 | db: &DB, |
50 | local_scope: Option<&ItemScope>, | ||
50 | macro_call: ast::MacroCall, | 51 | macro_call: ast::MacroCall, |
51 | ) -> Option<(Mark, T)> { | 52 | ) -> Option<(Mark, T)> { |
52 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 53 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
53 | 54 | ||
54 | if let Some(call_id) = | 55 | if let Some(call_id) = macro_call.as_call_id(db, |path| { |
55 | macro_call.as_call_id(db, |path| self.resolve_path_as_macro(db, &path)) | 56 | if let Some(local_scope) = local_scope { |
56 | { | 57 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
58 | return Some(def); | ||
59 | } | ||
60 | } | ||
61 | self.resolve_path_as_macro(db, &path) | ||
62 | }) { | ||
57 | let file_id = call_id.as_file(); | 63 | let file_id = call_id.as_file(); |
58 | if let Some(node) = db.parse_or_expand(file_id) { | 64 | if let Some(node) = db.parse_or_expand(file_id) { |
59 | if let Some(expr) = T::cast(node) { | 65 | if let Some(expr) = T::cast(node) { |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index ec1b0c2e7..54b5591d3 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | 5 | ||
6 | use hir_expand::name::{name, AsName, Name}; | 6 | use hir_expand::{ |
7 | name::{name, AsName, Name}, | ||
8 | MacroDefId, MacroDefKind, | ||
9 | }; | ||
7 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
8 | use ra_syntax::{ | 11 | use ra_syntax::{ |
9 | ast::{ | 12 | ast::{ |
@@ -452,19 +455,30 @@ where | |||
452 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | 455 | None => self.alloc_expr(Expr::Missing, syntax_ptr), |
453 | } | 456 | } |
454 | } | 457 | } |
455 | // FIXME expand to statements in statement position | ||
456 | ast::Expr::MacroCall(e) => { | 458 | ast::Expr::MacroCall(e) => { |
457 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | 459 | if let Some(name) = is_macro_rules(&e) { |
458 | match self.expander.enter_expand(self.db, e) { | 460 | let mac = MacroDefId { |
459 | Some((mark, expansion)) => { | 461 | krate: Some(self.expander.module.krate), |
460 | self.source_map | 462 | ast_id: Some(self.expander.ast_id(&e)), |
461 | .expansions | 463 | kind: MacroDefKind::Declarative, |
462 | .insert(macro_call, self.expander.current_file_id); | 464 | }; |
463 | let id = self.collect_expr(expansion); | 465 | self.body.item_scope.define_legacy_macro(name, mac); |
464 | self.expander.exit(self.db, mark); | 466 | |
465 | id | 467 | // FIXME: do we still need to allocate this as missing ? |
468 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
469 | } else { | ||
470 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
471 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
472 | Some((mark, expansion)) => { | ||
473 | self.source_map | ||
474 | .expansions | ||
475 | .insert(macro_call, self.expander.current_file_id); | ||
476 | let id = self.collect_expr(expansion); | ||
477 | self.expander.exit(self.db, mark); | ||
478 | id | ||
479 | } | ||
480 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
466 | } | 481 | } |
467 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
468 | } | 482 | } |
469 | } | 483 | } |
470 | 484 | ||
@@ -686,6 +700,16 @@ where | |||
686 | } | 700 | } |
687 | } | 701 | } |
688 | 702 | ||
703 | fn is_macro_rules(m: &ast::MacroCall) -> Option<Name> { | ||
704 | let name = m.path()?.segment()?.name_ref()?.as_name(); | ||
705 | |||
706 | if name == name![macro_rules] { | ||
707 | Some(m.name()?.as_name()) | ||
708 | } else { | ||
709 | None | ||
710 | } | ||
711 | } | ||
712 | |||
689 | impl From<ast::BinOp> for BinaryOp { | 713 | impl From<ast::BinOp> for BinaryOp { |
690 | fn from(ast_op: ast::BinOp) -> Self { | 714 | fn from(ast_op: ast::BinOp) -> Self { |
691 | match ast_op { | 715 | match ast_op { |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index a72eb5369..c0b16b7fa 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -34,7 +34,8 @@ pub struct FunctionData { | |||
34 | 34 | ||
35 | impl FunctionData { | 35 | impl FunctionData { |
36 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 36 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
37 | let src = func.lookup(db).source(db); | 37 | let loc = func.lookup(db); |
38 | let src = loc.source(db); | ||
38 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 39 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); |
39 | let mut params = Vec::new(); | 40 | let mut params = Vec::new(); |
40 | let mut has_self_param = false; | 41 | let mut has_self_param = false; |
@@ -76,7 +77,9 @@ impl FunctionData { | |||
76 | ret_type | 77 | ret_type |
77 | }; | 78 | }; |
78 | 79 | ||
79 | let visibility = RawVisibility::from_ast(db, src.map(|s| s.visibility())); | 80 | let vis_default = RawVisibility::default_for_container(loc.container); |
81 | let visibility = | ||
82 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | ||
80 | 83 | ||
81 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; | 84 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; |
82 | Arc::new(sig) | 85 | Arc::new(sig) |
@@ -105,10 +108,13 @@ impl TypeAliasData { | |||
105 | db: &impl DefDatabase, | 108 | db: &impl DefDatabase, |
106 | typ: TypeAliasId, | 109 | typ: TypeAliasId, |
107 | ) -> Arc<TypeAliasData> { | 110 | ) -> Arc<TypeAliasData> { |
108 | let node = typ.lookup(db).source(db); | 111 | let loc = typ.lookup(db); |
112 | let node = loc.source(db); | ||
109 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 113 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); |
110 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); | 114 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); |
111 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); | 115 | let vis_default = RawVisibility::default_for_container(loc.container); |
116 | let visibility = | ||
117 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
112 | Arc::new(TypeAliasData { name, type_ref, visibility }) | 118 | Arc::new(TypeAliasData { name, type_ref, visibility }) |
113 | } | 119 | } |
114 | } | 120 | } |
@@ -230,22 +236,26 @@ pub struct ConstData { | |||
230 | 236 | ||
231 | impl ConstData { | 237 | impl ConstData { |
232 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { | 238 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { |
233 | let node = konst.lookup(db).source(db); | 239 | let loc = konst.lookup(db); |
234 | Arc::new(ConstData::new(db, node)) | 240 | let node = loc.source(db); |
241 | let vis_default = RawVisibility::default_for_container(loc.container); | ||
242 | Arc::new(ConstData::new(db, vis_default, node)) | ||
235 | } | 243 | } |
236 | 244 | ||
237 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { | 245 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { |
238 | let node = konst.lookup(db).source(db); | 246 | let node = konst.lookup(db).source(db); |
239 | Arc::new(ConstData::new(db, node)) | 247 | Arc::new(ConstData::new(db, RawVisibility::private(), node)) |
240 | } | 248 | } |
241 | 249 | ||
242 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( | 250 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( |
243 | db: &impl DefDatabase, | 251 | db: &impl DefDatabase, |
252 | vis_default: RawVisibility, | ||
244 | node: InFile<N>, | 253 | node: InFile<N>, |
245 | ) -> ConstData { | 254 | ) -> ConstData { |
246 | let name = node.value.name().map(|n| n.as_name()); | 255 | let name = node.value.name().map(|n| n.as_name()); |
247 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); | 256 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); |
248 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); | 257 | let visibility = |
258 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
249 | ConstData { name, type_ref, visibility } | 259 | ConstData { name, type_ref, visibility } |
250 | } | 260 | } |
251 | } | 261 | } |
@@ -280,7 +290,7 @@ fn collect_impl_items_in_macro( | |||
280 | return Vec::new(); | 290 | return Vec::new(); |
281 | } | 291 | } |
282 | 292 | ||
283 | if let Some((mark, items)) = expander.enter_expand(db, m) { | 293 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { |
284 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 294 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
285 | let mut res = collect_impl_items( | 295 | let mut res = collect_impl_items( |
286 | db, | 296 | db, |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index d0459d9b0..db9838cb5 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -102,6 +102,7 @@ struct MacroDirective { | |||
102 | module_id: LocalModuleId, | 102 | module_id: LocalModuleId, |
103 | ast_id: AstIdWithPath<ast::MacroCall>, | 103 | ast_id: AstIdWithPath<ast::MacroCall>, |
104 | legacy: Option<MacroCallId>, | 104 | legacy: Option<MacroCallId>, |
105 | depth: usize, | ||
105 | } | 106 | } |
106 | 107 | ||
107 | #[derive(Clone, Debug, Eq, PartialEq)] | 108 | #[derive(Clone, Debug, Eq, PartialEq)] |
@@ -134,6 +135,7 @@ where | |||
134 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | 135 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
135 | ModCollector { | 136 | ModCollector { |
136 | def_collector: &mut *self, | 137 | def_collector: &mut *self, |
138 | macro_depth: 0, | ||
137 | module_id, | 139 | module_id, |
138 | file_id: file_id.into(), | 140 | file_id: file_id.into(), |
139 | raw_items: &raw_items, | 141 | raw_items: &raw_items, |
@@ -516,7 +518,7 @@ where | |||
516 | macros.retain(|directive| { | 518 | macros.retain(|directive| { |
517 | if let Some(call_id) = directive.legacy { | 519 | if let Some(call_id) = directive.legacy { |
518 | res = ReachedFixedPoint::No; | 520 | res = ReachedFixedPoint::No; |
519 | resolved.push((directive.module_id, call_id)); | 521 | resolved.push((directive.module_id, call_id, directive.depth)); |
520 | return false; | 522 | return false; |
521 | } | 523 | } |
522 | 524 | ||
@@ -530,7 +532,7 @@ where | |||
530 | ); | 532 | ); |
531 | resolved_res.resolved_def.take_macros() | 533 | resolved_res.resolved_def.take_macros() |
532 | }) { | 534 | }) { |
533 | resolved.push((directive.module_id, call_id)); | 535 | resolved.push((directive.module_id, call_id, directive.depth)); |
534 | res = ReachedFixedPoint::No; | 536 | res = ReachedFixedPoint::No; |
535 | return false; | 537 | return false; |
536 | } | 538 | } |
@@ -541,7 +543,7 @@ where | |||
541 | if let Some(call_id) = | 543 | if let Some(call_id) = |
542 | directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) | 544 | directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) |
543 | { | 545 | { |
544 | resolved.push((directive.module_id, call_id)); | 546 | resolved.push((directive.module_id, call_id, 0)); |
545 | res = ReachedFixedPoint::No; | 547 | res = ReachedFixedPoint::No; |
546 | return false; | 548 | return false; |
547 | } | 549 | } |
@@ -552,8 +554,12 @@ where | |||
552 | self.unexpanded_macros = macros; | 554 | self.unexpanded_macros = macros; |
553 | self.unexpanded_attribute_macros = attribute_macros; | 555 | self.unexpanded_attribute_macros = attribute_macros; |
554 | 556 | ||
555 | for (module_id, macro_call_id) in resolved { | 557 | for (module_id, macro_call_id, depth) in resolved { |
556 | self.collect_macro_expansion(module_id, macro_call_id); | 558 | if depth > 1024 { |
559 | log::debug!("Max macro expansion depth reached"); | ||
560 | continue; | ||
561 | } | ||
562 | self.collect_macro_expansion(module_id, macro_call_id, depth); | ||
557 | } | 563 | } |
558 | 564 | ||
559 | res | 565 | res |
@@ -573,12 +579,18 @@ where | |||
573 | None | 579 | None |
574 | } | 580 | } |
575 | 581 | ||
576 | fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) { | 582 | fn collect_macro_expansion( |
583 | &mut self, | ||
584 | module_id: LocalModuleId, | ||
585 | macro_call_id: MacroCallId, | ||
586 | depth: usize, | ||
587 | ) { | ||
577 | let file_id: HirFileId = macro_call_id.as_file(); | 588 | let file_id: HirFileId = macro_call_id.as_file(); |
578 | let raw_items = self.db.raw_items(file_id); | 589 | let raw_items = self.db.raw_items(file_id); |
579 | let mod_dir = self.mod_dirs[&module_id].clone(); | 590 | let mod_dir = self.mod_dirs[&module_id].clone(); |
580 | ModCollector { | 591 | ModCollector { |
581 | def_collector: &mut *self, | 592 | def_collector: &mut *self, |
593 | macro_depth: depth, | ||
582 | file_id, | 594 | file_id, |
583 | module_id, | 595 | module_id, |
584 | raw_items: &raw_items, | 596 | raw_items: &raw_items, |
@@ -595,6 +607,7 @@ where | |||
595 | /// Walks a single module, populating defs, imports and macros | 607 | /// Walks a single module, populating defs, imports and macros |
596 | struct ModCollector<'a, D> { | 608 | struct ModCollector<'a, D> { |
597 | def_collector: D, | 609 | def_collector: D, |
610 | macro_depth: usize, | ||
598 | module_id: LocalModuleId, | 611 | module_id: LocalModuleId, |
599 | file_id: HirFileId, | 612 | file_id: HirFileId, |
600 | raw_items: &'a raw::RawItems, | 613 | raw_items: &'a raw::RawItems, |
@@ -684,6 +697,7 @@ where | |||
684 | 697 | ||
685 | ModCollector { | 698 | ModCollector { |
686 | def_collector: &mut *self.def_collector, | 699 | def_collector: &mut *self.def_collector, |
700 | macro_depth: self.macro_depth, | ||
687 | module_id, | 701 | module_id, |
688 | file_id: self.file_id, | 702 | file_id: self.file_id, |
689 | raw_items: self.raw_items, | 703 | raw_items: self.raw_items, |
@@ -713,6 +727,7 @@ where | |||
713 | let raw_items = self.def_collector.db.raw_items(file_id.into()); | 727 | let raw_items = self.def_collector.db.raw_items(file_id.into()); |
714 | ModCollector { | 728 | ModCollector { |
715 | def_collector: &mut *self.def_collector, | 729 | def_collector: &mut *self.def_collector, |
730 | macro_depth: self.macro_depth, | ||
716 | module_id, | 731 | module_id, |
717 | file_id: file_id.into(), | 732 | file_id: file_id.into(), |
718 | raw_items: &raw_items, | 733 | raw_items: &raw_items, |
@@ -887,6 +902,7 @@ where | |||
887 | module_id: self.module_id, | 902 | module_id: self.module_id, |
888 | ast_id, | 903 | ast_id, |
889 | legacy: Some(macro_call_id), | 904 | legacy: Some(macro_call_id), |
905 | depth: self.macro_depth + 1, | ||
890 | }); | 906 | }); |
891 | 907 | ||
892 | return; | 908 | return; |
@@ -902,6 +918,7 @@ where | |||
902 | module_id: self.module_id, | 918 | module_id: self.module_id, |
903 | ast_id, | 919 | ast_id, |
904 | legacy: None, | 920 | legacy: None, |
921 | depth: self.macro_depth + 1, | ||
905 | }); | 922 | }); |
906 | } | 923 | } |
907 | 924 | ||
@@ -971,13 +988,26 @@ mod tests { | |||
971 | } | 988 | } |
972 | 989 | ||
973 | #[test] | 990 | #[test] |
974 | fn test_macro_expand_will_stop() { | 991 | fn test_macro_expand_will_stop_1() { |
992 | do_resolve( | ||
993 | r#" | ||
994 | macro_rules! foo { | ||
995 | ($($ty:ty)*) => { foo!($($ty)*); } | ||
996 | } | ||
997 | foo!(KABOOM); | ||
998 | "#, | ||
999 | ); | ||
1000 | } | ||
1001 | |||
1002 | #[ignore] // this test does succeed, but takes quite a while :/ | ||
1003 | #[test] | ||
1004 | fn test_macro_expand_will_stop_2() { | ||
975 | do_resolve( | 1005 | do_resolve( |
976 | r#" | 1006 | r#" |
977 | macro_rules! foo { | 1007 | macro_rules! foo { |
978 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } | 1008 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } |
979 | } | 1009 | } |
980 | foo!(KABOOM); | 1010 | foo!(KABOOM); |
981 | "#, | 1011 | "#, |
982 | ); | 1012 | ); |
983 | } | 1013 | } |
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index dda5ed699..3f33a75b9 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -102,6 +102,28 @@ fn crate_def_map_super_super() { | |||
102 | } | 102 | } |
103 | 103 | ||
104 | #[test] | 104 | #[test] |
105 | fn crate_def_map_fn_mod_same_name() { | ||
106 | let map = def_map( | ||
107 | " | ||
108 | //- /lib.rs | ||
109 | mod m { | ||
110 | pub mod z {} | ||
111 | pub fn z() {} | ||
112 | } | ||
113 | ", | ||
114 | ); | ||
115 | assert_snapshot!(map, @r###" | ||
116 | â‹®crate | ||
117 | â‹®m: t | ||
118 | â‹® | ||
119 | â‹®crate::m | ||
120 | â‹®z: t v | ||
121 | â‹® | ||
122 | â‹®crate::m::z | ||
123 | "###) | ||
124 | } | ||
125 | |||
126 | #[test] | ||
105 | fn bogus_paths() { | 127 | fn bogus_paths() { |
106 | covers!(bogus_paths); | 128 | covers!(bogus_paths); |
107 | let map = def_map( | 129 | let map = def_map( |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 2734d51a0..123fae72a 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -381,6 +381,11 @@ impl Resolver { | |||
381 | db: &impl DefDatabase, | 381 | db: &impl DefDatabase, |
382 | path: &ModPath, | 382 | path: &ModPath, |
383 | ) -> Option<MacroDefId> { | 383 | ) -> Option<MacroDefId> { |
384 | // Search item scope legacy macro first | ||
385 | if let Some(def) = self.resolve_local_macro_def(path) { | ||
386 | return Some(def); | ||
387 | } | ||
388 | |||
384 | let (item_map, module) = self.module_scope()?; | 389 | let (item_map, module) = self.module_scope()?; |
385 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() | 390 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
386 | } | 391 | } |
@@ -413,6 +418,16 @@ impl Resolver { | |||
413 | }) | 418 | }) |
414 | } | 419 | } |
415 | 420 | ||
421 | fn resolve_local_macro_def(&self, path: &ModPath) -> Option<MacroDefId> { | ||
422 | let name = path.as_ident()?; | ||
423 | self.scopes.iter().rev().find_map(|scope| { | ||
424 | if let Scope::LocalItemsScope(body) = scope { | ||
425 | return body.item_scope.get_legacy_macro(name); | ||
426 | } | ||
427 | None | ||
428 | }) | ||
429 | } | ||
430 | |||
416 | pub fn module(&self) -> Option<ModuleId> { | 431 | pub fn module(&self) -> Option<ModuleId> { |
417 | let (def_map, local_id) = self.module_scope()?; | 432 | let (def_map, local_id) = self.module_scope()?; |
418 | Some(ModuleId { krate: def_map.krate, local_id }) | 433 | Some(ModuleId { krate: def_map.krate, local_id }) |
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index d8296da4b..e0c59e905 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::ast; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | path::{ModPath, PathKind}, | 8 | path::{ModPath, PathKind}, |
9 | ModuleId, | 9 | AssocContainerId, ModuleId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// Visibility of an item, not yet resolved. | 12 | /// Visibility of an item, not yet resolved. |
@@ -20,11 +20,30 @@ pub enum RawVisibility { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | impl RawVisibility { | 22 | impl RawVisibility { |
23 | const fn private() -> RawVisibility { | 23 | pub(crate) const fn private() -> RawVisibility { |
24 | let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() }; | 24 | let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() }; |
25 | RawVisibility::Module(path) | 25 | RawVisibility::Module(path) |
26 | } | 26 | } |
27 | 27 | ||
28 | pub(crate) fn default_for_container(container_id: AssocContainerId) -> Self { | ||
29 | match container_id { | ||
30 | AssocContainerId::TraitId(_) => RawVisibility::Public, | ||
31 | _ => RawVisibility::private(), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn from_ast_with_default( | ||
36 | db: &impl DefDatabase, | ||
37 | default: RawVisibility, | ||
38 | node: InFile<Option<ast::Visibility>>, | ||
39 | ) -> RawVisibility { | ||
40 | Self::from_ast_with_hygiene_and_default( | ||
41 | node.value, | ||
42 | default, | ||
43 | &Hygiene::new(db, node.file_id), | ||
44 | ) | ||
45 | } | ||
46 | |||
28 | pub(crate) fn from_ast( | 47 | pub(crate) fn from_ast( |
29 | db: &impl DefDatabase, | 48 | db: &impl DefDatabase, |
30 | node: InFile<Option<ast::Visibility>>, | 49 | node: InFile<Option<ast::Visibility>>, |
@@ -36,8 +55,16 @@ impl RawVisibility { | |||
36 | node: Option<ast::Visibility>, | 55 | node: Option<ast::Visibility>, |
37 | hygiene: &Hygiene, | 56 | hygiene: &Hygiene, |
38 | ) -> RawVisibility { | 57 | ) -> RawVisibility { |
58 | Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn from_ast_with_hygiene_and_default( | ||
62 | node: Option<ast::Visibility>, | ||
63 | default: RawVisibility, | ||
64 | hygiene: &Hygiene, | ||
65 | ) -> RawVisibility { | ||
39 | let node = match node { | 66 | let node = match node { |
40 | None => return RawVisibility::private(), | 67 | None => return default, |
41 | Some(node) => node, | 68 | Some(node) => node, |
42 | }; | 69 | }; |
43 | match node.kind() { | 70 | match node.kind() { |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 3fce73e8a..7b72eb7a0 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -17,7 +17,7 @@ pub mod eager; | |||
17 | use std::hash::Hash; | 17 | use std::hash::Hash; |
18 | use std::sync::Arc; | 18 | use std::sync::Arc; |
19 | 19 | ||
20 | use ra_db::{salsa, CrateId, FileId}; | 20 | use ra_db::{impl_intern_key, salsa, CrateId, FileId}; |
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo, | 22 | algo, |
23 | ast::{self, AstNode}, | 23 | ast::{self, AstNode}, |
@@ -174,25 +174,11 @@ pub enum MacroCallId { | |||
174 | 174 | ||
175 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 175 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
176 | pub struct LazyMacroId(salsa::InternId); | 176 | pub struct LazyMacroId(salsa::InternId); |
177 | impl salsa::InternKey for LazyMacroId { | 177 | impl_intern_key!(LazyMacroId); |
178 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
179 | LazyMacroId(v) | ||
180 | } | ||
181 | fn as_intern_id(&self) -> salsa::InternId { | ||
182 | self.0 | ||
183 | } | ||
184 | } | ||
185 | 178 | ||
186 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 179 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
187 | pub struct EagerMacroId(salsa::InternId); | 180 | pub struct EagerMacroId(salsa::InternId); |
188 | impl salsa::InternKey for EagerMacroId { | 181 | impl_intern_key!(EagerMacroId); |
189 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
190 | EagerMacroId(v) | ||
191 | } | ||
192 | fn as_intern_id(&self) -> salsa::InternId { | ||
193 | self.0 | ||
194 | } | ||
195 | } | ||
196 | 182 | ||
197 | impl From<LazyMacroId> for MacroCallId { | 183 | impl From<LazyMacroId> for MacroCallId { |
198 | fn from(it: LazyMacroId) -> Self { | 184 | fn from(it: LazyMacroId) -> Self { |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 32457bbf7..3b7022ad5 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -363,6 +363,26 @@ fn main() { | |||
363 | } | 363 | } |
364 | 364 | ||
365 | #[test] | 365 | #[test] |
366 | fn infer_local_macro() { | ||
367 | assert_snapshot!( | ||
368 | infer(r#" | ||
369 | fn main() { | ||
370 | macro_rules! foo { | ||
371 | () => { 1usize } | ||
372 | } | ||
373 | let _a = foo!(); | ||
374 | } | ||
375 | "#), | ||
376 | @r###" | ||
377 | ![0; 6) '1usize': usize | ||
378 | [11; 90) '{ ...!(); }': () | ||
379 | [17; 66) 'macro_... }': {unknown} | ||
380 | [75; 77) '_a': usize | ||
381 | "### | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
366 | fn infer_builtin_macros_line() { | 386 | fn infer_builtin_macros_line() { |
367 | assert_snapshot!( | 387 | assert_snapshot!( |
368 | infer(r#" | 388 | infer(r#" |
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index 2b35a3803..39d09a07f 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -544,6 +544,20 @@ fn main() { | |||
544 | } | 544 | } |
545 | 545 | ||
546 | #[test] | 546 | #[test] |
547 | fn generic_struct() { | ||
548 | let info = call_info( | ||
549 | r#" | ||
550 | struct TS<T>(T); | ||
551 | fn main() { | ||
552 | let s = TS(<|>); | ||
553 | }"#, | ||
554 | ); | ||
555 | |||
556 | assert_eq!(info.label(), "struct TS<T>(T) -> TS"); | ||
557 | assert_eq!(info.active_parameter, Some(0)); | ||
558 | } | ||
559 | |||
560 | #[test] | ||
547 | #[should_panic] | 561 | #[should_panic] |
548 | fn cant_call_named_structs() { | 562 | fn cant_call_named_structs() { |
549 | let _ = call_info( | 563 | let _ = call_info( |
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 81e5037aa..f07611d88 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -402,6 +402,38 @@ mod tests { | |||
402 | } | 402 | } |
403 | 403 | ||
404 | #[test] | 404 | #[test] |
405 | fn completes_trait_method_from_other_module() { | ||
406 | assert_debug_snapshot!( | ||
407 | do_ref_completion( | ||
408 | r" | ||
409 | struct A {} | ||
410 | mod m { | ||
411 | pub trait Trait { fn the_method(&self); } | ||
412 | } | ||
413 | use m::Trait; | ||
414 | impl Trait for A {} | ||
415 | fn foo(a: A) { | ||
416 | a.<|> | ||
417 | } | ||
418 | ", | ||
419 | ), | ||
420 | @r###" | ||
421 | [ | ||
422 | CompletionItem { | ||
423 | label: "the_method()", | ||
424 | source_range: [219; 219), | ||
425 | delete: [219; 219), | ||
426 | insert: "the_method()$0", | ||
427 | kind: Method, | ||
428 | lookup: "the_method", | ||
429 | detail: "fn the_method(&self)", | ||
430 | }, | ||
431 | ] | ||
432 | "### | ||
433 | ); | ||
434 | } | ||
435 | |||
436 | #[test] | ||
405 | fn test_no_non_self_method() { | 437 | fn test_no_non_self_method() { |
406 | assert_debug_snapshot!( | 438 | assert_debug_snapshot!( |
407 | do_ref_completion( | 439 | do_ref_completion( |
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs index d588ee364..3db17f15f 100644 --- a/crates/ra_ide/src/completion/complete_path.rs +++ b/crates/ra_ide/src/completion/complete_path.rs | |||
@@ -967,4 +967,74 @@ mod tests { | |||
967 | ] | 967 | ] |
968 | "###); | 968 | "###); |
969 | } | 969 | } |
970 | |||
971 | #[test] | ||
972 | fn function_mod_share_name() { | ||
973 | assert_debug_snapshot!( | ||
974 | do_reference_completion( | ||
975 | r" | ||
976 | fn foo() { | ||
977 | self::m::<|> | ||
978 | } | ||
979 | |||
980 | mod m { | ||
981 | pub mod z {} | ||
982 | pub fn z() {} | ||
983 | } | ||
984 | ", | ||
985 | ), | ||
986 | @r###" | ||
987 | [ | ||
988 | CompletionItem { | ||
989 | label: "z", | ||
990 | source_range: [57; 57), | ||
991 | delete: [57; 57), | ||
992 | insert: "z", | ||
993 | kind: Module, | ||
994 | }, | ||
995 | CompletionItem { | ||
996 | label: "z()", | ||
997 | source_range: [57; 57), | ||
998 | delete: [57; 57), | ||
999 | insert: "z()$0", | ||
1000 | kind: Function, | ||
1001 | lookup: "z", | ||
1002 | detail: "pub fn z()", | ||
1003 | }, | ||
1004 | ] | ||
1005 | "### | ||
1006 | ); | ||
1007 | } | ||
1008 | |||
1009 | #[test] | ||
1010 | fn completes_hashmap_new() { | ||
1011 | assert_debug_snapshot!( | ||
1012 | do_reference_completion( | ||
1013 | r" | ||
1014 | struct RandomState; | ||
1015 | struct HashMap<K, V, S = RandomState> {} | ||
1016 | |||
1017 | impl<K, V> HashMap<K, V, RandomState> { | ||
1018 | pub fn new() -> HashMap<K, V, RandomState> { } | ||
1019 | } | ||
1020 | fn foo() { | ||
1021 | HashMap::<|> | ||
1022 | } | ||
1023 | " | ||
1024 | ), | ||
1025 | @r###" | ||
1026 | [ | ||
1027 | CompletionItem { | ||
1028 | label: "new()", | ||
1029 | source_range: [292; 292), | ||
1030 | delete: [292; 292), | ||
1031 | insert: "new()$0", | ||
1032 | kind: Function, | ||
1033 | lookup: "new", | ||
1034 | detail: "pub fn new() -> HashMap<K, V, RandomState>", | ||
1035 | }, | ||
1036 | ] | ||
1037 | "### | ||
1038 | ); | ||
1039 | } | ||
970 | } | 1040 | } |
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs index bd4adf23a..5ffff5a1c 100644 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ b/crates/ra_ide/src/completion/complete_scope.rs | |||
@@ -42,6 +42,7 @@ mod tests { | |||
42 | kind: Function, | 42 | kind: Function, |
43 | lookup: "quux", | 43 | lookup: "quux", |
44 | detail: "fn quux(x: i32)", | 44 | detail: "fn quux(x: i32)", |
45 | trigger_call_info: true, | ||
45 | }, | 46 | }, |
46 | CompletionItem { | 47 | CompletionItem { |
47 | label: "x", | 48 | label: "x", |
@@ -844,6 +845,7 @@ mod tests { | |||
844 | kind: Function, | 845 | kind: Function, |
845 | lookup: "quux", | 846 | lookup: "quux", |
846 | detail: "fn quux(x: i32)", | 847 | detail: "fn quux(x: i32)", |
848 | trigger_call_info: true, | ||
847 | }, | 849 | }, |
848 | CompletionItem { | 850 | CompletionItem { |
849 | label: "x", | 851 | label: "x", |
@@ -865,4 +867,38 @@ mod tests { | |||
865 | "### | 867 | "### |
866 | ); | 868 | ); |
867 | } | 869 | } |
870 | |||
871 | #[test] | ||
872 | fn completes_unresolved_uses() { | ||
873 | assert_debug_snapshot!( | ||
874 | do_reference_completion( | ||
875 | r" | ||
876 | use spam::Quux; | ||
877 | |||
878 | fn main() { | ||
879 | <|> | ||
880 | } | ||
881 | " | ||
882 | ), | ||
883 | @r###" | ||
884 | [ | ||
885 | CompletionItem { | ||
886 | label: "Quux", | ||
887 | source_range: [82; 82), | ||
888 | delete: [82; 82), | ||
889 | insert: "Quux", | ||
890 | }, | ||
891 | CompletionItem { | ||
892 | label: "main()", | ||
893 | source_range: [82; 82), | ||
894 | delete: [82; 82), | ||
895 | insert: "main()$0", | ||
896 | kind: Function, | ||
897 | lookup: "main", | ||
898 | detail: "fn main()", | ||
899 | }, | ||
900 | ] | ||
901 | "### | ||
902 | ); | ||
903 | } | ||
868 | } | 904 | } |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index ef0eb43b2..bc0f1aff5 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -80,6 +80,9 @@ impl fmt::Debug for CompletionItem { | |||
80 | if self.deprecated { | 80 | if self.deprecated { |
81 | s.field("deprecated", &true); | 81 | s.field("deprecated", &true); |
82 | } | 82 | } |
83 | if self.trigger_call_info { | ||
84 | s.field("trigger_call_info", &true); | ||
85 | } | ||
83 | s.finish() | 86 | s.finish() |
84 | } | 87 | } |
85 | } | 88 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 5213def20..253848602 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; | 3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -9,7 +9,10 @@ use crate::completion::{ | |||
9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::display::{const_label, macro_label, type_label, FunctionSignature}; | 12 | use crate::{ |
13 | display::{const_label, macro_label, type_label, FunctionSignature}, | ||
14 | RootDatabase, | ||
15 | }; | ||
13 | 16 | ||
14 | impl Completions { | 17 | impl Completions { |
15 | pub(crate) fn add_field( | 18 | pub(crate) fn add_field( |
@@ -273,8 +276,10 @@ impl Completions { | |||
273 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | 276 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { |
274 | let is_deprecated = is_deprecated(variant, ctx.db); | 277 | let is_deprecated = is_deprecated(variant, ctx.db); |
275 | let name = variant.name(ctx.db); | 278 | let name = variant.name(ctx.db); |
276 | let detail_types = | 279 | let detail_types = variant |
277 | variant.fields(ctx.db).into_iter().map(|field| (field.name(ctx.db), field.ty(ctx.db))); | 280 | .fields(ctx.db) |
281 | .into_iter() | ||
282 | .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); | ||
278 | let detail = match variant.kind(ctx.db) { | 283 | let detail = match variant.kind(ctx.db) { |
279 | StructKind::Tuple | StructKind::Unit => { | 284 | StructKind::Tuple | StructKind::Unit => { |
280 | join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) | 285 | join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) |
@@ -298,7 +303,7 @@ impl Completions { | |||
298 | } | 303 | } |
299 | } | 304 | } |
300 | 305 | ||
301 | fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { | 306 | fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { |
302 | node.attrs(db).by_key("deprecated").exists() | 307 | node.attrs(db).by_key("deprecated").exists() |
303 | } | 308 | } |
304 | 309 | ||
@@ -510,6 +515,7 @@ mod tests { | |||
510 | kind: Function, | 515 | kind: Function, |
511 | lookup: "with_args", | 516 | lookup: "with_args", |
512 | detail: "fn with_args(x: i32, y: String)", | 517 | detail: "fn with_args(x: i32, y: String)", |
518 | trigger_call_info: true, | ||
513 | }, | 519 | }, |
514 | ] | 520 | ] |
515 | "### | 521 | "### |
@@ -566,6 +572,7 @@ mod tests { | |||
566 | kind: Method, | 572 | kind: Method, |
567 | lookup: "foo", | 573 | lookup: "foo", |
568 | detail: "fn foo(&self, x: i32)", | 574 | detail: "fn foo(&self, x: i32)", |
575 | trigger_call_info: true, | ||
569 | }, | 576 | }, |
570 | ] | 577 | ] |
571 | "### | 578 | "### |
@@ -600,6 +607,7 @@ mod tests { | |||
600 | kind: Method, | 607 | kind: Method, |
601 | lookup: "foo", | 608 | lookup: "foo", |
602 | detail: "fn foo(&self, x: i32)", | 609 | detail: "fn foo(&self, x: i32)", |
610 | trigger_call_info: true, | ||
603 | }, | 611 | }, |
604 | ] | 612 | ] |
605 | "### | 613 | "### |
@@ -718,6 +726,7 @@ mod tests { | |||
718 | kind: Function, | 726 | kind: Function, |
719 | lookup: "foo", | 727 | lookup: "foo", |
720 | detail: "fn foo(xs: Ve)", | 728 | detail: "fn foo(xs: Ve)", |
729 | trigger_call_info: true, | ||
721 | }, | 730 | }, |
722 | ] | 731 | ] |
723 | "### | 732 | "### |
@@ -747,6 +756,7 @@ mod tests { | |||
747 | kind: Function, | 756 | kind: Function, |
748 | lookup: "foo", | 757 | lookup: "foo", |
749 | detail: "fn foo(xs: Ve)", | 758 | detail: "fn foo(xs: Ve)", |
759 | trigger_call_info: true, | ||
750 | }, | 760 | }, |
751 | ] | 761 | ] |
752 | "### | 762 | "### |
@@ -775,6 +785,7 @@ mod tests { | |||
775 | kind: Function, | 785 | kind: Function, |
776 | lookup: "foo", | 786 | lookup: "foo", |
777 | detail: "fn foo(xs: Ve)", | 787 | detail: "fn foo(xs: Ve)", |
788 | trigger_call_info: true, | ||
778 | }, | 789 | }, |
779 | ] | 790 | ] |
780 | "### | 791 | "### |
@@ -803,6 +814,7 @@ mod tests { | |||
803 | kind: Function, | 814 | kind: Function, |
804 | lookup: "foo", | 815 | lookup: "foo", |
805 | detail: "fn foo(xs: Ve<i128>)", | 816 | detail: "fn foo(xs: Ve<i128>)", |
817 | trigger_call_info: true, | ||
806 | }, | 818 | }, |
807 | ] | 819 | ] |
808 | "### | 820 | "### |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index eaeaaa2b4..c395057a7 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -6,6 +6,8 @@ mod navigation_target; | |||
6 | mod structure; | 6 | mod structure; |
7 | mod short_label; | 7 | mod short_label; |
8 | 8 | ||
9 | use std::fmt::{Display, Write}; | ||
10 | |||
9 | use ra_syntax::{ | 11 | use ra_syntax::{ |
10 | ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, | 12 | ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, |
11 | SyntaxKind::{ATTR, COMMENT}, | 13 | SyntaxKind::{ATTR, COMMENT}, |
@@ -67,24 +69,27 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | |||
67 | format!("{}macro_rules! {}", vis, name) | 69 | format!("{}macro_rules! {}", vis, name) |
68 | } | 70 | } |
69 | 71 | ||
70 | pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { | 72 | pub(crate) fn rust_code_markup(code: &impl Display) -> String { |
71 | rust_code_markup_with_doc::<_, &str>(val, None, None) | 73 | rust_code_markup_with_doc(code, None, None) |
72 | } | 74 | } |
73 | 75 | ||
74 | pub(crate) fn rust_code_markup_with_doc<CODE, DOC>( | 76 | pub(crate) fn rust_code_markup_with_doc( |
75 | val: CODE, | 77 | code: &impl Display, |
76 | doc: Option<DOC>, | 78 | doc: Option<&str>, |
77 | mod_path: Option<String>, | 79 | mod_path: Option<&str>, |
78 | ) -> String | 80 | ) -> String { |
79 | where | 81 | let mut markup = "```rust\n".to_owned(); |
80 | CODE: AsRef<str>, | 82 | |
81 | DOC: AsRef<str>, | 83 | if let Some(mod_path) = mod_path { |
82 | { | 84 | if !mod_path.is_empty() { |
83 | let mod_path = | 85 | write!(markup, "{}\n", mod_path).unwrap(); |
84 | mod_path.filter(|path| !path.is_empty()).map(|path| path + "\n").unwrap_or_default(); | 86 | } |
87 | } | ||
88 | write!(markup, "{}\n```", code).unwrap(); | ||
89 | |||
85 | if let Some(doc) = doc { | 90 | if let Some(doc) = doc { |
86 | format!("```rust\n{}{}\n```\n\n{}", mod_path, val.as_ref(), doc.as_ref()) | 91 | write!(markup, "\n\n{}", doc).unwrap(); |
87 | } else { | ||
88 | format!("```rust\n{}{}\n```", mod_path, val.as_ref()) | ||
89 | } | 92 | } |
93 | |||
94 | markup | ||
90 | } | 95 | } |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 2c4c932de..ec1bbd5a0 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -64,7 +64,7 @@ impl FunctionSignature { | |||
64 | .fields(db) | 64 | .fields(db) |
65 | .into_iter() | 65 | .into_iter() |
66 | .map(|field: hir::StructField| { | 66 | .map(|field: hir::StructField| { |
67 | let ty = field.ty(db); | 67 | let ty = field.signature_ty(db); |
68 | format!("{}", ty.display(db)) | 68 | format!("{}", ty.display(db)) |
69 | }) | 69 | }) |
70 | .collect(); | 70 | .collect(); |
@@ -102,7 +102,7 @@ impl FunctionSignature { | |||
102 | .into_iter() | 102 | .into_iter() |
103 | .map(|field: hir::StructField| { | 103 | .map(|field: hir::StructField| { |
104 | let name = field.name(db); | 104 | let name = field.name(db); |
105 | let ty = field.ty(db); | 105 | let ty = field.signature_ty(db); |
106 | format!("{}: {}", name, ty.display(db)) | 106 | format!("{}: {}", name, ty.display(db)) |
107 | }) | 107 | }) |
108 | .collect(); | 108 | .collect(); |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index a55a13ffc..a7be92ce3 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -788,6 +788,21 @@ mod tests { | |||
788 | } | 788 | } |
789 | 789 | ||
790 | #[test] | 790 | #[test] |
791 | fn goto_def_in_local_macro() { | ||
792 | check_goto( | ||
793 | " | ||
794 | //- /lib.rs | ||
795 | fn bar() { | ||
796 | macro_rules! foo { () => { () } } | ||
797 | <|>foo!(); | ||
798 | } | ||
799 | ", | ||
800 | "foo MACRO_CALL FileId(1) [15; 48) [28; 31)", | ||
801 | "macro_rules! foo { () => { () } }|foo", | ||
802 | ); | ||
803 | } | ||
804 | |||
805 | #[test] | ||
791 | fn goto_def_for_field_init_shorthand() { | 806 | fn goto_def_for_field_init_shorthand() { |
792 | covers!(ra_ide_db::goto_def_for_field_init_shorthand); | 807 | covers!(ra_ide_db::goto_def_for_field_init_shorthand); |
793 | check_goto( | 808 | check_goto( |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 0bbba4855..3bdd61a2e 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Logic for computing info that is displayed when the user hovers over any |
2 | //! source code items (e.g. function call, struct field, variable symbol...) | ||
2 | 3 | ||
3 | use hir::{ | 4 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | 5 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, |
@@ -24,35 +25,20 @@ use itertools::Itertools; | |||
24 | use std::iter::once; | 25 | use std::iter::once; |
25 | 26 | ||
26 | /// Contains the results when hovering over an item | 27 | /// Contains the results when hovering over an item |
27 | #[derive(Debug, Clone)] | 28 | #[derive(Debug, Default)] |
28 | pub struct HoverResult { | 29 | pub struct HoverResult { |
29 | results: Vec<String>, | 30 | results: Vec<String>, |
30 | exact: bool, | ||
31 | } | ||
32 | |||
33 | impl Default for HoverResult { | ||
34 | fn default() -> Self { | ||
35 | HoverResult::new() | ||
36 | } | ||
37 | } | 31 | } |
38 | 32 | ||
39 | impl HoverResult { | 33 | impl HoverResult { |
40 | pub fn new() -> HoverResult { | 34 | pub fn new() -> HoverResult { |
41 | HoverResult { | 35 | Self::default() |
42 | results: Vec::new(), | ||
43 | // We assume exact by default | ||
44 | exact: true, | ||
45 | } | ||
46 | } | 36 | } |
47 | 37 | ||
48 | pub fn extend(&mut self, item: Option<String>) { | 38 | pub fn extend(&mut self, item: Option<String>) { |
49 | self.results.extend(item); | 39 | self.results.extend(item); |
50 | } | 40 | } |
51 | 41 | ||
52 | pub fn is_exact(&self) -> bool { | ||
53 | self.exact | ||
54 | } | ||
55 | |||
56 | pub fn is_empty(&self) -> bool { | 42 | pub fn is_empty(&self) -> bool { |
57 | self.results.is_empty() | 43 | self.results.is_empty() |
58 | } | 44 | } |
@@ -72,20 +58,7 @@ impl HoverResult { | |||
72 | /// Returns the results converted into markup | 58 | /// Returns the results converted into markup |
73 | /// for displaying in a UI | 59 | /// for displaying in a UI |
74 | pub fn to_markup(&self) -> String { | 60 | pub fn to_markup(&self) -> String { |
75 | let mut markup = if !self.exact { | 61 | self.results.join("\n\n---\n") |
76 | let mut msg = String::from("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support traits."); | ||
77 | if !self.results.is_empty() { | ||
78 | msg.push_str(" \nThese items were found instead:"); | ||
79 | } | ||
80 | msg.push_str("\n\n---\n"); | ||
81 | msg | ||
82 | } else { | ||
83 | String::new() | ||
84 | }; | ||
85 | |||
86 | markup.push_str(&self.results.join("\n\n---\n")); | ||
87 | |||
88 | markup | ||
89 | } | 62 | } |
90 | } | 63 | } |
91 | 64 | ||
@@ -94,10 +67,10 @@ fn hover_text( | |||
94 | desc: Option<String>, | 67 | desc: Option<String>, |
95 | mod_path: Option<String>, | 68 | mod_path: Option<String>, |
96 | ) -> Option<String> { | 69 | ) -> Option<String> { |
97 | match (desc, docs, mod_path) { | 70 | if let Some(desc) = desc { |
98 | (Some(desc), docs, mod_path) => Some(rust_code_markup_with_doc(desc, docs, mod_path)), | 71 | Some(rust_code_markup_with_doc(&desc, docs.as_deref(), mod_path.as_deref())) |
99 | (None, Some(docs), _) => Some(docs), | 72 | } else { |
100 | _ => None, | 73 | docs |
101 | } | 74 | } |
102 | } | 75 | } |
103 | 76 | ||
@@ -133,7 +106,7 @@ fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | |||
133 | .flatten() | 106 | .flatten() |
134 | .join("::") | 107 | .join("::") |
135 | }); | 108 | }); |
136 | mod_path | 109 | mod_path // FIXME: replace dashes with underscores in crate display name |
137 | } | 110 | } |
138 | 111 | ||
139 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { | 112 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { |
@@ -170,9 +143,7 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
170 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 143 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
171 | ModuleDef::BuiltinType(it) => Some(it.to_string()), | 144 | ModuleDef::BuiltinType(it) => Some(it.to_string()), |
172 | }, | 145 | }, |
173 | Definition::Local(it) => { | 146 | Definition::Local(it) => Some(rust_code_markup(&it.ty(db).display_truncated(db, None))), |
174 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) | ||
175 | } | ||
176 | Definition::TypeParam(_) | Definition::SelfType(_) => { | 147 | Definition::TypeParam(_) | Definition::SelfType(_) => { |
177 | // FIXME: Hover for generic param | 148 | // FIXME: Hover for generic param |
178 | None | 149 | None |
@@ -237,7 +208,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
237 | } | 208 | } |
238 | }?; | 209 | }?; |
239 | 210 | ||
240 | res.extend(Some(rust_code_markup(ty.display_truncated(db, None).to_string()))); | 211 | res.extend(Some(rust_code_markup(&ty.display_truncated(db, None)))); |
241 | let range = sema.original_range(&node).range; | 212 | let range = sema.original_range(&node).range; |
242 | Some(RangeInfo::new(range, res)) | 213 | Some(RangeInfo::new(range, res)) |
243 | } | 214 | } |
@@ -595,7 +566,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
595 | ); | 566 | ); |
596 | let hover = analysis.hover(position).unwrap().unwrap(); | 567 | let hover = analysis.hover(position).unwrap().unwrap(); |
597 | assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing")); | 568 | assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing")); |
598 | assert_eq!(hover.info.is_exact(), true); | ||
599 | } | 569 | } |
600 | 570 | ||
601 | #[test] | 571 | #[test] |
@@ -618,7 +588,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
618 | ); | 588 | ); |
619 | let hover = analysis.hover(position).unwrap().unwrap(); | 589 | let hover = analysis.hover(position).unwrap().unwrap(); |
620 | assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32")); | 590 | assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32")); |
621 | assert_eq!(hover.info.is_exact(), true); | ||
622 | } | 591 | } |
623 | 592 | ||
624 | #[test] | 593 | #[test] |
@@ -635,7 +604,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
635 | ); | 604 | ); |
636 | let hover = analysis.hover(position).unwrap().unwrap(); | 605 | let hover = analysis.hover(position).unwrap().unwrap(); |
637 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); | 606 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); |
638 | assert_eq!(hover.info.is_exact(), true); | ||
639 | 607 | ||
640 | /* FIXME: revive these tests | 608 | /* FIXME: revive these tests |
641 | let (analysis, position) = single_file_with_position( | 609 | let (analysis, position) = single_file_with_position( |
@@ -651,7 +619,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
651 | 619 | ||
652 | let hover = analysis.hover(position).unwrap().unwrap(); | 620 | let hover = analysis.hover(position).unwrap().unwrap(); |
653 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); | 621 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); |
654 | assert_eq!(hover.info.is_exact(), true); | ||
655 | 622 | ||
656 | let (analysis, position) = single_file_with_position( | 623 | let (analysis, position) = single_file_with_position( |
657 | " | 624 | " |
@@ -665,7 +632,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
665 | ); | 632 | ); |
666 | let hover = analysis.hover(position).unwrap().unwrap(); | 633 | let hover = analysis.hover(position).unwrap().unwrap(); |
667 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); | 634 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); |
668 | assert_eq!(hover.info.is_exact(), true); | ||
669 | 635 | ||
670 | let (analysis, position) = single_file_with_position( | 636 | let (analysis, position) = single_file_with_position( |
671 | " | 637 | " |
@@ -678,7 +644,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
678 | ); | 644 | ); |
679 | let hover = analysis.hover(position).unwrap().unwrap(); | 645 | let hover = analysis.hover(position).unwrap().unwrap(); |
680 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); | 646 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); |
681 | assert_eq!(hover.info.is_exact(), true); | ||
682 | */ | 647 | */ |
683 | } | 648 | } |
684 | 649 | ||
@@ -696,7 +661,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
696 | ); | 661 | ); |
697 | let hover = analysis.hover(position).unwrap().unwrap(); | 662 | let hover = analysis.hover(position).unwrap().unwrap(); |
698 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 663 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); |
699 | assert_eq!(hover.info.is_exact(), true); | ||
700 | } | 664 | } |
701 | 665 | ||
702 | #[test] | 666 | #[test] |
@@ -714,7 +678,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
714 | ); | 678 | ); |
715 | let hover = analysis.hover(position).unwrap().unwrap(); | 679 | let hover = analysis.hover(position).unwrap().unwrap(); |
716 | assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); | 680 | assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); |
717 | assert_eq!(hover.info.is_exact(), true); | ||
718 | } | 681 | } |
719 | 682 | ||
720 | #[test] | 683 | #[test] |
@@ -726,7 +689,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
726 | ); | 689 | ); |
727 | let hover = analysis.hover(position).unwrap().unwrap(); | 690 | let hover = analysis.hover(position).unwrap().unwrap(); |
728 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 691 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); |
729 | assert_eq!(hover.info.is_exact(), true); | ||
730 | } | 692 | } |
731 | 693 | ||
732 | #[test] | 694 | #[test] |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index e9af80b6c..5ab06c6cf 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -473,9 +473,10 @@ impl Analysis { | |||
473 | pub fn structural_search_replace( | 473 | pub fn structural_search_replace( |
474 | &self, | 474 | &self, |
475 | query: &str, | 475 | query: &str, |
476 | parse_only: bool, | ||
476 | ) -> Cancelable<Result<SourceChange, SsrError>> { | 477 | ) -> Cancelable<Result<SourceChange, SsrError>> { |
477 | self.with_db(|db| { | 478 | self.with_db(|db| { |
478 | let edits = ssr::parse_search_replace(query, db)?; | 479 | let edits = ssr::parse_search_replace(query, parse_only, db)?; |
479 | Ok(SourceChange::source_file_edits("ssr", edits)) | 480 | Ok(SourceChange::source_file_edits("ssr", edits)) |
480 | }) | 481 | }) |
481 | } | 482 | } |
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index c011a2e74..1c9710a5d 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! structural search replace | 1 | //! structural search replace |
2 | 2 | ||
3 | use crate::source_change::SourceFileEdit; | 3 | use crate::source_change::SourceFileEdit; |
4 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | ||
5 | use ra_ide_db::symbol_index::SymbolsDatabase; | ||
4 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
5 | use ra_syntax::ast::make::expr_from_text; | 7 | use ra_syntax::ast::make::try_expr_from_text; |
6 | use ra_syntax::ast::{AstToken, Comment}; | 8 | use ra_syntax::ast::{AstToken, Comment}; |
7 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; | 9 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; |
8 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 10 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
@@ -10,9 +12,6 @@ use rustc_hash::FxHashMap; | |||
10 | use std::collections::HashMap; | 12 | use std::collections::HashMap; |
11 | use std::str::FromStr; | 13 | use std::str::FromStr; |
12 | 14 | ||
13 | pub use ra_db::{SourceDatabase, SourceDatabaseExt}; | ||
14 | use ra_ide_db::symbol_index::SymbolsDatabase; | ||
15 | |||
16 | #[derive(Debug, PartialEq)] | 15 | #[derive(Debug, PartialEq)] |
17 | pub struct SsrError(String); | 16 | pub struct SsrError(String); |
18 | 17 | ||
@@ -26,14 +25,17 @@ impl std::error::Error for SsrError {} | |||
26 | 25 | ||
27 | pub fn parse_search_replace( | 26 | pub fn parse_search_replace( |
28 | query: &str, | 27 | query: &str, |
28 | parse_only: bool, | ||
29 | db: &RootDatabase, | 29 | db: &RootDatabase, |
30 | ) -> Result<Vec<SourceFileEdit>, SsrError> { | 30 | ) -> Result<Vec<SourceFileEdit>, SsrError> { |
31 | let mut edits = vec![]; | 31 | let mut edits = vec![]; |
32 | let query: SsrQuery = query.parse()?; | 32 | let query: SsrQuery = query.parse()?; |
33 | if parse_only { | ||
34 | return Ok(edits); | ||
35 | } | ||
33 | for &root in db.local_roots().iter() { | 36 | for &root in db.local_roots().iter() { |
34 | let sr = db.source_root(root); | 37 | let sr = db.source_root(root); |
35 | for file_id in sr.walk() { | 38 | for file_id in sr.walk() { |
36 | dbg!(db.file_relative_path(file_id)); | ||
37 | let matches = find(&query.pattern, db.parse(file_id).tree().syntax()); | 39 | let matches = find(&query.pattern, db.parse(file_id).tree().syntax()); |
38 | if !matches.matches.is_empty() { | 40 | if !matches.matches.is_empty() { |
39 | edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) }); | 41 | edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) }); |
@@ -106,7 +108,10 @@ impl FromStr for SsrQuery { | |||
106 | template = replace_in_template(template, var, new_var); | 108 | template = replace_in_template(template, var, new_var); |
107 | } | 109 | } |
108 | 110 | ||
109 | let template = expr_from_text(&template).syntax().clone(); | 111 | let template = try_expr_from_text(&template) |
112 | .ok_or(SsrError("Template is not an expression".into()))? | ||
113 | .syntax() | ||
114 | .clone(); | ||
110 | let mut placeholders = FxHashMap::default(); | 115 | let mut placeholders = FxHashMap::default(); |
111 | 116 | ||
112 | traverse(&template, &mut |n| { | 117 | traverse(&template, &mut |n| { |
@@ -118,7 +123,13 @@ impl FromStr for SsrQuery { | |||
118 | } | 123 | } |
119 | }); | 124 | }); |
120 | 125 | ||
121 | let pattern = SsrPattern { pattern: expr_from_text(&pattern).syntax().clone(), vars }; | 126 | let pattern = SsrPattern { |
127 | pattern: try_expr_from_text(&pattern) | ||
128 | .ok_or(SsrError("Pattern is not an expression".into()))? | ||
129 | .syntax() | ||
130 | .clone(), | ||
131 | vars, | ||
132 | }; | ||
122 | let template = SsrTemplate { template, placeholders }; | 133 | let template = SsrTemplate { template, placeholders }; |
123 | Ok(SsrQuery { pattern, template }) | 134 | Ok(SsrQuery { pattern, template }) |
124 | } | 135 | } |
@@ -284,7 +295,6 @@ mod tests { | |||
284 | assert_eq!(result.pattern.vars[0].0, "__search_pattern_a"); | 295 | assert_eq!(result.pattern.vars[0].0, "__search_pattern_a"); |
285 | assert_eq!(result.pattern.vars[1].0, "__search_pattern_b"); | 296 | assert_eq!(result.pattern.vars[1].0, "__search_pattern_b"); |
286 | assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)"); | 297 | assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)"); |
287 | dbg!(result.template.placeholders); | ||
288 | } | 298 | } |
289 | 299 | ||
290 | #[test] | 300 | #[test] |
@@ -335,6 +345,16 @@ mod tests { | |||
335 | } | 345 | } |
336 | 346 | ||
337 | #[test] | 347 | #[test] |
348 | fn parser_invlid_pattern() { | ||
349 | assert_eq!(parse_error_text(" ==>> ()"), "Parse error: Pattern is not an expression"); | ||
350 | } | ||
351 | |||
352 | #[test] | ||
353 | fn parser_invlid_template() { | ||
354 | assert_eq!(parse_error_text("() ==>> )"), "Parse error: Template is not an expression"); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
338 | fn parse_match_replace() { | 358 | fn parse_match_replace() { |
339 | let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap(); | 359 | let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap(); |
340 | let input = "fn main() { foo(1+2); }"; | 360 | let input = "fn main() { foo(1+2); }"; |
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs index 55966daf3..f58e436d1 100644 --- a/crates/ra_ide/src/syntax_tree.rs +++ b/crates/ra_ide/src/syntax_tree.rs | |||
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase; | |||
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo, AstNode, NodeOrToken, SourceFile, | 6 | algo, AstNode, NodeOrToken, SourceFile, |
7 | SyntaxKind::{RAW_STRING, STRING}, | 7 | SyntaxKind::{RAW_STRING, STRING}, |
8 | SyntaxToken, TextRange, | 8 | SyntaxToken, TextRange, TextUnit, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | pub use ra_db::FileId; | 11 | pub use ra_db::FileId; |
@@ -56,19 +56,23 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St | |||
56 | let start = text_range.start() - node_range.start(); | 56 | let start = text_range.start() - node_range.start(); |
57 | 57 | ||
58 | // how many characters we have selected | 58 | // how many characters we have selected |
59 | let len = text_range.len().to_usize(); | 59 | let len = text_range.len(); |
60 | 60 | ||
61 | let node_len = node_range.len().to_usize(); | 61 | let node_len = node_range.len(); |
62 | 62 | ||
63 | let start = start.to_usize(); | 63 | let start = start; |
64 | 64 | ||
65 | // We want to cap our length | 65 | // We want to cap our length |
66 | let len = len.min(node_len); | 66 | let len = len.min(node_len); |
67 | 67 | ||
68 | // Ensure our slice is inside the actual string | 68 | // Ensure our slice is inside the actual string |
69 | let end = if start + len < text.len() { start + len } else { text.len() - start }; | 69 | let end = if start + len < TextUnit::of_str(&text) { |
70 | start + len | ||
71 | } else { | ||
72 | TextUnit::of_str(&text) - start | ||
73 | }; | ||
70 | 74 | ||
71 | let text = &text[start..end]; | 75 | let text = &text[TextRange::from_to(start, end)]; |
72 | 76 | ||
73 | // Remove possible extra string quotes from the start | 77 | // Remove possible extra string quotes from the start |
74 | // and the end of the string | 78 | // and the end of the string |
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 53c65f8bc..cb2cd2479 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -213,14 +213,14 @@ fn foo() { | |||
213 | type_char( | 213 | type_char( |
214 | '.', | 214 | '.', |
215 | r" | 215 | r" |
216 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 216 | fn main() { |
217 | self.child_impl(db, name) | 217 | xs.foo() |
218 | <|> | 218 | <|> |
219 | } | 219 | } |
220 | ", | 220 | ", |
221 | r" | 221 | r" |
222 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 222 | fn main() { |
223 | self.child_impl(db, name) | 223 | xs.foo() |
224 | . | 224 | . |
225 | } | 225 | } |
226 | ", | 226 | ", |
@@ -228,8 +228,8 @@ fn foo() { | |||
228 | type_char_noop( | 228 | type_char_noop( |
229 | '.', | 229 | '.', |
230 | r" | 230 | r" |
231 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 231 | fn main() { |
232 | self.child_impl(db, name) | 232 | xs.foo() |
233 | <|> | 233 | <|> |
234 | } | 234 | } |
235 | ", | 235 | ", |
@@ -241,14 +241,14 @@ fn foo() { | |||
241 | type_char( | 241 | type_char( |
242 | '.', | 242 | '.', |
243 | r" | 243 | r" |
244 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 244 | fn main() { |
245 | self.child_impl(db, name) | 245 | xs.foo() |
246 | <|>; | 246 | <|>; |
247 | } | 247 | } |
248 | ", | 248 | ", |
249 | r" | 249 | r" |
250 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 250 | fn main() { |
251 | self.child_impl(db, name) | 251 | xs.foo() |
252 | .; | 252 | .; |
253 | } | 253 | } |
254 | ", | 254 | ", |
@@ -256,8 +256,8 @@ fn foo() { | |||
256 | type_char_noop( | 256 | type_char_noop( |
257 | '.', | 257 | '.', |
258 | r" | 258 | r" |
259 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 259 | fn main() { |
260 | self.child_impl(db, name) | 260 | xs.foo() |
261 | <|>; | 261 | <|>; |
262 | } | 262 | } |
263 | ", | 263 | ", |
@@ -269,15 +269,15 @@ fn foo() { | |||
269 | type_char( | 269 | type_char( |
270 | '.', | 270 | '.', |
271 | r" | 271 | r" |
272 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 272 | fn main() { |
273 | self.child_impl(db, name) | 273 | xs.foo() |
274 | .first() | 274 | .first() |
275 | <|> | 275 | <|> |
276 | } | 276 | } |
277 | ", | 277 | ", |
278 | r" | 278 | r" |
279 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 279 | fn main() { |
280 | self.child_impl(db, name) | 280 | xs.foo() |
281 | .first() | 281 | .first() |
282 | . | 282 | . |
283 | } | 283 | } |
@@ -286,8 +286,8 @@ fn foo() { | |||
286 | type_char_noop( | 286 | type_char_noop( |
287 | '.', | 287 | '.', |
288 | r" | 288 | r" |
289 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 289 | fn main() { |
290 | self.child_impl(db, name) | 290 | xs.foo() |
291 | .first() | 291 | .first() |
292 | <|> | 292 | <|> |
293 | } | 293 | } |
@@ -334,7 +334,7 @@ fn foo() { | |||
334 | type_char_noop( | 334 | type_char_noop( |
335 | '.', | 335 | '.', |
336 | r" | 336 | r" |
337 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 337 | fn main() { |
338 | <|> | 338 | <|> |
339 | } | 339 | } |
340 | ", | 340 | ", |
@@ -342,7 +342,7 @@ fn foo() { | |||
342 | type_char_noop( | 342 | type_char_noop( |
343 | '.', | 343 | '.', |
344 | r" | 344 | r" |
345 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 345 | fn main() { |
346 | <|> | 346 | <|> |
347 | } | 347 | } |
348 | ", | 348 | ", |
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs index b9db5c276..8ae745ff2 100644 --- a/crates/ra_ide_db/src/line_index.rs +++ b/crates/ra_ide_db/src/line_index.rs | |||
@@ -59,7 +59,7 @@ impl LineIndex { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | let char_len = TextUnit::of_char(c); | 61 | let char_len = TextUnit::of_char(c); |
62 | if char_len.to_usize() > 1 { | 62 | if char_len > TextUnit::from_usize(1) { |
63 | utf16_chars.push(Utf16Char { start: curr_col, end: curr_col + char_len }); | 63 | utf16_chars.push(Utf16Char { start: curr_col, end: curr_col + char_len }); |
64 | } | 64 | } |
65 | 65 | ||
@@ -101,12 +101,12 @@ impl LineIndex { | |||
101 | .filter(|it| !it.is_empty()) | 101 | .filter(|it| !it.is_empty()) |
102 | } | 102 | } |
103 | 103 | ||
104 | fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize { | 104 | fn utf8_to_utf16_col(&self, line: u32, col: TextUnit) -> usize { |
105 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { | 105 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { |
106 | let mut correction = TextUnit::from_usize(0); | 106 | let mut correction = 0; |
107 | for c in utf16_chars { | 107 | for c in utf16_chars { |
108 | if col >= c.end { | 108 | if col >= c.end { |
109 | correction += c.len() - TextUnit::from_usize(1); | 109 | correction += c.len().to_usize() - 1; |
110 | } else { | 110 | } else { |
111 | // From here on, all utf16 characters come *after* the character we are mapping, | 111 | // From here on, all utf16 characters come *after* the character we are mapping, |
112 | // so we don't need to take them into account | 112 | // so we don't need to take them into account |
@@ -114,10 +114,10 @@ impl LineIndex { | |||
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | col -= correction; | 117 | col.to_usize() - correction |
118 | } else { | ||
119 | col.to_usize() | ||
118 | } | 120 | } |
119 | |||
120 | col.to_usize() | ||
121 | } | 121 | } |
122 | 122 | ||
123 | fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextUnit { | 123 | fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextUnit { |
diff --git a/crates/ra_ide_db/src/line_index_utils.rs b/crates/ra_ide_db/src/line_index_utils.rs index 75a498151..2ebbabdc6 100644 --- a/crates/ra_ide_db/src/line_index_utils.rs +++ b/crates/ra_ide_db/src/line_index_utils.rs | |||
@@ -145,7 +145,7 @@ impl Iterator for OffsetStepIter<'_> { | |||
145 | Some((next, next_offset)) | 145 | Some((next, next_offset)) |
146 | } else { | 146 | } else { |
147 | let char_len = TextUnit::of_char(c); | 147 | let char_len = TextUnit::of_char(c); |
148 | if char_len.to_usize() > 1 { | 148 | if char_len > TextUnit::from_usize(1) { |
149 | let start = self.offset + TextUnit::from_usize(i); | 149 | let start = self.offset + TextUnit::from_usize(i); |
150 | let end = start + char_len; | 150 | let end = start + char_len; |
151 | let next = Step::Utf16Char(TextRange::from_to(start, end)); | 151 | let next = Step::Utf16Char(TextRange::from_to(start, end)); |
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs index 272661b1d..f0da173cc 100644 --- a/crates/ra_parser/src/grammar/params.rs +++ b/crates/ra_parser/src/grammar/params.rs | |||
@@ -56,21 +56,17 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
56 | // fn f(#[attr1] pat: Type) {} | 56 | // fn f(#[attr1] pat: Type) {} |
57 | attributes::outer_attributes(p); | 57 | attributes::outer_attributes(p); |
58 | 58 | ||
59 | // test param_list_vararg | ||
60 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | ||
61 | match flavor { | ||
62 | FnDef | FnPointer if p.eat(T![...]) => break, | ||
63 | _ => (), | ||
64 | } | ||
65 | |||
66 | if !p.at_ts(VALUE_PARAMETER_FIRST) { | 59 | if !p.at_ts(VALUE_PARAMETER_FIRST) { |
67 | p.error("expected value parameter"); | 60 | p.error("expected value parameter"); |
68 | break; | 61 | break; |
69 | } | 62 | } |
70 | value_parameter(p, flavor); | 63 | let param = value_parameter(p, flavor); |
71 | if !p.at(ket) { | 64 | if !p.at(ket) { |
72 | p.expect(T![,]); | 65 | p.expect(T![,]); |
73 | } | 66 | } |
67 | if let Variadic(true) = param { | ||
68 | break; | ||
69 | } | ||
74 | } | 70 | } |
75 | 71 | ||
76 | p.expect(ket); | 72 | p.expect(ket); |
@@ -79,32 +75,25 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
79 | 75 | ||
80 | const VALUE_PARAMETER_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | 76 | const VALUE_PARAMETER_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); |
81 | 77 | ||
82 | fn value_parameter(p: &mut Parser, flavor: Flavor) { | 78 | struct Variadic(bool); |
79 | |||
80 | fn value_parameter(p: &mut Parser, flavor: Flavor) -> Variadic { | ||
81 | let mut res = Variadic(false); | ||
83 | let m = p.start(); | 82 | let m = p.start(); |
84 | match flavor { | 83 | match flavor { |
85 | // test trait_fn_placeholder_parameter | 84 | // test param_list_vararg |
86 | // trait Foo { | 85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } |
87 | // fn bar(_: u64, mut x: i32); | 86 | Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true), |
88 | // } | ||
89 | |||
90 | // test trait_fn_patterns | ||
91 | // trait T { | ||
92 | // fn f1((a, b): (usize, usize)) {} | ||
93 | // fn f2(S { a, b }: S) {} | ||
94 | // fn f3(NewType(a): NewType) {} | ||
95 | // fn f4(&&a: &&usize) {} | ||
96 | // } | ||
97 | 87 | ||
98 | // test fn_patterns | 88 | // test fn_def_param |
99 | // impl U { | 89 | // fn foo((x, y): (i32, i32)) {} |
100 | // fn f1((a, b): (usize, usize)) {} | ||
101 | // fn f2(S { a, b }: S) {} | ||
102 | // fn f3(NewType(a): NewType) {} | ||
103 | // fn f4(&&a: &&usize) {} | ||
104 | // } | ||
105 | Flavor::FnDef => { | 90 | Flavor::FnDef => { |
106 | patterns::pattern(p); | 91 | patterns::pattern(p); |
107 | types::ascription(p); | 92 | if variadic_param(p) { |
93 | res = Variadic(true) | ||
94 | } else { | ||
95 | types::ascription(p); | ||
96 | } | ||
108 | } | 97 | } |
109 | // test value_parameters_no_patterns | 98 | // test value_parameters_no_patterns |
110 | // type F = Box<Fn(i32, &i32, &i32, ())>; | 99 | // type F = Box<Fn(i32, &i32, &i32, ())>; |
@@ -120,7 +109,11 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
120 | Flavor::FnPointer => { | 109 | Flavor::FnPointer => { |
121 | if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { | 110 | if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { |
122 | patterns::pattern_single(p); | 111 | patterns::pattern_single(p); |
123 | types::ascription(p); | 112 | if variadic_param(p) { |
113 | res = Variadic(true) | ||
114 | } else { | ||
115 | types::ascription(p); | ||
116 | } | ||
124 | } else { | 117 | } else { |
125 | types::type_(p); | 118 | types::type_(p); |
126 | } | 119 | } |
@@ -137,6 +130,17 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
137 | } | 130 | } |
138 | } | 131 | } |
139 | m.complete(p, PARAM); | 132 | m.complete(p, PARAM); |
133 | res | ||
134 | } | ||
135 | |||
136 | fn variadic_param(p: &mut Parser) -> bool { | ||
137 | if p.at(T![:]) && p.nth_at(1, T![...]) { | ||
138 | p.bump(T![:]); | ||
139 | p.bump(T![...]); | ||
140 | true | ||
141 | } else { | ||
142 | false | ||
143 | } | ||
140 | } | 144 | } |
141 | 145 | ||
142 | // test self_param | 146 | // test self_param |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index ae8829807..9f6f1cc53 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -112,10 +112,14 @@ pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { | |||
112 | let token = token(op); | 112 | let token = token(op); |
113 | expr_from_text(&format!("{}{}", token, expr.syntax())) | 113 | expr_from_text(&format!("{}{}", token, expr.syntax())) |
114 | } | 114 | } |
115 | pub fn expr_from_text(text: &str) -> ast::Expr { | 115 | fn expr_from_text(text: &str) -> ast::Expr { |
116 | ast_from_text(&format!("const C: () = {};", text)) | 116 | ast_from_text(&format!("const C: () = {};", text)) |
117 | } | 117 | } |
118 | 118 | ||
119 | pub fn try_expr_from_text(text: &str) -> Option<ast::Expr> { | ||
120 | try_ast_from_text(&format!("const C: () = {};", text)) | ||
121 | } | ||
122 | |||
119 | pub fn bind_pat(name: ast::Name) -> ast::BindPat { | 123 | pub fn bind_pat(name: ast::Name) -> ast::BindPat { |
120 | return from_text(name.text()); | 124 | return from_text(name.text()); |
121 | 125 | ||
@@ -239,6 +243,16 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
239 | node | 243 | node |
240 | } | 244 | } |
241 | 245 | ||
246 | fn try_ast_from_text<N: AstNode>(text: &str) -> Option<N> { | ||
247 | let parse = SourceFile::parse(text); | ||
248 | let node = parse.tree().syntax().descendants().find_map(N::cast)?; | ||
249 | let node = node.syntax().clone(); | ||
250 | let node = unroot(node); | ||
251 | let node = N::cast(node).unwrap(); | ||
252 | assert_eq!(node.syntax().text_range().start(), 0.into()); | ||
253 | Some(node) | ||
254 | } | ||
255 | |||
242 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 256 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
243 | SyntaxNode::new_root(n.green().clone()) | 257 | SyntaxNode::new_root(n.green().clone()) |
244 | } | 258 | } |
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs index f2684c852..d1baaa607 100644 --- a/crates/ra_syntax/src/parsing/lexer.rs +++ b/crates/ra_syntax/src/parsing/lexer.rs | |||
@@ -65,7 +65,7 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { | |||
65 | /// Beware that unescape errors are not checked at tokenization time. | 65 | /// Beware that unescape errors are not checked at tokenization time. |
66 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { | 66 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { |
67 | lex_first_token(text) | 67 | lex_first_token(text) |
68 | .filter(|(token, _)| token.len.to_usize() == text.len()) | 68 | .filter(|(token, _)| token.len == TextUnit::of_str(text)) |
69 | .map(|(token, error)| (token.kind, error)) | 69 | .map(|(token, error)| (token.kind, error)) |
70 | } | 70 | } |
71 | 71 | ||
@@ -75,7 +75,7 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr | |||
75 | /// Beware that unescape errors are not checked at tokenization time. | 75 | /// Beware that unescape errors are not checked at tokenization time. |
76 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { | 76 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { |
77 | lex_first_token(text) | 77 | lex_first_token(text) |
78 | .filter(|(token, error)| !error.is_some() && token.len.to_usize() == text.len()) | 78 | .filter(|(token, error)| !error.is_some() && token.len == TextUnit::of_str(text)) |
79 | .map(|(token, _error)| token.kind) | 79 | .map(|(token, _error)| token.kind) |
80 | } | 80 | } |
81 | 81 | ||
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs index 912e6aec0..6a8cb6bb5 100644 --- a/crates/ra_syntax/src/tests.rs +++ b/crates/ra_syntax/src/tests.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | 5 | ||
6 | use test_utils::{collect_tests, dir_tests, project_dir, read_text}; | 6 | use test_utils::{collect_tests, dir_tests, project_dir, read_text}; |
7 | 7 | ||
8 | use crate::{fuzz, tokenize, SourceFile, SyntaxError, Token}; | 8 | use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextUnit, Token}; |
9 | 9 | ||
10 | #[test] | 10 | #[test] |
11 | fn lexer_tests() { | 11 | fn lexer_tests() { |
@@ -34,6 +34,7 @@ fn main() { | |||
34 | "##; | 34 | "##; |
35 | 35 | ||
36 | let parse = SourceFile::parse(code); | 36 | let parse = SourceFile::parse(code); |
37 | // eprintln!("{:#?}", parse.syntax_node()); | ||
37 | assert!(parse.ok().is_ok()); | 38 | assert!(parse.ok().is_ok()); |
38 | } | 39 | } |
39 | 40 | ||
@@ -120,11 +121,11 @@ fn assert_errors_are_absent(errors: &[SyntaxError], path: &Path) { | |||
120 | 121 | ||
121 | fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) -> String { | 122 | fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) -> String { |
122 | let mut acc = String::new(); | 123 | let mut acc = String::new(); |
123 | let mut offset = 0; | 124 | let mut offset = TextUnit::from_usize(0); |
124 | for token in tokens { | 125 | for token in tokens { |
125 | let token_len = token.len.to_usize(); | 126 | let token_len = token.len; |
126 | let token_text = &text[offset..offset + token_len]; | 127 | let token_text = &text[TextRange::offset_len(offset, token.len)]; |
127 | offset += token_len; | 128 | offset += token.len; |
128 | writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap(); | 129 | writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap(); |
129 | } | 130 | } |
130 | for err in errors { | 131 | for err in errors { |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.txt b/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.txt index a0a8aea76..4c17f0db8 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.txt | |||
@@ -81,7 +81,8 @@ SOURCE_FILE@[0; 113) | |||
81 | WHITESPACE@[97; 98) " " | 81 | WHITESPACE@[97; 98) " " |
82 | COMMA@[98; 99) "," | 82 | COMMA@[98; 99) "," |
83 | WHITESPACE@[99; 100) " " | 83 | WHITESPACE@[99; 100) " " |
84 | DOTDOTDOT@[100; 103) "..." | 84 | PARAM@[100; 103) |
85 | DOTDOTDOT@[100; 103) "..." | ||
85 | WHITESPACE@[103; 104) " " | 86 | WHITESPACE@[103; 104) " " |
86 | R_PAREN@[104; 105) ")" | 87 | R_PAREN@[104; 105) ")" |
87 | WHITESPACE@[105; 106) " " | 88 | WHITESPACE@[105; 106) " " |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.rs b/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.rs deleted file mode 100644 index 472cb8803..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.rs +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | trait Foo { | ||
2 | fn bar(_: u64, mut x: i32); | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.txt b/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.txt deleted file mode 100644 index 158236c5a..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0116_trait_fn_placeholder_parameter.txt +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | SOURCE_FILE@[0; 46) | ||
2 | TRAIT_DEF@[0; 45) | ||
3 | TRAIT_KW@[0; 5) "trait" | ||
4 | WHITESPACE@[5; 6) " " | ||
5 | NAME@[6; 9) | ||
6 | IDENT@[6; 9) "Foo" | ||
7 | WHITESPACE@[9; 10) " " | ||
8 | ITEM_LIST@[10; 45) | ||
9 | L_CURLY@[10; 11) "{" | ||
10 | WHITESPACE@[11; 16) "\n " | ||
11 | FN_DEF@[16; 43) | ||
12 | FN_KW@[16; 18) "fn" | ||
13 | WHITESPACE@[18; 19) " " | ||
14 | NAME@[19; 22) | ||
15 | IDENT@[19; 22) "bar" | ||
16 | PARAM_LIST@[22; 42) | ||
17 | L_PAREN@[22; 23) "(" | ||
18 | PARAM@[23; 29) | ||
19 | PLACEHOLDER_PAT@[23; 24) | ||
20 | UNDERSCORE@[23; 24) "_" | ||
21 | COLON@[24; 25) ":" | ||
22 | WHITESPACE@[25; 26) " " | ||
23 | PATH_TYPE@[26; 29) | ||
24 | PATH@[26; 29) | ||
25 | PATH_SEGMENT@[26; 29) | ||
26 | NAME_REF@[26; 29) | ||
27 | IDENT@[26; 29) "u64" | ||
28 | COMMA@[29; 30) "," | ||
29 | WHITESPACE@[30; 31) " " | ||
30 | PARAM@[31; 41) | ||
31 | BIND_PAT@[31; 36) | ||
32 | MUT_KW@[31; 34) "mut" | ||
33 | WHITESPACE@[34; 35) " " | ||
34 | NAME@[35; 36) | ||
35 | IDENT@[35; 36) "x" | ||
36 | COLON@[36; 37) ":" | ||
37 | WHITESPACE@[37; 38) " " | ||
38 | PATH_TYPE@[38; 41) | ||
39 | PATH@[38; 41) | ||
40 | PATH_SEGMENT@[38; 41) | ||
41 | NAME_REF@[38; 41) | ||
42 | IDENT@[38; 41) "i32" | ||
43 | R_PAREN@[41; 42) ")" | ||
44 | SEMI@[42; 43) ";" | ||
45 | WHITESPACE@[43; 44) "\n" | ||
46 | R_CURLY@[44; 45) "}" | ||
47 | WHITESPACE@[45; 46) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.txt b/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.txt index 836e8e55b..6c3b17868 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.txt | |||
@@ -32,7 +32,8 @@ SOURCE_FILE@[0; 57) | |||
32 | IDENT@[38; 40) "i8" | 32 | IDENT@[38; 40) "i8" |
33 | COMMA@[40; 41) "," | 33 | COMMA@[40; 41) "," |
34 | WHITESPACE@[41; 42) " " | 34 | WHITESPACE@[41; 42) " " |
35 | DOTDOTDOT@[42; 45) "..." | 35 | PARAM@[42; 45) |
36 | DOTDOTDOT@[42; 45) "..." | ||
36 | R_PAREN@[45; 46) ")" | 37 | R_PAREN@[45; 46) ")" |
37 | WHITESPACE@[46; 47) " " | 38 | WHITESPACE@[46; 47) " " |
38 | RET_TYPE@[47; 53) | 39 | RET_TYPE@[47; 53) |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rs b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rs new file mode 100644 index 000000000..7b277c16b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rs | |||
@@ -0,0 +1 @@ | |||
fn foo((x, y): (i32, i32)) {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.txt b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.txt new file mode 100644 index 000000000..103e254a6 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | SOURCE_FILE@[0; 30) | ||
2 | FN_DEF@[0; 29) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 26) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | PARAM@[7; 25) | ||
10 | TUPLE_PAT@[7; 13) | ||
11 | L_PAREN@[7; 8) "(" | ||
12 | BIND_PAT@[8; 9) | ||
13 | NAME@[8; 9) | ||
14 | IDENT@[8; 9) "x" | ||
15 | COMMA@[9; 10) "," | ||
16 | WHITESPACE@[10; 11) " " | ||
17 | BIND_PAT@[11; 12) | ||
18 | NAME@[11; 12) | ||
19 | IDENT@[11; 12) "y" | ||
20 | R_PAREN@[12; 13) ")" | ||
21 | COLON@[13; 14) ":" | ||
22 | WHITESPACE@[14; 15) " " | ||
23 | TUPLE_TYPE@[15; 25) | ||
24 | L_PAREN@[15; 16) "(" | ||
25 | PATH_TYPE@[16; 19) | ||
26 | PATH@[16; 19) | ||
27 | PATH_SEGMENT@[16; 19) | ||
28 | NAME_REF@[16; 19) | ||
29 | IDENT@[16; 19) "i32" | ||
30 | COMMA@[19; 20) "," | ||
31 | WHITESPACE@[20; 21) " " | ||
32 | PATH_TYPE@[21; 24) | ||
33 | PATH@[21; 24) | ||
34 | PATH_SEGMENT@[21; 24) | ||
35 | NAME_REF@[21; 24) | ||
36 | IDENT@[21; 24) "i32" | ||
37 | R_PAREN@[24; 25) ")" | ||
38 | R_PAREN@[25; 26) ")" | ||
39 | WHITESPACE@[26; 27) " " | ||
40 | BLOCK_EXPR@[27; 29) | ||
41 | BLOCK@[27; 29) | ||
42 | L_CURLY@[27; 28) "{" | ||
43 | R_CURLY@[28; 29) "}" | ||
44 | WHITESPACE@[29; 30) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt index 719c99c17..254eafc36 100644 --- a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt +++ b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt | |||
@@ -118,7 +118,8 @@ SOURCE_FILE@[0; 519) | |||
118 | IDENT@[108; 112) "attr" | 118 | IDENT@[108; 112) "attr" |
119 | R_BRACK@[112; 113) "]" | 119 | R_BRACK@[112; 113) "]" |
120 | WHITESPACE@[113; 114) " " | 120 | WHITESPACE@[113; 114) " " |
121 | DOTDOTDOT@[114; 117) "..." | 121 | PARAM@[114; 117) |
122 | DOTDOTDOT@[114; 117) "..." | ||
122 | R_PAREN@[117; 118) ")" | 123 | R_PAREN@[117; 118) ")" |
123 | WHITESPACE@[118; 119) " " | 124 | WHITESPACE@[118; 119) " " |
124 | RET_TYPE@[119; 125) | 125 | RET_TYPE@[119; 125) |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rs index a94bf378a..3b666af8e 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs +++ b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rs | |||
@@ -3,4 +3,5 @@ trait T { | |||
3 | fn f2(S { a, b }: S) {} | 3 | fn f2(S { a, b }: S) {} |
4 | fn f3(NewType(a): NewType) {} | 4 | fn f3(NewType(a): NewType) {} |
5 | fn f4(&&a: &&usize) {} | 5 | fn f4(&&a: &&usize) {} |
6 | fn bar(_: u64, mut x: i32); | ||
6 | } | 7 | } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.txt index b22df8dbe..eb2e3a503 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt +++ b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.txt | |||
@@ -1,11 +1,11 @@ | |||
1 | SOURCE_FILE@[0; 138) | 1 | SOURCE_FILE@[0; 170) |
2 | TRAIT_DEF@[0; 137) | 2 | TRAIT_DEF@[0; 169) |
3 | TRAIT_KW@[0; 5) "trait" | 3 | TRAIT_KW@[0; 5) "trait" |
4 | WHITESPACE@[5; 6) " " | 4 | WHITESPACE@[5; 6) " " |
5 | NAME@[6; 7) | 5 | NAME@[6; 7) |
6 | IDENT@[6; 7) "T" | 6 | IDENT@[6; 7) "T" |
7 | WHITESPACE@[7; 8) " " | 7 | WHITESPACE@[7; 8) " " |
8 | ITEM_LIST@[8; 137) | 8 | ITEM_LIST@[8; 169) |
9 | L_CURLY@[8; 9) "{" | 9 | L_CURLY@[8; 9) "{" |
10 | WHITESPACE@[9; 14) "\n " | 10 | WHITESPACE@[9; 14) "\n " |
11 | FN_DEF@[14; 46) | 11 | FN_DEF@[14; 46) |
@@ -156,6 +156,41 @@ SOURCE_FILE@[0; 138) | |||
156 | BLOCK@[133; 135) | 156 | BLOCK@[133; 135) |
157 | L_CURLY@[133; 134) "{" | 157 | L_CURLY@[133; 134) "{" |
158 | R_CURLY@[134; 135) "}" | 158 | R_CURLY@[134; 135) "}" |
159 | WHITESPACE@[135; 136) "\n" | 159 | WHITESPACE@[135; 140) "\n " |
160 | R_CURLY@[136; 137) "}" | 160 | FN_DEF@[140; 167) |
161 | WHITESPACE@[137; 138) "\n" | 161 | FN_KW@[140; 142) "fn" |
162 | WHITESPACE@[142; 143) " " | ||
163 | NAME@[143; 146) | ||
164 | IDENT@[143; 146) "bar" | ||
165 | PARAM_LIST@[146; 166) | ||
166 | L_PAREN@[146; 147) "(" | ||
167 | PARAM@[147; 153) | ||
168 | PLACEHOLDER_PAT@[147; 148) | ||
169 | UNDERSCORE@[147; 148) "_" | ||
170 | COLON@[148; 149) ":" | ||
171 | WHITESPACE@[149; 150) " " | ||
172 | PATH_TYPE@[150; 153) | ||
173 | PATH@[150; 153) | ||
174 | PATH_SEGMENT@[150; 153) | ||
175 | NAME_REF@[150; 153) | ||
176 | IDENT@[150; 153) "u64" | ||
177 | COMMA@[153; 154) "," | ||
178 | WHITESPACE@[154; 155) " " | ||
179 | PARAM@[155; 165) | ||
180 | BIND_PAT@[155; 160) | ||
181 | MUT_KW@[155; 158) "mut" | ||
182 | WHITESPACE@[158; 159) " " | ||
183 | NAME@[159; 160) | ||
184 | IDENT@[159; 160) "x" | ||
185 | COLON@[160; 161) ":" | ||
186 | WHITESPACE@[161; 162) " " | ||
187 | PATH_TYPE@[162; 165) | ||
188 | PATH@[162; 165) | ||
189 | PATH_SEGMENT@[162; 165) | ||
190 | NAME_REF@[162; 165) | ||
191 | IDENT@[162; 165) "i32" | ||
192 | R_PAREN@[165; 166) ")" | ||
193 | SEMI@[166; 167) ";" | ||
194 | WHITESPACE@[167; 168) "\n" | ||
195 | R_CURLY@[168; 169) "}" | ||
196 | WHITESPACE@[169; 170) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rs b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rs new file mode 100644 index 000000000..a16afbaf3 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | extern "C" { | ||
2 | fn a(_: *mut u8, ...,); | ||
3 | fn b(_: *mut u8, _: ...); | ||
4 | fn c(_: *mut u8, #[cfg(never)] [w, t, f]: ...,); | ||
5 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.txt b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.txt new file mode 100644 index 000000000..186f03626 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.txt | |||
@@ -0,0 +1,133 @@ | |||
1 | SOURCE_FILE@[0; 126) | ||
2 | EXTERN_BLOCK@[0; 125) | ||
3 | ABI@[0; 10) | ||
4 | EXTERN_KW@[0; 6) "extern" | ||
5 | WHITESPACE@[6; 7) " " | ||
6 | STRING@[7; 10) "\"C\"" | ||
7 | WHITESPACE@[10; 11) " " | ||
8 | EXTERN_ITEM_LIST@[11; 125) | ||
9 | L_CURLY@[11; 12) "{" | ||
10 | WHITESPACE@[12; 17) "\n " | ||
11 | FN_DEF@[17; 40) | ||
12 | FN_KW@[17; 19) "fn" | ||
13 | WHITESPACE@[19; 20) " " | ||
14 | NAME@[20; 21) | ||
15 | IDENT@[20; 21) "a" | ||
16 | PARAM_LIST@[21; 39) | ||
17 | L_PAREN@[21; 22) "(" | ||
18 | PARAM@[22; 32) | ||
19 | PLACEHOLDER_PAT@[22; 23) | ||
20 | UNDERSCORE@[22; 23) "_" | ||
21 | COLON@[23; 24) ":" | ||
22 | WHITESPACE@[24; 25) " " | ||
23 | POINTER_TYPE@[25; 32) | ||
24 | STAR@[25; 26) "*" | ||
25 | MUT_KW@[26; 29) "mut" | ||
26 | WHITESPACE@[29; 30) " " | ||
27 | PATH_TYPE@[30; 32) | ||
28 | PATH@[30; 32) | ||
29 | PATH_SEGMENT@[30; 32) | ||
30 | NAME_REF@[30; 32) | ||
31 | IDENT@[30; 32) "u8" | ||
32 | COMMA@[32; 33) "," | ||
33 | WHITESPACE@[33; 34) " " | ||
34 | PARAM@[34; 37) | ||
35 | DOTDOTDOT@[34; 37) "..." | ||
36 | COMMA@[37; 38) "," | ||
37 | R_PAREN@[38; 39) ")" | ||
38 | SEMI@[39; 40) ";" | ||
39 | WHITESPACE@[40; 45) "\n " | ||
40 | FN_DEF@[45; 70) | ||
41 | FN_KW@[45; 47) "fn" | ||
42 | WHITESPACE@[47; 48) " " | ||
43 | NAME@[48; 49) | ||
44 | IDENT@[48; 49) "b" | ||
45 | PARAM_LIST@[49; 69) | ||
46 | L_PAREN@[49; 50) "(" | ||
47 | PARAM@[50; 60) | ||
48 | PLACEHOLDER_PAT@[50; 51) | ||
49 | UNDERSCORE@[50; 51) "_" | ||
50 | COLON@[51; 52) ":" | ||
51 | WHITESPACE@[52; 53) " " | ||
52 | POINTER_TYPE@[53; 60) | ||
53 | STAR@[53; 54) "*" | ||
54 | MUT_KW@[54; 57) "mut" | ||
55 | WHITESPACE@[57; 58) " " | ||
56 | PATH_TYPE@[58; 60) | ||
57 | PATH@[58; 60) | ||
58 | PATH_SEGMENT@[58; 60) | ||
59 | NAME_REF@[58; 60) | ||
60 | IDENT@[58; 60) "u8" | ||
61 | COMMA@[60; 61) "," | ||
62 | WHITESPACE@[61; 62) " " | ||
63 | PARAM@[62; 68) | ||
64 | PLACEHOLDER_PAT@[62; 63) | ||
65 | UNDERSCORE@[62; 63) "_" | ||
66 | COLON@[63; 64) ":" | ||
67 | WHITESPACE@[64; 65) " " | ||
68 | DOTDOTDOT@[65; 68) "..." | ||
69 | R_PAREN@[68; 69) ")" | ||
70 | SEMI@[69; 70) ";" | ||
71 | WHITESPACE@[70; 75) "\n " | ||
72 | FN_DEF@[75; 123) | ||
73 | FN_KW@[75; 77) "fn" | ||
74 | WHITESPACE@[77; 78) " " | ||
75 | NAME@[78; 79) | ||
76 | IDENT@[78; 79) "c" | ||
77 | PARAM_LIST@[79; 122) | ||
78 | L_PAREN@[79; 80) "(" | ||
79 | PARAM@[80; 90) | ||
80 | PLACEHOLDER_PAT@[80; 81) | ||
81 | UNDERSCORE@[80; 81) "_" | ||
82 | COLON@[81; 82) ":" | ||
83 | WHITESPACE@[82; 83) " " | ||
84 | POINTER_TYPE@[83; 90) | ||
85 | STAR@[83; 84) "*" | ||
86 | MUT_KW@[84; 87) "mut" | ||
87 | WHITESPACE@[87; 88) " " | ||
88 | PATH_TYPE@[88; 90) | ||
89 | PATH@[88; 90) | ||
90 | PATH_SEGMENT@[88; 90) | ||
91 | NAME_REF@[88; 90) | ||
92 | IDENT@[88; 90) "u8" | ||
93 | COMMA@[90; 91) "," | ||
94 | WHITESPACE@[91; 92) " " | ||
95 | ATTR@[92; 105) | ||
96 | POUND@[92; 93) "#" | ||
97 | L_BRACK@[93; 94) "[" | ||
98 | PATH@[94; 97) | ||
99 | PATH_SEGMENT@[94; 97) | ||
100 | NAME_REF@[94; 97) | ||
101 | IDENT@[94; 97) "cfg" | ||
102 | TOKEN_TREE@[97; 104) | ||
103 | L_PAREN@[97; 98) "(" | ||
104 | IDENT@[98; 103) "never" | ||
105 | R_PAREN@[103; 104) ")" | ||
106 | R_BRACK@[104; 105) "]" | ||
107 | WHITESPACE@[105; 106) " " | ||
108 | PARAM@[106; 120) | ||
109 | SLICE_PAT@[106; 115) | ||
110 | L_BRACK@[106; 107) "[" | ||
111 | BIND_PAT@[107; 108) | ||
112 | NAME@[107; 108) | ||
113 | IDENT@[107; 108) "w" | ||
114 | COMMA@[108; 109) "," | ||
115 | WHITESPACE@[109; 110) " " | ||
116 | BIND_PAT@[110; 111) | ||
117 | NAME@[110; 111) | ||
118 | IDENT@[110; 111) "t" | ||
119 | COMMA@[111; 112) "," | ||
120 | WHITESPACE@[112; 113) " " | ||
121 | BIND_PAT@[113; 114) | ||
122 | NAME@[113; 114) | ||
123 | IDENT@[113; 114) "f" | ||
124 | R_BRACK@[114; 115) "]" | ||
125 | COLON@[115; 116) ":" | ||
126 | WHITESPACE@[116; 117) " " | ||
127 | DOTDOTDOT@[117; 120) "..." | ||
128 | COMMA@[120; 121) "," | ||
129 | R_PAREN@[121; 122) ")" | ||
130 | SEMI@[122; 123) ";" | ||
131 | WHITESPACE@[123; 124) "\n" | ||
132 | R_CURLY@[124; 125) "}" | ||
133 | WHITESPACE@[125; 126) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rs index b49e872d7..b49e872d7 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs +++ b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rs | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.txt index b30030de3..b30030de3 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt +++ b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.txt | |||
diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs index 3291ada42..5c37a08a8 100644 --- a/crates/ra_text_edit/src/text_edit.rs +++ b/crates/ra_text_edit/src/text_edit.rs | |||
@@ -63,12 +63,12 @@ impl TextEdit { | |||
63 | } | 63 | } |
64 | 64 | ||
65 | pub fn apply(&self, text: &str) -> String { | 65 | pub fn apply(&self, text: &str) -> String { |
66 | let mut total_len = text.len(); | 66 | let mut total_len = TextUnit::of_str(text); |
67 | for atom in self.atoms.iter() { | 67 | for atom in self.atoms.iter() { |
68 | total_len += atom.insert.len(); | 68 | total_len += TextUnit::of_str(&atom.insert); |
69 | total_len -= (atom.delete.end() - atom.delete.start()).to_usize(); | 69 | total_len -= atom.delete.end() - atom.delete.start(); |
70 | } | 70 | } |
71 | let mut buf = String::with_capacity(total_len); | 71 | let mut buf = String::with_capacity(total_len.to_usize()); |
72 | let mut prev = 0; | 72 | let mut prev = 0; |
73 | for atom in self.atoms.iter() { | 73 | for atom in self.atoms.iter() { |
74 | let start = atom.delete.start().to_usize(); | 74 | let start = atom.delete.start().to_usize(); |
@@ -80,7 +80,7 @@ impl TextEdit { | |||
80 | prev = end; | 80 | prev = end; |
81 | } | 81 | } |
82 | buf.push_str(&text[prev..text.len()]); | 82 | buf.push_str(&text[prev..text.len()]); |
83 | assert_eq!(buf.len(), total_len); | 83 | assert_eq!(TextUnit::of_str(&buf), total_len); |
84 | buf | 84 | buf |
85 | } | 85 | } |
86 | 86 | ||
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 53751aafb..321861b16 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -19,50 +19,48 @@ impl CargoTargetSpec { | |||
19 | pub(crate) fn runnable_args( | 19 | pub(crate) fn runnable_args( |
20 | spec: Option<CargoTargetSpec>, | 20 | spec: Option<CargoTargetSpec>, |
21 | kind: &RunnableKind, | 21 | kind: &RunnableKind, |
22 | ) -> Result<Vec<String>> { | 22 | ) -> Result<(Vec<String>, Vec<String>)> { |
23 | let mut res = Vec::new(); | 23 | let mut args = Vec::new(); |
24 | let mut extra_args = Vec::new(); | ||
24 | match kind { | 25 | match kind { |
25 | RunnableKind::Test { test_id } => { | 26 | RunnableKind::Test { test_id } => { |
26 | res.push("test".to_string()); | 27 | args.push("test".to_string()); |
27 | if let Some(spec) = spec { | 28 | if let Some(spec) = spec { |
28 | spec.push_to(&mut res); | 29 | spec.push_to(&mut args); |
29 | } | 30 | } |
30 | res.push("--".to_string()); | 31 | extra_args.push(test_id.to_string()); |
31 | res.push(test_id.to_string()); | ||
32 | if let TestId::Path(_) = test_id { | 32 | if let TestId::Path(_) = test_id { |
33 | res.push("--exact".to_string()); | 33 | extra_args.push("--exact".to_string()); |
34 | } | 34 | } |
35 | res.push("--nocapture".to_string()); | 35 | extra_args.push("--nocapture".to_string()); |
36 | } | 36 | } |
37 | RunnableKind::TestMod { path } => { | 37 | RunnableKind::TestMod { path } => { |
38 | res.push("test".to_string()); | 38 | args.push("test".to_string()); |
39 | if let Some(spec) = spec { | 39 | if let Some(spec) = spec { |
40 | spec.push_to(&mut res); | 40 | spec.push_to(&mut args); |
41 | } | 41 | } |
42 | res.push("--".to_string()); | 42 | extra_args.push(path.to_string()); |
43 | res.push(path.to_string()); | 43 | extra_args.push("--nocapture".to_string()); |
44 | res.push("--nocapture".to_string()); | ||
45 | } | 44 | } |
46 | RunnableKind::Bench { test_id } => { | 45 | RunnableKind::Bench { test_id } => { |
47 | res.push("bench".to_string()); | 46 | args.push("bench".to_string()); |
48 | if let Some(spec) = spec { | 47 | if let Some(spec) = spec { |
49 | spec.push_to(&mut res); | 48 | spec.push_to(&mut args); |
50 | } | 49 | } |
51 | res.push("--".to_string()); | 50 | extra_args.push(test_id.to_string()); |
52 | res.push(test_id.to_string()); | ||
53 | if let TestId::Path(_) = test_id { | 51 | if let TestId::Path(_) = test_id { |
54 | res.push("--exact".to_string()); | 52 | extra_args.push("--exact".to_string()); |
55 | } | 53 | } |
56 | res.push("--nocapture".to_string()); | 54 | extra_args.push("--nocapture".to_string()); |
57 | } | 55 | } |
58 | RunnableKind::Bin => { | 56 | RunnableKind::Bin => { |
59 | res.push("run".to_string()); | 57 | args.push("run".to_string()); |
60 | if let Some(spec) = spec { | 58 | if let Some(spec) = spec { |
61 | spec.push_to(&mut res); | 59 | spec.push_to(&mut args); |
62 | } | 60 | } |
63 | } | 61 | } |
64 | } | 62 | } |
65 | Ok(res) | 63 | Ok((args, extra_args)) |
66 | } | 64 | } |
67 | 65 | ||
68 | pub(crate) fn for_file( | 66 | pub(crate) fn for_file( |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 084e17b04..6b9a11a87 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -55,6 +55,9 @@ pub struct ServerConfig { | |||
55 | 55 | ||
56 | /// Cargo feature configurations. | 56 | /// Cargo feature configurations. |
57 | pub cargo_features: CargoFeatures, | 57 | pub cargo_features: CargoFeatures, |
58 | |||
59 | /// Enabled if the vscode_lldb extension is available. | ||
60 | pub vscode_lldb: bool, | ||
58 | } | 61 | } |
59 | 62 | ||
60 | impl Default for ServerConfig { | 63 | impl Default for ServerConfig { |
@@ -76,6 +79,7 @@ impl Default for ServerConfig { | |||
76 | additional_out_dirs: FxHashMap::default(), | 79 | additional_out_dirs: FxHashMap::default(), |
77 | cargo_features: Default::default(), | 80 | cargo_features: Default::default(), |
78 | rustfmt_args: Vec::new(), | 81 | rustfmt_args: Vec::new(), |
82 | vscode_lldb: false, | ||
79 | } | 83 | } |
80 | } | 84 | } |
81 | } | 85 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 2b3b16d35..eb29e8322 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -189,6 +189,7 @@ pub fn main_loop( | |||
189 | all_targets: config.cargo_watch_all_targets, | 189 | all_targets: config.cargo_watch_all_targets, |
190 | }, | 190 | }, |
191 | rustfmt_args: config.rustfmt_args, | 191 | rustfmt_args: config.rustfmt_args, |
192 | vscode_lldb: config.vscode_lldb, | ||
192 | } | 193 | } |
193 | }; | 194 | }; |
194 | 195 | ||
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 6482f3b77..1cc2f6571 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -381,6 +381,7 @@ pub fn handle_runnables( | |||
381 | label, | 381 | label, |
382 | bin: "cargo".to_string(), | 382 | bin: "cargo".to_string(), |
383 | args: check_args, | 383 | args: check_args, |
384 | extra_args: Vec::new(), | ||
384 | env: FxHashMap::default(), | 385 | env: FxHashMap::default(), |
385 | cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), | 386 | cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), |
386 | }); | 387 | }); |
@@ -794,18 +795,35 @@ pub fn handle_code_lens( | |||
794 | RunnableKind::Bin => "Run", | 795 | RunnableKind::Bin => "Run", |
795 | } | 796 | } |
796 | .to_string(); | 797 | .to_string(); |
797 | let r = to_lsp_runnable(&world, file_id, runnable)?; | 798 | let mut r = to_lsp_runnable(&world, file_id, runnable)?; |
798 | let lens = CodeLens { | 799 | let lens = CodeLens { |
799 | range: r.range, | 800 | range: r.range, |
800 | command: Some(Command { | 801 | command: Some(Command { |
801 | title, | 802 | title, |
802 | command: "rust-analyzer.runSingle".into(), | 803 | command: "rust-analyzer.runSingle".into(), |
803 | arguments: Some(vec![to_value(r).unwrap()]), | 804 | arguments: Some(vec![to_value(&r).unwrap()]), |
804 | }), | 805 | }), |
805 | data: None, | 806 | data: None, |
806 | }; | 807 | }; |
807 | |||
808 | lenses.push(lens); | 808 | lenses.push(lens); |
809 | |||
810 | if world.options.vscode_lldb { | ||
811 | if r.args[0] == "run" { | ||
812 | r.args[0] = "build".into(); | ||
813 | } else { | ||
814 | r.args.push("--no-run".into()); | ||
815 | } | ||
816 | let debug_lens = CodeLens { | ||
817 | range: r.range, | ||
818 | command: Some(Command { | ||
819 | title: "Debug".into(), | ||
820 | command: "rust-analyzer.debugSingle".into(), | ||
821 | arguments: Some(vec![to_value(r).unwrap()]), | ||
822 | }), | ||
823 | data: None, | ||
824 | }; | ||
825 | lenses.push(debug_lens); | ||
826 | } | ||
809 | } | 827 | } |
810 | 828 | ||
811 | // Handle impls | 829 | // Handle impls |
@@ -914,7 +932,10 @@ pub fn handle_document_highlight( | |||
914 | 932 | ||
915 | pub fn handle_ssr(world: WorldSnapshot, params: req::SsrParams) -> Result<req::SourceChange> { | 933 | pub fn handle_ssr(world: WorldSnapshot, params: req::SsrParams) -> Result<req::SourceChange> { |
916 | let _p = profile("handle_ssr"); | 934 | let _p = profile("handle_ssr"); |
917 | world.analysis().structural_search_replace(¶ms.arg)??.try_conv_with(&world) | 935 | world |
936 | .analysis() | ||
937 | .structural_search_replace(¶ms.query, params.parse_only)?? | ||
938 | .try_conv_with(&world) | ||
918 | } | 939 | } |
919 | 940 | ||
920 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { | 941 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
@@ -952,7 +973,7 @@ fn to_lsp_runnable( | |||
952 | runnable: Runnable, | 973 | runnable: Runnable, |
953 | ) -> Result<req::Runnable> { | 974 | ) -> Result<req::Runnable> { |
954 | let spec = CargoTargetSpec::for_file(world, file_id)?; | 975 | let spec = CargoTargetSpec::for_file(world, file_id)?; |
955 | let args = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; | 976 | let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; |
956 | let line_index = world.analysis().file_line_index(file_id)?; | 977 | let line_index = world.analysis().file_line_index(file_id)?; |
957 | let label = match &runnable.kind { | 978 | let label = match &runnable.kind { |
958 | RunnableKind::Test { test_id } => format!("test {}", test_id), | 979 | RunnableKind::Test { test_id } => format!("test {}", test_id), |
@@ -965,6 +986,7 @@ fn to_lsp_runnable( | |||
965 | label, | 986 | label, |
966 | bin: "cargo".to_string(), | 987 | bin: "cargo".to_string(), |
967 | args, | 988 | args, |
989 | extra_args, | ||
968 | env: { | 990 | env: { |
969 | let mut m = FxHashMap::default(); | 991 | let mut m = FxHashMap::default(); |
970 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | 992 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); |
@@ -973,6 +995,7 @@ fn to_lsp_runnable( | |||
973 | cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()), | 995 | cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()), |
974 | }) | 996 | }) |
975 | } | 997 | } |
998 | |||
976 | fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> { | 999 | fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> { |
977 | let line_index = world.analysis().file_line_index(file_id)?; | 1000 | let line_index = world.analysis().file_line_index(file_id)?; |
978 | let res = world | 1001 | let res = world |
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index a3efe3b9f..9e27d3f1c 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs | |||
@@ -169,6 +169,7 @@ pub struct Runnable { | |||
169 | pub label: String, | 169 | pub label: String, |
170 | pub bin: String, | 170 | pub bin: String, |
171 | pub args: Vec<String>, | 171 | pub args: Vec<String>, |
172 | pub extra_args: Vec<String>, | ||
172 | pub env: FxHashMap<String, String>, | 173 | pub env: FxHashMap<String, String>, |
173 | pub cwd: Option<String>, | 174 | pub cwd: Option<String>, |
174 | } | 175 | } |
@@ -217,6 +218,8 @@ impl Request for Ssr { | |||
217 | } | 218 | } |
218 | 219 | ||
219 | #[derive(Debug, Deserialize, Serialize)] | 220 | #[derive(Debug, Deserialize, Serialize)] |
221 | #[serde(rename_all = "camelCase")] | ||
220 | pub struct SsrParams { | 222 | pub struct SsrParams { |
221 | pub arg: String, | 223 | pub query: String, |
224 | pub parse_only: bool, | ||
222 | } | 225 | } |
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 058ce2af8..5743471bf 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -38,6 +38,7 @@ pub struct Options { | |||
38 | pub inlay_hints: InlayHintsOptions, | 38 | pub inlay_hints: InlayHintsOptions, |
39 | pub rustfmt_args: Vec<String>, | 39 | pub rustfmt_args: Vec<String>, |
40 | pub cargo_watch: CheckOptions, | 40 | pub cargo_watch: CheckOptions, |
41 | pub vscode_lldb: bool, | ||
41 | } | 42 | } |
42 | 43 | ||
43 | /// `WorldState` is the primary mutable state of the language server | 44 | /// `WorldState` is the primary mutable state of the language server |
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 970185dec..145429571 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -75,7 +75,8 @@ fn foo() { | |||
75 | RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, | 75 | RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, |
76 | json!([ | 76 | json!([ |
77 | { | 77 | { |
78 | "args": [ "test", "--", "foo", "--nocapture" ], | 78 | "args": [ "test" ], |
79 | "extraArgs": [ "foo", "--nocapture" ], | ||
79 | "bin": "cargo", | 80 | "bin": "cargo", |
80 | "env": { "RUST_BACKTRACE": "short" }, | 81 | "env": { "RUST_BACKTRACE": "short" }, |
81 | "cwd": null, | 82 | "cwd": null, |
@@ -90,6 +91,7 @@ fn foo() { | |||
90 | "check", | 91 | "check", |
91 | "--all" | 92 | "--all" |
92 | ], | 93 | ], |
94 | "extraArgs": [], | ||
93 | "bin": "cargo", | 95 | "bin": "cargo", |
94 | "env": {}, | 96 | "env": {}, |
95 | "cwd": null, | 97 | "cwd": null, |
@@ -141,13 +143,11 @@ fn main() {} | |||
141 | 143 | ||
142 | server.wait_until_workspace_is_loaded(); | 144 | server.wait_until_workspace_is_loaded(); |
143 | server.request::<Runnables>( | 145 | server.request::<Runnables>( |
144 | RunnablesParams { | 146 | RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, |
145 | text_document: server.doc_id("foo/tests/spam.rs"), | ||
146 | position: None, | ||
147 | }, | ||
148 | json!([ | 147 | json!([ |
149 | { | 148 | { |
150 | "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--exact", "--nocapture" ], | 149 | "args": [ "test", "--package", "foo", "--test", "spam" ], |
150 | "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], | ||
151 | "bin": "cargo", | 151 | "bin": "cargo", |
152 | "env": { "RUST_BACKTRACE": "short" }, | 152 | "env": { "RUST_BACKTRACE": "short" }, |
153 | "label": "test test_eggs", | 153 | "label": "test test_eggs", |
@@ -165,6 +165,7 @@ fn main() {} | |||
165 | "--test", | 165 | "--test", |
166 | "spam" | 166 | "spam" |
167 | ], | 167 | ], |
168 | "extraArgs": [], | ||
168 | "bin": "cargo", | 169 | "bin": "cargo", |
169 | "env": {}, | 170 | "env": {}, |
170 | "cwd": server.path().join("foo"), | 171 | "cwd": server.path().join("foo"), |
@@ -180,7 +181,7 @@ fn main() {} | |||
180 | } | 181 | } |
181 | } | 182 | } |
182 | } | 183 | } |
183 | ]) | 184 | ]), |
184 | ); | 185 | ); |
185 | } | 186 | } |
186 | 187 | ||
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index a0d8f4d37..db03df1c4 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -397,6 +397,8 @@ pub fn skip_slow_tests() -> bool { | |||
397 | should_skip | 397 | should_skip |
398 | } | 398 | } |
399 | 399 | ||
400 | const REWRITE: bool = false; | ||
401 | |||
400 | /// Asserts that `expected` and `actual` strings are equal. If they differ only | 402 | /// Asserts that `expected` and `actual` strings are equal. If they differ only |
401 | /// in trailing or leading whitespace the test won't fail and | 403 | /// in trailing or leading whitespace the test won't fail and |
402 | /// the contents of `actual` will be written to the file located at `path`. | 404 | /// the contents of `actual` will be written to the file located at `path`. |
@@ -412,7 +414,6 @@ fn assert_equal_text(expected: &str, actual: &str, path: &Path) { | |||
412 | fs::write(path, actual).unwrap(); | 414 | fs::write(path, actual).unwrap(); |
413 | return; | 415 | return; |
414 | } | 416 | } |
415 | const REWRITE: bool = false; | ||
416 | if REWRITE { | 417 | if REWRITE { |
417 | println!("rewriting {}", pretty_path.display()); | 418 | println!("rewriting {}", pretty_path.display()); |
418 | fs::write(path, actual).unwrap(); | 419 | fs::write(path, actual).unwrap(); |