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_tool_lint, lint_array};
6 use syntax::{ast::*, source_map::DUMMY_SP};
10 /// **What it does:** Checks to see if all common metadata is defined in
11 /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
13 /// **Why is this bad?** It will be more difficult for users to discover the
14 /// purpose of the crate, and key information related to it.
16 /// **Known problems:** None.
20 /// # This `Cargo.toml` is missing an authors field:
23 /// version = "0.0.212"
24 /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
25 /// repository = "https://github.com/rust-lang/rust-clippy"
26 /// readme = "README.md"
27 /// license = "MIT/Apache-2.0"
28 /// keywords = ["clippy", "lint", "plugin"]
29 /// categories = ["development-tools", "development-tools::cargo-plugins"]
31 declare_clippy_lint! {
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)
61 impl LintPass for Pass {
62 fn get_lints(&self) -> LintArray {
63 lint_array!(CARGO_COMMON_METADATA)
66 fn name(&self) -> &'static str {
71 impl EarlyLintPass for Pass {
72 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
73 let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
76 warning(cx, "could not read cargo metadata");
80 for package in metadata.packages {
81 if is_empty_vec(&package.authors) {
82 missing_warning(cx, &package, "package.authors");
85 if is_empty_str(&package.description) {
86 missing_warning(cx, &package, "package.description");
89 if is_empty_str(&package.license) {
90 missing_warning(cx, &package, "package.license");
93 if is_empty_str(&package.repository) {
94 missing_warning(cx, &package, "package.repository");
97 if is_empty_str(&package.readme) {
98 missing_warning(cx, &package, "package.readme");
101 if is_empty_vec(&package.keywords) {
102 missing_warning(cx, &package, "package.keywords");
105 if is_empty_vec(&package.categories) {
106 missing_warning(cx, &package, "package.categories");