1use std::ops::{Deref, DerefMut};
2use std::path::PathBuf;
3use std::process::Command;
4
5use clap::Parser;
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::check::CheckOptions;
11use crate::common::CommonOptions;
12use crate::heading;
13
14#[derive(Clone, Debug, Default, Parser)]
16#[command(
17 display_order = 1,
18 after_help = "Run `cargo help clippy` for more detailed information."
19)]
20#[group(skip)]
21#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
22pub struct Clippy {
23 #[command(flatten)]
24 #[cfg_attr(feature = "serde", serde(flatten))]
25 pub common: CommonOptions,
26
27 #[command(flatten)]
28 #[cfg_attr(feature = "serde", serde(flatten))]
29 pub check: CheckOptions,
30
31 #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
33 #[cfg_attr(feature = "serde", serde(default))]
34 pub manifest_path: Option<PathBuf>,
35
36 #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)]
38 #[cfg_attr(feature = "serde", serde(default))]
39 pub release: bool,
40
41 #[arg(long)]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub ignore_rust_version: bool,
45
46 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
48 #[cfg_attr(feature = "serde", serde(default))]
49 pub unit_graph: bool,
50
51 #[arg(long)]
53 #[cfg_attr(feature = "serde", serde(default))]
54 pub no_deps: bool,
55
56 #[arg(long)]
58 #[cfg_attr(feature = "serde", serde(default))]
59 pub fix: bool,
60
61 #[arg(long, hide = true)]
63 #[cfg_attr(feature = "serde", serde(default))]
64 pub allow_dirty: bool,
65
66 #[arg(long, hide = true)]
68 #[cfg_attr(feature = "serde", serde(default))]
69 pub allow_staged: bool,
70
71 #[arg(value_name = "args", trailing_var_arg = true, num_args = 0..)]
73 #[cfg_attr(feature = "serde", serde(default))]
74 pub args: Vec<String>,
75}
76
77impl Clippy {
78 pub fn command(&self) -> Command {
80 let mut cmd = CommonOptions::cargo_command();
81 cmd.arg("clippy");
82
83 self.common.apply(&mut cmd);
84 self.check.apply(&mut cmd);
85
86 if let Some(path) = self.manifest_path.as_ref() {
87 cmd.arg("--manifest-path").arg(path);
88 }
89 if self.release {
90 cmd.arg("--release");
91 }
92 if self.ignore_rust_version {
93 cmd.arg("--ignore-rust-version");
94 }
95 if self.unit_graph {
96 cmd.arg("--unit-graph");
97 }
98 if self.no_deps {
99 cmd.arg("--no-deps");
100 }
101 if self.fix {
102 cmd.arg("--fix");
103 }
104 if self.allow_dirty {
105 cmd.arg("--allow-dirty");
106 }
107 if self.allow_staged {
108 cmd.arg("--allow-staged");
109 }
110 if !self.args.is_empty() {
111 cmd.arg("--");
112 cmd.args(&self.args);
113 }
114
115 cmd
116 }
117}
118
119impl Deref for Clippy {
120 type Target = CommonOptions;
121
122 fn deref(&self) -> &Self::Target {
123 &self.common
124 }
125}
126
127impl DerefMut for Clippy {
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 &mut self.common
130 }
131}
132
133#[cfg(test)]
134mod test {
135 use super::Clippy;
136 use clap::CommandFactory;
137
138 #[test]
139 fn verify_cli() {
140 <Clippy as CommandFactory>::command().debug_assert()
141 }
142}