rustc: Add some more checks to the stability lint
This catches uses of unstable traits in ``` trait Foo: UnstableTrait { } ``` and ``` impl UnstableTrait for Foo { } ```
This commit is contained in:
parent
68ac44cb97
commit
f383ce62e8
@ -1581,6 +1581,36 @@ impl Stability {
|
|||||||
|
|
||||||
cx.span_lint(lint, span, msg.as_slice());
|
cx.span_lint(lint, span, msg.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_internal(&self, cx: &Context, span: Span) -> bool {
|
||||||
|
// first, check if the given expression was generated by a macro or not
|
||||||
|
// we need to go back the expn_info tree to check only the arguments
|
||||||
|
// of the initial macro call, not the nested ones.
|
||||||
|
let mut expnid = span.expn_id;
|
||||||
|
let mut is_internal = false;
|
||||||
|
while cx.tcx.sess.codemap().with_expn_info(expnid, |expninfo| {
|
||||||
|
match expninfo {
|
||||||
|
Some(ref info) => {
|
||||||
|
// save the parent expn_id for next loop iteration
|
||||||
|
expnid = info.call_site.expn_id;
|
||||||
|
if info.callee.span.is_none() {
|
||||||
|
// it's a compiler built-in, we *really* don't want to mess with it
|
||||||
|
// so we skip it, unless it was called by a regular macro, in which case
|
||||||
|
// we will handle the caller macro next turn
|
||||||
|
is_internal = true;
|
||||||
|
true // continue looping
|
||||||
|
} else {
|
||||||
|
// was this expression from the current macro arguments ?
|
||||||
|
is_internal = !( span.lo > info.call_site.lo &&
|
||||||
|
span.hi < info.call_site.hi );
|
||||||
|
true // continue looping
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => false // stop looping
|
||||||
|
}
|
||||||
|
}) { /* empty while loop body */ }
|
||||||
|
return is_internal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for Stability {
|
impl LintPass for Stability {
|
||||||
@ -1605,33 +1635,7 @@ impl LintPass for Stability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
// first, check if the given expression was generated by a macro or not
|
if self.is_internal(cx, e.span) { return; }
|
||||||
// we need to go back the expn_info tree to check only the arguments
|
|
||||||
// of the initial macro call, not the nested ones.
|
|
||||||
let mut expnid = e.span.expn_id;
|
|
||||||
let mut is_internal = false;
|
|
||||||
while cx.tcx.sess.codemap().with_expn_info(expnid, |expninfo| {
|
|
||||||
match expninfo {
|
|
||||||
Some(ref info) => {
|
|
||||||
// save the parent expn_id for next loop iteration
|
|
||||||
expnid = info.call_site.expn_id;
|
|
||||||
if info.callee.span.is_none() {
|
|
||||||
// it's a compiler built-in, we *really* don't want to mess with it
|
|
||||||
// so we skip it, unless it was called by a regular macro, in which case
|
|
||||||
// we will handle the caller macro next turn
|
|
||||||
is_internal = true;
|
|
||||||
true // continue looping
|
|
||||||
} else {
|
|
||||||
// was this expression from the current macro arguments ?
|
|
||||||
is_internal = !( e.span.lo > info.call_site.lo &&
|
|
||||||
e.span.hi < info.call_site.hi );
|
|
||||||
true // continue looping
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => false // stop looping
|
|
||||||
}
|
|
||||||
}) { /* empty while loop body */ }
|
|
||||||
if is_internal { return; }
|
|
||||||
|
|
||||||
let mut span = e.span;
|
let mut span = e.span;
|
||||||
|
|
||||||
@ -1677,6 +1681,29 @@ impl LintPass for Stability {
|
|||||||
};
|
};
|
||||||
self.lint(cx, id, span);
|
self.lint(cx, id, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
|
||||||
|
if self.is_internal(cx, item.span) { return }
|
||||||
|
|
||||||
|
match item.node {
|
||||||
|
ast::ItemTrait(_, _, ref supertraits, _) => {
|
||||||
|
for t in supertraits.iter() {
|
||||||
|
match *t {
|
||||||
|
ast::TraitTyParamBound(ref t) => {
|
||||||
|
let id = ty::trait_ref_to_def_id(cx.tcx, t);
|
||||||
|
self.lint(cx, id, t.path.span);
|
||||||
|
}
|
||||||
|
_ => (/* pass */)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::ItemImpl(_, Some(ref t), _, _) => {
|
||||||
|
let id = ty::trait_ref_to_def_id(cx.tcx, t);
|
||||||
|
self.lint(cx, id, t.path.span);
|
||||||
|
}
|
||||||
|
_ => (/* pass */)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub UNUSED_IMPORTS, Warn,
|
declare_lint!(pub UNUSED_IMPORTS, Warn,
|
||||||
|
@ -118,6 +118,9 @@ pub trait Trait {
|
|||||||
|
|
||||||
impl Trait for MethodTester {}
|
impl Trait for MethodTester {}
|
||||||
|
|
||||||
|
#[experimental]
|
||||||
|
pub trait ExperimentalTrait {}
|
||||||
|
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
pub struct DeprecatedStruct { pub i: int }
|
pub struct DeprecatedStruct { pub i: int }
|
||||||
#[experimental]
|
#[experimental]
|
||||||
|
@ -141,6 +141,12 @@ mod cross_crate {
|
|||||||
foo.trait_unmarked(); //~ ERROR use of unmarked item
|
foo.trait_unmarked(); //~ ERROR use of unmarked item
|
||||||
foo.trait_stable();
|
foo.trait_stable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl ExperimentalTrait for S { } //~ ERROR use of experimental item
|
||||||
|
|
||||||
|
trait LocalTrait : ExperimentalTrait { } //~ ERROR use of experimental item
|
||||||
}
|
}
|
||||||
|
|
||||||
mod inheritance {
|
mod inheritance {
|
||||||
@ -444,6 +450,15 @@ mod this_crate {
|
|||||||
foo.trait_unmarked();
|
foo.trait_unmarked();
|
||||||
foo.trait_stable();
|
foo.trait_stable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
pub trait DeprecatedTrait {}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl DeprecatedTrait for S { } //~ ERROR use of deprecated item
|
||||||
|
|
||||||
|
trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
Loading…
Reference in New Issue
Block a user