@@ -457,7 +457,7 @@ crate.
457457
458458Every lint is implemented via a ` struct ` that implements the ` LintPass ` ` trait `
459459(you also implement one of the more specific lint pass traits, either
460- ` EarlyLintPass ` or ` LateLintPass ` ). The trait implementation allows you to
460+ ` EarlyLintPass ` or ` LateLintPass ` ). The trait implementation allows you to
461461check certain syntactic constructs as the linter walks the source code. You can
462462then choose to emit lints in a very similar way to compile errors.
463463
@@ -482,35 +482,45 @@ declare_lint! {
482482 "suggest using `loop { }` instead of `while true { }`"
483483}
484484
485- // Define a struct and `impl LintPass` for it.
486- #[derive(Copy, Clone)]
487- pub struct WhileTrue;
488-
489- // This declares a lint pass, providing a list of associated lints. The
485+ // This declares a struct and a lint pass, providing a list of associated lints. The
490486// compiler currently doesn't use the associated lints directly (e.g., to not
491487// run the pass or otherwise check that the pass emits the appropriate set of
492488// lints). However, it's good to be accurate here as it's possible that we're
493489// going to register the lints via the get_lints method on our lint pass (that
494490// this macro generates).
495- impl_lint_pass!(
496- WhileTrue => [WHILE_TRUE],
497- );
491+ declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
492+
493+ // Helper function for `WhileTrue` lint.
494+ // Traverse through any amount of parenthesis and return the first non-parens expression.
495+ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
496+ while let ast::ExprKind::Paren(sub) = &expr.kind {
497+ expr = sub;
498+ }
499+ expr
500+ }
498501
499- // LateLintPass has lots of methods. We only override the definition of
502+ // `EarlyLintPass` has lots of methods. We only override the definition of
500503// `check_expr` for this lint because that's all we need, but you could
501504// override other methods for your own lint. See the rustc docs for a full
502505// list of methods.
503- impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
504- fn check_expr(&mut self, cx: &LateContext , e: &hir ::Expr) {
505- if let hir::ExprWhile(ref cond, ..) = e.node {
506- if let hir::ExprLit (ref lit) = cond.node {
507- if let ast::LitKind::Bool(true) = lit.node {
508- if lit.span.ctxt() == SyntaxContext::empty () {
506+ impl EarlyLintPass for WhileTrue {
507+ fn check_expr(&mut self, cx: &EarlyContext<'_> , e: &ast ::Expr) {
508+ if let ast::ExprKind::While( cond, ..) = &e.kind {
509+ if let ast::ExprKind::Lit (ref lit) = pierce_parens( cond).kind {
510+ if let ast::LitKind::Bool(true) = lit.kind {
511+ if ! lit.span.from_expansion () {
509512 let msg = "denote infinite loops with `loop { ... }`";
510- let condition_span = cx.tcx.sess.source_map().def_span(e.span);
511- let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
512- err.span_suggestion_short(condition_span, "use `loop`", "loop".to_owned());
513- err.emit();
513+ let condition_span = cx.sess.source_map().guess_head_span(e.span);
514+ cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
515+ lint.build(msg)
516+ .span_suggestion_short(
517+ condition_span,
518+ "use `loop`",
519+ "loop".to_owned(),
520+ Applicability::MachineApplicable,
521+ )
522+ .emit();
523+ })
514524 }
515525 }
516526 }
0 commit comments