Suggest removing inline attributes

This adds a `suggest_remove_item` helper that will remove an item and
all trailing whitespace. This should handle both attributes on the same
line as the function and on a separate line; the function takes the
position of the original attribute.
This commit is contained in:
Ryan Cumming 2018-01-18 06:08:03 +11:00
parent 5f3c340bfb
commit 7467b83377
4 changed files with 64 additions and 11 deletions

View File

@ -3,7 +3,8 @@
use rustc::lint::*;
use rustc::hir::*;
use syntax::ast::{Attribute, Name};
use utils::span_lint;
use utils::span_lint_and_then;
use utils::sugg::DiagnosticBuilderExt;
/// **What it does:** Checks for `#[inline]` on trait methods without bodies
///
@ -51,11 +52,14 @@ fn check_attrs(cx: &LateContext, name: &Name, attrs: &[Attribute]) {
continue;
}
span_lint(
span_lint_and_then(
cx,
INLINE_FN_WITHOUT_BODY,
attr.span,
&format!("use of `#[inline]` on trait method `{}` which has no body", name),
|db| {
db.suggest_remove_item(cx, attr.span, "remove");
},
);
}
}

View File

@ -15,6 +15,7 @@ use syntax::print::pprust::token_to_string;
use syntax::util::parser::AssocOp;
use syntax::ast;
use utils::{higher, snippet, snippet_opt};
use syntax_pos::{BytePos, Pos};
/// A helper type to build suggestion correctly handling parenthesis.
pub enum Sugg<'a> {
@ -454,6 +455,19 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
/// }");
/// ```
fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str);
/// Suggest to completely remove an item.
///
/// This will remove an item and all following whitespace until the next non-whitespace
/// character. This should work correctly if item is on the same indentation level as the
/// following item.
///
/// # Example
///
/// ```rust,ignore
/// db.suggest_remove_item(cx, item, "remove this")
/// ```
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str);
}
impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
@ -485,4 +499,21 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error
self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent));
}
}
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str) {
let mut remove_span = item;
let fmpos = cx.sess()
.codemap()
.lookup_byte_offset(remove_span.next_point().hi());
if let Some(ref src) = fmpos.fm.src {
let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
if let Some(non_whitespace_offset) = non_whitespace_offset {
remove_span = remove_span.with_hi(remove_span.hi() + BytePos(non_whitespace_offset as u32))
}
}
self.span_suggestion(remove_span, msg, String::new());
}
}

View File

@ -3,16 +3,21 @@
#![warn(inline_fn_without_body)]
#![allow(inline_always)]
trait Foo {
#[inline]
fn default_inline();
#[inline(always)]
fn always_inline();
#[inline(always)]fn always_inline();
#[inline(never)]
fn never_inline();
#[inline]
fn has_body() {
}
}
fn main() {}
fn main() {
}

View File

@ -1,14 +1,27 @@
error: use of `#[inline]` on trait method `default_inline` which has no body
--> $DIR/inline_fn_without_body.rs:7:5
--> $DIR/inline_fn_without_body.rs:8:5
|
7 | #[inline]
| ^^^^^^^^^
8 | #[inline]
| _____-^^^^^^^^
9 | | fn default_inline();
| |____- help: remove
|
= note: `-D inline-fn-without-body` implied by `-D warnings`
error: use of `#[inline]` on trait method `always_inline` which has no body
--> $DIR/inline_fn_without_body.rs:10:5
--> $DIR/inline_fn_without_body.rs:11:5
|
10 | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
11 | #[inline(always)]fn always_inline();
| ^^^^^^^^^^^^^^^^^ help: remove
error: use of `#[inline]` on trait method `never_inline` which has no body
--> $DIR/inline_fn_without_body.rs:13:5
|
13 | #[inline(never)]
| _____-^^^^^^^^^^^^^^^
14 | |
15 | | fn never_inline();
| |____- help: remove
error: aborting due to 3 previous errors