auto merge of #17508 : vberger/rust/stability_lint_for_nested_macros, r=pnkfelix
Finishes the job of #17286. Now the stability lint will successfully detect patterns such as: ``` first_macro!(second_macro!(deprecated_function())); ``` ``` macro_rules! foo ( ($e: expr) => (bar!($e)) ) foo!(deprected_function()); ``` and ``` println!("{}", deprecated_function()); ``` even with more levels of nesting, such as ``` println!("{}", foo!(bar!(deprecated_function()))); ```
This commit is contained in:
commit
b69cd73b7b
|
@ -43,7 +43,7 @@ use syntax::abi;
|
||||||
use syntax::ast_map;
|
use syntax::ast_map;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::codemap::{Span, NO_EXPANSION};
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::{ast, ast_util, visit};
|
use syntax::{ast, ast_util, visit};
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
@ -1473,27 +1473,33 @@ impl LintPass for Stability {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
// skip if `e` is not from macro arguments
|
// first, check if the given expression was generated by a macro or not
|
||||||
let skip = cx.tcx.sess.codemap().with_expn_info(e.span.expn_id, |expninfo| {
|
// 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 {
|
match expninfo {
|
||||||
Some(ref info) => {
|
Some(ref info) => {
|
||||||
if info.call_site.expn_id != NO_EXPANSION ||
|
// save the parent expn_id for next loop iteration
|
||||||
!( e.span.lo > info.call_site.lo && e.span.hi < info.call_site.hi ) {
|
expnid = info.call_site.expn_id;
|
||||||
// This code is not from the arguments,
|
if info.callee.span.is_none() {
|
||||||
// or this macro call was generated by an other macro
|
// it's a compiler built-in, we *really* don't want to mess with it
|
||||||
// We can't handle it.
|
// so we skip it, unless it was called by a regular macro, in which case
|
||||||
true
|
// we will handle the caller macro next turn
|
||||||
} else if info.callee.span.is_none() {
|
is_internal = true;
|
||||||
// We don't want to mess with compiler builtins.
|
true // continue looping
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
// 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 }
|
_ => false // stop looping
|
||||||
}
|
}
|
||||||
});
|
}) { /* empty while loop body */ }
|
||||||
if skip { return; }
|
if is_internal { return; }
|
||||||
|
|
||||||
let mut span = e.span;
|
let mut span = e.span;
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ mod cross_crate {
|
||||||
// on macros themselves are not yet linted.
|
// on macros themselves are not yet linted.
|
||||||
macro_test!();
|
macro_test!();
|
||||||
macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text
|
macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text
|
||||||
|
macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text
|
||||||
macro_test_arg_nested!(deprecated_text);
|
macro_test_arg_nested!(deprecated_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue