diff options
author | Paul Daniel Faria <[email protected]> | 2020-06-27 22:11:43 +0100 |
---|---|---|
committer | Paul Daniel Faria <[email protected]> | 2020-08-10 13:44:54 +0100 |
commit | d5f11e530dbf6edbdd0ca32d6cd5fafe634c8c4a (patch) | |
tree | b348ea6d5552be08913ac3a451836cad5ac75c1a /crates/ra_ide/src | |
parent | 38440d53d8329ac9f3f2013c6e32b3f69b069c72 (diff) |
Unsafe borrow of packed fields: account for borrow through ref binding, auto ref function calls
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 137 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting/tests.rs | 31 |
5 files changed, 136 insertions, 38 deletions
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 | |||
48 | let mut seen_methods = FxHashSet::default(); | 48 | let mut seen_methods = FxHashSet::default(); |
49 | let traits_in_scope = ctx.scope.traits_in_scope(); | 49 | let traits_in_scope = ctx.scope.traits_in_scope(); |
50 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | 50 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { |
51 | if func.has_self_param(ctx.db) | 51 | if func.self_param(ctx.db).is_some() |
52 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | 52 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) |
53 | && seen_methods.insert(func.name(ctx.db)) | 53 | && seen_methods.insert(func.name(ctx.db)) |
54 | { | 54 | { |
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( | |||
136 | .lookup_by(fn_name) | 136 | .lookup_by(fn_name) |
137 | .set_documentation(func.docs(ctx.db)); | 137 | .set_documentation(func.docs(ctx.db)); |
138 | 138 | ||
139 | let completion_kind = if func.has_self_param(ctx.db) { | 139 | let completion_kind = if func.self_param(ctx.db).is_some() { |
140 | CompletionItemKind::Method | 140 | CompletionItemKind::Method |
141 | } else { | 141 | } else { |
142 | CompletionItemKind::Function | 142 | 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 { | |||
191 | func: hir::Function, | 191 | func: hir::Function, |
192 | local_name: Option<String>, | 192 | local_name: Option<String>, |
193 | ) { | 193 | ) { |
194 | let has_self_param = func.has_self_param(ctx.db); | 194 | let has_self_param = func.self_param(ctx.db).is_some(); |
195 | 195 | ||
196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
197 | let ast_node = func.source(ctx.db).value; | 197 | 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( | |||
497 | match name_kind { | 497 | match name_kind { |
498 | Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(), | 498 | Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(), |
499 | Some(NameClass::Definition(def)) => { | 499 | Some(NameClass::Definition(def)) => { |
500 | highlight_name(db, def, false) | HighlightModifier::Definition | 500 | highlight_name(sema, db, def, None, false) | HighlightModifier::Definition |
501 | } | 501 | } |
502 | Some(NameClass::ConstReference(def)) => highlight_name(db, def, false), | 502 | Some(NameClass::ConstReference(def)) => highlight_name(sema, db, def, None, false), |
503 | Some(NameClass::FieldShorthand { field, .. }) => { | 503 | Some(NameClass::FieldShorthand { field, .. }) => { |
504 | let mut h = HighlightTag::Field.into(); | 504 | let mut h = HighlightTag::Field.into(); |
505 | if let Definition::Field(field) = field { | 505 | if let Definition::Field(field) = field { |
@@ -532,7 +532,7 @@ fn highlight_element( | |||
532 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | 532 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) |
533 | } | 533 | } |
534 | }; | 534 | }; |
535 | highlight_name(db, def, possibly_unsafe) | 535 | highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) |
536 | } | 536 | } |
537 | NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), | 537 | NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), |
538 | }, | 538 | }, |
@@ -565,8 +565,8 @@ fn highlight_element( | |||
565 | _ => h, | 565 | _ => h, |
566 | } | 566 | } |
567 | } | 567 | } |
568 | REF_EXPR => { | 568 | T![&] => { |
569 | let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?; | 569 | let ref_expr = element.parent().and_then(ast::RefExpr::cast)?; |
570 | let expr = ref_expr.expr()?; | 570 | let expr = ref_expr.expr()?; |
571 | let field_expr = match expr { | 571 | let field_expr = match expr { |
572 | ast::Expr::FieldExpr(fe) => fe, | 572 | ast::Expr::FieldExpr(fe) => fe, |
@@ -668,6 +668,52 @@ fn highlight_element( | |||
668 | HighlightTag::SelfKeyword.into() | 668 | HighlightTag::SelfKeyword.into() |
669 | } | 669 | } |
670 | } | 670 | } |
671 | T![ref] => { | ||
672 | let modifier: Option<HighlightModifier> = (|| { | ||
673 | let bind_pat = element.parent().and_then(ast::BindPat::cast)?; | ||
674 | let parent = bind_pat.syntax().parent()?; | ||
675 | |||
676 | let ty = if let Some(pat_list) = | ||
677 | ast::RecordFieldPatList::cast(parent.clone()) | ||
678 | { | ||
679 | let record_pat = | ||
680 | pat_list.syntax().parent().and_then(ast::RecordPat::cast)?; | ||
681 | sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) | ||
682 | } else if let Some(let_stmt) = ast::LetStmt::cast(parent.clone()) { | ||
683 | let field_expr = | ||
684 | if let ast::Expr::FieldExpr(field_expr) = let_stmt.initializer()? { | ||
685 | field_expr | ||
686 | } else { | ||
687 | return None; | ||
688 | }; | ||
689 | |||
690 | sema.type_of_expr(&field_expr.expr()?) | ||
691 | } else if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent) { | ||
692 | let record_pat = record_field_pat | ||
693 | .syntax() | ||
694 | .parent() | ||
695 | .and_then(ast::RecordFieldPatList::cast)? | ||
696 | .syntax() | ||
697 | .parent() | ||
698 | .and_then(ast::RecordPat::cast)?; | ||
699 | sema.type_of_pat(&ast::Pat::RecordPat(record_pat)) | ||
700 | } else { | ||
701 | None | ||
702 | }?; | ||
703 | |||
704 | if !ty.is_packed(db) { | ||
705 | return None; | ||
706 | } | ||
707 | |||
708 | Some(HighlightModifier::Unsafe) | ||
709 | })(); | ||
710 | |||
711 | if let Some(modifier) = modifier { | ||
712 | h | modifier | ||
713 | } else { | ||
714 | h | ||
715 | } | ||
716 | } | ||
671 | _ => h, | 717 | _ => h, |
672 | } | 718 | } |
673 | } | 719 | } |
@@ -697,7 +743,13 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { | |||
697 | } | 743 | } |
698 | } | 744 | } |
699 | 745 | ||
700 | fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight { | 746 | fn highlight_name( |
747 | sema: &Semantics<RootDatabase>, | ||
748 | db: &RootDatabase, | ||
749 | def: Definition, | ||
750 | name_ref: Option<ast::NameRef>, | ||
751 | possibly_unsafe: bool, | ||
752 | ) -> Highlight { | ||
701 | match def { | 753 | match def { |
702 | Definition::Macro(_) => HighlightTag::Macro, | 754 | Definition::Macro(_) => HighlightTag::Macro, |
703 | Definition::Field(field) => { | 755 | Definition::Field(field) => { |
@@ -716,6 +768,29 @@ fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> | |||
716 | let mut h = HighlightTag::Function.into(); | 768 | let mut h = HighlightTag::Function.into(); |
717 | if func.is_unsafe(db) { | 769 | if func.is_unsafe(db) { |
718 | h |= HighlightModifier::Unsafe; | 770 | h |= HighlightModifier::Unsafe; |
771 | } else { | ||
772 | (|| { | ||
773 | let method_call_expr = | ||
774 | name_ref?.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | ||
775 | let expr = method_call_expr.expr()?; | ||
776 | let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { | ||
777 | Some(field_expr) | ||
778 | } else { | ||
779 | None | ||
780 | }?; | ||
781 | let ty = sema.type_of_expr(&field_expr.expr()?)?; | ||
782 | if !ty.is_packed(db) { | ||
783 | return None; | ||
784 | } | ||
785 | |||
786 | let func = sema.resolve_method_call(&method_call_expr)?; | ||
787 | if func.self_param(db)?.is_ref { | ||
788 | Some(HighlightModifier::Unsafe) | ||
789 | } else { | ||
790 | None | ||
791 | } | ||
792 | })() | ||
793 | .map(|modifier| h |= modifier); | ||
719 | } | 794 | } |
720 | return h; | 795 | return h; |
721 | } | 796 | } |
@@ -787,8 +862,33 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas | |||
787 | _ => return default.into(), | 862 | _ => return default.into(), |
788 | }; | 863 | }; |
789 | 864 | ||
790 | let tag = match parent.kind() { | 865 | match parent.kind() { |
791 | METHOD_CALL_EXPR => HighlightTag::Function, | 866 | METHOD_CALL_EXPR => { |
867 | let mut h = Highlight::new(HighlightTag::Function); | ||
868 | let modifier: Option<HighlightModifier> = (|| { | ||
869 | let method_call_expr = ast::MethodCallExpr::cast(parent)?; | ||
870 | let expr = method_call_expr.expr()?; | ||
871 | let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { | ||
872 | field_expr | ||
873 | } else { | ||
874 | return None; | ||
875 | }; | ||
876 | |||
877 | let expr = field_expr.expr()?; | ||
878 | let ty = sema.type_of_expr(&expr)?; | ||
879 | if ty.is_packed(sema.db) { | ||
880 | Some(HighlightModifier::Unsafe) | ||
881 | } else { | ||
882 | None | ||
883 | } | ||
884 | })(); | ||
885 | |||
886 | if let Some(modifier) = modifier { | ||
887 | h |= modifier; | ||
888 | } | ||
889 | |||
890 | h | ||
891 | } | ||
792 | FIELD_EXPR => { | 892 | FIELD_EXPR => { |
793 | let h = HighlightTag::Field; | 893 | let h = HighlightTag::Field; |
794 | let is_union = ast::FieldExpr::cast(parent) | 894 | let is_union = ast::FieldExpr::cast(parent) |
@@ -801,7 +901,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas | |||
801 | }) | 901 | }) |
802 | }) | 902 | }) |
803 | .unwrap_or(false); | 903 | .unwrap_or(false); |
804 | return if is_union { h | HighlightModifier::Unsafe } else { h.into() }; | 904 | if is_union { h | HighlightModifier::Unsafe } else { h.into() } |
805 | } | 905 | } |
806 | PATH_SEGMENT => { | 906 | PATH_SEGMENT => { |
807 | let path = match parent.parent().and_then(ast::Path::cast) { | 907 | 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<RootDatabas | |||
826 | }; | 926 | }; |
827 | 927 | ||
828 | match parent.kind() { | 928 | match parent.kind() { |
829 | CALL_EXPR => HighlightTag::Function, | 929 | CALL_EXPR => HighlightTag::Function.into(), |
830 | _ => { | 930 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { |
831 | if name.text().chars().next().unwrap_or_default().is_uppercase() { | 931 | HighlightTag::Struct.into() |
832 | HighlightTag::Struct | 932 | } else { |
833 | } else { | 933 | HighlightTag::Constant |
834 | HighlightTag::Constant | ||
835 | } | ||
836 | } | 934 | } |
935 | .into(), | ||
837 | } | 936 | } |
838 | } | 937 | } |
839 | _ => default, | 938 | _ => default.into(), |
840 | }; | 939 | } |
841 | |||
842 | tag.into() | ||
843 | } | 940 | } |
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 { | |||
301 | fn calls_autoref(&self); | 301 | fn calls_autoref(&self); |
302 | } | 302 | } |
303 | 303 | ||
304 | struct NeedsAlign { | 304 | impl DoTheAutoref for u16 { |
305 | a: u16 | ||
306 | } | ||
307 | |||
308 | #[repr(packed)] | ||
309 | struct HasAligned { | ||
310 | a: NeedsAlign | ||
311 | } | ||
312 | |||
313 | impl DoTheAutoref for NeedsAlign { | ||
314 | fn calls_autoref(&self) {} | 305 | fn calls_autoref(&self) {} |
315 | } | 306 | } |
316 | 307 | ||
@@ -318,6 +309,7 @@ fn main() { | |||
318 | let x = &5 as *const _ as *const usize; | 309 | let x = &5 as *const _ as *const usize; |
319 | let u = Union { b: 0 }; | 310 | let u = Union { b: 0 }; |
320 | unsafe { | 311 | unsafe { |
312 | // unsafe fn and method calls | ||
321 | unsafe_fn(); | 313 | unsafe_fn(); |
322 | let b = u.b; | 314 | let b = u.b; |
323 | match u { | 315 | match u { |
@@ -325,13 +317,22 @@ fn main() { | |||
325 | Union { a } => (), | 317 | Union { a } => (), |
326 | } | 318 | } |
327 | HasUnsafeFn.unsafe_method(); | 319 | HasUnsafeFn.unsafe_method(); |
328 | let _y = *(x); | 320 | |
329 | let z = -x; | 321 | // unsafe deref |
322 | let y = *x; | ||
323 | |||
324 | // unsafe access to a static mut | ||
330 | let a = global_mut.a; | 325 | let a = global_mut.a; |
326 | |||
327 | // unsafe ref of packed fields | ||
331 | let packed = Packed { a: 0 }; | 328 | let packed = Packed { a: 0 }; |
332 | let _a = &packed.a; | 329 | let a = &packed.a; |
333 | let h = HasAligned{ a: NeedsAlign { a: 1 } }; | 330 | let ref a = packed.a; |
334 | h.a.calls_autoref(); | 331 | let Packed { ref a } = packed; |
332 | let Packed { a: ref _a } = packed; | ||
333 | |||
334 | // unsafe auto ref of packed field | ||
335 | packed.a.calls_autoref(); | ||
335 | } | 336 | } |
336 | } | 337 | } |
337 | "# | 338 | "# |