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(
38 short = 'r',
39 long,
40 conflicts_with = "profile",
41 help_heading = heading::COMPILATION_OPTIONS,
42 )]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub release: bool,
45
46 #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
48 #[cfg_attr(feature = "serde", serde(default))]
49 pub ignore_rust_version: bool,
50
51 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
53 #[cfg_attr(feature = "serde", serde(default))]
54 pub unit_graph: bool,
55
56 #[arg(long)]
58 #[cfg_attr(feature = "serde", serde(default))]
59 pub no_deps: bool,
60
61 #[arg(long)]
63 #[cfg_attr(feature = "serde", serde(default))]
64 pub fix: bool,
65
66 #[arg(long, hide = true)]
68 #[cfg_attr(feature = "serde", serde(default))]
69 pub allow_dirty: bool,
70
71 #[arg(long, hide = true)]
73 #[cfg_attr(feature = "serde", serde(default))]
74 pub allow_staged: bool,
75
76 #[arg(value_name = "ARGS", trailing_var_arg = true, num_args = 0..)]
78 #[cfg_attr(feature = "serde", serde(default))]
79 pub args: Vec<String>,
80}
81
82impl Clippy {
83 pub fn command(&self) -> Command {
85 let mut cmd = CommonOptions::cargo_command();
86 cmd.arg("clippy");
87
88 self.common.apply(&mut cmd);
89 self.check.apply(&mut cmd);
90
91 if let Some(path) = self.manifest_path.as_ref() {
92 cmd.arg("--manifest-path").arg(path);
93 }
94 if self.release {
95 cmd.arg("--release");
96 }
97 if self.ignore_rust_version {
98 cmd.arg("--ignore-rust-version");
99 }
100 if self.unit_graph {
101 cmd.arg("--unit-graph");
102 }
103 if self.no_deps {
104 cmd.arg("--no-deps");
105 }
106 if self.fix {
107 cmd.arg("--fix");
108 }
109 if self.allow_dirty {
110 cmd.arg("--allow-dirty");
111 }
112 if self.allow_staged {
113 cmd.arg("--allow-staged");
114 }
115 if !self.args.is_empty() {
116 cmd.arg("--");
117 cmd.args(&self.args);
118 }
119
120 cmd
121 }
122}
123
124impl Deref for Clippy {
125 type Target = CommonOptions;
126
127 fn deref(&self) -> &Self::Target {
128 &self.common
129 }
130}
131
132impl DerefMut for Clippy {
133 fn deref_mut(&mut self) -> &mut Self::Target {
134 &mut self.common
135 }
136}
137
138#[cfg(test)]
139mod test {
140 use super::Clippy;
141 use clap::CommandFactory;
142
143 #[test]
144 fn verify_cli() {
145 <Clippy as CommandFactory>::command().debug_assert()
146 }
147}