1
Fork 0

run rustfmt on librustc_lint folder

This commit is contained in:
Srinivas Reddy Thatiparthy 2016-10-09 09:38:07 +05:30
parent 19ac57926a
commit bf5dfacdde
No known key found for this signature in database
GPG key ID: 091C58F4BFC36571
5 changed files with 608 additions and 486 deletions

View file

@ -24,19 +24,21 @@ use rustc::hir::intravisit::FnKind;
pub enum MethodLateContext { pub enum MethodLateContext {
TraitDefaultImpl, TraitDefaultImpl,
TraitImpl, TraitImpl,
PlainImpl PlainImpl,
} }
pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
let def_id = cx.tcx.map.local_def_id(id); let def_id = cx.tcx.map.local_def_id(id);
match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
None => span_bug!(span, "missing method descriptor?!"), None => span_bug!(span, "missing method descriptor?!"),
Some(item) => match item.container() { Some(item) => {
ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, match item.container() {
ty::ImplContainer(cid) => { ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
match cx.tcx.impl_trait_ref(cid) { ty::ImplContainer(cid) => {
Some(_) => MethodLateContext::TraitImpl, match cx.tcx.impl_trait_ref(cid) {
None => MethodLateContext::PlainImpl Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl,
}
} }
} }
} }
@ -63,19 +65,20 @@ impl NonCamelCaseTypes {
// start with a non-lowercase letter rather than non-uppercase // start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase) // ones (some scripts don't have a concept of upper/lowercase)
!name.is_empty() && !name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_')
!name.chars().next().unwrap().is_lowercase() &&
!name.contains('_')
} }
fn to_camel_case(s: &str) -> String { fn to_camel_case(s: &str) -> String {
s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)| s.split('_')
if i == 0 { .flat_map(|word| {
c.to_uppercase().collect::<String>() word.chars().enumerate().map(|(i, c)| if i == 0 {
} else { c.to_uppercase().collect::<String>()
c.to_lowercase().collect() } else {
} c.to_lowercase().collect()
)).collect::<Vec<_>>().concat() })
})
.collect::<Vec<_>>()
.concat()
} }
let s = name.as_str(); let s = name.as_str();
@ -83,9 +86,14 @@ impl NonCamelCaseTypes {
if !is_camel_case(name) { if !is_camel_case(name) {
let c = to_camel_case(&s); let c = to_camel_case(&s);
let m = if c.is_empty() { let m = if c.is_empty() {
format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s) format!("{} `{}` should have a camel case name such as `CamelCase`",
sort,
s)
} else { } else {
format!("{} `{}` should have a camel case name such as `{}`", sort, s, c) format!("{} `{}` should have a camel case name such as `{}`",
sort,
s,
c)
}; };
cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
} }
@ -100,10 +108,14 @@ impl LintPass for NonCamelCaseTypes {
impl LateLintPass for NonCamelCaseTypes { impl LateLintPass for NonCamelCaseTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let extern_repr_count = it.attrs.iter().filter(|attr| { let extern_repr_count = it.attrs
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter() .iter()
.any(|r| r == &attr::ReprExtern) .filter(|attr| {
}).count(); attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
.iter()
.any(|r| r == &attr::ReprExtern)
})
.count();
let has_extern_repr = extern_repr_count > 0; let has_extern_repr = extern_repr_count > 0;
if has_extern_repr { if has_extern_repr {
@ -111,12 +123,10 @@ impl LateLintPass for NonCamelCaseTypes {
} }
match it.node { match it.node {
hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { hir::ItemTy(..) |
self.check_case(cx, "type", it.name, it.span) hir::ItemStruct(..) |
} hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
hir::ItemTrait(..) => { hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
self.check_case(cx, "trait", it.name, it.span)
}
hir::ItemEnum(ref enum_definition, _) => { hir::ItemEnum(ref enum_definition, _) => {
if has_extern_repr { if has_extern_repr {
return; return;
@ -126,7 +136,7 @@ impl LateLintPass for NonCamelCaseTypes {
self.check_case(cx, "variant", variant.node.name, variant.span); self.check_case(cx, "variant", variant.node.name, variant.span);
} }
} }
_ => () _ => (),
} }
} }
@ -165,9 +175,7 @@ impl NonSnakeCase {
continue; continue;
} }
for ch in s.chars() { for ch in s.chars() {
if !buf.is_empty() && buf != "'" if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
&& ch.is_uppercase()
&& !last_upper {
words.push(buf); words.push(buf);
buf = String::new(); buf = String::new();
} }
@ -205,10 +213,11 @@ impl NonSnakeCase {
let sc = NonSnakeCase::to_snake_case(name); let sc = NonSnakeCase::to_snake_case(name);
let msg = if sc != name { let msg = if sc != name {
format!("{} `{}` should have a snake case name such as `{}`", format!("{} `{}` should have a snake case name such as `{}`",
sort, name, sc) sort,
name,
sc)
} else { } else {
format!("{} `{}` should have a snake case name", format!("{} `{}` should have a snake case name", sort, name)
sort, name)
}; };
match span { match span {
Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg), Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
@ -226,8 +235,10 @@ impl LintPass for NonSnakeCase {
impl LateLintPass for NonSnakeCase { impl LateLintPass for NonSnakeCase {
fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) { fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name")) let attr_crate_name = cr.attrs
.and_then(|at| at.value_str().map(|s| (at, s))); .iter()
.find(|at| at.check_name("crate_name"))
.and_then(|at| at.value_str().map(|s| (at, s)));
if let Some(ref name) = cx.tcx.sess.opts.crate_name { if let Some(ref name) = cx.tcx.sess.opts.crate_name {
self.check_snake_case(cx, "crate", name, None); self.check_snake_case(cx, "crate", name, None);
} else if let Some((attr, ref name)) = attr_crate_name { } else if let Some((attr, ref name)) = attr_crate_name {
@ -235,22 +246,28 @@ impl LateLintPass for NonSnakeCase {
} }
} }
fn check_fn(&mut self, cx: &LateContext, fn check_fn(&mut self,
fk: FnKind, _: &hir::FnDecl, cx: &LateContext,
_: &hir::Block, span: Span, id: ast::NodeId) { fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
id: ast::NodeId) {
match fk { match fk {
FnKind::Method(name, ..) => match method_context(cx, id, span) { FnKind::Method(name, ..) => {
MethodLateContext::PlainImpl => { match method_context(cx, id, span) {
self.check_snake_case(cx, "method", &name.as_str(), Some(span)) MethodLateContext::PlainImpl => {
}, self.check_snake_case(cx, "method", &name.as_str(), Some(span))
MethodLateContext::TraitDefaultImpl => { }
self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) MethodLateContext::TraitDefaultImpl => {
}, self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
_ => (), }
}, _ => (),
}
}
FnKind::ItemFn(name, ..) => { FnKind::ItemFn(name, ..) => {
self.check_snake_case(cx, "function", &name.as_str(), Some(span)) self.check_snake_case(cx, "function", &name.as_str(), Some(span))
}, }
FnKind::Closure(_) => (), FnKind::Closure(_) => (),
} }
} }
@ -263,13 +280,17 @@ impl LateLintPass for NonSnakeCase {
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(_, None) = trait_item.node { if let hir::MethodTraitItem(_, None) = trait_item.node {
self.check_snake_case(cx, "trait method", &trait_item.name.as_str(), self.check_snake_case(cx,
"trait method",
&trait_item.name.as_str(),
Some(trait_item.span)); Some(trait_item.span));
} }
} }
fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), self.check_snake_case(cx,
"lifetime",
&t.lifetime.name.as_str(),
Some(t.lifetime.span)); Some(t.lifetime.span));
} }
@ -282,8 +303,12 @@ impl LateLintPass for NonSnakeCase {
} }
} }
fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData, fn check_struct_def(&mut self,
_: ast::Name, _: &hir::Generics, _: ast::NodeId) { cx: &LateContext,
s: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
_: ast::NodeId) {
for sf in s.fields() { for sf in s.fields() {
self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span)); self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span));
} }
@ -306,13 +331,16 @@ impl NonUpperCaseGlobals {
if s.chars().any(|c| c.is_lowercase()) { if s.chars().any(|c| c.is_lowercase()) {
let uc = NonSnakeCase::to_snake_case(&s).to_uppercase(); let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
if uc != &s[..] { if uc != &s[..] {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span, cx.span_lint(NON_UPPER_CASE_GLOBALS,
&format!("{} `{}` should have an upper case name such as `{}`", span,
sort, s, uc)); &format!("{} `{}` should have an upper case name such as `{}`",
sort,
s,
uc));
} else { } else {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span, cx.span_lint(NON_UPPER_CASE_GLOBALS,
&format!("{} `{}` should have an upper case name", span,
sort, s)); &format!("{} `{}` should have an upper case name", sort, s));
} }
} }
} }
@ -341,8 +369,7 @@ impl LateLintPass for NonUpperCaseGlobals {
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) { fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node { match ti.node {
hir::ConstTraitItem(..) => { hir::ConstTraitItem(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
ti.name, ti.span);
} }
_ => {} _ => {}
} }
@ -351,8 +378,7 @@ impl LateLintPass for NonUpperCaseGlobals {
fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
match ii.node { match ii.node {
hir::ImplItemKind::Const(..) => { hir::ImplItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span);
ii.name, ii.span);
} }
_ => {} _ => {}
} }
@ -363,8 +389,10 @@ impl LateLintPass for NonUpperCaseGlobals {
if let PatKind::Path(None, ref path) = p.node { if let PatKind::Path(None, ref path) = p.node {
if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = cx.tcx.expect_def(p.id) { if let Def::Const(..) = cx.tcx.expect_def(p.id) {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", NonUpperCaseGlobals::check_upper_case(cx,
path.segments[0].name, path.span); "constant in pattern",
path.segments[0].name,
path.span);
} }
} }
} }

View file

@ -37,15 +37,15 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::adjustment; use rustc::ty::adjustment;
use rustc::traits::{self, Reveal}; use rustc::traits::{self, Reveal};
use rustc::hir::map as hir_map; use rustc::hir::map as hir_map;
use util::nodemap::{NodeSet}; use util::nodemap::NodeSet;
use lint::{Level, LateContext, LintContext, LintArray, Lint}; use lint::{Level, LateContext, LintContext, LintArray, Lint};
use lint::{LintPass, LateLintPass}; use lint::{LintPass, LateLintPass};
use std::collections::HashSet; use std::collections::HashSet;
use syntax::{ast}; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax_pos::{Span}; use syntax_pos::Span;
use rustc::hir::{self, PatKind}; use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind; use rustc::hir::intravisit::FnKind;
@ -75,7 +75,8 @@ impl LateLintPass for WhileTrue {
if let hir::ExprWhile(ref cond, ..) = e.node { if let hir::ExprWhile(ref cond, ..) = e.node {
if let hir::ExprLit(ref lit) = cond.node { if let hir::ExprLit(ref lit) = cond.node {
if let ast::LitKind::Bool(true) = lit.node { if let ast::LitKind::Bool(true) = lit.node {
cx.span_lint(WHILE_TRUE, e.span, cx.span_lint(WHILE_TRUE,
e.span,
"denote infinite loops with loop { ... }"); "denote infinite loops with loop { ... }");
} }
} }
@ -93,8 +94,7 @@ declare_lint! {
pub struct BoxPointers; pub struct BoxPointers;
impl BoxPointers { impl BoxPointers {
fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
span: Span, ty: Ty<'tcx>) {
for leaf_ty in ty.walk() { for leaf_ty in ty.walk() {
if let ty::TyBox(_) = leaf_ty.sty { if let ty::TyBox(_) = leaf_ty.sty {
let m = format!("type uses owned (Box type) pointers: {}", ty); let m = format!("type uses owned (Box type) pointers: {}", ty);
@ -117,10 +117,8 @@ impl LateLintPass for BoxPointers {
hir::ItemTy(..) | hir::ItemTy(..) |
hir::ItemEnum(..) | hir::ItemEnum(..) |
hir::ItemStruct(..) | hir::ItemStruct(..) |
hir::ItemUnion(..) => hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)),
self.check_heap_type(cx, it.span, _ => (),
cx.tcx.node_id_to_type(it.id)),
_ => ()
} }
// If it's a struct, we also have to check the fields' types // If it's a struct, we also have to check the fields' types
@ -128,11 +126,12 @@ impl LateLintPass for BoxPointers {
hir::ItemStruct(ref struct_def, _) | hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => { hir::ItemUnion(ref struct_def, _) => {
for struct_field in struct_def.fields() { for struct_field in struct_def.fields() {
self.check_heap_type(cx, struct_field.span, self.check_heap_type(cx,
struct_field.span,
cx.tcx.node_id_to_type(struct_field.id)); cx.tcx.node_id_to_type(struct_field.id));
} }
} }
_ => () _ => (),
} }
} }
@ -166,9 +165,11 @@ impl LateLintPass for NonShorthandFieldPatterns {
} }
if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node { if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
if ident.node == fieldpat.node.name { if ident.node == fieldpat.node.name {
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
fieldpat.span,
&format!("the `{}:` in this pattern is redundant and can \ &format!("the `{}:` in this pattern is redundant and can \
be removed", ident.node)) be removed",
ident.node))
} }
} }
} }
@ -203,27 +204,35 @@ impl LateLintPass for UnsafeCode {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node { match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"), cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
}
hir::ItemImpl(hir::Unsafety::Unsafe, ..) => hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"), cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
}
_ => return, _ => return,
} }
} }
fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl, fn check_fn(&mut self,
_: &hir::Block, span: Span, _: ast::NodeId) { cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
_: ast::NodeId) {
match fk { match fk {
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"), cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
}
FnKind::Method(_, sig, ..) => { FnKind::Method(_, sig, ..) => {
if sig.unsafety == hir::Unsafety::Unsafe { if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
} }
}, }
_ => (), _ => (),
} }
@ -232,7 +241,8 @@ impl LateLintPass for UnsafeCode {
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node { if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
if sig.unsafety == hir::Unsafety::Unsafe { if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, trait_item.span, cx.span_lint(UNSAFE_CODE,
trait_item.span,
"declaration of an `unsafe` method") "declaration of an `unsafe` method")
} }
} }
@ -263,9 +273,9 @@ pub struct MissingDoc {
impl MissingDoc { impl MissingDoc {
pub fn new() -> MissingDoc { pub fn new() -> MissingDoc {
MissingDoc { MissingDoc {
struct_def_stack: vec!(), struct_def_stack: vec![],
in_variant: false, in_variant: false,
doc_hidden_stack: vec!(false), doc_hidden_stack: vec![false],
private_traits: HashSet::new(), private_traits: HashSet::new(),
} }
} }
@ -275,11 +285,11 @@ impl MissingDoc {
} }
fn check_missing_docs_attrs(&self, fn check_missing_docs_attrs(&self,
cx: &LateContext, cx: &LateContext,
id: Option<ast::NodeId>, id: Option<ast::NodeId>,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
sp: Span, sp: Span,
desc: &'static str) { desc: &'static str) {
// If we're building a test harness, then warning about // If we're building a test harness, then warning about
// documentation is probably not really relevant right now. // documentation is probably not really relevant right now.
if cx.sess().opts.test { if cx.sess().opts.test {
@ -302,7 +312,8 @@ impl MissingDoc {
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc { if !has_doc {
cx.span_lint(MISSING_DOCS, sp, cx.span_lint(MISSING_DOCS,
sp,
&format!("missing documentation for {}", desc)); &format!("missing documentation for {}", desc));
} }
} }
@ -316,8 +327,10 @@ impl LintPass for MissingDoc {
impl LateLintPass for MissingDoc { impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { let doc_hidden = self.doc_hidden() ||
attr.check_name("doc") && match attr.meta_item_list() { attrs.iter().any(|attr| {
attr.check_name("doc") &&
match attr.meta_item_list() {
None => false, None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"), Some(l) => attr::list_contains_name(&l[..], "hidden"),
} }
@ -329,13 +342,21 @@ impl LateLintPass for MissingDoc {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
} }
fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData, fn check_struct_def(&mut self,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { _: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
self.struct_def_stack.push(item_id); self.struct_def_stack.push(item_id);
} }
fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData, fn check_struct_def_post(&mut self,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { _: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
assert!(popped == item_id); assert!(popped == item_id);
} }
@ -358,10 +379,10 @@ impl LateLintPass for MissingDoc {
for itm in items { for itm in items {
self.private_traits.insert(itm.id); self.private_traits.insert(itm.id);
} }
return return;
} }
"a trait" "a trait"
}, }
hir::ItemTy(..) => "a type alias", hir::ItemTy(..) => "a type alias",
hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => { hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
// If the trait is private, add the impl items to private_traits so they don't get // If the trait is private, add the impl items to private_traits so they don't get
@ -369,26 +390,30 @@ impl LateLintPass for MissingDoc {
let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id(); let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) { if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
match cx.tcx.map.find(node_id) { match cx.tcx.map.find(node_id) {
Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited { Some(hir_map::NodeItem(item)) => {
for itm in impl_items { if item.vis == hir::Visibility::Inherited {
self.private_traits.insert(itm.id); for itm in impl_items {
self.private_traits.insert(itm.id);
}
} }
}, }
_ => { } _ => {}
} }
} }
return return;
}, }
hir::ItemConst(..) => "a constant", hir::ItemConst(..) => "a constant",
hir::ItemStatic(..) => "a static", hir::ItemStatic(..) => "a static",
_ => return _ => return,
}; };
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
} }
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if self.private_traits.contains(&trait_item.id) { return } if self.private_traits.contains(&trait_item.id) {
return;
}
let desc = match trait_item.node { let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant", hir::ConstTraitItem(..) => "an associated constant",
@ -396,9 +421,11 @@ impl LateLintPass for MissingDoc {
hir::TypeTraitItem(..) => "an associated type", hir::TypeTraitItem(..) => "an associated type",
}; };
self.check_missing_docs_attrs(cx, Some(trait_item.id), self.check_missing_docs_attrs(cx,
Some(trait_item.id),
&trait_item.attrs, &trait_item.attrs,
trait_item.span, desc); trait_item.span,
desc);
} }
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
@ -412,26 +439,34 @@ impl LateLintPass for MissingDoc {
hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Type(_) => "an associated type", hir::ImplItemKind::Type(_) => "an associated type",
}; };
self.check_missing_docs_attrs(cx, Some(impl_item.id), self.check_missing_docs_attrs(cx,
Some(impl_item.id),
&impl_item.attrs, &impl_item.attrs,
impl_item.span, desc); impl_item.span,
desc);
} }
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if !sf.is_positional() { if !sf.is_positional() {
if sf.vis == hir::Public || self.in_variant { if sf.vis == hir::Public || self.in_variant {
let cur_struct_def = *self.struct_def_stack.last() let cur_struct_def = *self.struct_def_stack
.last()
.expect("empty struct_def_stack"); .expect("empty struct_def_stack");
self.check_missing_docs_attrs(cx, Some(cur_struct_def), self.check_missing_docs_attrs(cx,
&sf.attrs, sf.span, Some(cur_struct_def),
&sf.attrs,
sf.span,
"a struct field") "a struct field")
} }
} }
} }
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
self.check_missing_docs_attrs(cx, Some(v.node.data.id()), self.check_missing_docs_attrs(cx,
&v.node.attrs, v.span, "a variant"); Some(v.node.data.id()),
&v.node.attrs,
v.span,
"a variant");
assert!(!self.in_variant); assert!(!self.in_variant);
self.in_variant = true; self.in_variant = true;
} }
@ -486,7 +521,9 @@ impl LateLintPass for MissingCopyImplementations {
} }
_ => return, _ => return,
}; };
if def.has_dtor() { return; } if def.has_dtor() {
return;
}
let parameter_environment = cx.tcx.empty_parameter_environment(); let parameter_environment = cx.tcx.empty_parameter_environment();
// FIXME (@jroesch) should probably inver this so that the parameter env still impls this // FIXME (@jroesch) should probably inver this so that the parameter env still impls this
// method // method
@ -514,9 +551,7 @@ pub struct MissingDebugImplementations {
impl MissingDebugImplementations { impl MissingDebugImplementations {
pub fn new() -> MissingDebugImplementations { pub fn new() -> MissingDebugImplementations {
MissingDebugImplementations { MissingDebugImplementations { impling_types: None }
impling_types: None,
}
} }
} }
@ -533,7 +568,9 @@ impl LateLintPass for MissingDebugImplementations {
} }
match item.node { match item.node {
hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {}, hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemEnum(..) => {}
_ => return, _ => return,
} }
@ -585,12 +622,13 @@ pub struct Deprecated {
impl Deprecated { impl Deprecated {
pub fn new() -> Deprecated { pub fn new() -> Deprecated {
Deprecated { Deprecated { current_item: ast::CRATE_NODE_ID }
current_item: ast::CRATE_NODE_ID,
}
} }
fn lint(&self, cx: &LateContext, _id: DefId, span: Span, fn lint(&self,
cx: &LateContext,
_id: DefId,
span: Span,
stability: &Option<&attr::Stability>, stability: &Option<&attr::Stability>,
deprecation: &Option<stability::DeprecationEntry>) { deprecation: &Option<stability::DeprecationEntry>) {
// Deprecated attributes apply in-crate and cross-crate. // Deprecated attributes apply in-crate and cross-crate.
@ -641,9 +679,10 @@ impl LintPass for Deprecated {
impl LateLintPass for Deprecated { impl LateLintPass for Deprecated {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
self.push_item(item.id); self.push_item(item.id);
stability::check_item(cx.tcx, item, false, stability::check_item(cx.tcx,
&mut |id, sp, stab, depr| item,
self.lint(cx, id, sp, &stab, &depr)); false,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
} }
fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) { fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) {
@ -651,27 +690,30 @@ impl LateLintPass for Deprecated {
} }
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
stability::check_expr(cx.tcx, e, stability::check_expr(cx.tcx,
&mut |id, sp, stab, depr| e,
self.lint(cx, id, sp, &stab, &depr)); &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
} }
fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) { fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
stability::check_path(cx.tcx, path, id, stability::check_path(cx.tcx,
&mut |id, sp, stab, depr| path,
self.lint(cx, id, sp, &stab, &depr)); id,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
} }
fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
stability::check_path_list_item(cx.tcx, item, stability::check_path_list_item(cx.tcx,
&mut |id, sp, stab, depr| item,
self.lint(cx, id, sp, &stab, &depr)); &mut |id, sp, stab, depr| {
self.lint(cx, id, sp, &stab, &depr)
});
} }
fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
stability::check_pat(cx.tcx, pat, stability::check_pat(cx.tcx,
&mut |id, sp, stab, depr| pat,
self.lint(cx, id, sp, &stab, &depr)); &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
} }
fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) { fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) {
@ -716,15 +758,20 @@ impl LintPass for UnconditionalRecursion {
} }
impl LateLintPass for UnconditionalRecursion { impl LateLintPass for UnconditionalRecursion {
fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, fn check_fn(&mut self,
blk: &hir::Block, sp: Span, id: ast::NodeId) { cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
blk: &hir::Block,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind { let method = match fn_kind {
FnKind::ItemFn(..) => None, FnKind::ItemFn(..) => None,
FnKind::Method(..) => { FnKind::Method(..) => {
cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
} }
// closures can't recur, so they don't matter. // closures can't recur, so they don't matter.
FnKind::Closure(_) => return FnKind::Closure(_) => return,
}; };
// Walk through this function (say `f`) looking to see if // Walk through this function (say `f`) looking to see if
@ -779,10 +826,8 @@ impl LateLintPass for UnconditionalRecursion {
// is this a recursive call? // is this a recursive call?
let self_recursive = if node_id != ast::DUMMY_NODE_ID { let self_recursive = if node_id != ast::DUMMY_NODE_ID {
match method { match method {
Some(ref method) => { Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
expr_refers_to_this_method(cx.tcx, method, node_id) None => expr_refers_to_this_fn(cx.tcx, id, node_id),
}
None => expr_refers_to_this_fn(cx.tcx, id, node_id)
} }
} else { } else {
false false
@ -808,7 +853,8 @@ impl LateLintPass for UnconditionalRecursion {
// no break */ }`) shouldn't be linted unless it actually // no break */ }`) shouldn't be linted unless it actually
// recurs. // recurs.
if !reached_exit_without_self_call && !self_call_spans.is_empty() { if !reached_exit_without_self_call && !self_call_spans.is_empty() {
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
sp,
"function cannot return without recurring"); "function cannot return without recurring");
// FIXME #19668: these could be span_lint_note's instead of this manual guard. // FIXME #19668: these could be span_lint_note's instead of this manual guard.
@ -829,23 +875,21 @@ impl LateLintPass for UnconditionalRecursion {
// Functions for identifying if the given Expr NodeId `id` // Functions for identifying if the given Expr NodeId `id`
// represents a call to the function `fn_id`/method `method`. // represents a call to the function `fn_id`/method `method`.
fn expr_refers_to_this_fn(tcx: TyCtxt, fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
fn_id: ast::NodeId,
id: ast::NodeId) -> bool {
match tcx.map.get(id) { match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
tcx.expect_def_or_none(callee.id).map_or(false, |def| { tcx.expect_def_or_none(callee.id)
def.def_id() == tcx.map.local_def_id(fn_id) .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id))
})
} }
_ => false _ => false,
} }
} }
// Check if the expression `id` performs a call to `method`. // Check if the expression `id` performs a call to `method`.
fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
method: &ty::Method, method: &ty::Method,
id: ast::NodeId) -> bool { id: ast::NodeId)
-> bool {
// Check for method calls and overloaded operators. // Check for method calls and overloaded operators.
let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned(); let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
if let Some(m) = opt_m { if let Some(m) = opt_m {
@ -859,9 +903,11 @@ impl LateLintPass for UnconditionalRecursion {
if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj { if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
for i in 0..adj.autoderefs { for i in 0..adj.autoderefs {
let method_call = ty::MethodCall::autoderef(id, i as u32); let method_call = ty::MethodCall::autoderef(id, i as u32);
if let Some(m) = tcx.tables.borrow().method_map if let Some(m) = tcx.tables
.get(&method_call) .borrow()
.cloned() { .method_map
.get(&method_call)
.cloned() {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true; return true;
} }
@ -877,13 +923,16 @@ impl LateLintPass for UnconditionalRecursion {
match tcx.expect_def_or_none(callee.id) { match tcx.expect_def_or_none(callee.id) {
Some(Def::Method(def_id)) => { Some(Def::Method(def_id)) => {
let item_substs = tcx.node_id_item_substs(callee.id); let item_substs = tcx.node_id_item_substs(callee.id);
method_call_refers_to_method( method_call_refers_to_method(tcx,
tcx, method, def_id, &item_substs.substs, id) method,
def_id,
&item_substs.substs,
id)
} }
_ => false _ => false,
} }
} }
_ => false _ => false,
} }
} }
@ -893,15 +942,14 @@ impl LateLintPass for UnconditionalRecursion {
method: &ty::Method, method: &ty::Method,
callee_id: DefId, callee_id: DefId,
callee_substs: &Substs<'tcx>, callee_substs: &Substs<'tcx>,
expr_id: ast::NodeId) -> bool { expr_id: ast::NodeId)
-> bool {
let callee_item = tcx.impl_or_trait_item(callee_id); let callee_item = tcx.impl_or_trait_item(callee_id);
match callee_item.container() { match callee_item.container() {
// This is an inherent method, so the `def_id` refers // This is an inherent method, so the `def_id` refers
// directly to the method definition. // directly to the method definition.
ty::ImplContainer(_) => { ty::ImplContainer(_) => callee_id == method.def_id,
callee_id == method.def_id
}
// A trait method, from any number of possible sources. // A trait method, from any number of possible sources.
// Attempt to select a concrete impl before checking. // Attempt to select a concrete impl before checking.
@ -939,13 +987,12 @@ impl LateLintPass for UnconditionalRecursion {
let container = ty::ImplContainer(vtable_impl.impl_def_id); let container = ty::ImplContainer(vtable_impl.impl_def_id);
// It matches if it comes from the same impl, // It matches if it comes from the same impl,
// and has the same method name. // and has the same method name.
container == method.container container == method.container && callee_item.name() == method.name
&& callee_item.name() == method.name
} }
// There's no way to know if this call is // There's no way to know if this call is
// recursive, so we assume it's not. // recursive, so we assume it's not.
_ => false _ => false,
} }
}) })
} }
@ -992,7 +1039,8 @@ impl LateLintPass for PluginAsLibrary {
}; };
if prfn.is_some() { if prfn.is_some() {
cx.span_lint(PLUGIN_AS_LIBRARY, it.span, cx.span_lint(PLUGIN_AS_LIBRARY,
it.span,
"compiler plugin used as an ordinary library"); "compiler plugin used as an ordinary library");
} }
} }
@ -1050,15 +1098,15 @@ impl LateLintPass for InvalidNoMangleItems {
"generic functions must be mangled"); "generic functions must be mangled");
} }
} }
}, }
hir::ItemStatic(..) => { hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") && if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.access_levels.is_reachable(it.id) { !cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported", let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name); it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg); cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
} }
}, }
hir::ItemConst(..) => { hir::ItemConst(..) => {
if attr::contains_name(&it.attrs, "no_mangle") { if attr::contains_name(&it.attrs, "no_mangle") {
// Const items do not refer to a particular location in memory, and therefore // Const items do not refer to a particular location in memory, and therefore
@ -1068,7 +1116,7 @@ impl LateLintPass for InvalidNoMangleItems {
cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
} }
} }
_ => {}, _ => {}
} }
} }
} }
@ -1096,19 +1144,21 @@ impl LateLintPass for MutableTransmutes {
consider instead using an UnsafeCell"; consider instead using an UnsafeCell";
match get_transmute_from_to(cx, expr) { match get_transmute_from_to(cx, expr) {
Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => { Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
if to_mt.mutbl == hir::Mutability::MutMutable if to_mt.mutbl == hir::Mutability::MutMutable &&
&& from_mt.mutbl == hir::Mutability::MutImmutable { from_mt.mutbl == hir::Mutability::MutImmutable {
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg); cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
} }
} }
_ => () _ => (),
} }
fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) fn get_transmute_from_to<'a, 'tcx>
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { (cx: &LateContext<'a, 'tcx>,
expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node { match expr.node {
hir::ExprPath(..) => (), hir::ExprPath(..) => (),
_ => return None _ => return None,
} }
if let Def::Fn(did) = cx.tcx.expect_def(expr.id) { if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
if !def_id_is_transmute(cx, did) { if !def_id_is_transmute(cx, did) {
@ -1120,8 +1170,8 @@ impl LateLintPass for MutableTransmutes {
let from = bare_fn.sig.0.inputs[0]; let from = bare_fn.sig.0.inputs[0];
let to = bare_fn.sig.0.output; let to = bare_fn.sig.0.output;
return Some((&from.sty, &to.sty)); return Some((&from.sty, &to.sty));
}, }
_ => () _ => (),
} }
} }
None None
@ -1130,7 +1180,7 @@ impl LateLintPass for MutableTransmutes {
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.lookup_item_type(def_id).ty.sty { match cx.tcx.lookup_item_type(def_id).ty.sty {
ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (), ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
_ => return false _ => return false,
} }
cx.tcx.item_name(def_id).as_str() == "transmute" cx.tcx.item_name(def_id).as_str() == "transmute"
} }

View file

@ -48,10 +48,10 @@ extern crate rustc_back;
extern crate rustc_const_eval; extern crate rustc_const_eval;
extern crate syntax_pos; extern crate syntax_pos;
pub use rustc::lint as lint; pub use rustc::lint;
pub use rustc::middle as middle; pub use rustc::middle;
pub use rustc::session as session; pub use rustc::session;
pub use rustc::util as util; pub use rustc::util;
use session::Session; use session::Session;
use lint::LintId; use lint::LintId;
@ -139,13 +139,24 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
MissingDebugImplementations, MissingDebugImplementations,
); );
add_lint_group!(sess, "bad_style", add_lint_group!(sess,
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); "bad_style",
NON_CAMEL_CASE_TYPES,
NON_SNAKE_CASE,
NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess, "unused", add_lint_group!(sess,
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, "unused",
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE, UNUSED_IMPORTS,
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES); UNUSED_VARIABLES,
UNUSED_ASSIGNMENTS,
DEAD_CODE,
UNUSED_MUT,
UNREACHABLE_CODE,
UNUSED_MUST_USE,
UNUSED_UNSAFE,
PATH_STATEMENTS,
UNUSED_ATTRIBUTES);
// Guidelines for creating a future incompatibility lint: // Guidelines for creating a future incompatibility lint:
// //
@ -155,7 +166,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
// and include the full URL. // and include the full URL.
// - Later, change lint to error // - Later, change lint to error
// - Eventually, remove lint // - Eventually, remove lint
store.register_future_incompatible(sess, vec![ store.register_future_incompatible(sess,
vec![
FutureIncompatibleInfo { FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC), id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
@ -209,11 +221,13 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
// Register renamed and removed lints // Register renamed and removed lints
store.register_renamed("unknown_features", "unused_features"); store.register_renamed("unknown_features", "unused_features");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("unsigned_negation",
"replaced by negate_unsigned feature gate");
store.register_removed("negate_unsigned", "cast a signed value instead"); store.register_removed("negate_unsigned", "cast a signed value instead");
store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok"); store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
// This was renamed to raw_pointer_derive, which was then removed, // This was renamed to raw_pointer_derive, which was then removed,
// so it is also considered removed // so it is also considered removed
store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok"); store.register_removed("raw_pointer_deriving",
"using derive with raw pointers is ok");
store.register_removed("drop_with_repr_extern", "drop flags have been removed"); store.register_removed("drop_with_repr_extern", "drop flags have been removed");
} }

View file

@ -18,7 +18,7 @@ use rustc::traits::Reveal;
use middle::const_val::ConstVal; use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet}; use util::nodemap::FnvHashSet;
use lint::{LateContext, LintContext, LintArray}; use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass}; use lint::{LintPass, LateLintPass};
@ -91,15 +91,15 @@ pub struct TypeLimits {
impl TypeLimits { impl TypeLimits {
pub fn new() -> TypeLimits { pub fn new() -> TypeLimits {
TypeLimits { TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
negated_expr_id: ast::DUMMY_NODE_ID,
}
} }
} }
impl LintPass for TypeLimits { impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) lint_array!(UNUSED_COMPARISONS,
OVERFLOWING_LITERALS,
EXCEEDING_BITSHIFTS)
} }
} }
@ -111,13 +111,13 @@ impl LateLintPass for TypeLimits {
match lit.node { match lit.node {
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => { ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
forbid_unsigned_negation(cx, e.span); forbid_unsigned_negation(cx, e.span);
}, }
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
forbid_unsigned_negation(cx, e.span); forbid_unsigned_negation(cx, e.span);
} }
}, }
_ => () _ => (),
} }
} else { } else {
let t = cx.tcx.node_id_to_type(expr.id); let t = cx.tcx.node_id_to_type(expr.id);
@ -129,10 +129,11 @@ impl LateLintPass for TypeLimits {
if self.negated_expr_id != e.id { if self.negated_expr_id != e.id {
self.negated_expr_id = expr.id; self.negated_expr_id = expr.id;
} }
}, }
hir::ExprBinary(binop, ref l, ref r) => { hir::ExprBinary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) { if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
cx.span_lint(UNUSED_COMPARISONS, e.span, cx.span_lint(UNUSED_COMPARISONS,
e.span,
"comparison is useless due to type limits"); "comparison is useless due to type limits");
} }
@ -140,30 +141,35 @@ impl LateLintPass for TypeLimits {
let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty { let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
_ => None _ => None,
}; };
if let Some(bits) = opt_ty_bits { if let Some(bits) = opt_ty_bits {
let exceeding = if let hir::ExprLit(ref lit) = r.node { let exceeding = if let hir::ExprLit(ref lit) = r.node {
if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits } if let ast::LitKind::Int(shift, _) = lit.node {
else { false } shift >= bits
} else {
false
}
} else { } else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
Ok(ConstVal::Integral(i)) => { Ok(ConstVal::Integral(i)) => {
i.is_negative() || i.to_u64() i.is_negative() ||
.map(|i| i >= bits) i.to_u64()
.unwrap_or(true) .map(|i| i >= bits)
}, .unwrap_or(true)
_ => { false } }
_ => false,
} }
}; };
if exceeding { if exceeding {
cx.span_lint(EXCEEDING_BITSHIFTS, e.span, cx.span_lint(EXCEEDING_BITSHIFTS,
e.span,
"bitshift exceeds the type's number of bits"); "bitshift exceeds the type's number of bits");
} }
}; };
} }
}, }
hir::ExprLit(ref lit) => { hir::ExprLit(ref lit) => {
match cx.tcx.node_id_to_type(e.id).sty { match cx.tcx.node_id_to_type(e.id).sty {
ty::TyInt(t) => { ty::TyInt(t) => {
@ -182,14 +188,15 @@ impl LateLintPass for TypeLimits {
// avoiding use of -min to prevent overflow/panic // avoiding use of -min to prevent overflow/panic
if (negative && v > max as u64 + 1) || if (negative && v > max as u64 + 1) ||
(!negative && v > max as u64) { (!negative && v > max as u64) {
cx.span_lint(OVERFLOWING_LITERALS, e.span, cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t)); &format!("literal out of range for {:?}", t));
return; return;
} }
} }
_ => bug!() _ => bug!(),
}; };
}, }
ty::TyUint(t) => { ty::TyUint(t) => {
let uint_type = if let ast::UintTy::Us = t { let uint_type = if let ast::UintTy::Us = t {
cx.sess().target.uint_type cx.sess().target.uint_type
@ -201,13 +208,14 @@ impl LateLintPass for TypeLimits {
// _v is u8, within range by definition // _v is u8, within range by definition
ast::LitKind::Byte(_v) => return, ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v, ast::LitKind::Int(v, _) => v,
_ => bug!() _ => bug!(),
}; };
if lit_val < min || lit_val > max { if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span, cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t)); &format!("literal out of range for {:?}", t));
} }
}, }
ty::TyFloat(t) => { ty::TyFloat(t) => {
let (min, max) = float_ty_range(t); let (min, max) = float_ty_range(t);
let lit_val: f64 = match lit.node { let lit_val: f64 = match lit.node {
@ -215,70 +223,71 @@ impl LateLintPass for TypeLimits {
ast::LitKind::FloatUnsuffixed(ref v) => { ast::LitKind::FloatUnsuffixed(ref v) => {
match v.parse() { match v.parse() {
Ok(f) => f, Ok(f) => f,
Err(_) => return Err(_) => return,
} }
} }
_ => bug!() _ => bug!(),
}; };
if lit_val < min || lit_val > max { if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span, cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t)); &format!("literal out of range for {:?}", t));
} }
}, }
_ => () _ => (),
}; };
}, }
_ => () _ => (),
}; };
fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T, fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
min: T, max: T) -> bool {
match binop.node { match binop.node {
hir::BiLt => v > min && v <= max, hir::BiLt => v > min && v <= max,
hir::BiLe => v >= min && v < max, hir::BiLe => v >= min && v < max,
hir::BiGt => v >= min && v < max, hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max, hir::BiGe => v > min && v <= max,
hir::BiEq | hir::BiNe => v >= min && v <= max, hir::BiEq | hir::BiNe => v >= min && v <= max,
_ => bug!() _ => bug!(),
} }
} }
fn rev_binop(binop: hir::BinOp) -> hir::BinOp { fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
codemap::respan(binop.span, match binop.node { codemap::respan(binop.span,
hir::BiLt => hir::BiGt, match binop.node {
hir::BiLe => hir::BiGe, hir::BiLt => hir::BiGt,
hir::BiGt => hir::BiLt, hir::BiLe => hir::BiGe,
hir::BiGe => hir::BiLe, hir::BiGt => hir::BiLt,
_ => return binop hir::BiGe => hir::BiLe,
}) _ => return binop,
})
} }
// for isize & usize, be conservative with the warnings, so that the // for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms // warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) { fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty { match int_ty {
ast::IntTy::Is => (i64::MIN, i64::MAX), ast::IntTy::Is => (i64::MIN, i64::MAX),
ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
ast::IntTy::I64 => (i64::MIN, i64::MAX) ast::IntTy::I64 => (i64::MIN, i64::MAX),
} }
} }
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty { match uint_ty {
ast::UintTy::Us => (u64::MIN, u64::MAX), ast::UintTy::Us => (u64::MIN, u64::MAX),
ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
ast::UintTy::U64 => (u64::MIN, u64::MAX) ast::UintTy::U64 => (u64::MIN, u64::MAX),
} }
} }
fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) { fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
match float_ty { match float_ty {
ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64), ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64),
ast::FloatTy::F64 => (f64::MIN, f64::MAX) ast::FloatTy::F64 => (f64::MIN, f64::MAX),
} }
} }
@ -305,60 +314,60 @@ impl LateLintPass for TypeLimits {
fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
binop: hir::BinOp, binop: hir::BinOp,
l: &hir::Expr, l: &hir::Expr,
r: &hir::Expr) -> bool { r: &hir::Expr)
-> bool {
let (lit, expr, swap) = match (&l.node, &r.node) { let (lit, expr, swap) = match (&l.node, &r.node) {
(&hir::ExprLit(_), _) => (l, r, true), (&hir::ExprLit(_), _) => (l, r, true),
(_, &hir::ExprLit(_)) => (r, l, false), (_, &hir::ExprLit(_)) => (r, l, false),
_ => return true _ => return true,
}; };
// Normalize the binop so that the literal is always on the RHS in // Normalize the binop so that the literal is always on the RHS in
// the comparison // the comparison
let norm_binop = if swap { let norm_binop = if swap { rev_binop(binop) } else { binop };
rev_binop(binop)
} else {
binop
};
match tcx.node_id_to_type(expr.id).sty { match tcx.node_id_to_type(expr.id).sty {
ty::TyInt(int_ty) => { ty::TyInt(int_ty) => {
let (min, max) = int_ty_range(int_ty); let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node { let lit_val: i64 = match lit.node {
hir::ExprLit(ref li) => match li.node { hir::ExprLit(ref li) => {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | match li.node {
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
_ => return true ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
}, _ => return true,
_ => bug!() }
}
_ => bug!(),
}; };
is_valid(norm_binop, lit_val, min, max) is_valid(norm_binop, lit_val, min, max)
} }
ty::TyUint(uint_ty) => { ty::TyUint(uint_ty) => {
let (min, max): (u64, u64) = uint_ty_range(uint_ty); let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node { let lit_val: u64 = match lit.node {
hir::ExprLit(ref li) => match li.node { hir::ExprLit(ref li) => {
ast::LitKind::Int(v, _) => v, match li.node {
_ => return true ast::LitKind::Int(v, _) => v,
}, _ => return true,
_ => bug!() }
}
_ => bug!(),
}; };
is_valid(norm_binop, lit_val, min, max) is_valid(norm_binop, lit_val, min, max)
} }
_ => true _ => true,
} }
} }
fn is_comparison(binop: hir::BinOp) -> bool { fn is_comparison(binop: hir::BinOp) -> bool {
match binop.node { match binop.node {
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
hir::BiNe | hir::BiGe | hir::BiGt => true, _ => false,
_ => false
} }
} }
fn forbid_unsigned_negation(cx: &LateContext, span: Span) { fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
cx.sess() cx.sess()
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519") .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
.span_help(span, "use a cast or the `!` operator") .span_help(span, "use a cast or the `!` operator")
.emit(); .emit();
} }
} }
} }
@ -370,7 +379,7 @@ declare_lint! {
} }
struct ImproperCTypesVisitor<'a, 'tcx: 'a> { struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx> cx: &'a LateContext<'a, 'tcx>,
} }
enum FfiResult { enum FfiResult {
@ -403,9 +412,13 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if def.variants[data_idx].fields.len() == 1 { if def.variants[data_idx].fields.len() == 1 {
match def.variants[data_idx].fields[0].ty(tcx, substs).sty { match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
ty::TyFnPtr(_) => { return true; } ty::TyFnPtr(_) => {
ty::TyRef(..) => { return true; } return true;
_ => { } }
ty::TyRef(..) => {
return true;
}
_ => {}
} }
} }
} }
@ -415,10 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined /// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code). /// representation which can be exported to C code).
fn check_type_for_ffi(&self, fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
cache: &mut FnvHashSet<Ty<'tcx>>,
ty: Ty<'tcx>)
-> FfiResult {
use self::FfiResult::*; use self::FfiResult::*;
let cx = self.cx.tcx; let cx = self.cx.tcx;
@ -431,112 +441,118 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
match ty.sty { match ty.sty {
ty::TyAdt(def, substs) => match def.adt_kind() { ty::TyAdt(def, substs) => {
AdtKind::Struct => { match def.adt_kind() {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { AdtKind::Struct => {
return FfiUnsafe( if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
"found struct without foreign-function-safe \ return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \ representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to \ consider adding a #[repr(C)] attribute to the type");
the type");
}
// We can't completely trust repr(C) markings; make sure the
// fields are actually safe.
if def.struct_variant().fields.is_empty() {
return FfiUnsafe(
"found zero-size struct in foreign module, consider \
adding a member to this struct");
}
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
} }
}
FfiSafe
}
AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe(
"found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to \
the type");
}
for field in &def.struct_variant().fields { // We can't completely trust repr(C) markings; make sure the
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); // fields are actually safe.
let r = self.check_type_for_ffi(cache, field_ty); if def.struct_variant().fields.is_empty() {
match r { return FfiUnsafe("found zero-size struct in foreign module, consider \
FfiSafe => {} adding a member to this struct");
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadUnion(def.did, s); }
} }
}
FfiSafe
}
AdtKind::Enum => {
if def.variants.is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe
}
// Check for a repr() attribute to specify the size of the for field in &def.struct_variant().fields {
// discriminant. let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let repr_hints = cx.lookup_repr_hints(def.did); let r = self.check_type_for_ffi(cache, field_ty);
match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe(
"found enum without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(...)] attribute to \
the type")
}
}
&[ref hint] => {
if !hint.is_ffi_safe() {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe(
"enum has unexpected #[repr(...)] attribute")
}
// Enum with an explicitly sized discriminant; either
// a C-style enum or a discriminated union.
// The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct?
}
_ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe(
"enum has too many #[repr(...)] attributes");
}
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
let arg = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, arg);
match r { match r {
FfiSafe => {} FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } return r;
}
FfiUnsafe(s) => {
return FfiBadStruct(def.did, s);
}
} }
} }
FfiSafe
}
AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
}
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadUnion(def.did, s);
}
}
}
FfiSafe
}
AdtKind::Enum => {
if def.variants.is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
// Check for a repr() attribute to specify the size of the
// discriminant.
let repr_hints = cx.lookup_repr_hints(def.did);
match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe("found enum without foreign-function-safe \
representation annotation in foreign \
module, consider adding a #[repr(...)] \
attribute to the type");
}
}
&[ref hint] => {
if !hint.is_ffi_safe() {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
}
// Enum with an explicitly sized discriminant; either
// a C-style enum or a discriminated union.
// The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct?
}
_ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has too many #[repr(...)] attributes");
}
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
let arg = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadEnum(def.did, s);
}
}
}
}
FfiSafe
} }
FfiSafe
} }
}, }
ty::TyChar => { ty::TyChar => {
FfiUnsafe("found Rust type `char` in foreign module, while \ FfiUnsafe("found Rust type `char` in foreign module, while \
@ -544,8 +560,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
// Primitive types with a stable representation. // Primitive types with a stable representation.
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBox(..) => { ty::TyBox(..) => {
FfiUnsafe("found Rust type Box<_> in foreign module, \ FfiUnsafe("found Rust type Box<_> in foreign module, \
@ -572,24 +587,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
consider using a struct instead") consider using a struct instead")
} }
ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => { ty::TyRawPtr(ref m) |
self.check_type_for_ffi(cache, m.ty) ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
}
ty::TyArray(ty, _) => { ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
self.check_type_for_ffi(cache, ty)
}
ty::TyFnPtr(bare_fn) => { ty::TyFnPtr(bare_fn) => {
match bare_fn.abi { match bare_fn.abi {
Abi::Rust | Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
Abi::RustIntrinsic | return FfiUnsafe("found function pointer with Rust calling convention in \
Abi::PlatformIntrinsic | foreign module; consider using an `extern` function \
Abi::RustCall => { pointer")
return FfiUnsafe(
"found function pointer with Rust calling \
convention in foreign module; consider using an \
`extern` function pointer")
} }
_ => {} _ => {}
} }
@ -599,24 +607,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let r = self.check_type_for_ffi(cache, sig.output); let r = self.check_type_for_ffi(cache, sig.output);
match r { match r {
FfiSafe => {} FfiSafe => {}
_ => { return r; } _ => {
return r;
}
} }
} }
for arg in sig.inputs { for arg in sig.inputs {
let r = self.check_type_for_ffi(cache, arg); let r = self.check_type_for_ffi(cache, arg);
match r { match r {
FfiSafe => {} FfiSafe => {}
_ => { return r; } _ => {
return r;
}
} }
} }
FfiSafe FfiSafe
} }
ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | ty::TyParam(..) |
ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) | ty::TyInfer(..) |
ty::TyFnDef(..) => { ty::TyError |
bug!("Unexpected type in foreign function") ty::TyClosure(..) |
} ty::TyProjection(..) |
ty::TyAnon(..) |
ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
} }
} }
@ -633,23 +647,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiResult::FfiBadStruct(_, s) => { FfiResult::FfiBadStruct(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't // FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field. // point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp, self.cx.span_lint(IMPROPER_CTYPES,
&format!("found non-foreign-function-safe member in \ sp,
struct marked #[repr(C)]: {}", s)); &format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}",
s));
} }
FfiResult::FfiBadUnion(_, s) => { FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't // FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field. // point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp, self.cx.span_lint(IMPROPER_CTYPES,
&format!("found non-foreign-function-safe member in \ sp,
union marked #[repr(C)]: {}", s)); &format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}",
s));
} }
FfiResult::FfiBadEnum(_, s) => { FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't // FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant. // point at the relevant variant.
self.cx.span_lint(IMPROPER_CTYPES, sp, self.cx.span_lint(IMPROPER_CTYPES,
&format!("found non-foreign-function-safe member in \ sp,
enum: {}", s)); &format!("found non-foreign-function-safe member in enum: {}",
s));
} }
} }
} }
@ -719,13 +738,13 @@ impl LintPass for VariantSizeDifferences {
impl LateLintPass for VariantSizeDifferences { impl LateLintPass for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types
let t = cx.tcx.node_id_to_type(it.id); let t = cx.tcx.node_id_to_type(it.id);
let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t); let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| { ty.layout(&infcx)
bug!("failed to get layout for `{}`: {}", t, e) .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
})
}); });
if let Layout::General { ref variants, ref size, discr, .. } = *layout { if let Layout::General { ref variants, ref size, discr, .. } = *layout {
@ -738,23 +757,21 @@ impl LateLintPass for VariantSizeDifferences {
.zip(variants) .zip(variants)
.map(|(variant, variant_layout)| { .map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant // Subtract the size of the enum discriminant
let bytes = variant_layout.min_size.bytes() let bytes = variant_layout.min_size
.saturating_sub(discr_size); .bytes()
.saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes); debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
bytes bytes
}) })
.enumerate() .enumerate()
.fold((0, 0, 0), .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
|(l, s, li), (idx, size)| (size, l, idx)
if size > l { } else if size > s {
(size, l, idx) (l, size, li)
} else if size > s { } else {
(l, size, li) (l, s, li)
} else { });
(l, s, li)
}
);
// we only warn if the largest variant is at least thrice as large as // we only warn if the largest variant is at least thrice as large as
// the second-largest. // the second-largest.
@ -762,7 +779,8 @@ impl LateLintPass for VariantSizeDifferences {
cx.span_lint(VARIANT_SIZE_DIFFERENCES, cx.span_lint(VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span, enum_definition.variants[largest_index].span,
&format!("enum variant is more than three times larger \ &format!("enum variant is more than three times larger \
({} bytes) than the next largest", largest)); ({} bytes) than the next largest",
largest));
} }
} }
} }

View file

@ -49,8 +49,12 @@ impl UnusedMut {
if let hir::BindByValue(hir::MutMutable) = mode { if let hir::BindByValue(hir::MutMutable) = mode {
if !name.as_str().starts_with("_") { if !name.as_str().starts_with("_") {
match mutables.entry(name.0 as usize) { match mutables.entry(name.0 as usize) {
Vacant(entry) => { entry.insert(vec![id]); }, Vacant(entry) => {
Occupied(mut entry) => { entry.get_mut().push(id); }, entry.insert(vec![id]);
}
Occupied(mut entry) => {
entry.get_mut().push(id);
}
} }
} }
} }
@ -60,7 +64,8 @@ impl UnusedMut {
let used_mutables = cx.tcx.used_mut_nodes.borrow(); let used_mutables = cx.tcx.used_mut_nodes.borrow();
for (_, v) in &mutables { for (_, v) in &mutables {
if !v.iter().any(|e| used_mutables.contains(e)) { if !v.iter().any(|e| used_mutables.contains(e)) {
cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]), cx.span_lint(UNUSED_MUT,
cx.tcx.map.span(v[0]),
"variable does not need to be mutable"); "variable does not need to be mutable");
} }
} }
@ -90,9 +95,13 @@ impl LateLintPass for UnusedMut {
} }
} }
fn check_fn(&mut self, cx: &LateContext, fn check_fn(&mut self,
_: FnKind, decl: &hir::FnDecl, cx: &LateContext,
_: &hir::Block, _: Span, _: ast::NodeId) { _: FnKind,
decl: &hir::FnDecl,
_: &hir::Block,
_: Span,
_: ast::NodeId) {
for a in &decl.inputs { for a in &decl.inputs {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
} }
@ -124,7 +133,7 @@ impl LateLintPass for UnusedResults {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
let expr = match s.node { let expr = match s.node {
hir::StmtSemi(ref expr, _) => &**expr, hir::StmtSemi(ref expr, _) => &**expr,
_ => return _ => return,
}; };
if let hir::ExprRet(..) = expr.node { if let hir::ExprRet(..) = expr.node {
@ -184,8 +193,8 @@ impl LateLintPass for UnusedUnsafe {
if let hir::ExprBlock(ref blk) = e.node { if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output. // Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) && if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
!cx.tcx.used_unsafe.borrow().contains(&blk.id) { !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
} }
} }
} }
@ -210,8 +219,7 @@ impl LateLintPass for PathStatements {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
if let hir::StmtSemi(ref expr, _) = s.node { if let hir::StmtSemi(ref expr, _) = s.node {
if let hir::ExprPath(..) = expr.node { if let hir::ExprPath(..) = expr.node {
cx.span_lint(PATH_STATEMENTS, s.span, cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
"path statement with no effect");
} }
} }
} }
@ -242,8 +250,8 @@ impl LateLintPass for UnusedAttributes {
AttributeType::Whitelisted if attr.check_name(name) => { AttributeType::Whitelisted if attr.check_name(name) => {
debug!("{:?} is Whitelisted", name); debug!("{:?} is Whitelisted", name);
break; break;
}, }
_ => () _ => (),
} }
} }
@ -259,24 +267,22 @@ impl LateLintPass for UnusedAttributes {
debug!("Emitting warning for: {:?}", attr); debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level? // Is it a builtin attribute that must be used at the crate level?
let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { let known_crate = KNOWN_ATTRIBUTES.iter()
attr.name() == name && .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
ty == AttributeType::CrateLevel .is_some();
}).is_some();
// Has a plugin registered this attribute as one which must be used at // Has a plugin registered this attribute as one which must be used at
// the crate level? // the crate level?
let plugin_crate = plugin_attributes.iter() let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| { .find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t)
&*attr.name() == x && .is_some();
AttributeType::CrateLevel == t if known_crate || plugin_crate {
}).is_some();
if known_crate || plugin_crate {
let msg = match attr.node.style { let msg = match attr.node.style {
ast::AttrStyle::Outer => "crate-level attribute should be an inner \ ast::AttrStyle::Outer => {
attribute: add an exclamation mark: #![foo]", "crate-level attribute should be an inner attribute: add an exclamation \
ast::AttrStyle::Inner => "crate-level attribute should be in the \ mark: #![foo]"
root module", }
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
}; };
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
} }
@ -296,12 +302,16 @@ declare_lint! {
pub struct UnusedParens; pub struct UnusedParens;
impl UnusedParens { impl UnusedParens {
fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str, fn check_unused_parens_core(&self,
cx: &EarlyContext,
value: &ast::Expr,
msg: &str,
struct_lit_needs_parens: bool) { struct_lit_needs_parens: bool) {
if let ast::ExprKind::Paren(ref inner) = value.node { if let ast::ExprKind::Paren(ref inner) = value.node {
let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner); let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
if !necessary { if !necessary {
cx.span_lint(UNUSED_PARENS, value.span, cx.span_lint(UNUSED_PARENS,
value.span,
&format!("unnecessary parentheses around {}", msg)) &format!("unnecessary parentheses around {}", msg))
} }
} }
@ -319,8 +329,7 @@ impl UnusedParens {
ast::ExprKind::AssignOp(_, ref lhs, ref rhs) | ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
ast::ExprKind::Binary(_, ref lhs, ref rhs) => { ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
// X { y: 1 } + X { y: 2 } // X { y: 1 } + X { y: 2 }
contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
contains_exterior_struct_lit(&rhs)
} }
ast::ExprKind::Unary(_, ref x) | ast::ExprKind::Unary(_, ref x) |
ast::ExprKind::Cast(ref x, _) | ast::ExprKind::Cast(ref x, _) |
@ -337,7 +346,7 @@ impl UnusedParens {
contains_exterior_struct_lit(&exprs[0]) contains_exterior_struct_lit(&exprs[0])
} }
_ => false _ => false,
} }
} }
} }
@ -363,18 +372,20 @@ impl EarlyLintPass for UnusedParens {
Assign(_, ref value) => (value, "assigned value", false), Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false), InPlace(_, ref value) => (value, "emplacement value", false),
_ => return _ => return,
}; };
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens); self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
} }
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) { fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
let (value, msg) = match s.node { let (value, msg) = match s.node {
ast::StmtKind::Local(ref local) => match local.init { ast::StmtKind::Local(ref local) => {
Some(ref value) => (value, "assigned value"), match local.init {
None => return Some(ref value) => (value, "assigned value"),
}, None => return,
_ => return }
}
_ => return,
}; };
self.check_unused_parens_core(cx, &value, msg, false); self.check_unused_parens_core(cx, &value, msg, false);
} }
@ -427,23 +438,24 @@ impl LateLintPass for UnusedAllocation {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
match e.node { match e.node {
hir::ExprBox(_) => {} hir::ExprBox(_) => {}
_ => return _ => return,
} }
if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
ref autoref, .. *adjustment {
}) = *adjustment {
match autoref { match autoref {
&Some(adjustment::AutoPtr(_, hir::MutImmutable)) => { &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span, cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use & instead"); "unnecessary allocation, use & instead");
} }
&Some(adjustment::AutoPtr(_, hir::MutMutable)) => { &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span, cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use &mut instead"); "unnecessary allocation, use &mut instead");
} }
_ => () _ => (),
} }
} }
} }