Skip to content

Commit 20340ac

Browse files
committed
Update lint declaration example
1 parent c2561c4 commit 20340ac

File tree

1 file changed

+30
-20
lines changed

1 file changed

+30
-20
lines changed

src/diagnostics.md

+30-20
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ crate.
275275

276276
Every lint is implemented via a `struct` that implements the `LintPass` `trait`
277277
(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
279279
check certain syntactic constructs as the linter walks the source code. You can
280280
then choose to emit lints in a very similar way to compile errors.
281281

@@ -300,35 +300,45 @@ declare_lint! {
300300
"suggest using `loop { }` instead of `while true { }`"
301301
}
302302
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
308304
// compiler currently doesn't use the associated lints directly (e.g., to not
309305
// run the pass or otherwise check that the pass emits the appropriate set of
310306
// lints). However, it's good to be accurate here as it's possible that we're
311307
// going to register the lints via the get_lints method on our lint pass (that
312308
// 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+
}
316319
317-
// LateLintPass has lots of methods. We only override the definition of
320+
// `EarlyLintPass` has lots of methods. We only override the definition of
318321
// `check_expr` for this lint because that's all we need, but you could
319322
// override other methods for your own lint. See the rustc docs for a full
320323
// 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() {
327330
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+
})
332342
}
333343
}
334344
}

0 commit comments

Comments
 (0)