1 //! lint on missing cargo common metadata
3 use crate::utils::span_lint;
4 use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
5 use rustc::{declare_lint_pass, declare_tool_lint};
6 use syntax::{ast::*, source_map::DUMMY_SP};
10 declare_clippy_lint! {
11 /// **What it does:** Checks to see if all common metadata is defined in
12 /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
14 /// **Why is this bad?** It will be more difficult for users to discover the
15 /// purpose of the crate, and key information related to it.
17 /// **Known problems:** None.
21 /// # This `Cargo.toml` is missing an authors field:
24 /// version = "0.0.212"
25 /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
26 /// repository = "https://github.com/rust-lang/rust-clippy"
27 /// readme = "README.md"
28 /// license = "MIT/Apache-2.0"
29 /// keywords = ["clippy", "lint", "plugin"]
30 /// categories = ["development-tools", "development-tools::cargo-plugins"]
32 pub CARGO_COMMON_METADATA,
34 "common metadata is defined in `Cargo.toml`"
37 fn warning(cx: &EarlyContext<'_>, message: &str) {
38 span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
41 fn missing_warning(cx: &EarlyContext<'_>, package: &cargo_metadata::Package, field: &str) {
42 let message = format!("package `{}` is missing `{}` metadata", package.name, field);
43 warning(cx, &message);
46 fn is_empty_str(value: &Option<String>) -> bool {
49 Some(value) if value.is_empty() => true,
54 fn is_empty_vec(value: &[String]) -> bool {
55 // This works because empty iterators return true
56 value.iter().all(std::string::String::is_empty)
59 declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]);
61 impl EarlyLintPass for CargoCommonMetadata {
62 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
63 let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
66 warning(cx, "could not read cargo metadata");
70 for package in metadata.packages {
71 if is_empty_vec(&package.authors) {
72 missing_warning(cx, &package, "package.authors");
75 if is_empty_str(&package.description) {
76 missing_warning(cx, &package, "package.description");
79 if is_empty_str(&package.license) {
80 missing_warning(cx, &package, "package.license");
83 if is_empty_str(&package.repository) {
84 missing_warning(cx, &package, "package.repository");
87 if is_empty_str(&package.readme) {
88 missing_warning(cx, &package, "package.readme");
91 if is_empty_vec(&package.keywords) {
92 missing_warning(cx, &package, "package.keywords");
95 if is_empty_vec(&package.categories) {
96 missing_warning(cx, &package, "package.categories");