@@ -275,7 +275,7 @@ crate.
275
275
276
276
Every lint is implemented via a ` struct ` that implements the ` LintPass ` ` trait `
277
277
(you also implement one of the more specific lint pass traits, either
278
- ` EarlyLintPass ` or ` LateLintPass ` ). The trait implementation allows you to
278
+ ` EarlyLintPass ` or ` LateLintPass ` ). The trait implementation allows you to
279
279
check certain syntactic constructs as the linter walks the source code. You can
280
280
then choose to emit lints in a very similar way to compile errors.
281
281
@@ -300,35 +300,45 @@ declare_lint! {
300
300
"suggest using `loop { }` instead of `while true { }`"
301
301
}
302
302
303
- // Define a struct and `impl LintPass` for it.
304
- #[derive(Copy, Clone)]
305
- pub struct WhileTrue;
306
-
307
- // This declares a lint pass, providing a list of associated lints. The
303
+ // This declares a struct and a lint pass, providing a list of associated lints. The
308
304
// compiler currently doesn't use the associated lints directly (e.g., to not
309
305
// run the pass or otherwise check that the pass emits the appropriate set of
310
306
// lints). However, it's good to be accurate here as it's possible that we're
311
307
// going to register the lints via the get_lints method on our lint pass (that
312
308
// this macro generates).
313
- impl_lint_pass!(
314
- WhileTrue => [WHILE_TRUE],
315
- );
309
+ declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
310
+
311
+ // Helper function for `WhileTrue` lint.
312
+ // Traverse through any amount of parenthesis and return the first non-parens expression.
313
+ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
314
+ while let ast::ExprKind::Paren(sub) = &expr.kind {
315
+ expr = sub;
316
+ }
317
+ expr
318
+ }
316
319
317
- // LateLintPass has lots of methods. We only override the definition of
320
+ // `EarlyLintPass` has lots of methods. We only override the definition of
318
321
// `check_expr` for this lint because that's all we need, but you could
319
322
// override other methods for your own lint. See the rustc docs for a full
320
323
// list of methods.
321
- impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
322
- fn check_expr(&mut self, cx: &LateContext , e: &hir ::Expr) {
323
- if let hir::ExprWhile(ref cond, ..) = e.node {
324
- if let hir::ExprLit (ref lit) = cond.node {
325
- if let ast::LitKind::Bool(true) = lit.node {
326
- if lit.span.ctxt() == SyntaxContext::empty () {
324
+ impl EarlyLintPass for WhileTrue {
325
+ fn check_expr(&mut self, cx: &EarlyContext<'_> , e: &ast ::Expr) {
326
+ if let ast::ExprKind::While( cond, ..) = &e.kind {
327
+ if let ast::ExprKind::Lit (ref lit) = pierce_parens( cond).kind {
328
+ if let ast::LitKind::Bool(true) = lit.kind {
329
+ if ! lit.span.from_expansion () {
327
330
let msg = "denote infinite loops with `loop { ... }`";
328
- let condition_span = cx.tcx.sess.source_map().def_span(e.span);
329
- let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
330
- err.span_suggestion_short(condition_span, "use `loop`", "loop".to_owned());
331
- err.emit();
331
+ let condition_span = cx.sess.source_map().guess_head_span(e.span);
332
+ cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
333
+ lint.build(msg)
334
+ .span_suggestion_short(
335
+ condition_span,
336
+ "use `loop`",
337
+ "loop".to_owned(),
338
+ Applicability::MachineApplicable,
339
+ )
340
+ .emit();
341
+ })
332
342
}
333
343
}
334
344
}
0 commit comments