mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 15:54:15 +00:00
Merge #6769
6769: Add native "remove this semicolon" diagnostics r=matklad a=ivan770 Closes #6739 ![demo2](https://user-images.githubusercontent.com/14003886/101530533-b76c3180-399a-11eb-9d18-5c8457721655.gif) Co-authored-by: ivan770 <leshenko.ivan770@gmail.com>
This commit is contained in:
commit
44978acf51
@ -5,5 +5,5 @@ pub use hir_expand::diagnostics::{
|
||||
};
|
||||
pub use hir_ty::diagnostics::{
|
||||
IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr,
|
||||
NoSuchField,
|
||||
NoSuchField, RemoveThisSemicolon,
|
||||
};
|
||||
|
@ -216,6 +216,30 @@ impl Diagnostic for MissingOkInTailExpr {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemoveThisSemicolon {
|
||||
pub file: HirFileId,
|
||||
pub expr: AstPtr<ast::Expr>,
|
||||
}
|
||||
|
||||
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<SyntaxNodePtr> {
|
||||
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.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId};
|
||||
use hir_def::{expr::Statement, path::path, resolver::HasResolver, AdtId, DefWithBodyId};
|
||||
use hir_expand::diagnostics::DiagnosticSink;
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{ast, AstPtr};
|
||||
@ -12,6 +12,7 @@ use crate::{
|
||||
diagnostics::{
|
||||
match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
|
||||
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields,
|
||||
RemoveThisSemicolon,
|
||||
},
|
||||
utils::variant_data,
|
||||
ApplicationTy, InferenceResult, Ty, TypeCtor,
|
||||
@ -76,8 +77,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);
|
||||
if let Expr::Block { statements, tail, .. } = body_expr {
|
||||
if let Some(t) = tail {
|
||||
self.validate_results_in_tail_expr(body.body_expr, *t, db);
|
||||
} else if let Some(Statement::Expr(id)) = statements.last() {
|
||||
self.validate_missing_tail_expr(body.body_expr, *id, db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,6 +322,34 @@ 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,
|
||||
};
|
||||
|
||||
let possible_tail_ty = match self.infer.type_of_expr.get(possible_tail_id) {
|
||||
Some(ty) => ty,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if mismatch.actual != Ty::unit() || mismatch.expected != *possible_tail_ty {
|
||||
return;
|
||||
}
|
||||
|
||||
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(
|
||||
|
@ -131,6 +131,9 @@ pub(crate) fn diagnostics(
|
||||
.on::<hir::diagnostics::NoSuchField, _>(|d| {
|
||||
res.borrow_mut().push(diagnostic_with_fix(d, &sema));
|
||||
})
|
||||
.on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| {
|
||||
res.borrow_mut().push(diagnostic_with_fix(d, &sema));
|
||||
})
|
||||
.on::<hir::diagnostics::IncorrectCase, _>(|d| {
|
||||
res.borrow_mut().push(warning_with_fix(d, &sema));
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ use hir::{
|
||||
db::AstDatabase,
|
||||
diagnostics::{
|
||||
Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField,
|
||||
UnresolvedModule,
|
||||
RemoveThisSemicolon, UnresolvedModule,
|
||||
},
|
||||
HasSource, HirDisplay, InFile, Semantics, VariantDef,
|
||||
};
|
||||
@ -105,6 +105,27 @@ impl DiagnosticWithFix for MissingOkInTailExpr {
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticWithFix for RemoveThisSemicolon {
|
||||
fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
|
||||
let root = sema.db.parse_or_expand(self.file)?;
|
||||
|
||||
let semicolon = self
|
||||
.expr
|
||||
.to_node(&root)
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::ExprStmt::cast)
|
||||
.and_then(|expr| expr.semicolon_token())?
|
||||
.text_range();
|
||||
|
||||
let edit = TextEdit::delete(semicolon);
|
||||
let source_change =
|
||||
SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
|
||||
|
||||
Some(Fix::new("Remove this semicolon", source_change, semicolon))
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticWithFix for IncorrectCase {
|
||||
fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
|
||||
let root = sema.db.parse_or_expand(self.file)?;
|
||||
|
Loading…
Reference in New Issue
Block a user