Skip to content

Commit

Permalink
Merge pull request #2924 from niklasf/copy-iterator
Browse files Browse the repository at this point in the history
Add copy_iterator lint (#1534)
  • Loading branch information
flip1995 authored Aug 24, 2018
2 parents dda6566 + afdf350 commit 72344f4
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
57 changes: 57 additions & 0 deletions clippy_lints/src/copy_iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
use rustc::hir::{Item, ItemKind};
use rustc::lint::*;
use rustc::{declare_lint, lint_array};

/// **What it does:** Checks for types that implement `Copy` as well as
/// `Iterator`.
///
/// **Why is this bad?** Implicit copies can be confusing when working with
/// iterator combinators.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[derive(Copy, Clone)]
/// struct Countdown(u8);
///
/// impl Iterator for Countdown {
/// // ...
/// }
///
/// let a: Vec<_> = my_iterator.take(1).collect();
/// let b: Vec<_> = my_iterator.collect();
/// ```
declare_clippy_lint! {
pub COPY_ITERATOR,
pedantic,
"implementing `Iterator` on a `Copy` type"
}

pub struct CopyIterator;

impl LintPass for CopyIterator {
fn get_lints(&self) -> LintArray {
lint_array![COPY_ITERATOR]
}
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.node {
let ty = cx.tcx.type_of(cx.tcx.hir.local_def_id(item.id));

if is_copy(cx, ty) && match_path(&trait_ref.path, &paths::ITERATOR) {
span_note_and_lint(
cx,
COPY_ITERATOR,
item.span,
"you are implementing `Iterator` on a `Copy` type",
item.span,
"consider implementing `IntoIterator` instead",
);
}
}
}
}
3 changes: 3 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub mod bytecount;
pub mod collapsible_if;
pub mod const_static_lifetime;
pub mod copies;
pub mod copy_iterator;
pub mod cyclomatic_complexity;
pub mod default_trait_access;
pub mod derive;
Expand Down Expand Up @@ -338,6 +339,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
reg.register_late_lint_pass(box types::InvalidUpcastComparisons);
reg.register_late_lint_pass(box regex::Pass::default());
reg.register_late_lint_pass(box copies::CopyAndPaste);
reg.register_late_lint_pass(box copy_iterator::CopyIterator);
reg.register_late_lint_pass(box format::Pass);
reg.register_early_lint_pass(box formatting::Formatting);
reg.register_late_lint_pass(box swap::Swap);
Expand Down Expand Up @@ -431,6 +433,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
reg.register_lint_group("clippy_pedantic", vec![
attrs::INLINE_ALWAYS,
copies::MATCH_SAME_ARMS,
copy_iterator::COPY_ITERATOR,
default_trait_access::DEFAULT_TRAIT_ACCESS,
derive::EXPL_IMPL_CLONE_ON_COPY,
doc::DOC_MARKDOWN,
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/copy_iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#![warn(copy_iterator)]

#[derive(Copy, Clone)]
struct Countdown(u8);

impl Iterator for Countdown {
type Item = u8;

fn next(&mut self) -> Option<u8> {
self.0.checked_sub(1).map(|c| {
self.0 = c;
c
})
}
}

fn main() {
let my_iterator = Countdown(5);
let a: Vec<_> = my_iterator.take(1).collect();
assert_eq!(a.len(), 1);
let b: Vec<_> = my_iterator.collect();
assert_eq!(b.len(), 5);
}
17 changes: 17 additions & 0 deletions tests/ui/copy_iterator.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: you are implementing `Iterator` on a `Copy` type
--> $DIR/copy_iterator.rs:6:1
|
6 | / impl Iterator for Countdown {
7 | | type Item = u8;
8 | |
9 | | fn next(&mut self) -> Option<u8> {
... |
14 | | }
15 | | }
| |_^
|
= note: `-D copy-iterator` implied by `-D warnings`
= note: consider implementing `IntoIterator` instead

error: aborting due to previous error

0 comments on commit 72344f4

Please sign in to comment.