wowlab_tidy/languages/rust/rules/api/
public_error_enum.rs1use ra_ap_syntax::ast::{self, HasName, HasVisibility, VisibilityKind};
2
3use crate::{AstCtx, Example, Violation};
4
5#[rustfmt::skip]
6const EXAMPLES: &[Example] = &[
7 Example {
8 label: "pub error enum",
9 code: "pub enum ParseError { Eof, Syntax }",
10 pass: false,
11 },
12 Example {
13 label: "pub error kind enum",
14 code: "pub enum IoErrorKind { NotFound, Denied }",
15 pass: false,
16 },
17 Example {
18 label: "private kind enum",
19 code: "enum ErrorKind { Io, Protocol }",
20 pass: true,
21 },
22 Example {
23 label: "pub(crate) error enum",
24 code: "pub(crate) enum ParseError { Eof }",
25 pass: true,
26 },
27 Example {
28 label: "pub enum without error suffix",
29 code: "pub enum Mode { Fast, Slow }",
30 pass: true,
31 },
32 Example {
33 label: "pub error struct",
34 code: "pub struct ParseError { line: usize }",
35 pass: true,
36 },
37 Example {
38 label: "pub error enum in test module",
39 code: "#[cfg(test)]\nmod tests {\n pub enum ParseError { Eof }\n}",
40 pass: true,
41 },
42];
43
44crate::ast_rule!(
45 public_error_enum,
46 "Flag `pub enum` named `*Error`/`*ErrorKind` — expose a situation-specific error struct with a private kind enum instead.",
47 "A public error enum exposes every failure mode as breaking API surface; a struct wrapping a private kind enum keeps internal failure modes non-breaking.",
48 Medium,
49);
50
51fn check_public_error_enum(ctx: &AstCtx<'_>) -> Vec<Violation> {
52 let public_enums = ctx
53 .nodes::<ast::Enum>()
54 .filter(|item| !ctx.is_in_test(item))
55 .filter(|item| {
56 item.visibility()
57 .is_some_and(|vis| matches!(vis.kind(), VisibilityKind::Pub))
58 });
59
60 public_enums
61 .filter_map(|item| {
62 let name = item.name()?;
63 let text = name.text().to_string();
64
65 (text.ends_with("Error") || text.ends_with("ErrorKind")).then(|| {
66 ctx.violation(
67 &name,
68 format!(
69 "public enum `{text}` — expose a situation-specific error struct with a private kind enum"
70 ),
71 )
72 })
73 })
74 .collect()
75}
76
77crate::tidy_ast_test!(check_public_error_enum, {
78 crate::example_tests!(EXAMPLES, check_public_error_enum);
79});