Auto merge of #96745 - ehuss:even-more-attribute-validation, r=cjgillot
Visit attributes in more places. This adds 3 loosely related changes (I can split PRs if desired): - Attribute checking on pattern struct fields. - Attribute checking on struct expression fields. - Lint level visiting on pattern struct fields, struct expression fields, and generic parameters. There are still some lints which ignore lint levels in various positions. This is a consequence of how the lints themselves are implemented. For example, lint levels on associated consts don't work with `unused_braces`.
This commit is contained in:
commit
6ce76091c7
23 changed files with 1520 additions and 141 deletions
|
@ -101,6 +101,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
run_early_pass!(self, check_pat_post, p);
|
||||
}
|
||||
|
||||
fn visit_pat_field(&mut self, field: &'a ast::PatField) {
|
||||
self.with_lint_attrs(field.id, &field.attrs, |cx| {
|
||||
ast_visit::walk_pat_field(cx, field);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'a ast::AnonConst) {
|
||||
self.check_id(c.id);
|
||||
ast_visit::walk_anon_const(self, c);
|
||||
|
@ -219,9 +225,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
|
||||
run_early_pass!(self, check_generic_param, param);
|
||||
self.check_id(param.id);
|
||||
ast_visit::walk_generic_param(self, param);
|
||||
self.with_lint_attrs(param.id, ¶m.attrs, |cx| {
|
||||
run_early_pass!(cx, check_generic_param, param);
|
||||
ast_visit::walk_generic_param(cx, param);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
||||
|
|
|
@ -766,6 +766,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
|
||||
self.with_lint_attrs(field.hir_id, |builder| {
|
||||
intravisit::walk_expr_field(builder, field);
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
|
||||
self.with_lint_attrs(s.hir_id, |builder| {
|
||||
intravisit::walk_field_def(builder, s);
|
||||
|
@ -801,6 +807,18 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
|
|||
intravisit::walk_impl_item(builder, impl_item);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
|
||||
self.with_lint_attrs(field.hir_id, |builder| {
|
||||
intravisit::walk_pat_field(builder, field);
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
||||
self.with_lint_attrs(p.hir_id, |builder| {
|
||||
intravisit::walk_generic_param(builder, p);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
|
|
@ -437,19 +437,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
|
||||
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
|
||||
if let PatKind::Binding(_, hid, ident, _) = p.kind {
|
||||
if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
|
||||
if let hir::Node::PatField(field) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
|
||||
{
|
||||
if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind {
|
||||
if field_pats
|
||||
.iter()
|
||||
.any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id)
|
||||
{
|
||||
// Only check if a new name has been introduced, to avoid warning
|
||||
// on both the struct definition and this pattern.
|
||||
self.check_snake_case(cx, "variable", &ident);
|
||||
}
|
||||
return;
|
||||
if !field.is_shorthand {
|
||||
// Only check if a new name has been introduced, to avoid warning
|
||||
// on both the struct definition and this pattern.
|
||||
self.check_snake_case(cx, "variable", &ident);
|
||||
}
|
||||
return;
|
||||
}
|
||||
self.check_snake_case(cx, "variable", &ident);
|
||||
}
|
||||
|
|
|
@ -125,45 +125,51 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
|||
lit_val: u128,
|
||||
max: u128,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
parent_expr: &'tcx hir::Expr<'tcx>,
|
||||
ty: &str,
|
||||
) -> bool {
|
||||
// We only want to handle exclusive (`..`) ranges,
|
||||
// which are represented as `ExprKind::Struct`.
|
||||
let par_id = cx.tcx.hir().get_parent_node(expr.hir_id);
|
||||
let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false };
|
||||
let field_par_id = cx.tcx.hir().get_parent_node(field.hir_id);
|
||||
let Node::Expr(struct_expr) = cx.tcx.hir().get(field_par_id) else { return false };
|
||||
if !is_range_literal(struct_expr) {
|
||||
return false;
|
||||
};
|
||||
let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false };
|
||||
if eps.len() != 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut overwritten = false;
|
||||
if let ExprKind::Struct(_, eps, _) = &parent_expr.kind {
|
||||
if eps.len() != 2 {
|
||||
return false;
|
||||
}
|
||||
// We can suggest using an inclusive range
|
||||
// (`..=`) instead only if it is the `end` that is
|
||||
// overflowing and only by 1.
|
||||
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| {
|
||||
let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
|
||||
err.set_arg("ty", ty);
|
||||
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
|
||||
use ast::{LitIntType, LitKind};
|
||||
// We need to preserve the literal's suffix,
|
||||
// as it may determine typing information.
|
||||
let suffix = match lit.node {
|
||||
LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) => "",
|
||||
_ => bug!(),
|
||||
};
|
||||
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
|
||||
err.span_suggestion(
|
||||
parent_expr.span,
|
||||
fluent::lint::suggestion,
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
overwritten = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// We can suggest using an inclusive range
|
||||
// (`..=`) instead only if it is the `end` that is
|
||||
// overflowing and only by 1.
|
||||
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| {
|
||||
let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
|
||||
err.set_arg("ty", ty);
|
||||
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
|
||||
use ast::{LitIntType, LitKind};
|
||||
// We need to preserve the literal's suffix,
|
||||
// as it may determine typing information.
|
||||
let suffix = match lit.node {
|
||||
LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) => "",
|
||||
_ => bug!(),
|
||||
};
|
||||
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
|
||||
err.span_suggestion(
|
||||
struct_expr.span,
|
||||
fluent::lint::suggestion,
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
overwritten = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
overwritten
|
||||
}
|
||||
|
@ -339,16 +345,9 @@ fn lint_int_literal<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
|
||||
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
|
||||
if let hir::ExprKind::Struct(..) = par_e.kind {
|
||||
if is_range_literal(par_e)
|
||||
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
|
||||
{
|
||||
// The overflowing literal lint was overridden.
|
||||
return;
|
||||
}
|
||||
}
|
||||
if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) {
|
||||
// The overflowing literal lint was overridden.
|
||||
return;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
|
||||
|
@ -408,16 +407,13 @@ fn lint_uint_literal<'tcx>(
|
|||
return;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Struct(..) if is_range_literal(par_e) => {
|
||||
let t = t.name_str();
|
||||
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
|
||||
// The overflowing literal lint was overridden.
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) {
|
||||
// The overflowing literal lint was overridden.
|
||||
return;
|
||||
}
|
||||
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
|
||||
report_bin_hex_error(
|
||||
cx,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue