1use clippy_utils::def_path_def_ids;
2use rustc_errors::{Applicability, Diag};
3use rustc_hir::def_id::DefIdMap;
4use rustc_middle::ty::TyCtxt;
5use rustc_span::Span;
6use serde::de::{self, Deserializer, Visitor};
7use serde::{Deserialize, Serialize, ser};
8use std::collections::HashMap;
9use std::fmt;
10
11#[derive(Debug, Deserialize)]
12pub struct Rename {
13 pub path: String,
14 pub rename: String,
15}
16
17pub type DisallowedPathWithoutReplacement = DisallowedPath<false>;
18
19#[derive(Debug, Serialize)]
20pub struct DisallowedPath<const REPLACEMENT_ALLOWED: bool = true> {
21 path: String,
22 reason: Option<String>,
23 replacement: Option<String>,
24}
25
26impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<REPLACEMENT_ALLOWED> {
27 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28 where
29 D: Deserializer<'de>,
30 {
31 let enum_ = DisallowedPathEnum::deserialize(deserializer)?;
32 if !REPLACEMENT_ALLOWED && enum_.replacement().is_some() {
33 return Err(de::Error::custom("replacement not allowed for this configuration"));
34 }
35 Ok(Self {
36 path: enum_.path().to_owned(),
37 reason: enum_.reason().map(ToOwned::to_owned),
38 replacement: enum_.replacement().map(ToOwned::to_owned),
39 })
40 }
41}
42
43#[derive(Debug, Deserialize, Serialize)]
46#[serde(untagged)]
47enum DisallowedPathEnum {
48 Simple(String),
49 WithReason {
50 path: String,
51 reason: Option<String>,
52 replacement: Option<String>,
53 },
54}
55
56impl<const REPLACEMENT_ALLOWED: bool> DisallowedPath<REPLACEMENT_ALLOWED> {
57 pub fn path(&self) -> &str {
58 &self.path
59 }
60
61 pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> {
62 move |diag| {
63 if let Some(replacement) = &self.replacement {
64 diag.span_suggestion(
65 span,
66 self.reason.as_ref().map_or_else(|| String::from("use"), Clone::clone),
67 replacement,
68 Applicability::MachineApplicable,
69 );
70 } else if let Some(reason) = &self.reason {
71 diag.note(reason.clone());
72 }
73 }
74 }
75}
76
77impl DisallowedPathEnum {
78 pub fn path(&self) -> &str {
79 let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
80
81 path
82 }
83
84 fn reason(&self) -> Option<&str> {
85 match &self {
86 Self::WithReason { reason, .. } => reason.as_deref(),
87 Self::Simple(_) => None,
88 }
89 }
90
91 fn replacement(&self) -> Option<&str> {
92 match &self {
93 Self::WithReason { replacement, .. } => replacement.as_deref(),
94 Self::Simple(_) => None,
95 }
96 }
97}
98
99pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
101 tcx: TyCtxt<'_>,
102 disallowed: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
103) -> DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> {
104 disallowed
105 .iter()
106 .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x))
107 .flat_map(|(name, path, disallowed_path)| {
108 def_path_def_ids(tcx, &path).map(move |id| (id, (name, disallowed_path)))
109 })
110 .collect()
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
114pub enum MatchLintBehaviour {
115 AllTypes,
116 WellKnownTypes,
117 Never,
118}
119
120#[derive(Debug)]
121pub struct MacroMatcher {
122 pub name: String,
123 pub braces: (char, char),
124}
125
126impl<'de> Deserialize<'de> for MacroMatcher {
127 fn deserialize<D>(deser: D) -> Result<Self, D::Error>
128 where
129 D: Deserializer<'de>,
130 {
131 #[derive(Deserialize)]
132 #[serde(field_identifier, rename_all = "lowercase")]
133 enum Field {
134 Name,
135 Brace,
136 }
137 struct MacVisitor;
138 impl<'de> Visitor<'de> for MacVisitor {
139 type Value = MacroMatcher;
140
141 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
142 formatter.write_str("struct MacroMatcher")
143 }
144
145 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
146 where
147 V: de::MapAccess<'de>,
148 {
149 let mut name = None;
150 let mut brace: Option<char> = None;
151 while let Some(key) = map.next_key()? {
152 match key {
153 Field::Name => {
154 if name.is_some() {
155 return Err(de::Error::duplicate_field("name"));
156 }
157 name = Some(map.next_value()?);
158 },
159 Field::Brace => {
160 if brace.is_some() {
161 return Err(de::Error::duplicate_field("brace"));
162 }
163 brace = Some(map.next_value()?);
164 },
165 }
166 }
167 let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
168 let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?;
169 Ok(MacroMatcher {
170 name,
171 braces: [('(', ')'), ('{', '}'), ('[', ']')]
172 .into_iter()
173 .find(|b| b.0 == brace)
174 .map(|(o, c)| (o.to_owned(), c.to_owned()))
175 .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
176 })
177 }
178 }
179
180 const FIELDS: &[&str] = &["name", "brace"];
181 deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor)
182 }
183}
184
185#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
187#[serde(rename_all = "snake_case")]
188pub enum SourceItemOrderingCategory {
189 Enum,
190 Impl,
191 Module,
192 Struct,
193 Trait,
194}
195
196pub struct SourceItemOrdering(Vec<SourceItemOrderingCategory>);
201
202impl SourceItemOrdering {
203 pub fn contains(&self, category: &SourceItemOrderingCategory) -> bool {
204 self.0.contains(category)
205 }
206}
207
208impl<T> From<T> for SourceItemOrdering
209where
210 T: Into<Vec<SourceItemOrderingCategory>>,
211{
212 fn from(value: T) -> Self {
213 Self(value.into())
214 }
215}
216
217impl core::fmt::Debug for SourceItemOrdering {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 self.0.fmt(f)
220 }
221}
222
223impl<'de> Deserialize<'de> for SourceItemOrdering {
224 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
225 where
226 D: Deserializer<'de>,
227 {
228 let items = Vec::<SourceItemOrderingCategory>::deserialize(deserializer)?;
229 let mut items_set = std::collections::HashSet::new();
230
231 for item in &items {
232 if items_set.contains(item) {
233 return Err(de::Error::custom(format!(
234 "The category \"{item:?}\" was enabled more than once in the source ordering configuration."
235 )));
236 }
237 items_set.insert(item);
238 }
239
240 Ok(Self(items))
241 }
242}
243
244impl Serialize for SourceItemOrdering {
245 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
246 where
247 S: ser::Serializer,
248 {
249 self.0.serialize(serializer)
250 }
251}
252
253#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
255#[serde(rename_all = "snake_case")]
256pub enum SourceItemOrderingModuleItemKind {
257 ExternCrate,
258 Mod,
259 ForeignMod,
260 Use,
261 Macro,
262 GlobalAsm,
263 Static,
264 Const,
265 TyAlias,
266 Enum,
267 Struct,
268 Union,
269 Trait,
270 TraitAlias,
271 Impl,
272 Fn,
273}
274
275impl SourceItemOrderingModuleItemKind {
276 pub fn all_variants() -> Vec<Self> {
277 #[allow(clippy::enum_glob_use)] use SourceItemOrderingModuleItemKind::*;
279 vec![
280 ExternCrate,
281 Mod,
282 ForeignMod,
283 Use,
284 Macro,
285 GlobalAsm,
286 Static,
287 Const,
288 TyAlias,
289 Enum,
290 Struct,
291 Union,
292 Trait,
293 TraitAlias,
294 Impl,
295 Fn,
296 ]
297 }
298}
299
300#[derive(Clone)]
305pub struct SourceItemOrderingModuleItemGroupings {
306 groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)>,
307 lut: HashMap<SourceItemOrderingModuleItemKind, usize>,
308 back_lut: HashMap<SourceItemOrderingModuleItemKind, String>,
309}
310
311impl SourceItemOrderingModuleItemGroupings {
312 fn build_lut(
313 groups: &[(String, Vec<SourceItemOrderingModuleItemKind>)],
314 ) -> HashMap<SourceItemOrderingModuleItemKind, usize> {
315 let mut lut = HashMap::new();
316 for (group_index, (_, items)) in groups.iter().enumerate() {
317 for item in items {
318 lut.insert(item.clone(), group_index);
319 }
320 }
321 lut
322 }
323
324 fn build_back_lut(
325 groups: &[(String, Vec<SourceItemOrderingModuleItemKind>)],
326 ) -> HashMap<SourceItemOrderingModuleItemKind, String> {
327 let mut lut = HashMap::new();
328 for (group_name, items) in groups {
329 for item in items {
330 lut.insert(item.clone(), group_name.clone());
331 }
332 }
333 lut
334 }
335
336 pub fn grouping_name_of(&self, item: &SourceItemOrderingModuleItemKind) -> Option<&String> {
337 self.back_lut.get(item)
338 }
339
340 pub fn grouping_names(&self) -> Vec<String> {
341 self.groups.iter().map(|(name, _)| name.clone()).collect()
342 }
343
344 pub fn is_grouping(&self, grouping: &str) -> bool {
345 self.groups.iter().any(|(g, _)| g == grouping)
346 }
347
348 pub fn module_level_order_of(&self, item: &SourceItemOrderingModuleItemKind) -> Option<usize> {
349 self.lut.get(item).copied()
350 }
351}
352
353impl From<&[(&str, &[SourceItemOrderingModuleItemKind])]> for SourceItemOrderingModuleItemGroupings {
354 fn from(value: &[(&str, &[SourceItemOrderingModuleItemKind])]) -> Self {
355 let groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)> =
356 value.iter().map(|item| (item.0.to_string(), item.1.to_vec())).collect();
357 let lut = Self::build_lut(&groups);
358 let back_lut = Self::build_back_lut(&groups);
359 Self { groups, lut, back_lut }
360 }
361}
362
363impl core::fmt::Debug for SourceItemOrderingModuleItemGroupings {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 self.groups.fmt(f)
366 }
367}
368
369impl<'de> Deserialize<'de> for SourceItemOrderingModuleItemGroupings {
370 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
371 where
372 D: Deserializer<'de>,
373 {
374 let groups = Vec::<(String, Vec<SourceItemOrderingModuleItemKind>)>::deserialize(deserializer)?;
375 let items_total: usize = groups.iter().map(|(_, v)| v.len()).sum();
376 let lut = Self::build_lut(&groups);
377 let back_lut = Self::build_back_lut(&groups);
378
379 let mut expected_items = SourceItemOrderingModuleItemKind::all_variants();
380 for item in lut.keys() {
381 expected_items.retain(|i| i != item);
382 }
383
384 let all_items = SourceItemOrderingModuleItemKind::all_variants();
385 if expected_items.is_empty() && items_total == all_items.len() {
386 let Some(use_group_index) = lut.get(&SourceItemOrderingModuleItemKind::Use) else {
387 return Err(de::Error::custom("Error in internal LUT."));
388 };
389 let Some((_, use_group_items)) = groups.get(*use_group_index) else {
390 return Err(de::Error::custom("Error in internal LUT."));
391 };
392 if use_group_items.len() > 1 {
393 return Err(de::Error::custom(
394 "The group containing the \"use\" item kind may not contain any other item kinds. \
395 The \"use\" items will (generally) be sorted by rustfmt already. \
396 Therefore it makes no sense to implement linting rules that may conflict with rustfmt.",
397 ));
398 }
399
400 Ok(Self { groups, lut, back_lut })
401 } else if items_total != all_items.len() {
402 Err(de::Error::custom(format!(
403 "Some module item kinds were configured more than once, or were missing, in the source ordering configuration. \
404 The module item kinds are: {all_items:?}"
405 )))
406 } else {
407 Err(de::Error::custom(format!(
408 "Not all module item kinds were part of the configured source ordering rule. \
409 All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
410 The module item kinds are: {all_items:?}"
411 )))
412 }
413 }
414}
415
416impl Serialize for SourceItemOrderingModuleItemGroupings {
417 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
418 where
419 S: ser::Serializer,
420 {
421 self.groups.serialize(serializer)
422 }
423}
424
425#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
427#[serde(rename_all = "snake_case")]
428pub enum SourceItemOrderingTraitAssocItemKind {
429 Const,
430 Fn,
431 Type,
432}
433
434impl SourceItemOrderingTraitAssocItemKind {
435 pub fn all_variants() -> Vec<Self> {
436 #[allow(clippy::enum_glob_use)] use SourceItemOrderingTraitAssocItemKind::*;
438 vec![Const, Fn, Type]
439 }
440}
441
442#[derive(Clone)]
450pub struct SourceItemOrderingTraitAssocItemKinds(Vec<SourceItemOrderingTraitAssocItemKind>);
451
452impl SourceItemOrderingTraitAssocItemKinds {
453 pub fn index_of(&self, item: &SourceItemOrderingTraitAssocItemKind) -> Option<usize> {
454 self.0.iter().position(|i| i == item)
455 }
456}
457
458impl<T> From<T> for SourceItemOrderingTraitAssocItemKinds
459where
460 T: Into<Vec<SourceItemOrderingTraitAssocItemKind>>,
461{
462 fn from(value: T) -> Self {
463 Self(value.into())
464 }
465}
466
467impl core::fmt::Debug for SourceItemOrderingTraitAssocItemKinds {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 self.0.fmt(f)
470 }
471}
472
473impl<'de> Deserialize<'de> for SourceItemOrderingTraitAssocItemKinds {
474 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
475 where
476 D: Deserializer<'de>,
477 {
478 let items = Vec::<SourceItemOrderingTraitAssocItemKind>::deserialize(deserializer)?;
479
480 let mut expected_items = SourceItemOrderingTraitAssocItemKind::all_variants();
481 for item in &items {
482 expected_items.retain(|i| i != item);
483 }
484
485 let all_items = SourceItemOrderingTraitAssocItemKind::all_variants();
486 if expected_items.is_empty() && items.len() == all_items.len() {
487 Ok(Self(items))
488 } else if items.len() != all_items.len() {
489 Err(de::Error::custom(format!(
490 "Some trait associated item kinds were configured more than once, or were missing, in the source ordering configuration. \
491 The trait associated item kinds are: {all_items:?}",
492 )))
493 } else {
494 Err(de::Error::custom(format!(
495 "Not all trait associated item kinds were part of the configured source ordering rule. \
496 All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
497 The trait associated item kinds are: {all_items:?}"
498 )))
499 }
500 }
501}
502
503impl Serialize for SourceItemOrderingTraitAssocItemKinds {
504 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
505 where
506 S: ser::Serializer,
507 {
508 self.0.serialize(serializer)
509 }
510}
511
512#[derive(Clone, Debug)]
520pub enum SourceItemOrderingWithinModuleItemGroupings {
521 All,
523
524 None,
526
527 Custom(Vec<String>),
529}
530
531impl SourceItemOrderingWithinModuleItemGroupings {
532 pub fn ordered_within(&self, grouping_name: &String) -> bool {
533 match self {
534 SourceItemOrderingWithinModuleItemGroupings::All => true,
535 SourceItemOrderingWithinModuleItemGroupings::None => false,
536 SourceItemOrderingWithinModuleItemGroupings::Custom(groups) => groups.contains(grouping_name),
537 }
538 }
539}
540
541#[derive(Deserialize)]
543#[serde(untagged)]
544enum StringOrVecOfString {
545 String(String),
546 Vec(Vec<String>),
547}
548
549impl<'de> Deserialize<'de> for SourceItemOrderingWithinModuleItemGroupings {
550 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
551 where
552 D: Deserializer<'de>,
553 {
554 let description = "The available options for configuring an ordering within module item groups are: \
555 \"all\", \"none\", or a list of module item group names \
556 (as configured with the `module-item-order-groupings` configuration option).";
557
558 match StringOrVecOfString::deserialize(deserializer) {
559 Ok(StringOrVecOfString::String(preset)) if preset == "all" => {
560 Ok(SourceItemOrderingWithinModuleItemGroupings::All)
561 },
562 Ok(StringOrVecOfString::String(preset)) if preset == "none" => {
563 Ok(SourceItemOrderingWithinModuleItemGroupings::None)
564 },
565 Ok(StringOrVecOfString::String(preset)) => Err(de::Error::custom(format!(
566 "Unknown configuration option: {preset}.\n{description}"
567 ))),
568 Ok(StringOrVecOfString::Vec(groupings)) => {
569 Ok(SourceItemOrderingWithinModuleItemGroupings::Custom(groupings))
570 },
571 Err(e) => Err(de::Error::custom(format!("{e}\n{description}"))),
572 }
573 }
574}
575
576impl Serialize for SourceItemOrderingWithinModuleItemGroupings {
577 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
578 where
579 S: ser::Serializer,
580 {
581 match self {
582 SourceItemOrderingWithinModuleItemGroupings::All => serializer.serialize_str("all"),
583 SourceItemOrderingWithinModuleItemGroupings::None => serializer.serialize_str("none"),
584 SourceItemOrderingWithinModuleItemGroupings::Custom(vec) => vec.serialize(serializer),
585 }
586 }
587}
588
589macro_rules! unimplemented_serialize {
592 ($($t:ty,)*) => {
593 $(
594 impl Serialize for $t {
595 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
596 where
597 S: ser::Serializer,
598 {
599 Err(ser::Error::custom("unimplemented"))
600 }
601 }
602 )*
603 }
604}
605
606unimplemented_serialize! {
607 Rename,
608 MacroMatcher,
609}
610
611#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
612pub enum PubUnderscoreFieldsBehaviour {
613 PubliclyExported,
614 AllPubFields,
615}