Rollup merge of #37049 - srinivasreddy:librustc_lint, r=nrc

run rustfmt on librustc_lint folder
This commit is contained in:
Alex Crichton 2016-10-12 10:15:27 -07:00
commit 4e65489e77
5 changed files with 608 additions and 486 deletions

View File

@ -24,19 +24,21 @@ use rustc::hir::intravisit::FnKind;
pub enum MethodLateContext {
TraitDefaultImpl,
TraitImpl,
PlainImpl
PlainImpl,
}
pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
let def_id = cx.tcx.map.local_def_id(id);
match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
None => span_bug!(span, "missing method descriptor?!"),
Some(item) => match item.container() {
ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match cx.tcx.impl_trait_ref(cid) {
Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl
Some(item) => {
match item.container() {
ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match cx.tcx.impl_trait_ref(cid) {
Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl,
}
}
}
}
@ -63,19 +65,20 @@ impl NonCamelCaseTypes {
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)
!name.is_empty() &&
!name.chars().next().unwrap().is_lowercase() &&
!name.contains('_')
!name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_')
}
fn to_camel_case(s: &str) -> String {
s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect()
}
)).collect::<Vec<_>>().concat()
s.split('_')
.flat_map(|word| {
word.chars().enumerate().map(|(i, c)| if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect()
})
})
.collect::<Vec<_>>()
.concat()
}
let s = name.as_str();
@ -83,9 +86,14 @@ impl NonCamelCaseTypes {
if !is_camel_case(name) {
let c = to_camel_case(&s);
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 {
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[..]);
}
@ -100,10 +108,14 @@ impl LintPass for NonCamelCaseTypes {
impl LateLintPass for NonCamelCaseTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let extern_repr_count = it.attrs.iter().filter(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
.any(|r| r == &attr::ReprExtern)
}).count();
let extern_repr_count = it.attrs
.iter()
.filter(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
.iter()
.any(|r| r == &attr::ReprExtern)
})
.count();
let has_extern_repr = extern_repr_count > 0;
if has_extern_repr {
@ -111,12 +123,10 @@ impl LateLintPass for NonCamelCaseTypes {
}
match it.node {
hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
self.check_case(cx, "type", it.name, it.span)
}
hir::ItemTrait(..) => {
self.check_case(cx, "trait", it.name, it.span)
}
hir::ItemTy(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
hir::ItemEnum(ref enum_definition, _) => {
if has_extern_repr {
return;
@ -126,7 +136,7 @@ impl LateLintPass for NonCamelCaseTypes {
self.check_case(cx, "variant", variant.node.name, variant.span);
}
}
_ => ()
_ => (),
}
}
@ -165,9 +175,7 @@ impl NonSnakeCase {
continue;
}
for ch in s.chars() {
if !buf.is_empty() && buf != "'"
&& ch.is_uppercase()
&& !last_upper {
if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
words.push(buf);
buf = String::new();
}
@ -205,10 +213,11 @@ impl NonSnakeCase {
let sc = NonSnakeCase::to_snake_case(name);
let msg = if sc != name {
format!("{} `{}` should have a snake case name such as `{}`",
sort, name, sc)
sort,
name,
sc)
} else {
format!("{} `{}` should have a snake case name",
sort, name)
format!("{} `{}` should have a snake case name", sort, name)
};
match span {
Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
@ -226,8 +235,10 @@ impl LintPass for NonSnakeCase {
impl LateLintPass for NonSnakeCase {
fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
.and_then(|at| at.value_str().map(|s| (at, s)));
let attr_crate_name = cr.attrs
.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 {
self.check_snake_case(cx, "crate", name, None);
} 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,
fk: FnKind, _: &hir::FnDecl,
_: &hir::Block, span: Span, id: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
id: ast::NodeId) {
match fk {
FnKind::Method(name, ..) => match method_context(cx, id, 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))
},
_ => (),
},
FnKind::Method(name, ..) => {
match method_context(cx, id, 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))
}
_ => (),
}
}
FnKind::ItemFn(name, ..) => {
self.check_snake_case(cx, "function", &name.as_str(), Some(span))
},
}
FnKind::Closure(_) => (),
}
}
@ -263,13 +280,17 @@ impl LateLintPass for NonSnakeCase {
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
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));
}
}
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));
}
@ -282,8 +303,12 @@ impl LateLintPass for NonSnakeCase {
}
}
fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
_: ast::Name, _: &hir::Generics, _: ast::NodeId) {
fn check_struct_def(&mut self,
cx: &LateContext,
s: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
_: ast::NodeId) {
for sf in s.fields() {
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()) {
let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
if uc != &s[..] {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
&format!("{} `{}` should have an upper case name such as `{}`",
sort, s, uc));
cx.span_lint(NON_UPPER_CASE_GLOBALS,
span,
&format!("{} `{}` should have an upper case name such as `{}`",
sort,
s,
uc));
} else {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
&format!("{} `{}` should have an upper case name",
sort, s));
cx.span_lint(NON_UPPER_CASE_GLOBALS,
span,
&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) {
match ti.node {
hir::ConstTraitItem(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
ti.name, ti.span);
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}
}
@ -351,8 +378,7 @@ impl LateLintPass for NonUpperCaseGlobals {
fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
ii.name, ii.span);
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span);
}
_ => {}
}
@ -363,8 +389,10 @@ impl LateLintPass for NonUpperCaseGlobals {
if let PatKind::Path(None, ref path) = p.node {
if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = cx.tcx.expect_def(p.id) {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
path.segments[0].name, path.span);
NonUpperCaseGlobals::check_upper_case(cx,
"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::traits::{self, Reveal};
use rustc::hir::map as hir_map;
use util::nodemap::{NodeSet};
use util::nodemap::NodeSet;
use lint::{Level, LateContext, LintContext, LintArray, Lint};
use lint::{LintPass, LateLintPass};
use std::collections::HashSet;
use syntax::{ast};
use syntax::ast;
use syntax::attr;
use syntax_pos::{Span};
use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind;
@ -75,7 +75,8 @@ impl LateLintPass for WhileTrue {
if let hir::ExprWhile(ref cond, ..) = e.node {
if let hir::ExprLit(ref lit) = cond.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 { ... }");
}
}
@ -93,8 +94,7 @@ declare_lint! {
pub struct BoxPointers;
impl BoxPointers {
fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>,
span: Span, ty: Ty<'tcx>) {
fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
for leaf_ty in ty.walk() {
if let ty::TyBox(_) = leaf_ty.sty {
let m = format!("type uses owned (Box type) pointers: {}", ty);
@ -117,10 +117,8 @@ impl LateLintPass for BoxPointers {
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) =>
self.check_heap_type(cx, it.span,
cx.tcx.node_id_to_type(it.id)),
_ => ()
hir::ItemUnion(..) => 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
@ -128,11 +126,12 @@ impl LateLintPass for BoxPointers {
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
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));
}
}
_ => ()
_ => (),
}
}
@ -166,9 +165,11 @@ impl LateLintPass 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, fieldpat.span,
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
fieldpat.span,
&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) {
match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
}
hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
}
_ => return,
}
}
fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
_: &hir::Block, span: Span, _: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
_: ast::NodeId) {
match fk {
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
}
FnKind::Method(_, sig, ..) => {
if sig.unsafety == hir::Unsafety::Unsafe {
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) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
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")
}
}
@ -263,9 +273,9 @@ pub struct MissingDoc {
impl MissingDoc {
pub fn new() -> MissingDoc {
MissingDoc {
struct_def_stack: vec!(),
struct_def_stack: vec![],
in_variant: false,
doc_hidden_stack: vec!(false),
doc_hidden_stack: vec![false],
private_traits: HashSet::new(),
}
}
@ -275,11 +285,11 @@ impl MissingDoc {
}
fn check_missing_docs_attrs(&self,
cx: &LateContext,
id: Option<ast::NodeId>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
cx: &LateContext,
id: Option<ast::NodeId>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
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");
if !has_doc {
cx.span_lint(MISSING_DOCS, sp,
cx.span_lint(MISSING_DOCS,
sp,
&format!("missing documentation for {}", desc));
}
}
@ -316,8 +327,10 @@ impl LintPass for MissingDoc {
impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
let doc_hidden = self.doc_hidden() ||
attrs.iter().any(|attr| {
attr.check_name("doc") &&
match attr.meta_item_list() {
None => false,
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");
}
fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
fn check_struct_def(&mut self,
_: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
self.struct_def_stack.push(item_id);
}
fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
fn check_struct_def_post(&mut self,
_: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
assert!(popped == item_id);
}
@ -358,10 +379,10 @@ impl LateLintPass for MissingDoc {
for itm in items {
self.private_traits.insert(itm.id);
}
return
return;
}
"a trait"
},
}
hir::ItemTy(..) => "a type alias",
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
@ -369,26 +390,30 @@ impl LateLintPass for MissingDoc {
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) {
match cx.tcx.map.find(node_id) {
Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
for itm in impl_items {
self.private_traits.insert(itm.id);
Some(hir_map::NodeItem(item)) => {
if item.vis == hir::Visibility::Inherited {
for itm in impl_items {
self.private_traits.insert(itm.id);
}
}
},
_ => { }
}
_ => {}
}
}
return
},
return;
}
hir::ItemConst(..) => "a constant",
hir::ItemStatic(..) => "a static",
_ => return
_ => return,
};
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) {
if self.private_traits.contains(&trait_item.id) { return }
if self.private_traits.contains(&trait_item.id) {
return;
}
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
@ -396,9 +421,11 @@ impl LateLintPass for MissingDoc {
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.span, desc);
trait_item.span,
desc);
}
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::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.span, desc);
impl_item.span,
desc);
}
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if !sf.is_positional() {
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");
self.check_missing_docs_attrs(cx, Some(cur_struct_def),
&sf.attrs, sf.span,
self.check_missing_docs_attrs(cx,
Some(cur_struct_def),
&sf.attrs,
sf.span,
"a struct field")
}
}
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
&v.node.attrs, v.span, "a variant");
self.check_missing_docs_attrs(cx,
Some(v.node.data.id()),
&v.node.attrs,
v.span,
"a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
@ -486,7 +521,9 @@ impl LateLintPass for MissingCopyImplementations {
}
_ => return,
};
if def.has_dtor() { return; }
if def.has_dtor() {
return;
}
let parameter_environment = cx.tcx.empty_parameter_environment();
// FIXME (@jroesch) should probably inver this so that the parameter env still impls this
// method
@ -514,9 +551,7 @@ pub struct MissingDebugImplementations {
impl MissingDebugImplementations {
pub fn new() -> MissingDebugImplementations {
MissingDebugImplementations {
impling_types: None,
}
MissingDebugImplementations { impling_types: None }
}
}
@ -533,7 +568,9 @@ impl LateLintPass for MissingDebugImplementations {
}
match item.node {
hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemEnum(..) => {}
_ => return,
}
@ -585,12 +622,13 @@ pub struct Deprecated {
impl Deprecated {
pub fn new() -> Deprecated {
Deprecated {
current_item: ast::CRATE_NODE_ID,
}
Deprecated { 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>,
deprecation: &Option<stability::DeprecationEntry>) {
// Deprecated attributes apply in-crate and cross-crate.
@ -641,9 +679,10 @@ impl LintPass for Deprecated {
impl LateLintPass for Deprecated {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
self.push_item(item.id);
stability::check_item(cx.tcx, item, false,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_item(cx.tcx,
item,
false,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
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) {
stability::check_expr(cx.tcx, e,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_expr(cx.tcx,
e,
&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) {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_path(cx.tcx,
path,
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) {
stability::check_path_list_item(cx.tcx, item,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_path_list_item(cx.tcx,
item,
&mut |id, sp, stab, depr| {
self.lint(cx, id, sp, &stab, &depr)
});
}
fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
stability::check_pat(cx.tcx, pat,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_pat(cx.tcx,
pat,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) {
@ -716,15 +758,20 @@ impl LintPass for UnconditionalRecursion {
}
impl LateLintPass for UnconditionalRecursion {
fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
blk: &hir::Block, sp: Span, id: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
blk: &hir::Block,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {
FnKind::ItemFn(..) => None,
FnKind::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.
FnKind::Closure(_) => return
FnKind::Closure(_) => return,
};
// Walk through this function (say `f`) looking to see if
@ -779,10 +826,8 @@ impl LateLintPass for UnconditionalRecursion {
// is this a recursive call?
let self_recursive = if node_id != ast::DUMMY_NODE_ID {
match method {
Some(ref method) => {
expr_refers_to_this_method(cx.tcx, method, node_id)
}
None => expr_refers_to_this_fn(cx.tcx, id, node_id)
Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
None => expr_refers_to_this_fn(cx.tcx, id, node_id),
}
} else {
false
@ -808,7 +853,8 @@ impl LateLintPass for UnconditionalRecursion {
// no break */ }`) shouldn't be linted unless it actually
// recurs.
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");
// 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`
// represents a call to the function `fn_id`/method `method`.
fn expr_refers_to_this_fn(tcx: TyCtxt,
fn_id: ast::NodeId,
id: ast::NodeId) -> bool {
fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
tcx.expect_def_or_none(callee.id).map_or(false, |def| {
def.def_id() == tcx.map.local_def_id(fn_id)
})
tcx.expect_def_or_none(callee.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`.
fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
method: &ty::Method,
id: ast::NodeId) -> bool {
id: ast::NodeId)
-> bool {
// Check for method calls and overloaded operators.
let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
if let Some(m) = opt_m {
@ -859,9 +903,11 @@ impl LateLintPass for UnconditionalRecursion {
if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
for i in 0..adj.autoderefs {
let method_call = ty::MethodCall::autoderef(id, i as u32);
if let Some(m) = tcx.tables.borrow().method_map
.get(&method_call)
.cloned() {
if let Some(m) = tcx.tables
.borrow()
.method_map
.get(&method_call)
.cloned() {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true;
}
@ -877,13 +923,16 @@ impl LateLintPass for UnconditionalRecursion {
match tcx.expect_def_or_none(callee.id) {
Some(Def::Method(def_id)) => {
let item_substs = tcx.node_id_item_substs(callee.id);
method_call_refers_to_method(
tcx, method, def_id, &item_substs.substs, id)
method_call_refers_to_method(tcx,
method,
def_id,
&item_substs.substs,
id)
}
_ => false
_ => false,
}
}
_ => false
_ => false,
}
}
@ -893,15 +942,14 @@ impl LateLintPass for UnconditionalRecursion {
method: &ty::Method,
callee_id: DefId,
callee_substs: &Substs<'tcx>,
expr_id: ast::NodeId) -> bool {
expr_id: ast::NodeId)
-> bool {
let callee_item = tcx.impl_or_trait_item(callee_id);
match callee_item.container() {
// This is an inherent method, so the `def_id` refers
// directly to the method definition.
ty::ImplContainer(_) => {
callee_id == method.def_id
}
ty::ImplContainer(_) => callee_id == method.def_id,
// A trait method, from any number of possible sources.
// 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);
// It matches if it comes from the same impl,
// and has the same method name.
container == method.container
&& callee_item.name() == method.name
container == method.container && callee_item.name() == method.name
}
// There's no way to know if this call is
// recursive, so we assume it's not.
_ => false
_ => false,
}
})
}
@ -992,7 +1039,8 @@ impl LateLintPass for PluginAsLibrary {
};
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");
}
}
@ -1050,15 +1098,15 @@ impl LateLintPass for InvalidNoMangleItems {
"generic functions must be mangled");
}
}
},
}
hir::ItemStatic(..) => {
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",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
}
},
}
hir::ItemConst(..) => {
if attr::contains_name(&it.attrs, "no_mangle") {
// 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);
}
}
_ => {},
_ => {}
}
}
}
@ -1096,19 +1144,21 @@ impl LateLintPass for MutableTransmutes {
consider instead using an UnsafeCell";
match get_transmute_from_to(cx, expr) {
Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
if to_mt.mutbl == hir::Mutability::MutMutable
&& from_mt.mutbl == hir::Mutability::MutImmutable {
if to_mt.mutbl == hir::Mutability::MutMutable &&
from_mt.mutbl == hir::Mutability::MutImmutable {
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
}
}
_ => ()
_ => (),
}
fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
fn get_transmute_from_to<'a, 'tcx>
(cx: &LateContext<'a, 'tcx>,
expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node {
hir::ExprPath(..) => (),
_ => return None
_ => return None,
}
if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
if !def_id_is_transmute(cx, did) {
@ -1120,8 +1170,8 @@ impl LateLintPass for MutableTransmutes {
let from = bare_fn.sig.0.inputs[0];
let to = bare_fn.sig.0.output;
return Some((&from.sty, &to.sty));
},
_ => ()
}
_ => (),
}
}
None
@ -1130,7 +1180,7 @@ impl LateLintPass for MutableTransmutes {
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.lookup_item_type(def_id).ty.sty {
ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
_ => return false
_ => return false,
}
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 syntax_pos;
pub use rustc::lint as lint;
pub use rustc::middle as middle;
pub use rustc::session as session;
pub use rustc::util as util;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;
use session::Session;
use lint::LintId;
@ -139,13 +139,24 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
MissingDebugImplementations,
);
add_lint_group!(sess, "bad_style",
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess,
"bad_style",
NON_CAMEL_CASE_TYPES,
NON_SNAKE_CASE,
NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
add_lint_group!(sess,
"unused",
UNUSED_IMPORTS,
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:
//
@ -155,7 +166,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
// and include the full URL.
// - Later, change lint to error
// - Eventually, remove lint
store.register_future_incompatible(sess, vec![
store.register_future_incompatible(sess,
vec![
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
@ -204,11 +216,13 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
// Register renamed and removed lints
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("raw_pointer_derive", "using derive with raw pointers is ok");
// This was renamed to raw_pointer_derive, which was then 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");
}

View File

@ -18,7 +18,7 @@ use rustc::traits::Reveal;
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet};
use util::nodemap::FnvHashSet;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
@ -91,15 +91,15 @@ pub struct TypeLimits {
impl TypeLimits {
pub fn new() -> TypeLimits {
TypeLimits {
negated_expr_id: ast::DUMMY_NODE_ID,
}
TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
}
}
impl LintPass for TypeLimits {
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 {
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
forbid_unsigned_negation(cx, e.span);
},
}
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
forbid_unsigned_negation(cx, e.span);
}
},
_ => ()
}
_ => (),
}
} else {
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 {
self.negated_expr_id = expr.id;
}
},
}
hir::ExprBinary(binop, ref l, ref 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");
}
@ -140,30 +141,35 @@ impl LateLintPass for TypeLimits {
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::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
_ => None
_ => None,
};
if let Some(bits) = opt_ty_bits {
let exceeding = if let hir::ExprLit(ref lit) = r.node {
if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits }
else { false }
if let ast::LitKind::Int(shift, _) = lit.node {
shift >= bits
} else {
false
}
} else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
Ok(ConstVal::Integral(i)) => {
i.is_negative() || i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
},
_ => { false }
i.is_negative() ||
i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
}
_ => false,
}
};
if exceeding {
cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
cx.span_lint(EXCEEDING_BITSHIFTS,
e.span,
"bitshift exceeds the type's number of bits");
}
};
}
},
}
hir::ExprLit(ref lit) => {
match cx.tcx.node_id_to_type(e.id).sty {
ty::TyInt(t) => {
@ -182,14 +188,15 @@ impl LateLintPass for TypeLimits {
// avoiding use of -min to prevent overflow/panic
if (negative && v > max as u64 + 1) ||
(!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));
return;
}
}
_ => bug!()
_ => bug!(),
};
},
}
ty::TyUint(t) => {
let uint_type = if let ast::UintTy::Us = t {
cx.sess().target.uint_type
@ -201,13 +208,14 @@ impl LateLintPass for TypeLimits {
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
_ => bug!()
_ => bug!(),
};
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));
}
},
}
ty::TyFloat(t) => {
let (min, max) = float_ty_range(t);
let lit_val: f64 = match lit.node {
@ -215,70 +223,71 @@ impl LateLintPass for TypeLimits {
ast::LitKind::FloatUnsuffixed(ref v) => {
match v.parse() {
Ok(f) => f,
Err(_) => return
Err(_) => return,
}
}
_ => bug!()
_ => bug!(),
};
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));
}
},
_ => ()
}
_ => (),
};
},
_ => ()
}
_ => (),
};
fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
min: T, max: T) -> bool {
fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
match binop.node {
hir::BiLt => v > min && v <= max,
hir::BiLe => v >= min && v < max,
hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max,
hir::BiLt => v > min && v <= max,
hir::BiLe => v >= min && v < max,
hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max,
hir::BiEq | hir::BiNe => v >= min && v <= max,
_ => bug!()
_ => bug!(),
}
}
fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
codemap::respan(binop.span, match binop.node {
hir::BiLt => hir::BiGt,
hir::BiLe => hir::BiGe,
hir::BiGt => hir::BiLt,
hir::BiGe => hir::BiLe,
_ => return binop
})
codemap::respan(binop.span,
match binop.node {
hir::BiLt => hir::BiGt,
hir::BiLe => hir::BiGe,
hir::BiGt => hir::BiLt,
hir::BiGe => hir::BiLe,
_ => return binop,
})
}
// for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty {
ast::IntTy::Is => (i64::MIN, i64::MAX),
ast::IntTy::I8 => (i8::MIN as i64, i8::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::I64 => (i64::MIN, i64::MAX)
ast::IntTy::Is => (i64::MIN, i64::MAX),
ast::IntTy::I8 => (i8::MIN as i64, i8::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::I64 => (i64::MIN, i64::MAX),
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty {
ast::UintTy::Us => (u64::MIN, u64::MAX),
ast::UintTy::U8 => (u8::MIN as u64, u8::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::U64 => (u64::MIN, u64::MAX)
ast::UintTy::Us => (u64::MIN, u64::MAX),
ast::UintTy::U8 => (u8::MIN as u64, u8::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::U64 => (u64::MIN, u64::MAX),
}
}
fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
match float_ty {
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>,
binop: hir::BinOp,
l: &hir::Expr,
r: &hir::Expr) -> bool {
r: &hir::Expr)
-> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
(&hir::ExprLit(_), _) => (l, r, true),
(_, &hir::ExprLit(_)) => (r, l, false),
_ => return true
_ => return true,
};
// Normalize the binop so that the literal is always on the RHS in
// the comparison
let norm_binop = if swap {
rev_binop(binop)
} else {
binop
};
let norm_binop = if swap { rev_binop(binop) } else { binop };
match tcx.node_id_to_type(expr.id).sty {
ty::TyInt(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
hir::ExprLit(ref li) => match li.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
_ => return true
},
_ => bug!()
hir::ExprLit(ref li) => {
match li.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
_ => return true,
}
}
_ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
ty::TyUint(uint_ty) => {
let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
hir::ExprLit(ref li) => match li.node {
ast::LitKind::Int(v, _) => v,
_ => return true
},
_ => bug!()
hir::ExprLit(ref li) => {
match li.node {
ast::LitKind::Int(v, _) => v,
_ => return true,
}
}
_ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
_ => true
_ => true,
}
}
fn is_comparison(binop: hir::BinOp) -> bool {
match binop.node {
hir::BiEq | hir::BiLt | hir::BiLe |
hir::BiNe | hir::BiGe | hir::BiGt => true,
_ => false
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
_ => false,
}
}
fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
cx.sess()
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
.span_help(span, "use a cast or the `!` operator")
.emit();
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
.span_help(span, "use a cast or the `!` operator")
.emit();
}
}
}
@ -370,7 +379,7 @@ declare_lint! {
}
struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>
cx: &'a LateContext<'a, 'tcx>,
}
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 {
match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
ty::TyFnPtr(_) => { return true; }
ty::TyRef(..) => { return true; }
_ => { }
ty::TyFnPtr(_) => {
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> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn check_type_for_ffi(&self,
cache: &mut FnvHashSet<Ty<'tcx>>,
ty: Ty<'tcx>)
-> FfiResult {
fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
use self::FfiResult::*;
let cx = self.cx.tcx;
@ -431,112 +441,118 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
match ty.sty {
ty::TyAdt(def, substs) => match def.adt_kind() {
AdtKind::Struct => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe(
"found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to \
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); }
ty::TyAdt(def, substs) => {
match def.adt_kind() {
AdtKind::Struct => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
}
}
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); }
// 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");
}
}
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);
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 FfiBadEnum(def.did, s); }
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 {
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 => {
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.
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBox(..) => {
FfiUnsafe("found Rust type Box<_> in foreign module, \
@ -572,24 +587,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
consider using a struct instead")
}
ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
self.check_type_for_ffi(cache, m.ty)
}
ty::TyRawPtr(ref m) |
ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
ty::TyArray(ty, _) => {
self.check_type_for_ffi(cache, ty)
}
ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
ty::TyFnPtr(bare_fn) => {
match bare_fn.abi {
Abi::Rust |
Abi::RustIntrinsic |
Abi::PlatformIntrinsic |
Abi::RustCall => {
return FfiUnsafe(
"found function pointer with Rust calling \
convention in foreign module; consider using an \
`extern` function pointer")
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
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);
match r {
FfiSafe => {}
_ => { return r; }
_ => {
return r;
}
}
}
for arg in sig.inputs {
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
_ => { return r; }
_ => {
return r;
}
}
}
FfiSafe
}
ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) |
ty::TyFnDef(..) => {
bug!("Unexpected type in foreign function")
}
ty::TyParam(..) |
ty::TyInfer(..) |
ty::TyError |
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) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
struct marked #[repr(C)]: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
union marked #[repr(C)]: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
enum: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in enum: {}",
s));
}
}
}
@ -719,13 +738,13 @@ impl LintPass for VariantSizeDifferences {
impl LateLintPass for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
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 layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
})
ty.layout(&infcx)
.unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
});
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
@ -738,23 +757,21 @@ impl LateLintPass for VariantSizeDifferences {
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant
let bytes = variant_layout.min_size.bytes()
.saturating_sub(discr_size);
let bytes = variant_layout.min_size
.bytes()
.saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
bytes
})
.enumerate()
.fold((0, 0, 0),
|(l, s, li), (idx, size)|
if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
}
);
.fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
});
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
@ -762,7 +779,8 @@ impl LateLintPass for VariantSizeDifferences {
cx.span_lint(VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
&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 !name.as_str().starts_with("_") {
match mutables.entry(name.0 as usize) {
Vacant(entry) => { entry.insert(vec![id]); },
Occupied(mut entry) => { entry.get_mut().push(id); },
Vacant(entry) => {
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();
for (_, v) in &mutables {
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");
}
}
@ -90,9 +95,13 @@ impl LateLintPass for UnusedMut {
}
}
fn check_fn(&mut self, cx: &LateContext,
_: FnKind, decl: &hir::FnDecl,
_: &hir::Block, _: Span, _: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
_: FnKind,
decl: &hir::FnDecl,
_: &hir::Block,
_: Span,
_: ast::NodeId) {
for a in &decl.inputs {
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) {
let expr = match s.node {
hir::StmtSemi(ref expr, _) => &**expr,
_ => return
_ => return,
};
if let hir::ExprRet(..) = expr.node {
@ -184,8 +193,8 @@ impl LateLintPass for UnusedUnsafe {
if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
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) {
if let hir::StmtSemi(ref expr, _) = s.node {
if let hir::ExprPath(..) = expr.node {
cx.span_lint(PATH_STATEMENTS, s.span,
"path statement with no effect");
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
}
}
}
@ -242,8 +250,8 @@ impl LateLintPass for UnusedAttributes {
AttributeType::Whitelisted if attr.check_name(name) => {
debug!("{:?} is Whitelisted", name);
break;
},
_ => ()
}
_ => (),
}
}
@ -259,24 +267,22 @@ impl LateLintPass for UnusedAttributes {
debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level?
let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
attr.name() == name &&
ty == AttributeType::CrateLevel
}).is_some();
let known_crate = KNOWN_ATTRIBUTES.iter()
.find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
.is_some();
// Has a plugin registered this attribute as one which must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| {
&*attr.name() == x &&
AttributeType::CrateLevel == t
}).is_some();
if known_crate || plugin_crate {
.find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t)
.is_some();
if known_crate || plugin_crate {
let msg = match attr.node.style {
ast::AttrStyle::Outer => "crate-level attribute should be an inner \
attribute: add an exclamation mark: #![foo]",
ast::AttrStyle::Inner => "crate-level attribute should be in the \
root module",
ast::AttrStyle::Outer => {
"crate-level attribute should be an inner attribute: add an exclamation \
mark: #![foo]"
}
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
};
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
}
@ -296,12 +302,16 @@ declare_lint! {
pub struct 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) {
if let ast::ExprKind::Paren(ref inner) = value.node {
let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
if !necessary {
cx.span_lint(UNUSED_PARENS, value.span,
cx.span_lint(UNUSED_PARENS,
value.span,
&format!("unnecessary parentheses around {}", msg))
}
}
@ -319,8 +329,7 @@ impl UnusedParens {
ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
// X { y: 1 } + X { y: 2 }
contains_exterior_struct_lit(&lhs) ||
contains_exterior_struct_lit(&rhs)
contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
}
ast::ExprKind::Unary(_, ref x) |
ast::ExprKind::Cast(ref x, _) |
@ -337,7 +346,7 @@ impl UnusedParens {
contains_exterior_struct_lit(&exprs[0])
}
_ => false
_ => false,
}
}
}
@ -363,18 +372,20 @@ impl EarlyLintPass for UnusedParens {
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
_ => return
_ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
}
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
let (value, msg) = match s.node {
ast::StmtKind::Local(ref local) => match local.init {
Some(ref value) => (value, "assigned value"),
None => return
},
_ => return
ast::StmtKind::Local(ref local) => {
match local.init {
Some(ref value) => (value, "assigned value"),
None => return,
}
}
_ => return,
};
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) {
match e.node {
hir::ExprBox(_) => {}
_ => return
_ => return,
}
if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
ref autoref, ..
}) = *adjustment {
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
*adjustment {
match autoref {
&Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use & instead");
}
&Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use &mut instead");
}
_ => ()
_ => (),
}
}
}