1use cargo_util_schemas::manifest::RustVersion;
57use cargo_util_schemas::manifest::TomlToolLints;
58
59use crate::CargoResult;
60use crate::core::Workspace;
61use crate::core::{Edition, Features, MaybePackage, Package};
62use crate::util::GlobalContext;
63
64mod lint;
65mod report;
66
67pub mod passes;
68pub mod rules;
69
70pub use lint::{Lint, LintGroup, LintLevel, LintLevelProduct, LintLevelSource};
71pub use report::{AsIndex, cwd_rel_path, get_key_value, get_key_value_span, workspace_rel_path};
72pub use rules::{LINT_GROUPS, LINTS};
73
74pub struct GlobalDiagnosticStats {
75 error_count: usize,
76}
77
78impl GlobalDiagnosticStats {
79 pub fn new() -> Self {
80 Self { error_count: 0 }
81 }
82
83 pub fn scope(&mut self) -> ScopedDiagnosticStats<'_> {
84 ScopedDiagnosticStats {
85 warning_count: 0,
86 lint_warning_count: 0,
87 error_count: 0,
88 global: self,
89 }
90 }
91
92 pub fn error_count(&self) -> usize {
93 self.error_count
94 }
95
96 pub fn ok(&self) -> CargoResult<()> {
97 if 0 < self.error_count {
98 Err(crate::Error::new(crate::AlreadyPrintedError::new(
99 anyhow::format_err!("see above"),
100 )))
101 } else {
102 Ok(())
103 }
104 }
105}
106
107pub struct ScopedDiagnosticStats<'g> {
108 warning_count: usize,
109 lint_warning_count: usize,
110 error_count: usize,
111 global: &'g mut GlobalDiagnosticStats,
112}
113
114impl ScopedDiagnosticStats<'_> {
115 pub fn lint_warning_count(&self) -> usize {
116 self.lint_warning_count
117 }
118
119 pub fn warning_count(&self) -> usize {
120 self.warning_count
121 }
122
123 pub fn error_count(&self) -> usize {
124 self.error_count
125 }
126
127 pub fn record_warning(&mut self) {
128 self.warning_count += 1;
129 }
130
131 pub fn record_error(&mut self) {
132 self.error_count += 1;
133 self.global.error_count += 1;
134 }
135
136 pub fn record_lint(&mut self, lint: LintLevel) {
137 match lint {
138 LintLevel::Forbid | LintLevel::Deny => {
139 self.record_error();
140 }
141 LintLevel::Warn => {
142 self.lint_warning_count += 1;
143 self.record_warning();
144 }
145 LintLevel::Allow => {}
146 }
147 }
148
149 pub fn report_summary(
153 &self,
154 action: &str,
155 name: Option<&str>,
156 gctx: &GlobalContext,
157 ) -> CargoResult<()> {
158 if 0 < self.warning_count {
159 let plural = if self.warning_count == 1 { "" } else { "s" };
160 let name = name
161 .map(|n| format!("`{n}`"))
162 .unwrap_or_else(|| "workspace".to_owned());
163 gctx.shell().warn(format!(
164 "{name} (manifest) generated {} warning{plural}",
165 self.warning_count
166 ))?;
167 }
168
169 if 0 < self.error_count {
170 let plural = if self.error_count == 1 { "" } else { "s" };
171 let name = name
172 .map(|n| format!("`{n}`"))
173 .unwrap_or_else(|| "workspace".to_owned());
174 gctx.shell().error(format!(
175 "could not {action} {name} (manifest) due to {} previous error{plural}",
176 self.error_count
177 ))?;
178 }
179
180 Ok(())
181 }
182}
183
184pub enum ManifestFor<'a> {
186 Package(&'a Package),
188 Workspace {
190 ws: &'a Workspace<'a>,
191 maybe_pkg: &'a MaybePackage,
192 },
193}
194
195impl ManifestFor<'_> {
196 fn lint_level(&self, pkg_lints: &TomlToolLints, lint: &Lint) -> LintLevelProduct {
197 lint.level(pkg_lints, self.rust_version(), self.unstable_features())
198 }
199
200 pub fn rust_version(&self) -> Option<&RustVersion> {
201 match self {
202 ManifestFor::Package(p) => p.rust_version(),
203 ManifestFor::Workspace { ws, maybe_pkg: _ } => ws.lowest_rust_version(),
204 }
205 }
206
207 pub fn contents(&self) -> Option<&str> {
208 match self {
209 ManifestFor::Package(p) => p.manifest().contents(),
210 ManifestFor::Workspace { ws: _, maybe_pkg } => maybe_pkg.contents(),
211 }
212 }
213
214 pub fn document(&self) -> Option<&toml::Spanned<toml::de::DeTable<'static>>> {
215 match self {
216 ManifestFor::Package(p) => p.manifest().document(),
217 ManifestFor::Workspace { ws: _, maybe_pkg } => maybe_pkg.document(),
218 }
219 }
220
221 pub fn edition(&self) -> Edition {
222 match self {
223 ManifestFor::Package(p) => p.manifest().edition(),
224 ManifestFor::Workspace { ws: _, maybe_pkg } => maybe_pkg.edition(),
225 }
226 }
227
228 pub fn unstable_features(&self) -> &Features {
229 match self {
230 ManifestFor::Package(p) => p.manifest().unstable_features(),
231 ManifestFor::Workspace { ws: _, maybe_pkg } => maybe_pkg.unstable_features(),
232 }
233 }
234}
235
236impl<'a> From<&'a Package> for ManifestFor<'a> {
237 fn from(value: &'a Package) -> ManifestFor<'a> {
238 ManifestFor::Package(value)
239 }
240}
241
242impl<'a> From<(&'a Workspace<'a>, &'a MaybePackage)> for ManifestFor<'a> {
243 fn from((ws, maybe_pkg): (&'a Workspace<'a>, &'a MaybePackage)) -> ManifestFor<'a> {
244 ManifestFor::Workspace { ws, maybe_pkg }
245 }
246}