Add a lint pass to check for while true { ... } loops

And suggest changing them to loop { ... }. Had to fix the few
remaining while true loops (in core::io). Closes #1962.
This commit is contained in:
Tim Chevalier 2012-04-19 18:04:41 -07:00
parent 594d22e7e2
commit cdc8722f95
3 changed files with 47 additions and 5 deletions

View File

@ -110,7 +110,7 @@ impl reader_util for reader {
fn read_line() -> str {
let mut buf: [u8] = [];
while true {
loop {
let ch = self.read_byte();
if ch == -1 || ch == 10 { break; }
buf += [ch as u8];
@ -120,7 +120,7 @@ impl reader_util for reader {
fn read_c_str() -> str {
let mut buf: [u8] = [];
while true {
loop {
let ch = self.read_byte();
if ch < 1 { break; } else { buf += [ch as u8]; }
}

View File

@ -5,6 +5,7 @@ import syntax::attr;
import syntax::codemap::span;
import std::map::{map,hashmap,hash_from_strs};
import io::writer_util;
import syntax::print::pprust::expr_to_str;
export lint, ctypes, unused_imports;
export level, ignore, warn, error;
@ -12,17 +13,18 @@ export lookup_lint, lint_dict, get_lint_dict, check_crate;
#[doc="
A 'lint' check is a kind of miscallaneous constraint that a user _might_ want
A 'lint' check is a kind of miscellaneous constraint that a user _might_ want
to enforce, but might reasonably want to permit as well, on a module-by-module
basis. They contrast with static constraints enforced by other phases of the
compiler, which are generally required to hold in order to compile the program
correctly at all.
at all.
"]
enum lint {
ctypes,
unused_imports,
while_true
}
enum level {
@ -35,6 +37,10 @@ type lint_spec = @{lint: lint,
type lint_dict = hashmap<str,lint_spec>;
/*
Pass names should not contain a '-', as the compiler normalizes
'-' to '_' in command-line flags
*/
fn get_lint_dict() -> lint_dict {
let v = [
("ctypes",
@ -45,7 +51,12 @@ fn get_lint_dict() -> lint_dict {
("unused_imports",
@{lint: unused_imports,
desc: "imports that are never used",
default: ignore})
default: ignore}),
("while_true",
@{lint: while_true,
desc: "suggest using loop { } instead of while(true) { }",
default: warn})
];
hash_from_strs(v)
}
@ -165,11 +176,34 @@ fn check_item(cx: ctxt, i: @ast::item) {
alt lint {
ctypes { check_item_ctypes(cx, level, i); }
unused_imports { check_item_unused_imports(cx, level, i); }
while_true { check_item_while_true(cx, level, i); }
}
}
}
}
fn check_item_while_true(cx: ctxt, level: level, it: @ast::item) {
let visit = visit::mk_simple_visitor(@{
visit_expr: fn@(e: @ast::expr) {
alt e.node {
ast::expr_while(cond, _) {
alt cond.node {
ast::expr_lit(@{node: ast::lit_bool(true),_}) {
cx.span_lint(
level, e.span,
"Denote infinite loops with loop { ... }");
}
_ {}
}
}
_ {}
}
}
with *visit::default_simple_visitor()
});
visit::visit_item(it, (), visit);
}
fn check_item_unused_imports(_cx: ctxt, _level: level, _it: @ast::item) {
// FIXME: Don't know how to check this in lint yet, it's currently being
// done over in resolve. When resolve is rewritten, do it here instead.

View File

@ -0,0 +1,8 @@
// compile-flags: -W err-while-true
fn main() {
let mut i = 0;
while true { //! ERROR Denote infinite loops with loop
i += 1;
if i == 5 { break; }
}
}