mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-26 22:50:56 +00:00
Merge pull request #94 from Manishearth/unicode
first unicode lint: zero_width_space
This commit is contained in:
commit
9de0e25f29
6 changed files with 84 additions and 4 deletions
|
@ -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:
|
||||
|
||||
|
|
|
@ -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,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -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
45
src/unicode.rs
Normal 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}")
|
||||
});
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
25
tests/compile-fail/unicode.rs
Normal file
25
tests/compile-fail/unicode.rs
Normal 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();
|
||||
}
|
Loading…
Reference in a new issue