Merge pull request #94 from Manishearth/unicode

first unicode lint: zero_width_space
This commit is contained in:
llogiq 2015-06-11 17:10:20 +02:00
commit 9de0e25f29
6 changed files with 84 additions and 4 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,
]);
}

View file

@ -7,8 +7,8 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float};
use syntax::codemap::{Span, Spanned};
use types::span_note_and_lint;
use utils::match_path;
pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
match ty.sty {
@ -248,8 +248,8 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) {
},
&ExprCall(ref path, _) => {
if let &ExprPath(None, ref path) = &path.node {
if path.segments.iter().zip(["String", "from_str"].iter()).all(
|(seg, name)| &seg.identifier.as_str() == name) {
if match_path(path, &["String", "from_str"]) ||
match_path(path, &["String", "from"]) {
cx.span_lint(CMP_OWNED, expr.span, &format!(
"this creates an owned instance just for comparison. \
Consider using {}.as_slice() to compare without allocation",

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

@ -13,5 +13,11 @@ fn main() {
x != "foo".to_owned(); //~ERROR this creates an owned instance
x != String::from_str("foo"); //~ERROR this creates an owned instance
#[allow(deprecated)] // for from_str
fn old_timey(x : &str) {
x != String::from_str("foo"); //~ERROR this creates an owned instance
}
old_timey(x);
x != String::from("foo"); //~ERROR this creates an owned instance
}

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();
}