first unicode lint: zero_width_space

This commit is contained in:
llogiq 2015-06-11 11:35:00 +02:00
parent ad8841c20b
commit 23caf3cccc
4 changed files with 74 additions and 0 deletions

View file

@ -29,6 +29,7 @@ Lints included in this crate:
- `redundant_closure` warns on creating a closure where none is needed, e.g. `|x| foo(x)`, where `foo` can be used directly
- `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea
- `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }`
- `zero_width_space`: Warns on encountering a unicode zero-width space
To use, add the following lines to your Cargo.toml:

View file

@ -26,6 +26,7 @@ pub mod mut_mut;
pub mod len_zero;
pub mod attrs;
pub mod collapsible_if;
pub mod unicode;
pub mod utils;
#[plugin_registrar]
@ -49,6 +50,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_lint_pass(box misc::CmpOwned as LintPassObject);
reg.register_lint_pass(box attrs::AttrPass as LintPassObject);
reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject);
reg.register_lint_pass(box unicode::Unicode as LintPassObject);
reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST,
misc::SINGLE_MATCH, misc::STR_TO_STRING,
@ -67,5 +69,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
len_zero::LEN_WITHOUT_IS_EMPTY,
attrs::INLINE_ALWAYS,
collapsible_if::COLLAPSIBLE_IF,
unicode::ZERO_WIDTH_SPACE,
]);
}

45
src/unicode.rs Normal file
View file

@ -0,0 +1,45 @@
use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::{BytePos, Span};
declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" }
#[derive(Copy, Clone)]
pub struct Unicode;
impl LintPass for Unicode {
fn get_lints(&self) -> LintArray {
lint_array!(ZERO_WIDTH_SPACE)
}
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
if let ExprLit(ref lit) = expr.node {
if let LitStr(ref string, _) = lit.node {
check_str(cx, string, lit.span)
}
}
}
}
fn check_str(cx: &Context, string: &str, span: Span) {
let mut start: Option<usize> = None;
for (i, c) in string.char_indices() {
if c == '\u{200B}' {
if start.is_none() { start = Some(i); }
} else {
lint_zero_width(cx, span, start);
start = None;
}
}
lint_zero_width(cx, span, start);
}
fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) {
start.map(|index| {
cx.span_lint(ZERO_WIDTH_SPACE, Span {
lo: span.lo + BytePos(index as u32),
hi: span.lo + BytePos(index as u32),
expn_id: span.expn_id,
}, "Zero-width space detected. Consider using \\u{200B}")
});
}

View file

@ -0,0 +1,25 @@
#![feature(plugin)]
#![plugin(clippy)]
#[deny(zero_width_space)]
fn zero() {
print!("Here >< is a ZWS, and another");
//~^ ERROR Zero-width space detected. Consider using \u{200B}
//~^^ ERROR Zero-width space detected. Consider using \u{200B}
}
//#[deny(unicode_canon)]
fn canon() {
print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à
}
//#[deny(ascii_only)]
fn uni() {
println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC}
}
fn main() {
zero();
uni();
canon();
}