From cb66bb8ff9609d4fc3702ac1ed6197802b54e473 Mon Sep 17 00:00:00 2001 From: ivan770 Date: Tue, 8 Dec 2020 20:47:20 +0200 Subject: Remove this semicolon --- crates/hir_ty/src/diagnostics.rs | 24 ++++++++++++++++++++++++ crates/hir_ty/src/diagnostics/expr.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'crates/hir_ty') diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index b58fe0ed7..e59487e54 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs @@ -216,6 +216,30 @@ impl Diagnostic for MissingOkInTailExpr { } } +#[derive(Debug)] +pub struct RemoveThisSemicolon { + pub file: HirFileId, + pub expr: AstPtr, +} + +impl Diagnostic for RemoveThisSemicolon { + fn code(&self) -> DiagnosticCode { + DiagnosticCode("remove-this-semicolon") + } + + fn message(&self) -> String { + "Remove this semicolon".to_string() + } + + fn display_source(&self) -> InFile { + InFile { file_id: self.file, value: self.expr.clone().into() } + } + + fn as_any(&self) -> &(dyn Any + Send + 'static) { + self + } +} + // Diagnostic: break-outside-of-loop // // This diagnostic is triggered if `break` keyword is used outside of a loop. diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 434b19354..313422968 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId}; +use hir_def::{AdtId, DefWithBodyId, expr::Statement, path::path, resolver::HasResolver}; use hir_expand::diagnostics::DiagnosticSink; use rustc_hash::FxHashSet; use syntax::{ast, AstPtr}; @@ -23,6 +23,8 @@ pub(crate) use hir_def::{ LocalFieldId, VariantId, }; +use super::RemoveThisSemicolon; + pub(super) struct ExprValidator<'a, 'b: 'a> { owner: DefWithBodyId, infer: Arc, @@ -78,6 +80,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> { let body_expr = &body[body.body_expr]; if let Expr::Block { tail: Some(t), .. } = body_expr { self.validate_results_in_tail_expr(body.body_expr, *t, db); + } else { + if let Expr::Block { statements, .. } = body_expr { + if let Some(Statement::Expr(id)) = statements.last() { + self.validate_missing_tail_expr(body.body_expr, *id, db); + } + } } } @@ -317,6 +325,23 @@ impl<'a, 'b> ExprValidator<'a, 'b> { } } } + + fn validate_missing_tail_expr(&mut self, body_id: ExprId, possible_tail_id: ExprId, db: &dyn HirDatabase) { + let mismatch = match self.infer.type_mismatch_for_expr(body_id) { + Some(m) => m, + None => return, + }; + + if let Some(possible_tail_ty) = self.infer.type_of_expr.get(possible_tail_id) { + if mismatch.actual == Ty::unit() && mismatch.expected == *possible_tail_ty { + let (_, source_map) = db.body_with_source_map(self.owner.into()); + + if let Ok(source_ptr) = source_map.expr_syntax(possible_tail_id) { + self.sink.push(RemoveThisSemicolon { file: source_ptr.file_id, expr: source_ptr.value }); + } + } + } + } } pub fn record_literal_missing_fields( -- cgit v1.2.3