1use clippy_utils::def_path_def_ids;
2use rustc_hir::def_id::DefIdMap;
3use rustc_middle::ty::TyCtxt;
4use serde::de::{self, Deserializer, Visitor};
5use serde::{Deserialize, Serialize, ser};
6use std::collections::HashMap;
7use std::fmt;
8
9#[derive(Debug, Deserialize)]
10pub struct Rename {
11 pub path: String,
12 pub rename: String,
13}
14
15#[derive(Debug, Deserialize)]
16#[serde(untagged)]
17pub enum DisallowedPath {
18 Simple(String),
19 WithReason { path: String, reason: Option<String> },
20}
21
22impl DisallowedPath {
23 pub fn path(&self) -> &str {
24 let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
25
26 path
27 }
28
29 pub fn reason(&self) -> Option<&str> {
30 match &self {
31 Self::WithReason { reason, .. } => reason.as_deref(),
32 Self::Simple(_) => None,
33 }
34 }
35}
36
37pub fn create_disallowed_map(
39 tcx: TyCtxt<'_>,
40 disallowed: &'static [DisallowedPath],
41) -> DefIdMap<(&'static str, Option<&'static str>)> {
42 disallowed
43 .iter()
44 .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x.reason()))
45 .flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason))))
46 .collect()
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
50pub enum MatchLintBehaviour {
51 AllTypes,
52 WellKnownTypes,
53 Never,
54}
55
56#[derive(Debug)]
57pub struct MacroMatcher {
58 pub name: String,
59 pub braces: (char, char),
60}
61
62impl<'de> Deserialize<'de> for MacroMatcher {
63 fn deserialize<D>(deser: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 #[derive(Deserialize)]
68 #[serde(field_identifier, rename_all = "lowercase")]
69 enum Field {
70 Name,
71 Brace,
72 }
73 struct MacVisitor;
74 impl<'de> Visitor<'de> for MacVisitor {
75 type Value = MacroMatcher;
76
77 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
78 formatter.write_str("struct MacroMatcher")
79 }
80
81 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
82 where
83 V: de::MapAccess<'de>,
84 {
85 let mut name = None;
86 let mut brace: Option<char> = None;
87 while let Some(key) = map.next_key()? {
88 match key {
89 Field::Name => {
90 if name.is_some() {
91 return Err(de::Error::duplicate_field("name"));
92 }
93 name = Some(map.next_value()?);
94 },
95 Field::Brace => {
96 if brace.is_some() {
97 return Err(de::Error::duplicate_field("brace"));
98 }
99 brace = Some(map.next_value()?);
100 },
101 }
102 }
103 let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
104 let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?;
105 Ok(MacroMatcher {
106 name,
107 braces: [('(', ')'), ('{', '}'), ('[', ']')]
108 .into_iter()
109 .find(|b| b.0 == brace)
110 .map(|(o, c)| (o.to_owned(), c.to_owned()))
111 .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
112 })
113 }
114 }
115
116 const FIELDS: &[&str] = &["name", "brace"];
117 deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor)
118 }
119}
120
121#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
123#[serde(rename_all = "snake_case")]
124pub enum SourceItemOrderingCategory {
125 Enum,
126 Impl,
127 Module,
128 Struct,
129 Trait,
130}
131
132pub struct SourceItemOrdering(Vec<SourceItemOrderingCategory>);
137
138impl SourceItemOrdering {
139 pub fn contains(&self, category: &SourceItemOrderingCategory) -> bool {
140 self.0.contains(category)
141 }
142}
143
144impl<T> From<T> for SourceItemOrdering
145where
146 T: Into<Vec<SourceItemOrderingCategory>>,
147{
148 fn from(value: T) -> Self {
149 Self(value.into())
150 }
151}
152
153impl core::fmt::Debug for SourceItemOrdering {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 self.0.fmt(f)
156 }
157}
158
159impl<'de> Deserialize<'de> for SourceItemOrdering {
160 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
161 where
162 D: Deserializer<'de>,
163 {
164 let items = Vec::<SourceItemOrderingCategory>::deserialize(deserializer)?;
165 let mut items_set = std::collections::HashSet::new();
166
167 for item in &items {
168 if items_set.contains(item) {
169 return Err(de::Error::custom(format!(
170 "The category \"{item:?}\" was enabled more than once in the source ordering configuration."
171 )));
172 }
173 items_set.insert(item);
174 }
175
176 Ok(Self(items))
177 }
178}
179
180impl Serialize for SourceItemOrdering {
181 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
182 where
183 S: ser::Serializer,
184 {
185 self.0.serialize(serializer)
186 }
187}
188
189#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
191#[serde(rename_all = "snake_case")]
192pub enum SourceItemOrderingModuleItemKind {
193 ExternCrate,
194 Mod,
195 ForeignMod,
196 Use,
197 Macro,
198 GlobalAsm,
199 Static,
200 Const,
201 TyAlias,
202 Enum,
203 Struct,
204 Union,
205 Trait,
206 TraitAlias,
207 Impl,
208 Fn,
209}
210
211impl SourceItemOrderingModuleItemKind {
212 pub fn all_variants() -> Vec<Self> {
213 #[allow(clippy::enum_glob_use)] use SourceItemOrderingModuleItemKind::*;
215 vec![
216 ExternCrate,
217 Mod,
218 ForeignMod,
219 Use,
220 Macro,
221 GlobalAsm,
222 Static,
223 Const,
224 TyAlias,
225 Enum,
226 Struct,
227 Union,
228 Trait,
229 TraitAlias,
230 Impl,
231 Fn,
232 ]
233 }
234}
235
236#[derive(Clone)]
241pub struct SourceItemOrderingModuleItemGroupings {
242 groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)>,
243 lut: HashMap<SourceItemOrderingModuleItemKind, usize>,
244}
245
246impl SourceItemOrderingModuleItemGroupings {
247 fn build_lut(
248 groups: &[(String, Vec<SourceItemOrderingModuleItemKind>)],
249 ) -> HashMap<SourceItemOrderingModuleItemKind, usize> {
250 let mut lut = HashMap::new();
251 for (group_index, (_, items)) in groups.iter().enumerate() {
252 for item in items {
253 lut.insert(item.clone(), group_index);
254 }
255 }
256 lut
257 }
258
259 pub fn module_level_order_of(&self, item: &SourceItemOrderingModuleItemKind) -> Option<usize> {
260 self.lut.get(item).copied()
261 }
262}
263
264impl From<&[(&str, &[SourceItemOrderingModuleItemKind])]> for SourceItemOrderingModuleItemGroupings {
265 fn from(value: &[(&str, &[SourceItemOrderingModuleItemKind])]) -> Self {
266 let groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)> =
267 value.iter().map(|item| (item.0.to_string(), item.1.to_vec())).collect();
268 let lut = Self::build_lut(&groups);
269 Self { groups, lut }
270 }
271}
272
273impl core::fmt::Debug for SourceItemOrderingModuleItemGroupings {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 self.groups.fmt(f)
276 }
277}
278
279impl<'de> Deserialize<'de> for SourceItemOrderingModuleItemGroupings {
280 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
281 where
282 D: Deserializer<'de>,
283 {
284 let groups = Vec::<(String, Vec<SourceItemOrderingModuleItemKind>)>::deserialize(deserializer)?;
285 let items_total: usize = groups.iter().map(|(_, v)| v.len()).sum();
286 let lut = Self::build_lut(&groups);
287
288 let mut expected_items = SourceItemOrderingModuleItemKind::all_variants();
289 for item in lut.keys() {
290 expected_items.retain(|i| i != item);
291 }
292
293 let all_items = SourceItemOrderingModuleItemKind::all_variants();
294 if expected_items.is_empty() && items_total == all_items.len() {
295 let Some(use_group_index) = lut.get(&SourceItemOrderingModuleItemKind::Use) else {
296 return Err(de::Error::custom("Error in internal LUT."));
297 };
298 let Some((_, use_group_items)) = groups.get(*use_group_index) else {
299 return Err(de::Error::custom("Error in internal LUT."));
300 };
301 if use_group_items.len() > 1 {
302 return Err(de::Error::custom(
303 "The group containing the \"use\" item kind may not contain any other item kinds. \
304 The \"use\" items will (generally) be sorted by rustfmt already. \
305 Therefore it makes no sense to implement linting rules that may conflict with rustfmt.",
306 ));
307 }
308
309 Ok(Self { groups, lut })
310 } else if items_total != all_items.len() {
311 Err(de::Error::custom(format!(
312 "Some module item kinds were configured more than once, or were missing, in the source ordering configuration. \
313 The module item kinds are: {all_items:?}"
314 )))
315 } else {
316 Err(de::Error::custom(format!(
317 "Not all module item kinds were part of the configured source ordering rule. \
318 All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
319 The module item kinds are: {all_items:?}"
320 )))
321 }
322 }
323}
324
325impl Serialize for SourceItemOrderingModuleItemGroupings {
326 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
327 where
328 S: ser::Serializer,
329 {
330 self.groups.serialize(serializer)
331 }
332}
333
334#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
336#[serde(rename_all = "snake_case")]
337pub enum SourceItemOrderingTraitAssocItemKind {
338 Const,
339 Fn,
340 Type,
341}
342
343impl SourceItemOrderingTraitAssocItemKind {
344 pub fn all_variants() -> Vec<Self> {
345 #[allow(clippy::enum_glob_use)] use SourceItemOrderingTraitAssocItemKind::*;
347 vec![Const, Fn, Type]
348 }
349}
350
351#[derive(Clone)]
359pub struct SourceItemOrderingTraitAssocItemKinds(Vec<SourceItemOrderingTraitAssocItemKind>);
360
361impl SourceItemOrderingTraitAssocItemKinds {
362 pub fn index_of(&self, item: &SourceItemOrderingTraitAssocItemKind) -> Option<usize> {
363 self.0.iter().position(|i| i == item)
364 }
365}
366
367impl<T> From<T> for SourceItemOrderingTraitAssocItemKinds
368where
369 T: Into<Vec<SourceItemOrderingTraitAssocItemKind>>,
370{
371 fn from(value: T) -> Self {
372 Self(value.into())
373 }
374}
375
376impl core::fmt::Debug for SourceItemOrderingTraitAssocItemKinds {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 self.0.fmt(f)
379 }
380}
381
382impl<'de> Deserialize<'de> for SourceItemOrderingTraitAssocItemKinds {
383 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
384 where
385 D: Deserializer<'de>,
386 {
387 let items = Vec::<SourceItemOrderingTraitAssocItemKind>::deserialize(deserializer)?;
388
389 let mut expected_items = SourceItemOrderingTraitAssocItemKind::all_variants();
390 for item in &items {
391 expected_items.retain(|i| i != item);
392 }
393
394 let all_items = SourceItemOrderingTraitAssocItemKind::all_variants();
395 if expected_items.is_empty() && items.len() == all_items.len() {
396 Ok(Self(items))
397 } else if items.len() != all_items.len() {
398 Err(de::Error::custom(format!(
399 "Some trait associated item kinds were configured more than once, or were missing, in the source ordering configuration. \
400 The trait associated item kinds are: {all_items:?}",
401 )))
402 } else {
403 Err(de::Error::custom(format!(
404 "Not all trait associated item kinds were part of the configured source ordering rule. \
405 All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
406 The trait associated item kinds are: {all_items:?}"
407 )))
408 }
409 }
410}
411
412impl Serialize for SourceItemOrderingTraitAssocItemKinds {
413 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
414 where
415 S: ser::Serializer,
416 {
417 self.0.serialize(serializer)
418 }
419}
420
421macro_rules! unimplemented_serialize {
424 ($($t:ty,)*) => {
425 $(
426 impl Serialize for $t {
427 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
428 where
429 S: ser::Serializer,
430 {
431 Err(ser::Error::custom("unimplemented"))
432 }
433 }
434 )*
435 }
436}
437
438unimplemented_serialize! {
439 DisallowedPath,
440 Rename,
441 MacroMatcher,
442}
443
444#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
445pub enum PubUnderscoreFieldsBehaviour {
446 PubliclyExported,
447 AllPubFields,
448}