mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Add diagnostic for break outside of loop
This commit is contained in:
parent
f8bf94a4b9
commit
d0129c4ddb
4 changed files with 62 additions and 1 deletions
|
@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
|
||||||
ast::Expr::cast(node).unwrap()
|
ast::Expr::cast(node).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BreakOutsideOfLoop {
|
||||||
|
pub file: HirFileId,
|
||||||
|
pub expr: AstPtr<ast::Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic for BreakOutsideOfLoop {
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"break outside of loop".to_string()
|
||||||
|
}
|
||||||
|
fn source(&self) -> InFile<SyntaxNodePtr> {
|
||||||
|
InFile { file_id: self.file, value: self.expr.clone().into() }
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AstDiagnostic for BreakOutsideOfLoop {
|
||||||
|
type AST = ast::Expr;
|
||||||
|
|
||||||
|
fn ast(&self, db: &impl AstDatabase) -> Self::AST {
|
||||||
|
let root = db.parse_or_expand(self.file).unwrap();
|
||||||
|
let node = self.source().value.to_node(&root);
|
||||||
|
ast::Expr::cast(node).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -717,11 +717,15 @@ mod diagnostics {
|
||||||
use hir_def::{expr::ExprId, FunctionId};
|
use hir_def::{expr::ExprId, FunctionId};
|
||||||
use hir_expand::diagnostics::DiagnosticSink;
|
use hir_expand::diagnostics::DiagnosticSink;
|
||||||
|
|
||||||
use crate::{db::HirDatabase, diagnostics::NoSuchField};
|
use crate::{
|
||||||
|
db::HirDatabase,
|
||||||
|
diagnostics::{BreakOutsideOfLoop, NoSuchField},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub(super) enum InferenceDiagnostic {
|
pub(super) enum InferenceDiagnostic {
|
||||||
NoSuchField { expr: ExprId, field: usize },
|
NoSuchField { expr: ExprId, field: usize },
|
||||||
|
BreakOutsideOfLoop { expr: ExprId },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InferenceDiagnostic {
|
impl InferenceDiagnostic {
|
||||||
|
@ -737,6 +741,13 @@ mod diagnostics {
|
||||||
let field = source_map.field_syntax(*expr, *field);
|
let field = source_map.field_syntax(*expr, *field);
|
||||||
sink.push(NoSuchField { file: field.file_id, field: field.value })
|
sink.push(NoSuchField { file: field.file_id, field: field.value })
|
||||||
}
|
}
|
||||||
|
InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
|
||||||
|
let (_, source_map) = db.body_with_source_map(owner.into());
|
||||||
|
let ptr = source_map
|
||||||
|
.expr_syntax(*expr)
|
||||||
|
.expect("break outside of loop in synthetic syntax");
|
||||||
|
sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
if let Some(ctxt) = self.breakables.last_mut() {
|
if let Some(ctxt) = self.breakables.last_mut() {
|
||||||
ctxt.may_break = true;
|
ctxt.may_break = true;
|
||||||
|
} else {
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||||
|
expr: tgt_expr,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ty::simple(TypeCtor::Never)
|
Ty::simple(TypeCtor::Never)
|
||||||
}
|
}
|
||||||
|
|
|
@ -518,3 +518,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
|
||||||
|
|
||||||
assert_snapshot!(diagnostics, @"");
|
assert_snapshot!(diagnostics, @"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn break_outside_of_loop() {
|
||||||
|
let diagnostics = TestDB::with_files(
|
||||||
|
r"
|
||||||
|
//- /lib.rs
|
||||||
|
fn foo() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.diagnostics()
|
||||||
|
.0;
|
||||||
|
|
||||||
|
assert_snapshot!(diagnostics, @r###""break": break outside of loop
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue