2015-06-11 04:35:00 -05:00
|
|
|
use rustc::lint::*;
|
|
|
|
use syntax::ast::*;
|
|
|
|
use syntax::codemap::{BytePos, Span};
|
2015-07-26 09:53:11 -05:00
|
|
|
use utils::span_lint;
|
2015-06-11 04:35:00 -05:00
|
|
|
|
|
|
|
declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" }
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct Unicode;
|
|
|
|
|
|
|
|
impl LintPass for Unicode {
|
2015-08-11 13:22:20 -05:00
|
|
|
fn get_lints(&self) -> LintArray {
|
2015-06-11 04:35:00 -05:00
|
|
|
lint_array!(ZERO_WIDTH_SPACE)
|
|
|
|
}
|
2015-08-11 13:22:20 -05:00
|
|
|
|
2015-06-11 04:35:00 -05:00
|
|
|
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
2015-08-11 13:22:20 -05:00
|
|
|
if let ExprLit(ref lit) = expr.node {
|
|
|
|
if let LitStr(ref string, _) = lit.node {
|
|
|
|
check_str(cx, string, lit.span)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-11 04:35:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_str(cx: &Context, string: &str, span: Span) {
|
2015-08-11 13:22:20 -05:00
|
|
|
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);
|
2015-06-11 04:35:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) {
|
2015-08-11 13:22:20 -05:00
|
|
|
start.map(|index| {
|
|
|
|
span_lint(cx, ZERO_WIDTH_SPACE, Span {
|
|
|
|
lo: span.lo + BytePos(index as u32),
|
|
|
|
hi: span.lo + BytePos(index as u32),
|
|
|
|
expn_id: span.expn_id,
|
2015-08-12 03:46:49 -05:00
|
|
|
}, "zero-width space detected. Consider using `\\u{200B}`.")
|
2015-08-11 13:22:20 -05:00
|
|
|
});
|
2015-06-11 04:35:00 -05:00
|
|
|
}
|