]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/cargo/mod.rs
Merge commit 'e329249b6a3a98830d860c74c8234a8dd9407436' into clippyup
[rust.git] / src / tools / clippy / clippy_lints / src / cargo / mod.rs
1 use cargo_metadata::MetadataCommand;
2 use clippy_utils::diagnostics::span_lint;
3 use clippy_utils::is_lint_allowed;
4 use rustc_hir::hir_id::CRATE_HIR_ID;
5 use rustc_lint::{LateContext, LateLintPass, Lint};
6 use rustc_session::{declare_tool_lint, impl_lint_pass};
7 use rustc_span::DUMMY_SP;
8
9 mod common_metadata;
10 mod feature_name;
11 mod multiple_crate_versions;
12 mod wildcard_dependencies;
13
14 declare_clippy_lint! {
15     /// ### What it does
16     /// Checks to see if all common metadata is defined in
17     /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
18     ///
19     /// ### Why is this bad?
20     /// It will be more difficult for users to discover the
21     /// purpose of the crate, and key information related to it.
22     ///
23     /// ### Example
24     /// ```toml
25     /// # This `Cargo.toml` is missing a description field:
26     /// [package]
27     /// name = "clippy"
28     /// version = "0.0.212"
29     /// repository = "https://github.com/rust-lang/rust-clippy"
30     /// readme = "README.md"
31     /// license = "MIT OR Apache-2.0"
32     /// keywords = ["clippy", "lint", "plugin"]
33     /// categories = ["development-tools", "development-tools::cargo-plugins"]
34     /// ```
35     ///
36     /// Should include a description field like:
37     ///
38     /// ```toml
39     /// # This `Cargo.toml` includes all common metadata
40     /// [package]
41     /// name = "clippy"
42     /// version = "0.0.212"
43     /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
44     /// repository = "https://github.com/rust-lang/rust-clippy"
45     /// readme = "README.md"
46     /// license = "MIT OR Apache-2.0"
47     /// keywords = ["clippy", "lint", "plugin"]
48     /// categories = ["development-tools", "development-tools::cargo-plugins"]
49     /// ```
50     #[clippy::version = "1.32.0"]
51     pub CARGO_COMMON_METADATA,
52     cargo,
53     "common metadata is defined in `Cargo.toml`"
54 }
55
56 declare_clippy_lint! {
57     /// ### What it does
58     /// Checks for feature names with prefix `use-`, `with-` or suffix `-support`
59     ///
60     /// ### Why is this bad?
61     /// These prefixes and suffixes have no significant meaning.
62     ///
63     /// ### Example
64     /// ```toml
65     /// # The `Cargo.toml` with feature name redundancy
66     /// [features]
67     /// default = ["use-abc", "with-def", "ghi-support"]
68     /// use-abc = []  // redundant
69     /// with-def = []   // redundant
70     /// ghi-support = []   // redundant
71     /// ```
72     ///
73     /// Use instead:
74     /// ```toml
75     /// [features]
76     /// default = ["abc", "def", "ghi"]
77     /// abc = []
78     /// def = []
79     /// ghi = []
80     /// ```
81     ///
82     #[clippy::version = "1.57.0"]
83     pub REDUNDANT_FEATURE_NAMES,
84     cargo,
85     "usage of a redundant feature name"
86 }
87
88 declare_clippy_lint! {
89     /// ### What it does
90     /// Checks for negative feature names with prefix `no-` or `not-`
91     ///
92     /// ### Why is this bad?
93     /// Features are supposed to be additive, and negatively-named features violate it.
94     ///
95     /// ### Example
96     /// ```toml
97     /// # The `Cargo.toml` with negative feature names
98     /// [features]
99     /// default = []
100     /// no-abc = []
101     /// not-def = []
102     ///
103     /// ```
104     /// Use instead:
105     /// ```toml
106     /// [features]
107     /// default = ["abc", "def"]
108     /// abc = []
109     /// def = []
110     ///
111     /// ```
112     #[clippy::version = "1.57.0"]
113     pub NEGATIVE_FEATURE_NAMES,
114     cargo,
115     "usage of a negative feature name"
116 }
117
118 declare_clippy_lint! {
119     /// ### What it does
120     /// Checks to see if multiple versions of a crate are being
121     /// used.
122     ///
123     /// ### Why is this bad?
124     /// This bloats the size of targets, and can lead to
125     /// confusing error messages when structs or traits are used interchangeably
126     /// between different versions of a crate.
127     ///
128     /// ### Known problems
129     /// Because this can be caused purely by the dependencies
130     /// themselves, it's not always possible to fix this issue.
131     ///
132     /// ### Example
133     /// ```toml
134     /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning.
135     /// [dependencies]
136     /// ctrlc = "=3.1.0"
137     /// ansi_term = "=0.11.0"
138     /// ```
139     #[clippy::version = "pre 1.29.0"]
140     pub MULTIPLE_CRATE_VERSIONS,
141     cargo,
142     "multiple versions of the same crate being used"
143 }
144
145 declare_clippy_lint! {
146     /// ### What it does
147     /// Checks for wildcard dependencies in the `Cargo.toml`.
148     ///
149     /// ### Why is this bad?
150     /// [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html),
151     /// it is highly unlikely that you work with any possible version of your dependency,
152     /// and wildcard dependencies would cause unnecessary breakage in the ecosystem.
153     ///
154     /// ### Example
155     /// ```toml
156     /// [dependencies]
157     /// regex = "*"
158     /// ```
159     #[clippy::version = "1.32.0"]
160     pub WILDCARD_DEPENDENCIES,
161     cargo,
162     "wildcard dependencies being used"
163 }
164
165 pub struct Cargo {
166     pub ignore_publish: bool,
167 }
168
169 impl_lint_pass!(Cargo => [
170     CARGO_COMMON_METADATA,
171     REDUNDANT_FEATURE_NAMES,
172     NEGATIVE_FEATURE_NAMES,
173     MULTIPLE_CRATE_VERSIONS,
174     WILDCARD_DEPENDENCIES
175 ]);
176
177 impl LateLintPass<'_> for Cargo {
178     fn check_crate(&mut self, cx: &LateContext<'_>) {
179         static NO_DEPS_LINTS: &[&Lint] = &[
180             CARGO_COMMON_METADATA,
181             REDUNDANT_FEATURE_NAMES,
182             NEGATIVE_FEATURE_NAMES,
183             WILDCARD_DEPENDENCIES,
184         ];
185         static WITH_DEPS_LINTS: &[&Lint] = &[MULTIPLE_CRATE_VERSIONS];
186
187         if !NO_DEPS_LINTS
188             .iter()
189             .all(|&lint| is_lint_allowed(cx, lint, CRATE_HIR_ID))
190         {
191             match MetadataCommand::new().no_deps().exec() {
192                 Ok(metadata) => {
193                     common_metadata::check(cx, &metadata, self.ignore_publish);
194                     feature_name::check(cx, &metadata);
195                     wildcard_dependencies::check(cx, &metadata);
196                 },
197                 Err(e) => {
198                     for lint in NO_DEPS_LINTS {
199                         span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e));
200                     }
201                 },
202             }
203         }
204
205         if !WITH_DEPS_LINTS
206             .iter()
207             .all(|&lint| is_lint_allowed(cx, lint, CRATE_HIR_ID))
208         {
209             match MetadataCommand::new().exec() {
210                 Ok(metadata) => {
211                     multiple_crate_versions::check(cx, &metadata);
212                 },
213                 Err(e) => {
214                     for lint in WITH_DEPS_LINTS {
215                         span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e));
216                     }
217                 },
218             }
219         }
220     }
221 }