Add trim_multiline utility (fixes #139)

This commit is contained in:
Manish Goregaokar 2015-08-12 16:44:14 +05:30
parent 847070e19d
commit 83487c060f
4 changed files with 34 additions and 4 deletions

View file

@ -18,7 +18,7 @@ use rustc::middle::def::*;
use syntax::ast::*; use syntax::ast::*;
use syntax::ptr::P; use syntax::ptr::P;
use syntax::codemap::{Span, Spanned, ExpnInfo}; 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! { declare_lint! {
pub COLLAPSIBLE_IF, pub COLLAPSIBLE_IF,
@ -55,7 +55,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
"this if statement can be collapsed", "this if statement can be collapsed",
&format!("try\nif {} && {} {}", &format!("try\nif {} && {} {}",
check_to_string(cx, check), check_to_string(cx, check_inner), check_to_string(cx, check), check_to_string(cx, check_inner),
snippet(cx, content.span, ".."))); snippet_block(cx, content.span, "..")));
} }
} }
} }

View file

@ -1,5 +1,6 @@
#![feature(plugin_registrar, box_syntax)] #![feature(plugin_registrar, box_syntax)]
#![feature(rustc_private, collections)] #![feature(rustc_private, collections)]
#![feature(str_split_at)]
#![allow(unused_imports, unknown_lints)] #![allow(unused_imports, unknown_lints)]
#[macro_use] #[macro_use]

View file

@ -7,7 +7,7 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty; use rustc::middle::ty;
use syntax::codemap::{Span, Spanned}; 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 /// Handles uncategorized lints
/// Currently handles linting of if-let-able matches /// 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 // an enum is extended. So we only consider cases where a `_` wildcard is used
if arms[1].pats[0].node == PatWild(PatWildSingle) && if arms[1].pats[0].node == PatWild(PatWildSingle) &&
arms[0].pats.len() == 1 { 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 { let suggestion = if let ExprBlock(_) = arms[0].body.node {
body_code.into_owned() body_code.into_owned()
} else { } else {

View file

@ -51,6 +51,35 @@ 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)) 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<'a>(s: Cow<'a, str>, ignore_first: bool) -> Cow<'a, str> {
let x = s.lines().skip(ignore_first as usize)
.map(|l| l.char_indices()
.find(|&(_,x)| x != ' ')
.unwrap_or((l.len(),' ')).0)
.min().unwrap_or(0);
if x > 0 {
Cow::Owned(s.lines().enumerate().map(|(i,l)| if ignore_first && i==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 /// 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> { pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> {
let map = &cx.tcx.map; let map = &cx.tcx.map;