From 263f9a7f231a474dd56d02adbcd7c57d079e88fd Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Wed, 3 Jun 2020 23:38:25 -0400 Subject: Add tracking of packed repr, use it to highlight unsafe refs Taking a reference to a misaligned field on a packed struct is an unsafe operation. Highlight that behavior. Currently, the misaligned part isn't tracked, so this highlight is a bit too aggressive. --- crates/ra_ide/src/syntax_highlighting.rs | 24 ++++++++++++++++++++++++ crates/ra_ide/src/syntax_highlighting/tests.rs | 11 +++++++++++ 2 files changed, 35 insertions(+) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 6b7874460..0cab684eb 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -565,6 +565,30 @@ fn highlight_element( _ => h, } } + REF_EXPR => { + let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?; + let expr = ref_expr.expr()?; + let field_expr = match expr { + ast::Expr::FieldExpr(fe) => fe, + _ => return None, + }; + + let expr = field_expr.expr()?; + let ty = match sema.type_of_expr(&expr) { + Some(ty) => ty, + None => { + println!("No type :("); + return None; + } + }; + if !ty.is_packed(db) { + return None; + } + + // FIXME account for alignment... somehow + + Highlight::new(HighlightTag::Operator) | HighlightModifier::Unsafe + } p if p.is_punct() => match p { T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { HighlightTag::Operator.into() diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 09062c38e..f2c078d34 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -292,6 +292,13 @@ struct TypeForStaticMut { static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; +#[repr(packed)] +struct Packed { + a: u16, + b: u8, + c: u32, +} + fn main() { let x = &5 as *const usize; let u = Union { b: 0 }; @@ -306,6 +313,10 @@ fn main() { let y = *(x); let z = -x; let a = global_mut.a; + let packed = Packed { a: 0, b: 0, c: 0 }; + let a = &packed.a; + let b = &packed.b; + let c = &packed.c; } } "# -- cgit v1.2.3 From fd30134cf84b134259fe8140e513b152e37f3f88 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 15 Jun 2020 07:19:45 -0400 Subject: Remove token tree from ReprKind::Other variant, expose ReprKind higher, remove debug println. --- crates/ra_ide/src/syntax_highlighting.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 0cab684eb..b82b51efd 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -574,13 +574,7 @@ fn highlight_element( }; let expr = field_expr.expr()?; - let ty = match sema.type_of_expr(&expr) { - Some(ty) => ty, - None => { - println!("No type :("); - return None; - } - }; + let ty = sema.type_of_expr(&expr)?; if !ty.is_packed(db) { return None; } -- cgit v1.2.3 From 4a4b1f48efeff4ebe578eb92b7bb8338d0181a83 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 15 Jun 2020 07:41:13 -0400 Subject: Limit scope of unsafe to & instead of all ref exprs, add test showing missing support for autoref behavior --- crates/ra_ide/src/syntax_highlighting.rs | 2 +- crates/ra_ide/src/syntax_highlighting/tests.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index b82b51efd..c5098189b 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -565,7 +565,7 @@ fn highlight_element( _ => h, } } - REF_EXPR => { + T![&] => { let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?; let expr = ref_expr.expr()?; let field_expr = match expr { diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index f2c078d34..c40805850 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -299,6 +299,23 @@ struct Packed { c: u32, } +trait DoTheAutoref { + fn calls_autoref(&self); +} + +struct NeedsAlign { + a: u16 +} + +#[repr(packed)] +struct HasAligned { + a: NeedsAlign +} + +impl DoTheAutoref for NeedsAlign { + fn calls_autored(&self) {} +} + fn main() { let x = &5 as *const usize; let u = Union { b: 0 }; @@ -317,6 +334,8 @@ fn main() { let a = &packed.a; let b = &packed.b; let c = &packed.c; + let h = HasAligned{ a: NeedsAlign { a: 1 } }; + h.a.calls_autoref(); } } "# -- cgit v1.2.3 From c9e670b8754b8262b5071a96c32cbcd22ff968f4 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 15 Jun 2020 08:21:32 -0400 Subject: Update FIXME comment to be more useful --- crates/ra_ide/src/syntax_highlighting.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index c5098189b..9e8419c5f 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -579,7 +579,8 @@ fn highlight_element( return None; } - // FIXME account for alignment... somehow + // FIXME This needs layout computation to be correct. It will highlight + // more than it should with the current implementation. Highlight::new(HighlightTag::Operator) | HighlightModifier::Unsafe } -- cgit v1.2.3 From 38440d53d8329ac9f3f2013c6e32b3f69b069c72 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 27 Jun 2020 14:42:42 -0400 Subject: Cleanup repr check, fix packed repr check and test --- crates/ra_ide/src/syntax_highlighting.rs | 4 ++-- crates/ra_ide/src/syntax_highlighting/tests.rs | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 9e8419c5f..a4a7aa228 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -565,7 +565,7 @@ fn highlight_element( _ => h, } } - T![&] => { + REF_EXPR => { let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?; let expr = ref_expr.expr()?; let field_expr = match expr { @@ -582,7 +582,7 @@ fn highlight_element( // FIXME This needs layout computation to be correct. It will highlight // more than it should with the current implementation. - Highlight::new(HighlightTag::Operator) | HighlightModifier::Unsafe + HighlightTag::Operator | HighlightModifier::Unsafe } p if p.is_punct() => match p { T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index c40805850..a7f5ad862 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -295,8 +295,6 @@ static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; #[repr(packed)] struct Packed { a: u16, - b: u8, - c: u32, } trait DoTheAutoref { @@ -313,11 +311,11 @@ struct HasAligned { } impl DoTheAutoref for NeedsAlign { - fn calls_autored(&self) {} + fn calls_autoref(&self) {} } fn main() { - let x = &5 as *const usize; + let x = &5 as *const _ as *const usize; let u = Union { b: 0 }; unsafe { unsafe_fn(); @@ -327,13 +325,11 @@ fn main() { Union { a } => (), } HasUnsafeFn.unsafe_method(); - let y = *(x); + let _y = *(x); let z = -x; let a = global_mut.a; - let packed = Packed { a: 0, b: 0, c: 0 }; - let a = &packed.a; - let b = &packed.b; - let c = &packed.c; + let packed = Packed { a: 0 }; + let _a = &packed.a; let h = HasAligned{ a: NeedsAlign { a: 1 } }; h.a.calls_autoref(); } -- cgit v1.2.3 From d5f11e530dbf6edbdd0ca32d6cd5fafe634c8c4a Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 27 Jun 2020 17:11:43 -0400 Subject: Unsafe borrow of packed fields: account for borrow through ref binding, auto ref function calls --- crates/ra_ide/src/completion/complete_dot.rs | 2 +- .../ra_ide/src/completion/complete_trait_impl.rs | 2 +- crates/ra_ide/src/completion/presentation.rs | 2 +- crates/ra_ide/src/syntax_highlighting.rs | 137 ++++++++++++++++++--- crates/ra_ide/src/syntax_highlighting/tests.rs | 31 ++--- 5 files changed, 136 insertions(+), 38 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 532665285..5488db43f 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs @@ -48,7 +48,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T let mut seen_methods = FxHashSet::default(); let traits_in_scope = ctx.scope.traits_in_scope(); receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { - if func.has_self_param(ctx.db) + if func.self_param(ctx.db).is_some() && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) && seen_methods.insert(func.name(ctx.db)) { diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index d9a0ef167..e3ba7ebc4 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -136,7 +136,7 @@ fn add_function_impl( .lookup_by(fn_name) .set_documentation(func.docs(ctx.db)); - let completion_kind = if func.has_self_param(ctx.db) { + let completion_kind = if func.self_param(ctx.db).is_some() { CompletionItemKind::Method } else { CompletionItemKind::Function diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 9a94ff476..fc3d1a4bd 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -191,7 +191,7 @@ impl Completions { func: hir::Function, local_name: Option, ) { - let has_self_param = func.has_self_param(ctx.db); + let has_self_param = func.self_param(ctx.db).is_some(); let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); let ast_node = func.source(ctx.db).value; diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index a4a7aa228..454fef39c 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -497,9 +497,9 @@ fn highlight_element( match name_kind { Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(), Some(NameClass::Definition(def)) => { - highlight_name(db, def, false) | HighlightModifier::Definition + highlight_name(sema, db, def, None, false) | HighlightModifier::Definition } - Some(NameClass::ConstReference(def)) => highlight_name(db, def, false), + Some(NameClass::ConstReference(def)) => highlight_name(sema, db, def, None, false), Some(NameClass::FieldShorthand { field, .. }) => { let mut h = HighlightTag::Field.into(); if let Definition::Field(field) = field { @@ -532,7 +532,7 @@ fn highlight_element( binding_hash = Some(calc_binding_hash(&name, *shadow_count)) } }; - highlight_name(db, def, possibly_unsafe) + highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) } NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), }, @@ -565,8 +565,8 @@ fn highlight_element( _ => h, } } - REF_EXPR => { - let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?; + T![&] => { + let ref_expr = element.parent().and_then(ast::RefExpr::cast)?; let expr = ref_expr.expr()?; let field_expr = match expr { ast::Expr::FieldExpr(fe) => fe, @@ -668,6 +668,52 @@ fn highlight_element( HighlightTag::SelfKeyword.into() } } + T![ref] => { + let modifier: Option = (|| { + let bind_pat = element.parent().and_then(ast::BindPat::cast)?; + let parent = bind_pat.syntax().parent()?; + + let ty = if let Some(pat_list) = + ast::RecordFieldPatList::cast(parent.clone()) + { + let record_pat = + pat_list.syntax().parent().and_then(ast::RecordPat::cast)?; + sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) + } else if let Some(let_stmt) = ast::LetStmt::cast(parent.clone()) { + let field_expr = + if let ast::Expr::FieldExpr(field_expr) = let_stmt.initializer()? { + field_expr + } else { + return None; + }; + + sema.type_of_expr(&field_expr.expr()?) + } else if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent) { + let record_pat = record_field_pat + .syntax() + .parent() + .and_then(ast::RecordFieldPatList::cast)? + .syntax() + .parent() + .and_then(ast::RecordPat::cast)?; + sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) + } else { + None + }?; + + if !ty.is_packed(db) { + return None; + } + + Some(HighlightModifier::Unsafe) + })(); + + if let Some(modifier) = modifier { + h | modifier + } else { + h + } + } _ => h, } } @@ -697,7 +743,13 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { } } -fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight { +fn highlight_name( + sema: &Semantics, + db: &RootDatabase, + def: Definition, + name_ref: Option, + possibly_unsafe: bool, +) -> Highlight { match def { Definition::Macro(_) => HighlightTag::Macro, Definition::Field(field) => { @@ -716,6 +768,29 @@ fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> let mut h = HighlightTag::Function.into(); if func.is_unsafe(db) { h |= HighlightModifier::Unsafe; + } else { + (|| { + let method_call_expr = + name_ref?.syntax().parent().and_then(ast::MethodCallExpr::cast)?; + let expr = method_call_expr.expr()?; + let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { + Some(field_expr) + } else { + None + }?; + let ty = sema.type_of_expr(&field_expr.expr()?)?; + if !ty.is_packed(db) { + return None; + } + + let func = sema.resolve_method_call(&method_call_expr)?; + if func.self_param(db)?.is_ref { + Some(HighlightModifier::Unsafe) + } else { + None + } + })() + .map(|modifier| h |= modifier); } return h; } @@ -787,8 +862,33 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics return default.into(), }; - let tag = match parent.kind() { - METHOD_CALL_EXPR => HighlightTag::Function, + match parent.kind() { + METHOD_CALL_EXPR => { + let mut h = Highlight::new(HighlightTag::Function); + let modifier: Option = (|| { + let method_call_expr = ast::MethodCallExpr::cast(parent)?; + let expr = method_call_expr.expr()?; + let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { + field_expr + } else { + return None; + }; + + let expr = field_expr.expr()?; + let ty = sema.type_of_expr(&expr)?; + if ty.is_packed(sema.db) { + Some(HighlightModifier::Unsafe) + } else { + None + } + })(); + + if let Some(modifier) = modifier { + h |= modifier; + } + + h + } FIELD_EXPR => { let h = HighlightTag::Field; let is_union = ast::FieldExpr::cast(parent) @@ -801,7 +901,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let path = match parent.parent().and_then(ast::Path::cast) { @@ -826,18 +926,15 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics HighlightTag::Function, - _ => { - if name.text().chars().next().unwrap_or_default().is_uppercase() { - HighlightTag::Struct - } else { - HighlightTag::Constant - } + CALL_EXPR => HighlightTag::Function.into(), + _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { + HighlightTag::Struct.into() + } else { + HighlightTag::Constant } + .into(), } } - _ => default, - }; - - tag.into() + _ => default.into(), + } } diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index a7f5ad862..a8087635a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -301,16 +301,7 @@ trait DoTheAutoref { fn calls_autoref(&self); } -struct NeedsAlign { - a: u16 -} - -#[repr(packed)] -struct HasAligned { - a: NeedsAlign -} - -impl DoTheAutoref for NeedsAlign { +impl DoTheAutoref for u16 { fn calls_autoref(&self) {} } @@ -318,6 +309,7 @@ fn main() { let x = &5 as *const _ as *const usize; let u = Union { b: 0 }; unsafe { + // unsafe fn and method calls unsafe_fn(); let b = u.b; match u { @@ -325,13 +317,22 @@ fn main() { Union { a } => (), } HasUnsafeFn.unsafe_method(); - let _y = *(x); - let z = -x; + + // unsafe deref + let y = *x; + + // unsafe access to a static mut let a = global_mut.a; + + // unsafe ref of packed fields let packed = Packed { a: 0 }; - let _a = &packed.a; - let h = HasAligned{ a: NeedsAlign { a: 1 } }; - h.a.calls_autoref(); + let a = &packed.a; + let ref a = packed.a; + let Packed { ref a } = packed; + let Packed { a: ref _a } = packed; + + // unsafe auto ref of packed field + packed.a.calls_autoref(); } } "# -- cgit v1.2.3 From aca3d6c57ec2c668cdb51eca34d6f7bc8fa7412b Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 27 Jun 2020 17:28:07 -0400 Subject: Deduplicate unsafe method call into a single function --- crates/ra_ide/src/syntax_highlighting.rs | 72 ++++++++++++++------------------ 1 file changed, 31 insertions(+), 41 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 454fef39c..02b16b13c 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -743,6 +743,26 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { } } +fn is_method_call_unsafe( + sema: &Semantics, + method_call_expr: ast::MethodCallExpr, +) -> Option<()> { + let expr = method_call_expr.expr()?; + let field_expr = + if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None }; + let ty = sema.type_of_expr(&field_expr.expr()?)?; + if !ty.is_packed(sema.db) { + return None; + } + + let func = sema.resolve_method_call(&method_call_expr)?; + if func.self_param(sema.db)?.is_ref { + Some(()) + } else { + None + } +} + fn highlight_name( sema: &Semantics, db: &RootDatabase, @@ -769,28 +789,13 @@ fn highlight_name( if func.is_unsafe(db) { h |= HighlightModifier::Unsafe; } else { - (|| { - let method_call_expr = - name_ref?.syntax().parent().and_then(ast::MethodCallExpr::cast)?; - let expr = method_call_expr.expr()?; - let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { - Some(field_expr) - } else { - None - }?; - let ty = sema.type_of_expr(&field_expr.expr()?)?; - if !ty.is_packed(db) { - return None; - } - - let func = sema.resolve_method_call(&method_call_expr)?; - if func.self_param(db)?.is_ref { - Some(HighlightModifier::Unsafe) - } else { - None - } - })() - .map(|modifier| h |= modifier); + let is_unsafe = name_ref + .and_then(|name_ref| name_ref.syntax().parent()) + .and_then(ast::MethodCallExpr::cast) + .and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr)); + if is_unsafe.is_some() { + h |= HighlightModifier::Unsafe; + } } return h; } @@ -865,26 +870,11 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let mut h = Highlight::new(HighlightTag::Function); - let modifier: Option = (|| { - let method_call_expr = ast::MethodCallExpr::cast(parent)?; - let expr = method_call_expr.expr()?; - let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { - field_expr - } else { - return None; - }; - - let expr = field_expr.expr()?; - let ty = sema.type_of_expr(&expr)?; - if ty.is_packed(sema.db) { - Some(HighlightModifier::Unsafe) - } else { - None - } - })(); + let is_unsafe = ast::MethodCallExpr::cast(parent) + .and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr)); - if let Some(modifier) = modifier { - h |= modifier; + if is_unsafe.is_some() { + h |= HighlightModifier::Unsafe; } h -- cgit v1.2.3 From c5cc24cb312c70159e63315ea49769b575e8cb65 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 28 Jun 2020 16:04:00 -0400 Subject: Revert function structs back to using bool to track self param, use first param for self information in syntax highlighting instead --- crates/ra_ide/src/completion/complete_dot.rs | 2 +- crates/ra_ide/src/completion/complete_trait_impl.rs | 2 +- crates/ra_ide/src/completion/presentation.rs | 2 +- crates/ra_ide/src/syntax_highlighting.rs | 11 ++++++++--- 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 5488db43f..532665285 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs @@ -48,7 +48,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T let mut seen_methods = FxHashSet::default(); let traits_in_scope = ctx.scope.traits_in_scope(); receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { - if func.self_param(ctx.db).is_some() + if func.has_self_param(ctx.db) && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) && seen_methods.insert(func.name(ctx.db)) { diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index e3ba7ebc4..d9a0ef167 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -136,7 +136,7 @@ fn add_function_impl( .lookup_by(fn_name) .set_documentation(func.docs(ctx.db)); - let completion_kind = if func.self_param(ctx.db).is_some() { + let completion_kind = if func.has_self_param(ctx.db) { CompletionItemKind::Method } else { CompletionItemKind::Function diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index fc3d1a4bd..9a94ff476 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -191,7 +191,7 @@ impl Completions { func: hir::Function, local_name: Option, ) { - let has_self_param = func.self_param(ctx.db).is_some(); + let has_self_param = func.has_self_param(ctx.db); let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); let ast_node = func.source(ctx.db).value; diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 02b16b13c..d5a5f69cc 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Name, Semantics, VariantDef}; +use hir::{Name, Semantics, TypeRef, VariantDef}; use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, @@ -756,8 +756,13 @@ fn is_method_call_unsafe( } let func = sema.resolve_method_call(&method_call_expr)?; - if func.self_param(sema.db)?.is_ref { - Some(()) + if func.has_self_param(sema.db) { + let params = func.params(sema.db); + if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) { + Some(()) + } else { + None + } } else { None } -- cgit v1.2.3 From 08182aa9fad4021e60cdc80ee0a578929507e115 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 19 Jul 2020 11:45:46 -0400 Subject: Move unsafe packed ref logic to Semantics, use `Attrs::by_key` to simplify repr attr lookup --- crates/ra_ide/src/call_info.rs.orig | 769 +++++++++++++++++++++++++++++++ crates/ra_ide/src/syntax_highlighting.rs | 34 +- 2 files changed, 771 insertions(+), 32 deletions(-) create mode 100644 crates/ra_ide/src/call_info.rs.orig (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/call_info.rs.orig b/crates/ra_ide/src/call_info.rs.orig new file mode 100644 index 000000000..0e04c0b60 --- /dev/null +++ b/crates/ra_ide/src/call_info.rs.orig @@ -0,0 +1,769 @@ +//! FIXME: write short doc here +use either::Either; +use hir::{Docs, HirDisplay, Semantics, Type}; +use ra_ide_db::RootDatabase; +use ra_syntax::{ + ast::{self, ArgListOwner}, + match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, +}; +use stdx::format_to; +use test_utils::mark; + +use crate::FilePosition; + +/// Contains information about a call site. Specifically the +/// `FunctionSignature`and current parameter. +#[derive(Debug)] +pub struct CallInfo { + pub doc: Option, + pub signature: String, + pub active_parameter: Option, + parameters: Vec, +} + +impl CallInfo { + pub fn parameter_labels(&self) -> impl Iterator + '_ { + self.parameters.iter().map(move |&it| &self.signature[it]) + } + pub fn parameter_ranges(&self) -> &[TextRange] { + &self.parameters + } + fn push_param(&mut self, param: &str) { + if !self.signature.ends_with('(') { + self.signature.push_str(", "); + } + let start = TextSize::of(&self.signature); + self.signature.push_str(param); + let end = TextSize::of(&self.signature); + self.parameters.push(TextRange::new(start, end)) + } +} + +/// Computes parameter information for the given call expression. +pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { + let sema = Semantics::new(db); + let file = sema.parse(position.file_id); + let file = file.syntax(); + let token = file.token_at_offset(position.offset).next()?; + let token = sema.descend_into_macros(token); + + let (callable, active_parameter) = call_info_impl(&sema, token)?; + + let mut res = + CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter }; + + match callable.kind() { + hir::CallableKind::Function(func) => { + res.doc = func.docs(db).map(|it| it.as_str().to_string()); + format_to!(res.signature, "fn {}", func.name(db)); + } + hir::CallableKind::TupleStruct(strukt) => { + res.doc = strukt.docs(db).map(|it| it.as_str().to_string()); + format_to!(res.signature, "struct {}", strukt.name(db)); + } + hir::CallableKind::TupleEnumVariant(variant) => { + res.doc = variant.docs(db).map(|it| it.as_str().to_string()); + format_to!( + res.signature, + "enum {}::{}", + variant.parent_enum(db).name(db), + variant.name(db) + ); + } + hir::CallableKind::Closure => (), + } + + res.signature.push('('); + { + if let Some(self_param) = callable.receiver_param(db) { + format_to!(res.signature, "{}", self_param) + } + let mut buf = String::new(); + for (pat, ty) in callable.params(db) { + buf.clear(); + if let Some(pat) = pat { + match pat { + Either::Left(_self) => format_to!(buf, "self: "), + Either::Right(pat) => format_to!(buf, "{}: ", pat), + } + } + format_to!(buf, "{}", ty.display(db)); + res.push_param(&buf); + } + } + res.signature.push(')'); + + match callable.kind() { + hir::CallableKind::Function(_) | hir::CallableKind::Closure => { + let ret_type = callable.return_type(); + if !ret_type.is_unit() { + format_to!(res.signature, " -> {}", ret_type.display(db)); + } + } + hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} + } + Some(res) +} + +fn call_info_impl( + sema: &Semantics, + token: SyntaxToken, +) -> Option<(hir::Callable, Option)> { + // Find the calling expression and it's NameRef + let calling_node = FnCallNode::with_node(&token.parent())?; + +<<<<<<< HEAD + let callable = match &calling_node { + FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, + FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, + }; + let active_param = if let Some(arg_list) = calling_node.arg_list() { + // Number of arguments specified at the call site + let num_args_at_callsite = arg_list.args().count(); + + let arg_list_range = arg_list.syntax().text_range(); + if !arg_list_range.contains_inclusive(token.text_range().start()) { + mark::hit!(call_info_bad_offset); + return None; +======= + let (mut call_info, has_self) = match &calling_node { + FnCallNode::CallExpr(call) => { + //FIXME: Type::as_callable is broken + let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; + match callable_def { + hir::CallableDef::FunctionId(it) => { + let fn_def = it.into(); + (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db)) + } + hir::CallableDef::StructId(it) => { + (CallInfo::with_struct(sema.db, it.into())?, false) + } + hir::CallableDef::EnumVariantId(it) => { + (CallInfo::with_enum_variant(sema.db, it.into())?, false) + } + } + } + FnCallNode::MethodCallExpr(method_call) => { + let function = sema.resolve_method_call(&method_call)?; + (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db)) + } + FnCallNode::MacroCallExpr(macro_call) => { + let macro_def = sema.resolve_macro_call(¯o_call)?; + (CallInfo::with_macro(sema.db, macro_def)?, false) +>>>>>>> Revert function structs back to using bool to track self param, use first param for self information in syntax highlighting instead + } + let param = std::cmp::min( + num_args_at_callsite, + arg_list + .args() + .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) + .count(), + ); + + Some(param) + } else { + None + }; + Some((callable, active_param)) +} + +#[derive(Debug)] +pub(crate) struct ActiveParameter { + pub(crate) ty: Type, + pub(crate) name: String, +} + +impl ActiveParameter { + pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option { + let sema = Semantics::new(db); + let file = sema.parse(position.file_id); + let file = file.syntax(); + let token = file.token_at_offset(position.offset).next()?; + let token = sema.descend_into_macros(token); + Self::at_token(&sema, token) + } + + pub(crate) fn at_token(sema: &Semantics, token: SyntaxToken) -> Option { + let (signature, active_parameter) = call_info_impl(&sema, token)?; + + let idx = active_parameter?; + let mut params = signature.params(sema.db); + if !(idx < params.len()) { + mark::hit!(too_many_arguments); + return None; + } + let (pat, ty) = params.swap_remove(idx); + let name = pat?.to_string(); + Some(ActiveParameter { ty, name }) + } +} + +#[derive(Debug)] +pub(crate) enum FnCallNode { + CallExpr(ast::CallExpr), + MethodCallExpr(ast::MethodCallExpr), +} + +impl FnCallNode { + fn with_node(syntax: &SyntaxNode) -> Option { + syntax.ancestors().find_map(|node| { + match_ast! { + match node { + ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), + ast::MethodCallExpr(it) => { + let arg_list = it.arg_list()?; + if !arg_list.syntax().text_range().contains_range(syntax.text_range()) { + return None; + } + Some(FnCallNode::MethodCallExpr(it)) + }, + _ => None, + } + } + }) + } + + pub(crate) fn with_node_exact(node: &SyntaxNode) -> Option { + match_ast! { + match node { + ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), + ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), + _ => None, + } + } + } + + pub(crate) fn name_ref(&self) -> Option { + match self { + FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? { + ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, + _ => return None, + }), + + FnCallNode::MethodCallExpr(call_expr) => { + call_expr.syntax().children().filter_map(ast::NameRef::cast).next() + } + } + } + + fn arg_list(&self) -> Option { + match self { + FnCallNode::CallExpr(expr) => expr.arg_list(), + FnCallNode::MethodCallExpr(expr) => expr.arg_list(), + } + } +} + +#[cfg(test)] +mod tests { + use expect::{expect, Expect}; + use test_utils::mark; + + use crate::mock_analysis::analysis_and_position; + + fn check(ra_fixture: &str, expect: Expect) { + let (analysis, position) = analysis_and_position(ra_fixture); + let call_info = analysis.call_info(position).unwrap(); + let actual = match call_info { + Some(call_info) => { + let docs = match &call_info.doc { + None => "".to_string(), + Some(docs) => format!("{}\n------\n", docs.as_str()), + }; + let params = call_info + .parameter_labels() + .enumerate() + .map(|(i, param)| { + if Some(i) == call_info.active_parameter { + format!("<{}>", param) + } else { + param.to_string() + } + }) + .collect::>() + .join(", "); + format!("{}{}\n({})\n", docs, call_info.signature, params) + } + None => String::new(), + }; + expect.assert_eq(&actual); + } + + #[test] + fn test_fn_signature_two_args() { + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(<|>3, ); } +"#, + expect![[r#" + fn foo(x: u32, y: u32) -> u32 + (, y: u32) + "#]], + ); + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(3<|>, ); } +"#, + expect![[r#" + fn foo(x: u32, y: u32) -> u32 + (, y: u32) + "#]], + ); + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(3,<|> ); } +"#, + expect![[r#" + fn foo(x: u32, y: u32) -> u32 + (x: u32, ) + "#]], + ); + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(3, <|>); } +"#, + expect![[r#" + fn foo(x: u32, y: u32) -> u32 + (x: u32, ) + "#]], + ); + } + + #[test] + fn test_fn_signature_two_args_empty() { + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(<|>); } +"#, + expect![[r#" + fn foo(x: u32, y: u32) -> u32 + (, y: u32) + "#]], + ); + } + + #[test] + fn test_fn_signature_two_args_first_generics() { + check( + r#" +fn foo(x: T, y: U) -> u32 + where T: Copy + Display, U: Debug +{ x + y } + +fn bar() { foo(<|>3, ); } +"#, + expect![[r#" + fn foo(x: i32, y: {unknown}) -> u32 + (, y: {unknown}) + "#]], + ); + } + + #[test] + fn test_fn_signature_no_params() { + check( + r#" +fn foo() -> T where T: Copy + Display {} +fn bar() { foo(<|>); } +"#, + expect![[r#" + fn foo() -> {unknown} + () + "#]], + ); + } + + #[test] + fn test_fn_signature_for_impl() { + check( + r#" +struct F; +impl F { pub fn new() { } } +fn bar() { + let _ : F = F::new(<|>); +} +"#, + expect![[r#" + fn new() + () + "#]], + ); + } + + #[test] + fn test_fn_signature_for_method_self() { + check( + r#" +struct S; +impl S { pub fn do_it(&self) {} } + +fn bar() { + let s: S = S; + s.do_it(<|>); +} +"#, + expect![[r#" + fn do_it(&self) + () + "#]], + ); + } + + #[test] + fn test_fn_signature_for_method_with_arg() { + check( + r#" +struct S; +impl S { + fn foo(&self, x: i32) {} +} + +fn main() { S.foo(<|>); } +"#, + expect![[r#" + fn foo(&self, x: i32) + () + "#]], + ); + } + + #[test] + fn test_fn_signature_for_method_with_arg_as_assoc_fn() { + check( + r#" +struct S; +impl S { + fn foo(&self, x: i32) {} +} + +fn main() { S::foo(<|>); } +"#, + expect![[r#" + fn foo(self: &S, x: i32) + (, x: i32) + "#]], + ); + } + + #[test] + fn test_fn_signature_with_docs_simple() { + check( + r#" +/// test +// non-doc-comment +fn foo(j: u32) -> u32 { + j +} + +fn bar() { + let _ = foo(<|>); +} +"#, + expect![[r#" + test + ------ + fn foo(j: u32) -> u32 + () + "#]], + ); + } + + #[test] + fn test_fn_signature_with_docs() { + check( + r#" +/// Adds one to the number given. +/// +/// # Examples +/// +/// ``` +/// let five = 5; +/// +/// assert_eq!(6, my_crate::add_one(5)); +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} + +pub fn do() { + add_one(<|> +}"#, + expect![[r##" + Adds one to the number given. + + # Examples + + ``` + let five = 5; + + assert_eq!(6, my_crate::add_one(5)); + ``` + ------ + fn add_one(x: i32) -> i32 + () + "##]], + ); + } + + #[test] + fn test_fn_signature_with_docs_impl() { + check( + r#" +struct addr; +impl addr { + /// Adds one to the number given. + /// + /// # Examples + /// + /// ``` + /// let five = 5; + /// + /// assert_eq!(6, my_crate::add_one(5)); + /// ``` + pub fn add_one(x: i32) -> i32 { + x + 1 + } +} + +pub fn do_it() { + addr {}; + addr::add_one(<|>); +} +"#, + expect![[r##" + Adds one to the number given. + + # Examples + + ``` + let five = 5; + + assert_eq!(6, my_crate::add_one(5)); + ``` + ------ + fn add_one(x: i32) -> i32 + () + "##]], + ); + } + + #[test] + fn test_fn_signature_with_docs_from_actix() { + check( + r#" +struct WriteHandler; + +impl WriteHandler { + /// Method is called when writer emits error. + /// + /// If this method returns `ErrorAction::Continue` writer processing + /// continues otherwise stream processing stops. + fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { + Running::Stop + } + + /// Method is called when writer finishes. + /// + /// By default this method stops actor's `Context`. + fn finished(&mut self, ctx: &mut Self::Context) { + ctx.stop() + } +} + +pub fn foo(mut r: WriteHandler<()>) { + r.finished(<|>); +} +"#, + expect![[r#" + Method is called when writer finishes. + + By default this method stops actor's `Context`. + ------ + fn finished(&mut self, ctx: &mut {unknown}) + () + "#]], + ); + } + + #[test] + fn call_info_bad_offset() { + mark::check!(call_info_bad_offset); + check( + r#" +fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo <|> (3, ); } +"#, + expect![[""]], + ); + } + + #[test] + fn test_nested_method_in_lambda() { + check( + r#" +struct Foo; +impl Foo { fn bar(&self, _: u32) { } } + +fn bar(_: u32) { } + +fn main() { + let foo = Foo; + std::thread::spawn(move || foo.bar(<|>)); +} +"#, + expect![[r#" + fn bar(&self, _: u32) + (<_: u32>) + "#]], + ); + } + + #[test] + fn works_for_tuple_structs() { + check( + r#" +/// A cool tuple struct +struct S(u32, i32); +fn main() { + let s = S(0, <|>); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S(u32, i32) + (u32, ) + "#]], + ); + } + + #[test] + fn generic_struct() { + check( + r#" +struct S(T); +fn main() { + let s = S(<|>); +} +"#, + expect![[r#" + struct S({unknown}) + (<{unknown}>) + "#]], + ); + } + + #[test] + fn works_for_enum_variants() { + check( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C { a: i32, b: i32 } +} + +fn main() { + let a = E::A(<|>); +} +"#, + expect![[r#" + A Variant + ------ + enum E::A(i32) + () + "#]], + ); + } + + #[test] + fn cant_call_struct_record() { + check( + r#" +struct S { x: u32, y: i32 } +fn main() { + let s = S(<|>); +} +"#, + expect![[""]], + ); + } + + #[test] + fn cant_call_enum_record() { + check( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C { a: i32, b: i32 } +} + +fn main() { + let a = E::C(<|>); +} +"#, + expect![[""]], + ); + } + + #[test] + fn fn_signature_for_call_in_macro() { + check( + r#" +macro_rules! id { ($($tt:tt)*) => { $($tt)* } } +fn foo() { } +id! { + fn bar() { foo(<|>); } +} +"#, + expect![[r#" + fn foo() + () + "#]], + ); + } + + #[test] + fn call_info_for_lambdas() { + check( + r#" +struct S; +fn foo(s: S) -> i32 { 92 } +fn main() { + (|s| foo(s))(<|>) +} + "#, + expect![[r#" + (S) -> i32 + () + "#]], + ) + } + + #[test] + fn call_info_for_fn_ptr() { + check( + r#" +fn main(f: fn(i32, f64) -> char) { + f(0, <|>) +} + "#, + expect![[r#" + (i32, f64) -> char + (i32, ) + "#]], + ) + } +} diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index d5a5f69cc..cf93205b6 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -671,41 +671,11 @@ fn highlight_element( T![ref] => { let modifier: Option = (|| { let bind_pat = element.parent().and_then(ast::BindPat::cast)?; - let parent = bind_pat.syntax().parent()?; - - let ty = if let Some(pat_list) = - ast::RecordFieldPatList::cast(parent.clone()) - { - let record_pat = - pat_list.syntax().parent().and_then(ast::RecordPat::cast)?; - sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) - } else if let Some(let_stmt) = ast::LetStmt::cast(parent.clone()) { - let field_expr = - if let ast::Expr::FieldExpr(field_expr) = let_stmt.initializer()? { - field_expr - } else { - return None; - }; - - sema.type_of_expr(&field_expr.expr()?) - } else if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent) { - let record_pat = record_field_pat - .syntax() - .parent() - .and_then(ast::RecordFieldPatList::cast)? - .syntax() - .parent() - .and_then(ast::RecordPat::cast)?; - sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) + if sema.is_unsafe_pat(&ast::Pat::BindPat(bind_pat)) { + Some(HighlightModifier::Unsafe) } else { None - }?; - - if !ty.is_packed(db) { - return None; } - - Some(HighlightModifier::Unsafe) })(); if let Some(modifier) = modifier { -- cgit v1.2.3 From 87cb09365cf841b559e76951eedb826f2d4d3dfd Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 23 Jul 2020 09:39:53 -0400 Subject: Remove merge backup --- crates/ra_ide/src/call_info.rs.orig | 769 ------------------------------------ 1 file changed, 769 deletions(-) delete mode 100644 crates/ra_ide/src/call_info.rs.orig (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/call_info.rs.orig b/crates/ra_ide/src/call_info.rs.orig deleted file mode 100644 index 0e04c0b60..000000000 --- a/crates/ra_ide/src/call_info.rs.orig +++ /dev/null @@ -1,769 +0,0 @@ -//! FIXME: write short doc here -use either::Either; -use hir::{Docs, HirDisplay, Semantics, Type}; -use ra_ide_db::RootDatabase; -use ra_syntax::{ - ast::{self, ArgListOwner}, - match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, -}; -use stdx::format_to; -use test_utils::mark; - -use crate::FilePosition; - -/// Contains information about a call site. Specifically the -/// `FunctionSignature`and current parameter. -#[derive(Debug)] -pub struct CallInfo { - pub doc: Option, - pub signature: String, - pub active_parameter: Option, - parameters: Vec, -} - -impl CallInfo { - pub fn parameter_labels(&self) -> impl Iterator + '_ { - self.parameters.iter().map(move |&it| &self.signature[it]) - } - pub fn parameter_ranges(&self) -> &[TextRange] { - &self.parameters - } - fn push_param(&mut self, param: &str) { - if !self.signature.ends_with('(') { - self.signature.push_str(", "); - } - let start = TextSize::of(&self.signature); - self.signature.push_str(param); - let end = TextSize::of(&self.signature); - self.parameters.push(TextRange::new(start, end)) - } -} - -/// Computes parameter information for the given call expression. -pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { - let sema = Semantics::new(db); - let file = sema.parse(position.file_id); - let file = file.syntax(); - let token = file.token_at_offset(position.offset).next()?; - let token = sema.descend_into_macros(token); - - let (callable, active_parameter) = call_info_impl(&sema, token)?; - - let mut res = - CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter }; - - match callable.kind() { - hir::CallableKind::Function(func) => { - res.doc = func.docs(db).map(|it| it.as_str().to_string()); - format_to!(res.signature, "fn {}", func.name(db)); - } - hir::CallableKind::TupleStruct(strukt) => { - res.doc = strukt.docs(db).map(|it| it.as_str().to_string()); - format_to!(res.signature, "struct {}", strukt.name(db)); - } - hir::CallableKind::TupleEnumVariant(variant) => { - res.doc = variant.docs(db).map(|it| it.as_str().to_string()); - format_to!( - res.signature, - "enum {}::{}", - variant.parent_enum(db).name(db), - variant.name(db) - ); - } - hir::CallableKind::Closure => (), - } - - res.signature.push('('); - { - if let Some(self_param) = callable.receiver_param(db) { - format_to!(res.signature, "{}", self_param) - } - let mut buf = String::new(); - for (pat, ty) in callable.params(db) { - buf.clear(); - if let Some(pat) = pat { - match pat { - Either::Left(_self) => format_to!(buf, "self: "), - Either::Right(pat) => format_to!(buf, "{}: ", pat), - } - } - format_to!(buf, "{}", ty.display(db)); - res.push_param(&buf); - } - } - res.signature.push(')'); - - match callable.kind() { - hir::CallableKind::Function(_) | hir::CallableKind::Closure => { - let ret_type = callable.return_type(); - if !ret_type.is_unit() { - format_to!(res.signature, " -> {}", ret_type.display(db)); - } - } - hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} - } - Some(res) -} - -fn call_info_impl( - sema: &Semantics, - token: SyntaxToken, -) -> Option<(hir::Callable, Option)> { - // Find the calling expression and it's NameRef - let calling_node = FnCallNode::with_node(&token.parent())?; - -<<<<<<< HEAD - let callable = match &calling_node { - FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, - FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, - }; - let active_param = if let Some(arg_list) = calling_node.arg_list() { - // Number of arguments specified at the call site - let num_args_at_callsite = arg_list.args().count(); - - let arg_list_range = arg_list.syntax().text_range(); - if !arg_list_range.contains_inclusive(token.text_range().start()) { - mark::hit!(call_info_bad_offset); - return None; -======= - let (mut call_info, has_self) = match &calling_node { - FnCallNode::CallExpr(call) => { - //FIXME: Type::as_callable is broken - let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; - match callable_def { - hir::CallableDef::FunctionId(it) => { - let fn_def = it.into(); - (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db)) - } - hir::CallableDef::StructId(it) => { - (CallInfo::with_struct(sema.db, it.into())?, false) - } - hir::CallableDef::EnumVariantId(it) => { - (CallInfo::with_enum_variant(sema.db, it.into())?, false) - } - } - } - FnCallNode::MethodCallExpr(method_call) => { - let function = sema.resolve_method_call(&method_call)?; - (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db)) - } - FnCallNode::MacroCallExpr(macro_call) => { - let macro_def = sema.resolve_macro_call(¯o_call)?; - (CallInfo::with_macro(sema.db, macro_def)?, false) ->>>>>>> Revert function structs back to using bool to track self param, use first param for self information in syntax highlighting instead - } - let param = std::cmp::min( - num_args_at_callsite, - arg_list - .args() - .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) - .count(), - ); - - Some(param) - } else { - None - }; - Some((callable, active_param)) -} - -#[derive(Debug)] -pub(crate) struct ActiveParameter { - pub(crate) ty: Type, - pub(crate) name: String, -} - -impl ActiveParameter { - pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option { - let sema = Semantics::new(db); - let file = sema.parse(position.file_id); - let file = file.syntax(); - let token = file.token_at_offset(position.offset).next()?; - let token = sema.descend_into_macros(token); - Self::at_token(&sema, token) - } - - pub(crate) fn at_token(sema: &Semantics, token: SyntaxToken) -> Option { - let (signature, active_parameter) = call_info_impl(&sema, token)?; - - let idx = active_parameter?; - let mut params = signature.params(sema.db); - if !(idx < params.len()) { - mark::hit!(too_many_arguments); - return None; - } - let (pat, ty) = params.swap_remove(idx); - let name = pat?.to_string(); - Some(ActiveParameter { ty, name }) - } -} - -#[derive(Debug)] -pub(crate) enum FnCallNode { - CallExpr(ast::CallExpr), - MethodCallExpr(ast::MethodCallExpr), -} - -impl FnCallNode { - fn with_node(syntax: &SyntaxNode) -> Option { - syntax.ancestors().find_map(|node| { - match_ast! { - match node { - ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), - ast::MethodCallExpr(it) => { - let arg_list = it.arg_list()?; - if !arg_list.syntax().text_range().contains_range(syntax.text_range()) { - return None; - } - Some(FnCallNode::MethodCallExpr(it)) - }, - _ => None, - } - } - }) - } - - pub(crate) fn with_node_exact(node: &SyntaxNode) -> Option { - match_ast! { - match node { - ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), - ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), - _ => None, - } - } - } - - pub(crate) fn name_ref(&self) -> Option { - match self { - FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? { - ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, - _ => return None, - }), - - FnCallNode::MethodCallExpr(call_expr) => { - call_expr.syntax().children().filter_map(ast::NameRef::cast).next() - } - } - } - - fn arg_list(&self) -> Option { - match self { - FnCallNode::CallExpr(expr) => expr.arg_list(), - FnCallNode::MethodCallExpr(expr) => expr.arg_list(), - } - } -} - -#[cfg(test)] -mod tests { - use expect::{expect, Expect}; - use test_utils::mark; - - use crate::mock_analysis::analysis_and_position; - - fn check(ra_fixture: &str, expect: Expect) { - let (analysis, position) = analysis_and_position(ra_fixture); - let call_info = analysis.call_info(position).unwrap(); - let actual = match call_info { - Some(call_info) => { - let docs = match &call_info.doc { - None => "".to_string(), - Some(docs) => format!("{}\n------\n", docs.as_str()), - }; - let params = call_info - .parameter_labels() - .enumerate() - .map(|(i, param)| { - if Some(i) == call_info.active_parameter { - format!("<{}>", param) - } else { - param.to_string() - } - }) - .collect::>() - .join(", "); - format!("{}{}\n({})\n", docs, call_info.signature, params) - } - None => String::new(), - }; - expect.assert_eq(&actual); - } - - #[test] - fn test_fn_signature_two_args() { - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(<|>3, ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - (, y: u32) - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3<|>, ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - (, y: u32) - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3,<|> ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - (x: u32, ) - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3, <|>); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - (x: u32, ) - "#]], - ); - } - - #[test] - fn test_fn_signature_two_args_empty() { - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(<|>); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - (, y: u32) - "#]], - ); - } - - #[test] - fn test_fn_signature_two_args_first_generics() { - check( - r#" -fn foo(x: T, y: U) -> u32 - where T: Copy + Display, U: Debug -{ x + y } - -fn bar() { foo(<|>3, ); } -"#, - expect![[r#" - fn foo(x: i32, y: {unknown}) -> u32 - (, y: {unknown}) - "#]], - ); - } - - #[test] - fn test_fn_signature_no_params() { - check( - r#" -fn foo() -> T where T: Copy + Display {} -fn bar() { foo(<|>); } -"#, - expect![[r#" - fn foo() -> {unknown} - () - "#]], - ); - } - - #[test] - fn test_fn_signature_for_impl() { - check( - r#" -struct F; -impl F { pub fn new() { } } -fn bar() { - let _ : F = F::new(<|>); -} -"#, - expect![[r#" - fn new() - () - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_self() { - check( - r#" -struct S; -impl S { pub fn do_it(&self) {} } - -fn bar() { - let s: S = S; - s.do_it(<|>); -} -"#, - expect![[r#" - fn do_it(&self) - () - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_with_arg() { - check( - r#" -struct S; -impl S { - fn foo(&self, x: i32) {} -} - -fn main() { S.foo(<|>); } -"#, - expect![[r#" - fn foo(&self, x: i32) - () - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_with_arg_as_assoc_fn() { - check( - r#" -struct S; -impl S { - fn foo(&self, x: i32) {} -} - -fn main() { S::foo(<|>); } -"#, - expect![[r#" - fn foo(self: &S, x: i32) - (, x: i32) - "#]], - ); - } - - #[test] - fn test_fn_signature_with_docs_simple() { - check( - r#" -/// test -// non-doc-comment -fn foo(j: u32) -> u32 { - j -} - -fn bar() { - let _ = foo(<|>); -} -"#, - expect![[r#" - test - ------ - fn foo(j: u32) -> u32 - () - "#]], - ); - } - - #[test] - fn test_fn_signature_with_docs() { - check( - r#" -/// Adds one to the number given. -/// -/// # Examples -/// -/// ``` -/// let five = 5; -/// -/// assert_eq!(6, my_crate::add_one(5)); -/// ``` -pub fn add_one(x: i32) -> i32 { - x + 1 -} - -pub fn do() { - add_one(<|> -}"#, - expect![[r##" - Adds one to the number given. - - # Examples - - ``` - let five = 5; - - assert_eq!(6, my_crate::add_one(5)); - ``` - ------ - fn add_one(x: i32) -> i32 - () - "##]], - ); - } - - #[test] - fn test_fn_signature_with_docs_impl() { - check( - r#" -struct addr; -impl addr { - /// Adds one to the number given. - /// - /// # Examples - /// - /// ``` - /// let five = 5; - /// - /// assert_eq!(6, my_crate::add_one(5)); - /// ``` - pub fn add_one(x: i32) -> i32 { - x + 1 - } -} - -pub fn do_it() { - addr {}; - addr::add_one(<|>); -} -"#, - expect![[r##" - Adds one to the number given. - - # Examples - - ``` - let five = 5; - - assert_eq!(6, my_crate::add_one(5)); - ``` - ------ - fn add_one(x: i32) -> i32 - () - "##]], - ); - } - - #[test] - fn test_fn_signature_with_docs_from_actix() { - check( - r#" -struct WriteHandler; - -impl WriteHandler { - /// Method is called when writer emits error. - /// - /// If this method returns `ErrorAction::Continue` writer processing - /// continues otherwise stream processing stops. - fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { - Running::Stop - } - - /// Method is called when writer finishes. - /// - /// By default this method stops actor's `Context`. - fn finished(&mut self, ctx: &mut Self::Context) { - ctx.stop() - } -} - -pub fn foo(mut r: WriteHandler<()>) { - r.finished(<|>); -} -"#, - expect![[r#" - Method is called when writer finishes. - - By default this method stops actor's `Context`. - ------ - fn finished(&mut self, ctx: &mut {unknown}) - () - "#]], - ); - } - - #[test] - fn call_info_bad_offset() { - mark::check!(call_info_bad_offset); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo <|> (3, ); } -"#, - expect![[""]], - ); - } - - #[test] - fn test_nested_method_in_lambda() { - check( - r#" -struct Foo; -impl Foo { fn bar(&self, _: u32) { } } - -fn bar(_: u32) { } - -fn main() { - let foo = Foo; - std::thread::spawn(move || foo.bar(<|>)); -} -"#, - expect![[r#" - fn bar(&self, _: u32) - (<_: u32>) - "#]], - ); - } - - #[test] - fn works_for_tuple_structs() { - check( - r#" -/// A cool tuple struct -struct S(u32, i32); -fn main() { - let s = S(0, <|>); -} -"#, - expect![[r#" - A cool tuple struct - ------ - struct S(u32, i32) - (u32, ) - "#]], - ); - } - - #[test] - fn generic_struct() { - check( - r#" -struct S(T); -fn main() { - let s = S(<|>); -} -"#, - expect![[r#" - struct S({unknown}) - (<{unknown}>) - "#]], - ); - } - - #[test] - fn works_for_enum_variants() { - check( - r#" -enum E { - /// A Variant - A(i32), - /// Another - B, - /// And C - C { a: i32, b: i32 } -} - -fn main() { - let a = E::A(<|>); -} -"#, - expect![[r#" - A Variant - ------ - enum E::A(i32) - () - "#]], - ); - } - - #[test] - fn cant_call_struct_record() { - check( - r#" -struct S { x: u32, y: i32 } -fn main() { - let s = S(<|>); -} -"#, - expect![[""]], - ); - } - - #[test] - fn cant_call_enum_record() { - check( - r#" -enum E { - /// A Variant - A(i32), - /// Another - B, - /// And C - C { a: i32, b: i32 } -} - -fn main() { - let a = E::C(<|>); -} -"#, - expect![[""]], - ); - } - - #[test] - fn fn_signature_for_call_in_macro() { - check( - r#" -macro_rules! id { ($($tt:tt)*) => { $($tt)* } } -fn foo() { } -id! { - fn bar() { foo(<|>); } -} -"#, - expect![[r#" - fn foo() - () - "#]], - ); - } - - #[test] - fn call_info_for_lambdas() { - check( - r#" -struct S; -fn foo(s: S) -> i32 { 92 } -fn main() { - (|s| foo(s))(<|>) -} - "#, - expect![[r#" - (S) -> i32 - () - "#]], - ) - } - - #[test] - fn call_info_for_fn_ptr() { - check( - r#" -fn main(f: fn(i32, f64) -> char) { - f(0, <|>) -} - "#, - expect![[r#" - (i32, f64) -> char - (i32, ) - "#]], - ) - } -} -- cgit v1.2.3 From a6af0272f7bf129a3063cdd7096f685fc58438e6 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 23 Jul 2020 10:11:37 -0400 Subject: Move semantic logic into Semantics, fix missing tag for safe amp operator, using functional methods rather than clunky inline closure --- crates/ra_ide/src/syntax_highlighting.rs | 89 ++++++++++---------------------- 1 file changed, 28 insertions(+), 61 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index cf93205b6..e29f65a78 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -565,29 +565,21 @@ fn highlight_element( _ => h, } } - T![&] => { - let ref_expr = element.parent().and_then(ast::RefExpr::cast)?; - let expr = ref_expr.expr()?; - let field_expr = match expr { - ast::Expr::FieldExpr(fe) => fe, - _ => return None, - }; - - let expr = field_expr.expr()?; - let ty = sema.type_of_expr(&expr)?; - if !ty.is_packed(db) { - return None; - } - - // FIXME This needs layout computation to be correct. It will highlight - // more than it should with the current implementation. - - HighlightTag::Operator | HighlightModifier::Unsafe - } p if p.is_punct() => match p { - T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { - HighlightTag::Operator.into() + T![&] => { + let h = HighlightTag::Operator.into(); + let is_unsafe = element + .parent() + .and_then(ast::RefExpr::cast) + .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) + .unwrap_or(false); + if is_unsafe { + h | HighlightModifier::Unsafe + } else { + h + } } + T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] => HighlightTag::Operator.into(), T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { HighlightTag::Macro.into() } @@ -668,22 +660,18 @@ fn highlight_element( HighlightTag::SelfKeyword.into() } } - T![ref] => { - let modifier: Option = (|| { - let bind_pat = element.parent().and_then(ast::BindPat::cast)?; - if sema.is_unsafe_pat(&ast::Pat::BindPat(bind_pat)) { + T![ref] => element + .parent() + .and_then(ast::BindPat::cast) + .and_then(|bind_pat| { + if sema.is_unsafe_bind_pat(&bind_pat) { Some(HighlightModifier::Unsafe) } else { None } - })(); - - if let Some(modifier) = modifier { - h | modifier - } else { - h - } - } + }) + .map(|modifier| h | modifier) + .unwrap_or(h), _ => h, } } @@ -713,31 +701,6 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { } } -fn is_method_call_unsafe( - sema: &Semantics, - method_call_expr: ast::MethodCallExpr, -) -> Option<()> { - let expr = method_call_expr.expr()?; - let field_expr = - if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None }; - let ty = sema.type_of_expr(&field_expr.expr()?)?; - if !ty.is_packed(sema.db) { - return None; - } - - let func = sema.resolve_method_call(&method_call_expr)?; - if func.has_self_param(sema.db) { - let params = func.params(sema.db); - if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) { - Some(()) - } else { - None - } - } else { - None - } -} - fn highlight_name( sema: &Semantics, db: &RootDatabase, @@ -767,7 +730,7 @@ fn highlight_name( let is_unsafe = name_ref .and_then(|name_ref| name_ref.syntax().parent()) .and_then(ast::MethodCallExpr::cast) - .and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr)); + .and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)); if is_unsafe.is_some() { h |= HighlightModifier::Unsafe; } @@ -846,7 +809,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let mut h = Highlight::new(HighlightTag::Function); let is_unsafe = ast::MethodCallExpr::cast(parent) - .and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr)); + .and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)); if is_unsafe.is_some() { h |= HighlightModifier::Unsafe; @@ -866,7 +829,11 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let path = match parent.parent().and_then(ast::Path::cast) { -- cgit v1.2.3 From 39fdd41df4052cef5da4876067ae28615012476b Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 23 Jul 2020 18:31:28 -0400 Subject: Return bool from is_unsafe_method_call and cleanup usages --- crates/ra_ide/src/syntax_highlighting.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index e29f65a78..4527885e9 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -730,8 +730,9 @@ fn highlight_name( let is_unsafe = name_ref .and_then(|name_ref| name_ref.syntax().parent()) .and_then(ast::MethodCallExpr::cast) - .and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)); - if is_unsafe.is_some() { + .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) + .unwrap_or(false); + if is_unsafe { h |= HighlightModifier::Unsafe; } } @@ -809,9 +810,9 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let mut h = Highlight::new(HighlightTag::Function); let is_unsafe = ast::MethodCallExpr::cast(parent) - .and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)); - - if is_unsafe.is_some() { + .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) + .unwrap_or(false); + if is_unsafe { h |= HighlightModifier::Unsafe; } -- cgit v1.2.3 From 2199d0cda9c745ecb460dd987b8da982d02bc130 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Fri, 7 Aug 2020 10:40:09 -0400 Subject: Fix type names broken by rebase, redo expected test because of rebase --- crates/ra_ide/src/syntax_highlighting.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 4527885e9..c62bb3f1a 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -662,9 +662,9 @@ fn highlight_element( } T![ref] => element .parent() - .and_then(ast::BindPat::cast) - .and_then(|bind_pat| { - if sema.is_unsafe_bind_pat(&bind_pat) { + .and_then(ast::IdentPat::cast) + .and_then(|ident_pat| { + if sema.is_unsafe_ident_pat(&ident_pat) { Some(HighlightModifier::Unsafe) } else { None -- cgit v1.2.3 From 72baf1acdd544c645fd69c16967b91be9e75371b Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 9 Aug 2020 18:54:04 -0400 Subject: Remove unused import left behind after rebasing --- crates/ra_ide/src/syntax_highlighting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index c62bb3f1a..c10e15db8 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Name, Semantics, TypeRef, VariantDef}; +use hir::{Name, Semantics, VariantDef}; use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, -- cgit v1.2.3