Skip to content

Commit 7de706b

Browse files
committed
Lint for multiple versions of dependencies
1 parent 1742229 commit 7de706b

File tree

6 files changed

+86
-0
lines changed

6 files changed

+86
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ We have a bunch of lint categories to allow you to choose how much clippy is sup
1717
* `clippy_style` (code that should be written in a more idiomatic way)
1818
* `clippy_complexity` (code that does something simple but in a complex way)
1919
* `clippy_perf` (code that can be written in a faster way)
20+
* `clippy_cargo` (checks against the cargo manifest)
2021
* **`clippy_correctness`** (code that is just outright wrong or very very useless)
2122

2223
More to come, please [file an issue](https://github.com/rust-lang-nursery/rust-clippy/issues) if you have ideas!

clippy_lints/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ license = "MPL-2.0"
1616
keywords = ["clippy", "lint", "plugin"]
1717

1818
[dependencies]
19+
cargo_metadata = "0.5"
1920
itertools = "0.7"
2021
lazy_static = "1.0"
2122
matches = "0.1.2"

clippy_lints/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#![feature(iterator_find_map)]
1717

1818

19+
extern crate cargo_metadata;
1920
#[macro_use]
2021
extern crate rustc;
2122
extern crate rustc_typeck;
@@ -81,6 +82,9 @@ macro_rules! declare_clippy_lint {
8182
{ pub $name:tt, restriction, $description:tt } => {
8283
declare_lint! { pub $name, Allow, $description }
8384
};
85+
{ pub $name:tt, cargo, $description:tt } => {
86+
declare_lint! { pub $name, Allow, $description }
87+
};
8488
{ pub $name:tt, nursery, $description:tt } => {
8589
declare_lint! { pub $name, Allow, $description }
8690
};
@@ -158,6 +162,7 @@ pub mod minmax;
158162
pub mod misc;
159163
pub mod misc_early;
160164
pub mod missing_doc;
165+
pub mod multiple_crate_versions;
161166
pub mod mut_mut;
162167
pub mod mut_reference;
163168
pub mod mutex_atomic;
@@ -412,6 +417,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
412417
reg.register_late_lint_pass(box question_mark::QuestionMarkPass);
413418
reg.register_late_lint_pass(box suspicious_trait_impl::SuspiciousImpl);
414419
reg.register_late_lint_pass(box redundant_field_names::RedundantFieldNames);
420+
reg.register_early_lint_pass(box multiple_crate_versions::Pass);
415421
reg.register_late_lint_pass(box map_unit_fn::Pass);
416422
reg.register_late_lint_pass(box infallible_destructuring_match::Pass);
417423

@@ -895,6 +901,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
895901
vec::USELESS_VEC,
896902
]);
897903

904+
reg.register_lint_group("clippy_cargo", vec![
905+
multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
906+
]);
907+
898908
reg.register_lint_group("clippy_nursery", vec![
899909
attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
900910
fallible_impl_from::FALLIBLE_IMPL_FROM,
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//! lint on multiple versions of a crate being used
2+
3+
use rustc::lint::*;
4+
use syntax::ast::*;
5+
6+
use cargo_metadata;
7+
use itertools::Itertools;
8+
9+
/// **What it does:** Checks to see if multiple versions of a crate are being
10+
/// used.
11+
///
12+
/// **Why is this bad?** This bloats the size of targets, and can lead to
13+
/// confusing error messages when structs or traits are used interchangeably
14+
/// between different versions of a crate.
15+
///
16+
/// **Known problems:** Because this can be caused purely by the dependencies
17+
/// themselves, it's not always possible to fix this issue.
18+
///
19+
/// **Example:**
20+
/// ```toml
21+
/// # This will pull in both winapi v0.3.4 and v0.2.8, triggering a warning.
22+
/// [dependencies]
23+
/// ctrlc = "3.1.0"
24+
/// ansi_term = "0.11.0"
25+
/// ```
26+
declare_clippy_lint! {
27+
pub MULTIPLE_CRATE_VERSIONS,
28+
cargo,
29+
"multiple versions of the same crate being used"
30+
}
31+
32+
pub struct Pass;
33+
34+
impl LintPass for Pass {
35+
fn get_lints(&self) -> LintArray {
36+
lint_array!(MULTIPLE_CRATE_VERSIONS)
37+
}
38+
}
39+
40+
impl EarlyLintPass for Pass {
41+
fn check_crate(&mut self, cx: &EarlyContext, krate: &Crate) {
42+
let metadata = match cargo_metadata::metadata_deps(None, true) {
43+
Ok(metadata) => metadata,
44+
Err(_) => {
45+
cx.span_lint(
46+
MULTIPLE_CRATE_VERSIONS,
47+
krate.span,
48+
"could not read cargo metadata"
49+
);
50+
51+
return;
52+
}
53+
};
54+
55+
let mut packages = metadata.packages;
56+
packages.sort_by(|a, b| a.name.cmp(&b.name));
57+
58+
for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) {
59+
let group: Vec<cargo_metadata::Package> = group.collect();
60+
61+
if group.len() > 1 {
62+
let versions = group.into_iter().map(|p| p.version).join(", ");
63+
64+
cx.span_lint(
65+
MULTIPLE_CRATE_VERSIONS,
66+
krate.span,
67+
&format!("multiple versions for dependency `{}`: {}", name, versions),
68+
);
69+
}
70+
}
71+
}
72+
}

util/lintlib.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"restriction": 'Allow',
2525
"pedantic": 'Allow',
2626
"nursery": 'Allow',
27+
"cargo": 'Allow',
2728
}
2829

2930

util/update_lints.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ def main(print_only=False, check=False):
129129
"perf": [],
130130
"restriction": [],
131131
"pedantic": [],
132+
"cargo": [],
132133
"nursery": [],
133134
}
134135

0 commit comments

Comments
 (0)