mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-14 08:57:30 +00:00
Merge pull request #141 from Manishearth/multilinetrim
Add trim_multiline utility (fixes #139)
This commit is contained in:
commit
1afc5b6235
5 changed files with 97 additions and 4 deletions
|
@ -18,7 +18,7 @@ use rustc::middle::def::*;
|
|||
use syntax::ast::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::{Span, Spanned, ExpnInfo};
|
||||
use utils::{in_macro, span_help_and_lint, snippet};
|
||||
use utils::{in_macro, span_help_and_lint, snippet, snippet_block};
|
||||
|
||||
declare_lint! {
|
||||
pub COLLAPSIBLE_IF,
|
||||
|
@ -55,7 +55,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
|
|||
"this if statement can be collapsed",
|
||||
&format!("try\nif {} && {} {}",
|
||||
check_to_string(cx, check), check_to_string(cx, check_inner),
|
||||
snippet(cx, content.span, "..")));
|
||||
snippet_block(cx, content.span, "..")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(plugin_registrar, box_syntax)]
|
||||
#![feature(rustc_private, collections)]
|
||||
#![feature(str_split_at)]
|
||||
#![allow(unused_imports, unknown_lints)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
|
|||
use rustc::middle::ty;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
|
||||
use utils::{match_path, snippet, span_lint, span_help_and_lint, walk_ptrs_ty};
|
||||
use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty};
|
||||
|
||||
/// Handles uncategorized lints
|
||||
/// Currently handles linting of if-let-able matches
|
||||
|
@ -37,7 +37,7 @@ impl LintPass for MiscPass {
|
|||
// an enum is extended. So we only consider cases where a `_` wildcard is used
|
||||
if arms[1].pats[0].node == PatWild(PatWildSingle) &&
|
||||
arms[0].pats.len() == 1 {
|
||||
let body_code = snippet(cx, arms[0].body.span, "..");
|
||||
let body_code = snippet_block(cx, arms[0].body.span, "..");
|
||||
let suggestion = if let ExprBlock(_) = arms[0].body.node {
|
||||
body_code.into_owned()
|
||||
} else {
|
||||
|
|
38
src/utils.rs
38
src/utils.rs
|
@ -51,6 +51,44 @@ pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> {
|
|||
cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default))
|
||||
}
|
||||
|
||||
/// convert a span (from a block) to a code snippet if available, otherwise use default, e.g.
|
||||
/// `snippet(cx, expr.span, "..")`
|
||||
/// This trims the code of indentation, except for the first line
|
||||
/// Use it for blocks or block-like things which need to be printed as such
|
||||
pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> {
|
||||
let snip = snippet(cx, span, default);
|
||||
trim_multiline(snip, true)
|
||||
}
|
||||
|
||||
/// Trim indentation from a multiline string
|
||||
/// with possibility of ignoring the first line
|
||||
pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> {
|
||||
let s = trim_multiline_inner(s, ignore_first, ' ');
|
||||
let s = trim_multiline_inner(s, ignore_first, '\t');
|
||||
trim_multiline_inner(s, ignore_first, ' ')
|
||||
}
|
||||
|
||||
fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> {
|
||||
let x = s.lines().skip(ignore_first as usize)
|
||||
.filter_map(|l| { if l.len() > 0 { // ignore empty lines
|
||||
Some(l.char_indices()
|
||||
.find(|&(_,x)| x != ch)
|
||||
.unwrap_or((l.len(), ch)).0)
|
||||
} else {None}})
|
||||
.min().unwrap_or(0);
|
||||
if x > 0 {
|
||||
Cow::Owned(s.lines().enumerate().map(|(i,l)| if (ignore_first && i == 0) ||
|
||||
l.len() == 0 {
|
||||
l
|
||||
} else {
|
||||
l.split_at(x).1
|
||||
}).collect::<Vec<_>>()
|
||||
.join("\n"))
|
||||
} else {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
/// get a parent expr if any – this is useful to constrain a lint
|
||||
pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> {
|
||||
let map = &cx.tcx.map;
|
||||
|
|
54
tests/trim_multiline.rs
Normal file
54
tests/trim_multiline.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
/// test the multiline-trim function
|
||||
#[allow(plugin_as_library)]
|
||||
extern crate clippy;
|
||||
|
||||
use clippy::utils::trim_multiline;
|
||||
|
||||
#[test]
|
||||
fn test_single_line() {
|
||||
assert_eq!("", trim_multiline("".into(), false));
|
||||
assert_eq!("...", trim_multiline("...".into(), false));
|
||||
assert_eq!("...", trim_multiline(" ...".into(), false));
|
||||
assert_eq!("...", trim_multiline("\t...".into(), false));
|
||||
assert_eq!("...", trim_multiline("\t\t...".into(), false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block() {
|
||||
assert_eq!("\
|
||||
if x {
|
||||
y
|
||||
} else {
|
||||
z
|
||||
}", trim_multiline(" if x {
|
||||
y
|
||||
} else {
|
||||
z
|
||||
}".into(), false));
|
||||
assert_eq!("\
|
||||
if x {
|
||||
\ty
|
||||
} else {
|
||||
\tz
|
||||
}", trim_multiline(" if x {
|
||||
\ty
|
||||
} else {
|
||||
\tz
|
||||
}".into(), false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_line() {
|
||||
assert_eq!("\
|
||||
if x {
|
||||
y
|
||||
|
||||
} else {
|
||||
z
|
||||
}", trim_multiline(" if x {
|
||||
y
|
||||
|
||||
} else {
|
||||
z
|
||||
}".into(), false));
|
||||
}
|
Loading…
Reference in a new issue