From 83487c060ff64498fb9a3eb472ce71af1d26fe89 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 12 Aug 2015 16:44:14 +0530 Subject: [PATCH] Add trim_multiline utility (fixes #139) --- src/collapsible_if.rs | 4 ++-- src/lib.rs | 1 + src/misc.rs | 4 ++-- src/utils.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index be34458e0dc..8a41f208938 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -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, ".."))); } } } diff --git a/src/lib.rs b/src/lib.rs index 9135ecaca6c..01a2d65606c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] +#![feature(str_split_at)] #![allow(unused_imports, unknown_lints)] #[macro_use] diff --git a/src/misc.rs b/src/misc.rs index 7372bfed6c5..861e4a73dd2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -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 { diff --git a/src/utils.rs b/src/utils.rs index c54a7f56f7e..5b9c995589b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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)) } +/// 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::>() + .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;