diff options
Diffstat (limited to 'src/librustc_lint/builtin.rs')
| -rw-r--r-- | src/librustc_lint/builtin.rs | 176 |
1 files changed, 140 insertions, 36 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f3bf37c11a5..07874a8cc69 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use std::collections::HashSet; use syntax::ast; use syntax::attr; use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; -use syntax_pos::{Span, SyntaxContext}; +use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; use rustc::hir::{self, PatKind}; @@ -56,6 +56,31 @@ use bad_style::{MethodLateContext, method_context}; pub use lint::builtin::*; declare_lint! { + pub AUTO_IMPL, + Deny, + "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`" +} + +#[derive(Copy, Clone)] +pub struct AutoImpl; + +impl LintPass for AutoImpl { + fn get_lints(&self) -> LintArray { + lint_array!(AUTO_IMPL) + } +} + +impl EarlyLintPass for AutoImpl { + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + let msg = "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`"; + match item.node { + ast::ItemKind::AutoImpl(..) => cx.span_lint(AUTO_IMPL, item.span, msg), + _ => () + } + } +} + +declare_lint! { WHILE_TRUE, Warn, "suggest using `loop { }` instead of `while true { }`" @@ -76,9 +101,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { if lit.span.ctxt() == SyntaxContext::empty() { - cx.span_lint(WHILE_TRUE, - e.span, - "denote infinite loops with loop { ... }"); + let msg = "denote infinite loops with `loop { ... }`"; + let mut err = cx.struct_span_lint(WHILE_TRUE, e.span, msg); + let condition_span = cx.tcx.sess.codemap().def_span(e.span); + err.span_suggestion_short(condition_span, + "use `loop`", + "loop".to_owned()); + err.emit(); } } } @@ -149,7 +178,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { declare_lint! { NON_SHORTHAND_FIELD_PATTERNS, Warn, - "using `Struct { x: x }` instead of `Struct { x }`" + "using `Struct { x: x }` instead of `Struct { x }` in a pattern" } #[derive(Copy, Clone)] @@ -170,11 +199,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { } if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node { if ident.node == fieldpat.node.name { - cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, + let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, - &format!("the `{}:` in this pattern is redundant and can \ - be removed", - ident.node)) + &format!("the `{}:` in this pattern is redundant", + ident.node)); + let subspan = cx.tcx.sess.codemap().span_through_char(fieldpat.span, ':'); + err.span_suggestion_short(subspan, + "remove this", + format!("{}", ident.node)); + err.emit(); } } } @@ -220,7 +253,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { - hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { + hir::ItemTrait(_, hir::Unsafety::Unsafe, ..) => { self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait") } @@ -613,12 +646,6 @@ impl EarlyLintPass for AnonymousParameters { } } -declare_lint! { - DEPRECATED_ATTR, - Warn, - "detects use of deprecated attributes" -} - /// Checks for use of attributes which have been deprecated. #[derive(Clone)] pub struct DeprecatedAttr { @@ -637,7 +664,7 @@ impl DeprecatedAttr { impl LintPass for DeprecatedAttr { fn get_lints(&self) -> LintArray { - lint_array!(DEPRECATED_ATTR) + lint_array!() } } @@ -650,10 +677,11 @@ impl EarlyLintPass for DeprecatedAttr { ref name, ref reason, _) = g { - cx.span_lint(DEPRECATED, - attr.span, - &format!("use of deprecated attribute `{}`: {}. See {}", - name, reason, link)); + let msg = format!("use of deprecated attribute `{}`: {}. See {}", + name, reason, link); + let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg); + err.span_suggestion_short(attr.span, "remove this attribute", "".to_owned()); + err.emit(); } return; } @@ -889,7 +917,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, "function cannot return without recurring"); - // FIXME #19668: these could be span_lint_note's instead of this manual guard. // offer some help to the programmer. for call in &self_call_spans { db.span_note(*call, "recursive call site"); @@ -1125,35 +1152,55 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemFn(.., ref generics, _) => { - if attr::contains_name(&it.attrs, "no_mangle") && - !attr::contains_name(&it.attrs, "linkage") { + if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") { + if attr::contains_name(&it.attrs, "linkage") { + return; + } if !cx.access_levels.is_reachable(it.id) { - let msg = format!("function {} is marked #[no_mangle], but not exported", - it.name); - cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg); + let msg = "function is marked #[no_mangle], but not exported"; + let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg); + let insertion_span = it.span.with_hi(it.span.lo()); + err.span_suggestion(insertion_span, + "try making it public", + "pub ".to_owned()); + err.emit(); } if generics.is_type_parameterized() { - cx.span_lint(NO_MANGLE_GENERIC_ITEMS, - it.span, - "functions generic over types must be mangled"); + let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, + it.span, + "functions generic over \ + types must be mangled"); + err.span_suggestion_short(no_mangle_attr.span, + "remove this attribute", + "".to_owned()); + err.emit(); } } } hir::ItemStatic(..) => { if attr::contains_name(&it.attrs, "no_mangle") && !cx.access_levels.is_reachable(it.id) { - let msg = format!("static {} is marked #[no_mangle], but not exported", - it.name); - cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg); + let msg = "static is marked #[no_mangle], but not exported"; + let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg); + let insertion_span = it.span.with_hi(it.span.lo()); + err.span_suggestion(insertion_span, + "try making it public", + "pub ".to_owned()); + err.emit(); } } hir::ItemConst(..) => { if attr::contains_name(&it.attrs, "no_mangle") { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to - let msg = "const items should never be #[no_mangle], consider instead using \ - `pub static`"; - cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); + let msg = "const items should never be #[no_mangle]"; + let mut err = cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); + // `const` is 5 chars + let const_span = it.span.with_hi(BytePos(it.span.lo().0 + 5)); + err.span_suggestion(const_span, + "try a static value", + "pub static".to_owned()); + err.emit(); } } _ => {} @@ -1279,3 +1326,60 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { } } } + +/// Lint for items marked `pub` that aren't reachable from other crates +pub struct UnreachablePub; + +declare_lint! { + UNREACHABLE_PUB, + Allow, + "`pub` items not reachable from crate root" +} + +impl LintPass for UnreachablePub { + fn get_lints(&self) -> LintArray { + lint_array!(UNREACHABLE_PUB) + } +} + +impl UnreachablePub { + fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId, + vis: &hir::Visibility, span: Span, exportable: bool) { + if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public { + let def_span = cx.tcx.sess.codemap().def_span(span); + let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span, + &format!("unreachable `pub` {}", what)); + // visibility is token at start of declaration (can be macro + // variable rather than literal `pub`) + let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); + let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + "crate" + } else { + "pub(crate)" + }.to_owned(); + err.span_suggestion(pub_span, "consider restricting its visibility", replacement); + if exportable { + err.help("or consider exporting it for use by other crates"); + } + err.emit(); + } + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + self.perform_lint(cx, "item", item.id, &item.vis, item.span, true); + } + + fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) { + self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true); + } + + fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) { + self.perform_lint(cx, "field", field.id, &field.vis, field.span, false); + } + + fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { + self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false); + } +} |
