Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs')
-rw-r--r--crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs175
1 files changed, 175 insertions, 0 deletions
diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
new file mode 100644
index 0000000000..32e321107e
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -0,0 +1,175 @@
+use crate::{Diagnostic, DiagnosticsContext};
+use hir::HirDisplay;
+
+// Diagnostic: moved-out-of-ref
+//
+// This diagnostic is triggered on moving non copy things out of references.
+pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOfRef) -> Diagnostic {
+ Diagnostic::new(
+ "moved-out-of-ref",
+ format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)),
+ ctx.sema.diagnostics_display_range(d.span.clone()).range,
+ )
+ .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ // FIXME: spans are broken
+
+ #[test]
+ fn move_by_explicit_deref() {
+ check_diagnostics(
+ r#"
+struct X;
+fn main() {
+ let a = &X;
+ let b = *a;
+ //^ error: cannot move `X` out of reference
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn move_out_of_field() {
+ check_diagnostics(
+ r#"
+//- minicore: copy
+struct X;
+struct Y(X, i32);
+fn main() {
+ let a = &Y(X, 5);
+ let b = a.0;
+ //^ error: cannot move `X` out of reference
+ let y = a.1;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn move_out_of_static() {
+ check_diagnostics(
+ r#"
+//- minicore: copy
+struct X;
+fn main() {
+ static S: X = X;
+ let s = S;
+ //^ error: cannot move `X` out of reference
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn generic_types() {
+ check_diagnostics(
+ r#"
+//- minicore: derive, copy
+
+#[derive(Copy)]
+struct X<T>(T);
+struct Y;
+
+fn consume<T>(_: X<T>) {
+
+}
+
+fn main() {
+ let a = &X(Y);
+ consume(*a);
+ //^^^^^^^^^^^ error: cannot move `X<Y>` out of reference
+ let a = &X(5);
+ consume(*a);
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn no_false_positive_simple() {
+ check_diagnostics(
+ r#"
+//- minicore: copy
+fn f(_: i32) {}
+fn main() {
+ let x = &2;
+ f(*x);
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn no_false_positive_unknown_type() {
+ check_diagnostics(
+ r#"
+//- minicore: derive, copy
+fn f(x: &Unknown) -> Unknown {
+ *x
+}
+
+#[derive(Copy)]
+struct X<T>(T);
+
+struct Y<T>(T);
+
+fn g(x: &X<Unknown>) -> X<Unknown> {
+ *x
+}
+
+fn h(x: &Y<Unknown>) -> Y<Unknown> {
+ // FIXME: we should show error for this, as `Y` is not copy
+ // regardless of its generic parameter.
+ *x
+}
+
+"#,
+ );
+ }
+
+ #[test]
+ fn no_false_positive_dyn_fn() {
+ check_diagnostics(
+ r#"
+//- minicore: copy, fn
+fn f(x: &mut &mut dyn Fn()) {
+ x();
+}
+
+struct X<'a> {
+ field: &'a mut dyn Fn(),
+}
+
+fn f(x: &mut X<'_>) {
+ (x.field)();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn no_false_positive_match_and_closure_capture() {
+ check_diagnostics(
+ r#"
+//- minicore: copy, fn
+enum X {
+ Foo(u16),
+ Bar,
+}
+
+fn main() {
+ let x = &X::Bar;
+ let c = || match *x {
+ X::Foo(t) => t,
+ _ => 5,
+ };
+}
+ "#,
+ );
+ }
+}