diff options
author | Akshay <[email protected]> | 2021-10-31 16:01:04 +0000 |
---|---|---|
committer | Akshay <[email protected]> | 2021-10-31 16:01:04 +0000 |
commit | 15ccd864c8869f87a564e5ab7e923dcc2bb54340 (patch) | |
tree | 9d47b230d5d4ad1b0f40ba88f097418b981805a4 | |
parent | 4567a246a0b63418f17ead4adc81f5ebab8bdd81 (diff) |
add explainations to each lint
-rw-r--r-- | bin/src/main.rs | 4 | ||||
-rw-r--r-- | lib/src/lints/bool_comparison.rs | 27 | ||||
-rw-r--r-- | lib/src/lints/collapsible_let_in.rs | 28 | ||||
-rw-r--r-- | lib/src/lints/empty_let_in.rs | 19 | ||||
-rw-r--r-- | lib/src/lints/empty_pattern.rs | 27 | ||||
-rw-r--r-- | lib/src/lints/eta_reduction.rs | 26 | ||||
-rw-r--r-- | lib/src/lints/legacy_let_syntax.rs | 28 | ||||
-rw-r--r-- | lib/src/lints/manual_inherit.rs | 24 | ||||
-rw-r--r-- | lib/src/lints/manual_inherit_from.rs | 24 | ||||
-rw-r--r-- | lib/src/lints/redundant_pattern_bind.rs | 21 | ||||
-rw-r--r-- | lib/src/lints/unquoted_splice.rs | 24 | ||||
-rw-r--r-- | lib/src/lints/useless_parens.rs | 25 | ||||
-rw-r--r-- | macros/src/explain.rs | 14 |
13 files changed, 265 insertions, 26 deletions
diff --git a/bin/src/main.rs b/bin/src/main.rs index 138b243..31f6823 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs | |||
@@ -88,8 +88,8 @@ fn _main() -> Result<(), StatixErr> { | |||
88 | } | 88 | } |
89 | } | 89 | } |
90 | SubCommand::Explain(explain_config) => { | 90 | SubCommand::Explain(explain_config) => { |
91 | let explaination = explain::explain(explain_config.target)?; | 91 | let explanation = explain::explain(explain_config.target)?; |
92 | println!("{}", explaination); | 92 | println!("{}", explanation) |
93 | } | 93 | } |
94 | } | 94 | } |
95 | Ok(()) | 95 | Ok(()) |
diff --git a/lib/src/lints/bool_comparison.rs b/lib/src/lints/bool_comparison.rs index 6636faf..5c9bee8 100644 --- a/lib/src/lints/bool_comparison.rs +++ b/lib/src/lints/bool_comparison.rs | |||
@@ -7,28 +7,25 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// What it does | 10 | /// ## What it does |
11 | /// ------------ | 11 | /// Checks for expressions of the form `x == true`, `x != true` and |
12 | /// Checks for expressions of the form x == true, x != true and | ||
13 | /// suggests using the variable directly. | 12 | /// suggests using the variable directly. |
14 | /// | 13 | /// |
15 | /// Why is this bad? | 14 | /// ## Why is this bad? |
16 | /// ---------------- | ||
17 | /// Unnecessary code. | 15 | /// Unnecessary code. |
18 | /// | 16 | /// |
19 | /// Example | 17 | /// ## Example |
20 | /// -------- | 18 | /// Instead of checking the value of `x`: |
21 | /// Instead of checking the value of x: | ||
22 | /// | 19 | /// |
23 | /// if x == true | 20 | /// ``` |
24 | /// then 0 | 21 | /// if x == true then 0 else 1 |
25 | /// else 1 | 22 | /// ``` |
26 | /// | 23 | /// |
27 | /// Use x directly: | 24 | /// Use `x` directly: |
28 | /// | 25 | /// |
29 | /// if x | 26 | /// ``` |
30 | /// then 0 | 27 | /// if x then 0 else 1 |
31 | /// else 1 | 28 | /// ``` |
32 | #[lint( | 29 | #[lint( |
33 | name = "bool_comparison", | 30 | name = "bool_comparison", |
34 | note = "Unnecessary comparison with boolean", | 31 | note = "Unnecessary comparison with boolean", |
diff --git a/lib/src/lints/collapsible_let_in.rs b/lib/src/lints/collapsible_let_in.rs index cb76c37..21199a8 100644 --- a/lib/src/lints/collapsible_let_in.rs +++ b/lib/src/lints/collapsible_let_in.rs | |||
@@ -8,6 +8,34 @@ use rnix::{ | |||
8 | }; | 8 | }; |
9 | use rowan::Direction; | 9 | use rowan::Direction; |
10 | 10 | ||
11 | /// ## What it does | ||
12 | /// Checks for `let-in` expressions whose body is another `let-in` | ||
13 | /// expression. | ||
14 | /// | ||
15 | /// ## Why is this bad? | ||
16 | /// Unnecessary code, the `let-in` expressions can be merged. | ||
17 | /// | ||
18 | /// ## Example | ||
19 | /// | ||
20 | /// ``` | ||
21 | /// let | ||
22 | /// a = 2; | ||
23 | /// in | ||
24 | /// let | ||
25 | /// b = 3; | ||
26 | /// in | ||
27 | /// a + b | ||
28 | /// ``` | ||
29 | /// | ||
30 | /// Merge both `let-in` expressions: | ||
31 | /// | ||
32 | /// ``` | ||
33 | /// let | ||
34 | /// a = 2; | ||
35 | /// b = 3; | ||
36 | /// in | ||
37 | /// a + b | ||
38 | /// ``` | ||
11 | #[lint( | 39 | #[lint( |
12 | name = "collapsible let in", | 40 | name = "collapsible let in", |
13 | note = "These let-in expressions are collapsible", | 41 | note = "These let-in expressions are collapsible", |
diff --git a/lib/src/lints/empty_let_in.rs b/lib/src/lints/empty_let_in.rs index 4e0887d..b255c23 100644 --- a/lib/src/lints/empty_let_in.rs +++ b/lib/src/lints/empty_let_in.rs | |||
@@ -7,7 +7,24 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// empty let-in found | 10 | /// ## What it does |
11 | /// Checks for `let-in` expressions which create no new bindings. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// `let-in` expressions that create no new bindings are useless. | ||
15 | /// These are probably remnants from debugging or editing expressions. | ||
16 | /// | ||
17 | /// ## Example | ||
18 | /// | ||
19 | /// ``` | ||
20 | /// let in pkgs.statix | ||
21 | /// ``` | ||
22 | /// | ||
23 | /// Preserve only the body of the `let-in` expression: | ||
24 | /// | ||
25 | /// ``` | ||
26 | /// pkgs.statix | ||
27 | /// ``` | ||
11 | #[lint( | 28 | #[lint( |
12 | name = "empty let-in", | 29 | name = "empty let-in", |
13 | note = "Useless let-in expression", | 30 | note = "Useless let-in expression", |
diff --git a/lib/src/lints/empty_pattern.rs b/lib/src/lints/empty_pattern.rs index ef47c69..5312548 100644 --- a/lib/src/lints/empty_pattern.rs +++ b/lib/src/lints/empty_pattern.rs | |||
@@ -7,6 +7,33 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for an empty variadic pattern: `{...}`, in a function | ||
12 | /// argument. | ||
13 | /// | ||
14 | /// ## Why is this bad? | ||
15 | /// The intention with empty patterns is not instantly obvious. Prefer | ||
16 | /// an underscore identifier instead, to indicate that the argument | ||
17 | /// is being ignored. | ||
18 | /// | ||
19 | /// ## Example | ||
20 | /// | ||
21 | /// ``` | ||
22 | /// client = { ... }: { | ||
23 | /// imports = [ self.nixosModules.irmaseal-pkg ]; | ||
24 | /// services.irmaseal-pkg.enable = true; | ||
25 | /// }; | ||
26 | /// ``` | ||
27 | /// | ||
28 | /// Replace the empty variadic pattern with `_` to indicate that you | ||
29 | /// intend to ignore the argument: | ||
30 | /// | ||
31 | /// ``` | ||
32 | /// client = _: { | ||
33 | /// imports = [ self.nixosModules.irmaseal-pkg ]; | ||
34 | /// services.irmaseal-pkg.enable = true; | ||
35 | /// }; | ||
36 | /// ``` | ||
10 | #[lint( | 37 | #[lint( |
11 | name = "empty pattern", | 38 | name = "empty pattern", |
12 | note = "Found empty pattern in function argument", | 39 | note = "Found empty pattern in function argument", |
diff --git a/lib/src/lints/eta_reduction.rs b/lib/src/lints/eta_reduction.rs index b329ae8..3a483d0 100644 --- a/lib/src/lints/eta_reduction.rs +++ b/lib/src/lints/eta_reduction.rs | |||
@@ -7,6 +7,32 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for eta-reducible functions, i.e.: converts lambda | ||
12 | /// expressions into free standing functions where applicable. | ||
13 | /// | ||
14 | /// ## Why is this bad? | ||
15 | /// Oftentimes, eta-reduction results in code that is more natural | ||
16 | /// to read. | ||
17 | /// | ||
18 | /// ## Example | ||
19 | /// | ||
20 | /// ``` | ||
21 | /// let | ||
22 | /// double = i: 2 * i; | ||
23 | /// in | ||
24 | /// map (x: double x) [ 1 2 3 ] | ||
25 | /// ``` | ||
26 | /// | ||
27 | /// The lambda passed to the `map` function is eta-reducible, and the | ||
28 | /// result reads more naturally: | ||
29 | /// | ||
30 | /// ``` | ||
31 | /// let | ||
32 | /// double = i: 2 * i; | ||
33 | /// in | ||
34 | /// map double [ 1 2 3 ] | ||
35 | /// ``` | ||
10 | #[lint( | 36 | #[lint( |
11 | name = "eta reduction", | 37 | name = "eta reduction", |
12 | note = "This function expression is eta reducible", | 38 | note = "This function expression is eta reducible", |
diff --git a/lib/src/lints/legacy_let_syntax.rs b/lib/src/lints/legacy_let_syntax.rs index 8b37df8..139f633 100644 --- a/lib/src/lints/legacy_let_syntax.rs +++ b/lib/src/lints/legacy_let_syntax.rs | |||
@@ -7,6 +7,34 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for legacy-let syntax that was never formalized. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// This syntax construct is undocumented, refrain from using it. | ||
15 | /// | ||
16 | /// ## Example | ||
17 | /// | ||
18 | /// Legacy let syntax makes use of an attribute set annotated with | ||
19 | /// `let` and expects a `body` attribute. | ||
20 | /// ``` | ||
21 | /// let { | ||
22 | /// body = x + y; | ||
23 | /// x = 2; | ||
24 | /// y = 3; | ||
25 | /// } | ||
26 | /// ``` | ||
27 | /// | ||
28 | /// This is trivially representible via `rec`, which is documented | ||
29 | /// and more widely known: | ||
30 | /// | ||
31 | /// ``` | ||
32 | /// rec { | ||
33 | /// body = x + y; | ||
34 | /// x = 2; | ||
35 | /// y = 3; | ||
36 | /// }.body | ||
37 | /// ``` | ||
10 | #[lint( | 38 | #[lint( |
11 | name = "legacy let syntax", | 39 | name = "legacy let syntax", |
12 | note = "Using undocumented `let` syntax", | 40 | note = "Using undocumented `let` syntax", |
diff --git a/lib/src/lints/manual_inherit.rs b/lib/src/lints/manual_inherit.rs index 1c10cbf..2d119c3 100644 --- a/lib/src/lints/manual_inherit.rs +++ b/lib/src/lints/manual_inherit.rs | |||
@@ -7,6 +7,30 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for bindings of the form `a = a`. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// If the aim is to bring attributes from a larger scope into | ||
15 | /// the current scope, prefer an inherit statement. | ||
16 | /// | ||
17 | /// ## Example | ||
18 | /// | ||
19 | /// ``` | ||
20 | /// let | ||
21 | /// a = 2; | ||
22 | /// in | ||
23 | /// { a = a; b = 3; } | ||
24 | /// ``` | ||
25 | /// | ||
26 | /// Try `inherit` instead: | ||
27 | /// | ||
28 | /// ``` | ||
29 | /// let | ||
30 | /// a = 2; | ||
31 | /// in | ||
32 | /// { inherit a; b = 3; } | ||
33 | /// ``` | ||
10 | #[lint( | 34 | #[lint( |
11 | name = "manual inherit", | 35 | name = "manual inherit", |
12 | note = "Assignment instead of inherit", | 36 | note = "Assignment instead of inherit", |
diff --git a/lib/src/lints/manual_inherit_from.rs b/lib/src/lints/manual_inherit_from.rs index 146d55b..8d0f539 100644 --- a/lib/src/lints/manual_inherit_from.rs +++ b/lib/src/lints/manual_inherit_from.rs | |||
@@ -7,6 +7,30 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for bindings of the form `a = someAttr.a`. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// If the aim is to extract or bring attributes of an attrset into | ||
15 | /// scope, prefer an inherit statement. | ||
16 | /// | ||
17 | /// ## Example | ||
18 | /// | ||
19 | /// ``` | ||
20 | /// let | ||
21 | /// mtl = pkgs.haskellPackages.mtl; | ||
22 | /// in | ||
23 | /// null | ||
24 | /// ``` | ||
25 | /// | ||
26 | /// Try `inherit` instead: | ||
27 | /// | ||
28 | /// ``` | ||
29 | /// let | ||
30 | /// inherit (pkgs.haskellPackages) mtl; | ||
31 | /// in | ||
32 | /// null | ||
33 | /// ``` | ||
10 | #[lint( | 34 | #[lint( |
11 | name = "manual inherit from", | 35 | name = "manual inherit from", |
12 | note = "Assignment instead of inherit from", | 36 | note = "Assignment instead of inherit from", |
diff --git a/lib/src/lints/redundant_pattern_bind.rs b/lib/src/lints/redundant_pattern_bind.rs index ad1aba8..5b0711f 100644 --- a/lib/src/lints/redundant_pattern_bind.rs +++ b/lib/src/lints/redundant_pattern_bind.rs | |||
@@ -7,10 +7,29 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for binds of the form `inputs @ { ... }` in function | ||
12 | /// arguments. | ||
13 | /// | ||
14 | /// ## Why is this bad? | ||
15 | /// The variadic pattern here is redundant, as it does not capture | ||
16 | /// anything. | ||
17 | /// | ||
18 | /// ## Example | ||
19 | /// | ||
20 | /// ``` | ||
21 | /// inputs @ { ... }: inputs.nixpkgs | ||
22 | /// ``` | ||
23 | /// | ||
24 | /// Remove the pattern altogether: | ||
25 | /// | ||
26 | /// ``` | ||
27 | /// inputs: inputs.nixpkgs | ||
28 | /// ``` | ||
10 | #[lint( | 29 | #[lint( |
11 | name = "redundant pattern bind", | 30 | name = "redundant pattern bind", |
12 | note = "Found redundant pattern bind in function argument", | 31 | note = "Found redundant pattern bind in function argument", |
13 | code = 10, | 32 | code = 11, |
14 | match_with = SyntaxKind::NODE_PATTERN | 33 | match_with = SyntaxKind::NODE_PATTERN |
15 | )] | 34 | )] |
16 | struct RedundantPatternBind; | 35 | struct RedundantPatternBind; |
diff --git a/lib/src/lints/unquoted_splice.rs b/lib/src/lints/unquoted_splice.rs index 2831c1b..c2fd6e4 100644 --- a/lib/src/lints/unquoted_splice.rs +++ b/lib/src/lints/unquoted_splice.rs | |||
@@ -7,6 +7,30 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for antiquote/splice expressions that are not quoted. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// An *anti*quoted expression should always occur within a *quoted* | ||
15 | /// expression. | ||
16 | /// | ||
17 | /// ## Example | ||
18 | /// | ||
19 | /// ``` | ||
20 | /// let | ||
21 | /// pkgs = nixpkgs.legacyPackages.${system}; | ||
22 | /// in | ||
23 | /// pkgs | ||
24 | /// ``` | ||
25 | /// | ||
26 | /// Quote the splice expression: | ||
27 | /// | ||
28 | /// ``` | ||
29 | /// let | ||
30 | /// pkgs = nixpkgs.legacyPackages."${system}"; | ||
31 | /// in | ||
32 | /// pkgs | ||
33 | /// ``` | ||
10 | #[lint( | 34 | #[lint( |
11 | name = "unquoted splice", | 35 | name = "unquoted splice", |
12 | note = "Found unquoted splice expression", | 36 | note = "Found unquoted splice expression", |
diff --git a/lib/src/lints/useless_parens.rs b/lib/src/lints/useless_parens.rs index 9dfeabb..36ad1b7 100644 --- a/lib/src/lints/useless_parens.rs +++ b/lib/src/lints/useless_parens.rs | |||
@@ -7,6 +7,31 @@ use rnix::{ | |||
7 | NodeOrToken, SyntaxElement, SyntaxKind, | 7 | NodeOrToken, SyntaxElement, SyntaxKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | /// ## What it does | ||
11 | /// Checks for unnecessary parentheses. | ||
12 | /// | ||
13 | /// ## Why is this bad? | ||
14 | /// Unnecessarily parenthesized code is hard to read. | ||
15 | /// | ||
16 | /// ## Example | ||
17 | /// | ||
18 | /// ``` | ||
19 | /// let | ||
20 | /// double = (x: 2 * x); | ||
21 | /// ls = map (double) [ 1 2 3 ]; | ||
22 | /// in | ||
23 | /// (2 + 3) | ||
24 | /// ``` | ||
25 | /// | ||
26 | /// Remove unnecessary parentheses: | ||
27 | /// | ||
28 | /// ``` | ||
29 | /// let | ||
30 | /// double = x: 2 * x; | ||
31 | /// ls = map double [ 1 2 3 ]; | ||
32 | /// in | ||
33 | /// 2 + 3 | ||
34 | /// ``` | ||
10 | #[lint( | 35 | #[lint( |
11 | name = "useless parens", | 36 | name = "useless parens", |
12 | note = "These parentheses can be omitted", | 37 | note = "These parentheses can be omitted", |
diff --git a/macros/src/explain.rs b/macros/src/explain.rs index 8b00740..9bc3c29 100644 --- a/macros/src/explain.rs +++ b/macros/src/explain.rs | |||
@@ -7,15 +7,15 @@ pub fn generate_explain_impl(struct_item: &ItemStruct) -> TokenStream2 { | |||
7 | let explain = struct_item | 7 | let explain = struct_item |
8 | .attrs | 8 | .attrs |
9 | .iter() | 9 | .iter() |
10 | .filter_map(|a| a.parse_meta().ok()) | 10 | .filter_map(|attr| match attr.parse_meta().ok() { |
11 | .filter_map(|meta| match meta { | 11 | Some(Meta::NameValue(MetaNameValue { |
12 | Meta::NameValue(MetaNameValue { path, lit, .. }) if path.is_ident("doc") => Some(lit), | 12 | path, |
13 | _ => None, | 13 | lit: Lit::Str(str_lit), |
14 | }) | 14 | .. |
15 | .filter_map(|lit| match lit { | 15 | })) if path.is_ident("doc") => Some(str_lit.value()), |
16 | Lit::Str(str_lit) => Some(str_lit.value()), | ||
17 | _ => None, | 16 | _ => None, |
18 | }) | 17 | }) |
18 | .map(|s| s.strip_prefix(' ').unwrap_or(&s).to_owned()) | ||
19 | .collect::<Vec<_>>() | 19 | .collect::<Vec<_>>() |
20 | .join("\n"); | 20 | .join("\n"); |
21 | quote! { | 21 | quote! { |