More macro checks

This commit is contained in:
Manish Goregaokar 2015-08-27 04:01:35 +05:30
parent 7a1082d916
commit 9ebcd0bf29
5 changed files with 22 additions and 11 deletions

View File

@ -4,7 +4,7 @@ use syntax::codemap::Span;
use consts::{constant, is_negative};
use consts::Constant::ConstantInt;
use utils::{span_lint, snippet};
use utils::{span_lint, snippet, in_external_macro};
declare_lint! { pub IDENTITY_OP, Warn,
"using identity operations, e.g. `x + 0` or `y / 1`" }
@ -53,6 +53,7 @@ fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) {
1 => !is_negative(ty) && v == 1,
_ => unreachable!(),
} {
if in_external_macro(cx, e.span) {return;}
span_lint(cx, IDENTITY_OP, span, &format!(
"the operation is ineffective. Consider reducing it to `{}`",
snippet(cx, arg, "..")));

View File

@ -3,7 +3,8 @@ use syntax::ast;
use syntax::ast::*;
use std::borrow::Cow;
use utils::{snippet, snippet_block, span_lint, span_help_and_lint};
use utils::{snippet, snippet_block};
use utils::{span_lint, span_help_and_lint, in_external_macro};
declare_lint!(pub SINGLE_MATCH, Warn,
"a match statement with a single nontrivial arm (i.e, where the other arm \
@ -36,6 +37,7 @@ impl LintPass for MatchPass {
// finally, we don't want any content in the second arm (unit or empty block)
is_unit_expr(&arms[1].body)
{
if in_external_macro(cx, expr.span) {return;}
let body_code = snippet_block(cx, arms[0].body.span, "..");
let body_code = if let ExprBlock(_) = arms[0].body.node {
body_code

View File

@ -3,7 +3,7 @@ use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use syntax::visit::FnKind;
use utils::{span_lint, snippet, match_path};
use utils::{span_lint, snippet, match_path, in_external_macro};
declare_lint!(pub NEEDLESS_RETURN, Warn,
"using a return statement like `return expr;` where an expression would suffice");
@ -58,6 +58,7 @@ impl ReturnPass {
}
fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) {
if in_external_macro(cx, spans.1) {return;}
span_lint(cx, NEEDLESS_RETURN, spans.0, &format!(
"unneeded return statement. Consider using `{}` \
without the return and trailing semicolon",
@ -84,6 +85,7 @@ impl ReturnPass {
}
fn emit_let_lint(&mut self, cx: &Context, lint_span: Span, note_span: Span) {
if in_external_macro(cx, note_span) {return;}
span_lint(cx, LET_AND_RETURN, lint_span,
"returning the result of a let binding. \
Consider returning the expression directly.");

View File

@ -5,9 +5,8 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::codemap::Span;
use syntax::visit::{FnKind, Visitor, walk_ty};
use rustc::middle::ty;
use syntax::codemap::ExpnInfo;
use utils::{in_macro, match_type, snippet, span_lint, span_help_and_lint, in_external_macro};
use utils::{match_type, snippet, span_lint, span_help_and_lint, in_external_macro};
use utils::{LL_PATH, VEC_PATH};
/// Handles all the linting of funky types
@ -55,11 +54,11 @@ declare_lint!(pub LET_UNIT_VALUE, Warn,
"creating a let binding to a value of unit type, which usually can't be used afterwards");
fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
if in_macro(cx, info) { return; }
fn check_let_unit(cx: &Context, decl: &Decl) {
if let DeclLocal(ref local) = decl.node {
let bindtype = &cx.tcx.pat_ty(&local.pat).sty;
if *bindtype == ty::TyTuple(vec![]) {
if in_external_macro(cx, decl.span) { return; }
span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
"this let-binding has unit value. Consider omitting `let {} =`",
snippet(cx, local.pat.span, "..")));
@ -73,9 +72,7 @@ impl LintPass for LetPass {
}
fn check_decl(&mut self, cx: &Context, decl: &Decl) {
cx.sess().codemap().with_expn_info(
decl.span.expn_id,
|info| check_let_unit(cx, decl, info));
check_let_unit(cx, decl)
}
}

View File

@ -1,6 +1,6 @@
use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::{ExpnInfo, Span};
use syntax::codemap::{ExpnInfo, Span, ExpnFormat};
use rustc::ast_map::Node::NodeExpr;
use rustc::middle::def_id::DefId;
use rustc::middle::ty;
@ -18,6 +18,14 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke
pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool {
// no ExpnInfo = no macro
opt_info.map_or(false, |info| {
if info.callee.format == ExpnFormat::CompilerExpansion {
if info.callee.name == "closure expansion" {
return false;
}
} else if info.callee.format == ExpnFormat::MacroAttribute {
// these are all plugins
return true;
}
// no span for the callee = external macro
info.callee.span.map_or(true, |span| {
// no snippet = external macro or compiler-builtin expansion
@ -31,6 +39,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool {
}
/// invokes in_macro with the expansion info of the given span
/// slightly heavy, try to use this after other checks have already happened
pub fn in_external_macro(cx: &Context, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id,
|info| in_macro(cx, info))