diff options
author | Florian Diebold <[email protected]> | 2020-05-08 18:48:03 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-05-08 18:48:03 +0100 |
commit | d0129c4ddba3b72e7b26e94e9c25546d37dbf166 (patch) | |
tree | 465c1af378252ce1fea0f47e30f69892332761a0 | |
parent | f8bf94a4b94074eb344e495dfb4dab4bec6bc20e (diff) |
Add diagnostic for break outside of loop
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 18 |
4 files changed, 62 insertions, 1 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index c8fd54861..41ac70272 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr { | |||
131 | ast::Expr::cast(node).unwrap() | 131 | ast::Expr::cast(node).unwrap() |
132 | } | 132 | } |
133 | } | 133 | } |
134 | |||
135 | #[derive(Debug)] | ||
136 | pub struct BreakOutsideOfLoop { | ||
137 | pub file: HirFileId, | ||
138 | pub expr: AstPtr<ast::Expr>, | ||
139 | } | ||
140 | |||
141 | impl Diagnostic for BreakOutsideOfLoop { | ||
142 | fn message(&self) -> String { | ||
143 | "break outside of loop".to_string() | ||
144 | } | ||
145 | fn source(&self) -> InFile<SyntaxNodePtr> { | ||
146 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
147 | } | ||
148 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
149 | self | ||
150 | } | ||
151 | } | ||
152 | |||
153 | impl AstDiagnostic for BreakOutsideOfLoop { | ||
154 | type AST = ast::Expr; | ||
155 | |||
156 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { | ||
157 | let root = db.parse_or_expand(self.file).unwrap(); | ||
158 | let node = self.source().value.to_node(&root); | ||
159 | ast::Expr::cast(node).unwrap() | ||
160 | } | ||
161 | } | ||
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 413904518..a21ad8d86 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -717,11 +717,15 @@ mod diagnostics { | |||
717 | use hir_def::{expr::ExprId, FunctionId}; | 717 | use hir_def::{expr::ExprId, FunctionId}; |
718 | use hir_expand::diagnostics::DiagnosticSink; | 718 | use hir_expand::diagnostics::DiagnosticSink; |
719 | 719 | ||
720 | use crate::{db::HirDatabase, diagnostics::NoSuchField}; | 720 | use crate::{ |
721 | db::HirDatabase, | ||
722 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | ||
723 | }; | ||
721 | 724 | ||
722 | #[derive(Debug, PartialEq, Eq, Clone)] | 725 | #[derive(Debug, PartialEq, Eq, Clone)] |
723 | pub(super) enum InferenceDiagnostic { | 726 | pub(super) enum InferenceDiagnostic { |
724 | NoSuchField { expr: ExprId, field: usize }, | 727 | NoSuchField { expr: ExprId, field: usize }, |
728 | BreakOutsideOfLoop { expr: ExprId }, | ||
725 | } | 729 | } |
726 | 730 | ||
727 | impl InferenceDiagnostic { | 731 | impl InferenceDiagnostic { |
@@ -737,6 +741,13 @@ mod diagnostics { | |||
737 | let field = source_map.field_syntax(*expr, *field); | 741 | let field = source_map.field_syntax(*expr, *field); |
738 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | 742 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
739 | } | 743 | } |
744 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
745 | let (_, source_map) = db.body_with_source_map(owner.into()); | ||
746 | let ptr = source_map | ||
747 | .expr_syntax(*expr) | ||
748 | .expect("break outside of loop in synthetic syntax"); | ||
749 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
750 | } | ||
740 | } | 751 | } |
741 | } | 752 | } |
742 | } | 753 | } |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 9cac0c787..0b67d216a 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -235,6 +235,10 @@ impl<'a> InferenceContext<'a> { | |||
235 | } | 235 | } |
236 | if let Some(ctxt) = self.breakables.last_mut() { | 236 | if let Some(ctxt) = self.breakables.last_mut() { |
237 | ctxt.may_break = true; | 237 | ctxt.may_break = true; |
238 | } else { | ||
239 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { | ||
240 | expr: tgt_expr, | ||
241 | }); | ||
238 | } | 242 | } |
239 | Ty::simple(TypeCtor::Never) | 243 | Ty::simple(TypeCtor::Never) |
240 | } | 244 | } |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index d60732e19..5af88b368 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -518,3 +518,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | |||
518 | 518 | ||
519 | assert_snapshot!(diagnostics, @""); | 519 | assert_snapshot!(diagnostics, @""); |
520 | } | 520 | } |
521 | |||
522 | #[test] | ||
523 | fn break_outside_of_loop() { | ||
524 | let diagnostics = TestDB::with_files( | ||
525 | r" | ||
526 | //- /lib.rs | ||
527 | fn foo() { | ||
528 | break; | ||
529 | } | ||
530 | ", | ||
531 | ) | ||
532 | .diagnostics() | ||
533 | .0; | ||
534 | |||
535 | assert_snapshot!(diagnostics, @r###""break": break outside of loop | ||
536 | "### | ||
537 | ); | ||
538 | } | ||