Skip to content

Rust upgrade to rustc 1.5.0-nightly (9d3e79ad3 2015-10-10) #377

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Oct 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box misc::ModuloOne);
reg.register_late_lint_pass(box unicode::Unicode);
reg.register_late_lint_pass(box strings::StringAdd);
reg.register_late_lint_pass(box returns::ReturnPass);
reg.register_early_lint_pass(box returns::ReturnPass);
reg.register_late_lint_pass(box methods::MethodsPass);
reg.register_late_lint_pass(box shadow::ShadowPass);
reg.register_late_lint_pass(box types::LetPass);
Expand Down
28 changes: 14 additions & 14 deletions src/returns.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use rustc::lint::*;
use rustc_front::hir::*;
use reexport::*;
use syntax::ast::*;
//use reexport::*;
use syntax::codemap::{Span, Spanned};
use rustc_front::visit::FnKind;
use syntax::visit::FnKind;

use utils::{span_lint, snippet, match_path, in_external_macro};
use utils::{span_lint, snippet, match_path_ast, in_external_macro};

declare_lint!(pub NEEDLESS_RETURN, Warn,
"using a return statement like `return expr;` where an expression would suffice");
Expand All @@ -17,7 +17,7 @@ pub struct ReturnPass;

impl ReturnPass {
// Check the final stmt or expr in a block for unnecessary return.
fn check_block_return(&mut self, cx: &LateContext, block: &Block) {
fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) {
if let Some(ref expr) = block.expr {
self.check_final_expr(cx, expr);
} else if let Some(stmt) = block.stmts.last() {
Expand All @@ -30,7 +30,7 @@ impl ReturnPass {
}

// Check a the final expression in a block if it's a return.
fn check_final_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
match expr.node {
// simple return is always "bad"
ExprRet(Some(ref inner)) => {
Expand All @@ -48,7 +48,7 @@ impl ReturnPass {
self.check_final_expr(cx, elsexpr);
}
// a match expr, check all arms
ExprMatch(_, ref arms, _) => {
ExprMatch(_, ref arms) => {
for arm in arms {
self.check_final_expr(cx, &arm.body);
}
Expand All @@ -57,7 +57,7 @@ impl ReturnPass {
}
}

fn emit_return_lint(&mut self, cx: &LateContext, spans: (Span, Span)) {
fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) {
if in_external_macro(cx, spans.1) {return;}
span_lint(cx, NEEDLESS_RETURN, spans.0, &format!(
"unneeded return statement. Consider using `{}` \
Expand All @@ -66,7 +66,7 @@ impl ReturnPass {
}

// Check for "let x = EXPR; x"
fn check_let_return(&mut self, cx: &LateContext, block: &Block) {
fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) {
// we need both a let-binding stmt and an expr
if_let_chain! {
[
Expand All @@ -77,14 +77,14 @@ impl ReturnPass {
let Some(ref initexpr) = local.init,
let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node,
let ExprPath(_, ref path) = retexpr.node,
match_path(path, &[&id.name.as_str()])
match_path_ast(path, &[&id.name.as_str()])
], {
self.emit_let_lint(cx, retexpr.span, initexpr.span);
}
}
}

fn emit_let_lint(&mut self, cx: &LateContext, lint_span: Span, note_span: Span) {
fn emit_let_lint(&mut self, cx: &EarlyContext, 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 from a block. \
Expand All @@ -102,13 +102,13 @@ impl LintPass for ReturnPass {
}
}

impl LateLintPass for ReturnPass {
fn check_fn(&mut self, cx: &LateContext, _: FnKind, _: &FnDecl,
impl EarlyLintPass for ReturnPass {
fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl,
block: &Block, _: Span, _: NodeId) {
self.check_block_return(cx, block);
}

fn check_block(&mut self, cx: &LateContext, block: &Block) {
fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
self.check_let_return(cx, block);
}
}
3 changes: 2 additions & 1 deletion src/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_front::visit::FnKind;
use rustc::lint::*;
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint, span_note_and_lint};
use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint};

declare_lint!(pub SHADOW_SAME, Allow,
"rebinding a name to itself, e.g. `let mut x = &mut x`");
Expand Down Expand Up @@ -60,6 +60,7 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>

fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) {
if in_external_macro(cx, decl.span) { return; }
if is_from_for_desugar(decl) { return; }
if let DeclLocal(ref local) = decl.node {
let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
Expand Down
10 changes: 6 additions & 4 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
use syntax::ast::FloatTy::*;

use utils::{match_type, snippet, span_lint, span_help_and_lint, in_macro, in_external_macro};
use utils::{match_type, snippet, span_lint, span_help_and_lint};
use utils::{is_from_for_desugar, in_macro, in_external_macro};
use utils::{LL_PATH, VEC_PATH};

/// Handles all the linting of funky types
Expand Down Expand Up @@ -61,9 +62,10 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) {
if *bindtype == ty::TyTuple(vec![]) {
if in_external_macro(cx, decl.span) ||
in_macro(cx, local.pat.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, "..")));
if is_from_for_desugar(decl) { return; }
span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
"this let-binding has unit value. Consider omitting `let {} =`",
snippet(cx, local.pat.span, "..")));
}
}
}
Expand Down
139 changes: 76 additions & 63 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc::middle::def_id::DefId;
use rustc::middle::ty;
use std::borrow::Cow;
use syntax::ast::Lit_::*;
use syntax::ast;

// module DefPaths for certain structs/enums we check for
pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"];
Expand All @@ -15,15 +16,56 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];

/// Produce a nested chain of if-lets and ifs from the patterns:
///
/// if_let_chain! {
/// [
/// Some(y) = x,
/// y.len() == 2,
/// Some(z) = y,
/// ],
/// {
/// block
/// }
/// }
///
/// becomes
///
/// if let Some(y) = x {
/// if y.len() == 2 {
/// if let Some(z) = y {
/// block
/// }
/// }
/// }
#[macro_export]
macro_rules! if_let_chain {
([let $pat:pat = $expr:expr, $($tt:tt)+], $block:block) => {
if let $pat = $expr {
if_let_chain!{ [$($tt)+], $block }
}
};
([let $pat:pat = $expr:expr], $block:block) => {
if let $pat = $expr {
$block
}
};
([$expr:expr, $($tt:tt)+], $block:block) => {
if $expr {
if_let_chain!{ [$($tt)+], $block }
}
};
([$expr:expr], $block:block) => {
if $expr {
$block
}
};
}

/// returns true this expn_info was expanded by any macro
pub fn in_macro(cx: &LateContext, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id,
|info| info.map_or(false, |i| {
match i.callee.format {
ExpnFormat::CompilerExpansion(..) => false,
_ => true,
}
}))
|info| info.is_some())
}

/// returns true if the macro that expanded the crate was outside of
Expand All @@ -34,17 +76,9 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool {
fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool {
// no ExpnInfo = no macro
opt_info.map_or(false, |info| {
match info.callee.format {
ExpnFormat::CompilerExpansion(..) => {
if info.callee.name().as_str() == "closure expansion" {
return false;
}
},
ExpnFormat::MacroAttribute(..) => {
// these are all plugins
return true;
},
_ => (),
if let ExpnFormat::MacroAttribute(..) = info.callee.format {
// these are all plugins
return true;
}
// no span for the callee = external macro
info.callee.span.map_or(true, |span| {
Expand Down Expand Up @@ -102,6 +136,13 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool {
|(a, b)| a.identifier.name.as_str() == *b)
}

/// match a Path against a slice of segment string literals, e.g.
/// `match_path(path, &["std", "rt", "begin_unwind"])`
pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
path.segments.iter().rev().zip(segments.iter().rev()).all(
|(a, b)| a.identifier.name.as_str() == *b)
}

/// get the name of the item the expression is in, if available
pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
let parent_id = cx.tcx.map.get_parent(expr.id);
Expand All @@ -115,6 +156,24 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
}
}

/// checks if a `let` decl is from a for loop desugaring
pub fn is_from_for_desugar(decl: &Decl) -> bool {
if_let_chain! {
[
let DeclLocal(ref loc) = decl.node,
let Some(ref expr) = loc.init,
// FIXME: This should check for MatchSource::ForLoop
// but right now there's a bug where the match source isn't
// set during lowering
// https://github.com/rust-lang/rust/pull/28973
let ExprMatch(_, _, _) = expr.node
],
{ return true; }
};
false
}


/// convert a span to a code snippet if available, otherwise use default, e.g.
/// `snippet(cx, expr.span, "..")`
pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
Expand Down Expand Up @@ -262,49 +321,3 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool
}
false
}

/// Produce a nested chain of if-lets and ifs from the patterns:
///
/// if_let_chain! {
/// [
/// Some(y) = x,
/// y.len() == 2,
/// Some(z) = y,
/// ],
/// {
/// block
/// }
/// }
///
/// becomes
///
/// if let Some(y) = x {
/// if y.len() == 2 {
/// if let Some(z) = y {
/// block
/// }
/// }
/// }
#[macro_export]
macro_rules! if_let_chain {
([let $pat:pat = $expr:expr, $($tt:tt)+], $block:block) => {
if let $pat = $expr {
if_let_chain!{ [$($tt)+], $block }
}
};
([let $pat:pat = $expr:expr], $block:block) => {
if let $pat = $expr {
$block
}
};
([$expr:expr, $($tt:tt)+], $block:block) => {
if $expr {
if_let_chain!{ [$($tt)+], $block }
}
};
([$expr:expr], $block:block) => {
if $expr {
$block
}
};
}
6 changes: 3 additions & 3 deletions tests/compile-fail/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
fn add_only() { // ignores assignment distinction
let mut x = "".to_owned();

for _ in (1..3) {
for _ in 1..3 {
x = x + "."; //~ERROR you added something to a string.
}

Expand All @@ -20,7 +20,7 @@ fn add_only() { // ignores assignment distinction
fn add_assign_only() {
let mut x = "".to_owned();

for _ in (1..3) {
for _ in 1..3 {
x = x + "."; //~ERROR you assigned the result of adding something to this string.
}

Expand All @@ -34,7 +34,7 @@ fn add_assign_only() {
fn both() {
let mut x = "".to_owned();

for _ in (1..3) {
for _ in 1..3 {
x = x + "."; //~ERROR you assigned the result of adding something to this string.
}

Expand Down