From 4e063b2abc402ac4d6902647e821978269025c7d Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 3 Nov 2021 14:48:35 +0530 Subject: add snapshot test suite --- Cargo.lock | 186 ++++++++++++++++++--- bin/Cargo.toml | 12 +- bin/src/config.rs | 14 +- bin/src/lib.rs | 7 + bin/src/main.rs | 18 +- bin/tests/data/bool_comparison.nix | 13 ++ bin/tests/data/collapsible_let_in.nix | 9 + bin/tests/data/deprecated_is_null.nix | 6 + bin/tests/data/empty_let_in.nix | 3 + bin/tests/data/empty_pattern.nix | 9 + bin/tests/data/eta_reduction.nix | 18 ++ bin/tests/data/legacy_let_syntax.nix | 5 + bin/tests/data/manual_inherit.nix | 12 ++ bin/tests/data/manual_inherit_from.nix | 8 + bin/tests/data/redundant_pattern_bind.nix | 1 + bin/tests/data/unquoted_splices.nix | 15 ++ bin/tests/data/unquoted_uri.nix | 1 + bin/tests/data/useless_parens.nix | 16 ++ bin/tests/main.rs | 47 ++++++ bin/tests/snapshots/main__bool_comparison.snap | 62 +++++++ bin/tests/snapshots/main__collapsible_let_in.snap | 17 ++ bin/tests/snapshots/main__deprecated_is_null.snap | 13 ++ bin/tests/snapshots/main__empty_let_in.snap | 14 ++ bin/tests/snapshots/main__empty_pattern.snap | 20 +++ bin/tests/snapshots/main__eta_reduction.snap | 13 ++ bin/tests/snapshots/main__legacy_let_syntax.snap | 14 ++ bin/tests/snapshots/main__manual_inherit.snap | 13 ++ bin/tests/snapshots/main__manual_inherit_from.snap | 20 +++ .../snapshots/main__redundant_pattern_bind.snap | 13 ++ bin/tests/snapshots/main__unquoted_splices.snap | 35 ++++ bin/tests/snapshots/main__unquoted_uri.snap | 13 ++ bin/tests/snapshots/main__useless_parens.snap | 48 ++++++ flake.nix | 7 +- lib/src/lints/useless_parens.rs | 10 +- vfs/src/lib.rs | 2 +- 35 files changed, 665 insertions(+), 49 deletions(-) create mode 100644 bin/src/lib.rs create mode 100644 bin/tests/data/bool_comparison.nix create mode 100644 bin/tests/data/collapsible_let_in.nix create mode 100644 bin/tests/data/deprecated_is_null.nix create mode 100644 bin/tests/data/empty_let_in.nix create mode 100644 bin/tests/data/empty_pattern.nix create mode 100644 bin/tests/data/eta_reduction.nix create mode 100644 bin/tests/data/legacy_let_syntax.nix create mode 100644 bin/tests/data/manual_inherit.nix create mode 100644 bin/tests/data/manual_inherit_from.nix create mode 100644 bin/tests/data/redundant_pattern_bind.nix create mode 100644 bin/tests/data/unquoted_splices.nix create mode 100644 bin/tests/data/unquoted_uri.nix create mode 100644 bin/tests/data/useless_parens.nix create mode 100644 bin/tests/main.rs create mode 100644 bin/tests/snapshots/main__bool_comparison.snap create mode 100644 bin/tests/snapshots/main__collapsible_let_in.snap create mode 100644 bin/tests/snapshots/main__deprecated_is_null.snap create mode 100644 bin/tests/snapshots/main__empty_let_in.snap create mode 100644 bin/tests/snapshots/main__empty_pattern.snap create mode 100644 bin/tests/snapshots/main__eta_reduction.snap create mode 100644 bin/tests/snapshots/main__legacy_let_syntax.snap create mode 100644 bin/tests/snapshots/main__manual_inherit.snap create mode 100644 bin/tests/snapshots/main__manual_inherit_from.snap create mode 100644 bin/tests/snapshots/main__redundant_pattern_bind.snap create mode 100644 bin/tests/snapshots/main__unquoted_splices.snap create mode 100644 bin/tests/snapshots/main__unquoted_uri.snap create mode 100644 bin/tests/snapshots/main__useless_parens.snap diff --git a/Cargo.lock b/Cargo.lock index 5b4b0eb..08881fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,12 @@ dependencies = [ "yansi", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "atty" version = "0.2.14" @@ -69,9 +75,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" +checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" dependencies = [ "atty", "bitflags", @@ -82,14 +88,14 @@ dependencies = [ "strsim", "termcolor", "textwrap", - "vec_map", + "unicase", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" +checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" dependencies = [ "heck", "proc-macro-error", @@ -98,6 +104,19 @@ dependencies = [ "syn", ] +[[package]] +name = "console" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "winapi", +] + [[package]] name = "countme" version = "2.0.4" @@ -114,6 +133,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "fnv" version = "1.0.7" @@ -197,6 +228,21 @@ dependencies = [ "hashbrown 0.11.2", ] +[[package]] +name = "insta" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15226a375927344c78d39dc6b49e2d5562a5b0705e26a589093c6792e52eed8e" +dependencies = [ + "console", + "lazy_static", + "serde", + "serde_json", + "serde_yaml", + "similar 1.3.0", + "uuid", +] + [[package]] name = "itoa" version = "0.4.8" @@ -224,9 +270,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "log" @@ -278,9 +330,12 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "os_str_bytes" -version = "3.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" +checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" +dependencies = [ + "memchr", +] [[package]] name = "proc-macro-error" @@ -308,18 +363,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] @@ -343,9 +398,9 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rnix" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b37f8af07a0354606141df076458660af7e22238e4117a041c21c548080addd" +checksum = "294becb48f58c496d96c10a12df290266204ca75c9799be4d04222bfaebb6a37" dependencies = [ "cbitset", "rowan", @@ -417,6 +472,24 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" +dependencies = [ + "dtoa", + "indexmap", + "serde", + "yaml-rust", +] + +[[package]] +name = "similar" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec" + [[package]] name = "similar" version = "2.1.0" @@ -425,9 +498,12 @@ checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" [[package]] name = "smol_str" -version = "0.1.18" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b203e79e90905594272c1c97c7af701533d42adaab0beb3859018e477d54a3b0" +checksum = "559b173452ec4061933b0c0e22d7d429c90ecdc1b3ae1c6e64238e7c15c3ee15" +dependencies = [ + "serde", +] [[package]] name = "statix" @@ -436,15 +512,26 @@ dependencies = [ "ariadne", "clap", "ignore", + "insta", "lib", "rnix", "serde", "serde_json", - "similar", + "similar 2.1.0", + "strip-ansi-escapes", "thiserror", "vfs", ] +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.10.0" @@ -453,9 +540,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.76" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", @@ -471,6 +558,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "text-size" version = "1.1.0" @@ -515,6 +612,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-segmentation" version = "1.8.0" @@ -534,10 +640,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "vec_map" +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[package]] +name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "version_check" @@ -552,6 +664,27 @@ dependencies = [ "indexmap", ] +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "walkdir" version = "2.3.2" @@ -594,6 +727,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.0" diff --git a/bin/Cargo.toml b/bin/Cargo.toml index d67e6c1..7c48083 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -6,7 +6,13 @@ license = "MIT" authors = [ "Akshay " ] description = "Lints and suggestions for the Nix programming language" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "statix" +path = "src/lib.rs" + +[[bin]] +name = "statix" +path = "src/main.rs" [dependencies] ariadne = "0.1.3" @@ -27,5 +33,9 @@ version = "1.0.68" features = [ "derive" ] optional = true +[dev-dependencies] +insta = "1.8.0" +strip-ansi-escapes = "0.1.1" + [features] json = [ "lib/json-out", "serde_json", "serde" ] diff --git a/bin/src/config.rs b/bin/src/config.rs index 25c2a7f..d3944ac 100644 --- a/bin/src/config.rs +++ b/bin/src/config.rs @@ -2,17 +2,17 @@ use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr}; use crate::{dirs, err::ConfigErr}; -use clap::Clap; +use clap::Parser; use vfs::ReadOnlyVfs; -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] #[clap(version, author, about)] pub struct Opts { #[clap(subcommand)] pub cmd: SubCommand, } -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] pub enum SubCommand { /// Lints and suggestions for the nix programming language Check(Check), @@ -24,7 +24,7 @@ pub enum SubCommand { Explain(Explain), } -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] pub struct Check { /// File or directory to run check on #[clap(default_value = ".", parse(from_os_str))] @@ -67,7 +67,7 @@ impl Check { } } -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] pub struct Fix { /// File or directory to run fix on #[clap(default_value = ".", parse(from_os_str))] @@ -127,7 +127,7 @@ impl Fix { } } -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] pub struct Single { /// File to run single-fix on #[clap(parse(from_os_str))] @@ -174,7 +174,7 @@ impl Single { } } -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] pub struct Explain { /// Warning code to explain #[clap(parse(try_from_str = parse_warning_code))] diff --git a/bin/src/lib.rs b/bin/src/lib.rs new file mode 100644 index 0000000..49c1a41 --- /dev/null +++ b/bin/src/lib.rs @@ -0,0 +1,7 @@ +pub mod config; +pub mod dirs; +pub mod err; +pub mod explain; +pub mod fix; +pub mod lint; +pub mod traits; diff --git a/bin/src/main.rs b/bin/src/main.rs index fabc509..f504796 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -1,15 +1,9 @@ -mod config; -mod dirs; -mod err; -mod explain; -mod fix; -mod lint; -mod traits; - -use crate::err::StatixErr; - -use clap::Clap; -use config::{Opts, SubCommand}; +use clap::Parser; +use statix::{ + config::{Opts, SubCommand}, + err::StatixErr, + explain, fix, lint, +}; fn _main() -> Result<(), StatixErr> { let opts = Opts::parse(); diff --git a/bin/tests/data/bool_comparison.nix b/bin/tests/data/bool_comparison.nix new file mode 100644 index 0000000..dee2d08 --- /dev/null +++ b/bin/tests/data/bool_comparison.nix @@ -0,0 +1,13 @@ +[ + # trivial + (a == true) + (b == true) + (true == c) + (true == d) + + # not equals + (e != true) + (f != false) + (true != g) + (false != h) +] diff --git a/bin/tests/data/collapsible_let_in.nix b/bin/tests/data/collapsible_let_in.nix new file mode 100644 index 0000000..7b41014 --- /dev/null +++ b/bin/tests/data/collapsible_let_in.nix @@ -0,0 +1,9 @@ +let + a = 2; + b = 3; +in + let + c = 5; + d = 6; + in + a + b + c + d diff --git a/bin/tests/data/deprecated_is_null.nix b/bin/tests/data/deprecated_is_null.nix new file mode 100644 index 0000000..42596d7 --- /dev/null +++ b/bin/tests/data/deprecated_is_null.nix @@ -0,0 +1,6 @@ +let + e = null; +in +if isNull e +then "no" +else "yes" diff --git a/bin/tests/data/empty_let_in.nix b/bin/tests/data/empty_let_in.nix new file mode 100644 index 0000000..3ecb6e4 --- /dev/null +++ b/bin/tests/data/empty_let_in.nix @@ -0,0 +1,3 @@ +let +in + null diff --git a/bin/tests/data/empty_pattern.nix b/bin/tests/data/empty_pattern.nix new file mode 100644 index 0000000..23d99e8 --- /dev/null +++ b/bin/tests/data/empty_pattern.nix @@ -0,0 +1,9 @@ +[ + # match + ({ ... }: 42) + + # don't match + ({ a, ... }: a) + ({ ... } @ inputs: inputs) +] + diff --git a/bin/tests/data/eta_reduction.nix b/bin/tests/data/eta_reduction.nix new file mode 100644 index 0000000..e717ee7 --- /dev/null +++ b/bin/tests/data/eta_reduction.nix @@ -0,0 +1,18 @@ +let + double = x: x * 2; + inherit (builtins) map; + xs = [ 1 2 3 ]; + f = { + inherit double; + val = 2; + }; +in +[ + (map (x: double x) xs) + + # don't lint on non-free exprs + (map (f: f.double f.val) [ f ]) + + # other non-free forms + (map (f: {inherit f;}.double f.val) [ f ]) +] diff --git a/bin/tests/data/legacy_let_syntax.nix b/bin/tests/data/legacy_let_syntax.nix new file mode 100644 index 0000000..46e3191 --- /dev/null +++ b/bin/tests/data/legacy_let_syntax.nix @@ -0,0 +1,5 @@ +let { + body = x + y; + x = "hello,"; + y = " world!"; +} diff --git a/bin/tests/data/manual_inherit.nix b/bin/tests/data/manual_inherit.nix new file mode 100644 index 0000000..53ae4d7 --- /dev/null +++ b/bin/tests/data/manual_inherit.nix @@ -0,0 +1,12 @@ +let + a = 2; + y = "y"; +in +{ + # trivial + a = a; + + # don't lint + x.y = y; +} + diff --git a/bin/tests/data/manual_inherit_from.nix b/bin/tests/data/manual_inherit_from.nix new file mode 100644 index 0000000..214b2a3 --- /dev/null +++ b/bin/tests/data/manual_inherit_from.nix @@ -0,0 +1,8 @@ +let + a = {b = 2; c = 3;}; +in +{ + b = a.b; + c = a.c; +} + diff --git a/bin/tests/data/redundant_pattern_bind.nix b/bin/tests/data/redundant_pattern_bind.nix new file mode 100644 index 0000000..d328c50 --- /dev/null +++ b/bin/tests/data/redundant_pattern_bind.nix @@ -0,0 +1 @@ +{ ... } @ inputs: null diff --git a/bin/tests/data/unquoted_splices.nix b/bin/tests/data/unquoted_splices.nix new file mode 100644 index 0000000..30935b0 --- /dev/null +++ b/bin/tests/data/unquoted_splices.nix @@ -0,0 +1,15 @@ +let + x = 2; + y = 3; + a = { "2" = y; }; +in +[ + ${x} + ${toString (x + y)} + a.${toString x} + + # multiline test + ${ + toString x + } +] diff --git a/bin/tests/data/unquoted_uri.nix b/bin/tests/data/unquoted_uri.nix new file mode 100644 index 0000000..e56574a --- /dev/null +++ b/bin/tests/data/unquoted_uri.nix @@ -0,0 +1 @@ +github:nerdypepper/statix diff --git a/bin/tests/data/useless_parens.nix b/bin/tests/data/useless_parens.nix new file mode 100644 index 0000000..cf26441 --- /dev/null +++ b/bin/tests/data/useless_parens.nix @@ -0,0 +1,16 @@ +let + # parens around primitives + a = { + b = ("hello"); + c = (d); + e = ({ f = 2; }); + }; + + # parens around let-value + g = (1 + 2); + h = ({ inherit i; }); + + # TODO: binary exprs, function args etc. +in + # parens around let body + (null) diff --git a/bin/tests/main.rs b/bin/tests/main.rs new file mode 100644 index 0000000..6175c90 --- /dev/null +++ b/bin/tests/main.rs @@ -0,0 +1,47 @@ +mod util { + #[macro_export] + macro_rules! test_lint { + ($($tname:ident),*,) => { + test_lint!($($tname),*); + }; + ($($tname:ident),*) => { + $( + #[test] + fn $tname() { + use statix::{config::OutFormat, traits::WriteDiagnostic, lint}; + use vfs::ReadOnlyVfs; + + let file_path = concat!("data/", stringify!($tname), ".nix"); + let contents = include_str!(concat!("data/", stringify!($tname), ".nix")); + + let vfs = ReadOnlyVfs::singleton(file_path, contents.as_bytes()); + + let mut buffer = Vec::new(); + vfs.iter().map(lint::lint).for_each(|r| { + buffer.write(&r, &vfs, OutFormat::StdErr).unwrap(); + }); + + let stripped = strip_ansi_escapes::strip(&buffer).unwrap(); + let out = std::str::from_utf8(&stripped).unwrap(); + insta::assert_snapshot!(&out); + } + )* + }; + } +} + +test_lint! { + bool_comparison, + empty_let_in, + manual_inherit, + manual_inherit_from, + legacy_let_syntax, + collapsible_let_in, + eta_reduction, + useless_parens, + unquoted_splices, + empty_pattern, + redundant_pattern_bind, + unquoted_uri, + deprecated_is_null, +} diff --git a/bin/tests/snapshots/main__bool_comparison.snap b/bin/tests/snapshots/main__bool_comparison.snap new file mode 100644 index 0000000..0865332 --- /dev/null +++ b/bin/tests/snapshots/main__bool_comparison.snap @@ -0,0 +1,62 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:3:4] + │ + 3 │ (a == true) + · ────┬──── + · ╰────── Comparing a with boolean literal true +───╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:4:4] + │ + 4 │ (b == true) + · ────┬──── + · ╰────── Comparing b with boolean literal true +───╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:5:4] + │ + 5 │ (true == c) + · ────┬──── + · ╰────── Comparing c with boolean literal true +───╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:6:4] + │ + 6 │ (true == d) + · ────┬──── + · ╰────── Comparing d with boolean literal true +───╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:9:4] + │ + 9 │ (e != true) + · ────┬──── + · ╰────── Comparing e with boolean literal true +───╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:10:4] + │ + 10 │ (f != false) + · ─────┬──── + · ╰────── Comparing f with boolean literal false +────╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:11:4] + │ + 11 │ (true != g) + · ────┬──── + · ╰────── Comparing g with boolean literal true +────╯ +[W01] Warning: Unnecessary comparison with boolean + ╭─[data/bool_comparison.nix:12:4] + │ + 12 │ (false != h) + · ─────┬──── + · ╰────── Comparing h with boolean literal false +────╯ + diff --git a/bin/tests/snapshots/main__collapsible_let_in.snap b/bin/tests/snapshots/main__collapsible_let_in.snap new file mode 100644 index 0000000..b135abc --- /dev/null +++ b/bin/tests/snapshots/main__collapsible_let_in.snap @@ -0,0 +1,17 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W06] Warning: These let-in expressions are collapsible + ╭─[data/collapsible_let_in.nix:1:1] + │ + 1 │ ╭───▶ let + 5 │ │ ╭─▶ let + 9 │ │ ├─▶ a + b + c + d + · │ │ │ + · │ ╰───────────────────── This let in expression is nested + · │ │ + · ╰───────────────────┴─── This let in expression contains a nested let in expression +───╯ + diff --git a/bin/tests/snapshots/main__deprecated_is_null.snap b/bin/tests/snapshots/main__deprecated_is_null.snap new file mode 100644 index 0000000..d49b381 --- /dev/null +++ b/bin/tests/snapshots/main__deprecated_is_null.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W13] Warning: Found usage of deprecated builtin isNull + ╭─[data/deprecated_is_null.nix:4:4] + │ + 4 │ if isNull e + · ────┬─── + · ╰───── isNull is deprecated, check equality with null instead +───╯ + diff --git a/bin/tests/snapshots/main__empty_let_in.snap b/bin/tests/snapshots/main__empty_let_in.snap new file mode 100644 index 0000000..426692f --- /dev/null +++ b/bin/tests/snapshots/main__empty_let_in.snap @@ -0,0 +1,14 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W02] Warning: Useless let-in expression + ╭─[data/empty_let_in.nix:1:1] + │ + 1 │ ╭─▶ let + 3 │ ├─▶ null + · │ + · ╰──────────── This let-in expression has no entries +───╯ + diff --git a/bin/tests/snapshots/main__empty_pattern.snap b/bin/tests/snapshots/main__empty_pattern.snap new file mode 100644 index 0000000..3ea7ae0 --- /dev/null +++ b/bin/tests/snapshots/main__empty_pattern.snap @@ -0,0 +1,20 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W10] Warning: Found empty pattern in function argument + ╭─[data/empty_pattern.nix:3:4] + │ + 3 │ ({ ... }: 42) + · ───┬─── + · ╰───── This pattern is empty, use _ instead +───╯ +[W11] Warning: Found redundant pattern bind in function argument + ╭─[data/empty_pattern.nix:7:4] + │ + 7 │ ({ ... } @ inputs: inputs) + · ────────┬─────── + · ╰───────── This pattern bind is redundant, use inputs instead +───╯ + diff --git a/bin/tests/snapshots/main__eta_reduction.snap b/bin/tests/snapshots/main__eta_reduction.snap new file mode 100644 index 0000000..6271980 --- /dev/null +++ b/bin/tests/snapshots/main__eta_reduction.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W07] Warning: This function expression is eta reducible + ╭─[data/eta_reduction.nix:11:9] + │ + 11 │ (map (x: double x) xs) + · ─────┬───── + · ╰─────── Found eta-reduction: double +────╯ + diff --git a/bin/tests/snapshots/main__legacy_let_syntax.snap b/bin/tests/snapshots/main__legacy_let_syntax.snap new file mode 100644 index 0000000..35aa7ee --- /dev/null +++ b/bin/tests/snapshots/main__legacy_let_syntax.snap @@ -0,0 +1,14 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W05] Warning: Using undocumented `let` syntax + ╭─[data/legacy_let_syntax.nix:1:1] + │ + 1 │ ╭─▶ let { + 5 │ ├─▶ } + · │ + · ╰─────── Prefer rec over undocumented let syntax +───╯ + diff --git a/bin/tests/snapshots/main__manual_inherit.snap b/bin/tests/snapshots/main__manual_inherit.snap new file mode 100644 index 0000000..063867c --- /dev/null +++ b/bin/tests/snapshots/main__manual_inherit.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W03] Warning: Assignment instead of inherit + ╭─[data/manual_inherit.nix:7:3] + │ + 7 │ a = a; + · ───┬── + · ╰──── This assignment is better written with inherit +───╯ + diff --git a/bin/tests/snapshots/main__manual_inherit_from.snap b/bin/tests/snapshots/main__manual_inherit_from.snap new file mode 100644 index 0000000..9cf1f5d --- /dev/null +++ b/bin/tests/snapshots/main__manual_inherit_from.snap @@ -0,0 +1,20 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W04] Warning: Assignment instead of inherit from + ╭─[data/manual_inherit_from.nix:5:3] + │ + 5 │ b = a.b; + · ────┬─── + · ╰───── This assignment is better written with inherit +───╯ +[W04] Warning: Assignment instead of inherit from + ╭─[data/manual_inherit_from.nix:6:3] + │ + 6 │ c = a.c; + · ────┬─── + · ╰───── This assignment is better written with inherit +───╯ + diff --git a/bin/tests/snapshots/main__redundant_pattern_bind.snap b/bin/tests/snapshots/main__redundant_pattern_bind.snap new file mode 100644 index 0000000..2f26818 --- /dev/null +++ b/bin/tests/snapshots/main__redundant_pattern_bind.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W11] Warning: Found redundant pattern bind in function argument + ╭─[data/redundant_pattern_bind.nix:1:1] + │ + 1 │ { ... } @ inputs: null + · ────────┬──────── + · ╰────────── This pattern bind is redundant, use inputs instead +───╯ + diff --git a/bin/tests/snapshots/main__unquoted_splices.snap b/bin/tests/snapshots/main__unquoted_splices.snap new file mode 100644 index 0000000..5fd1917 --- /dev/null +++ b/bin/tests/snapshots/main__unquoted_splices.snap @@ -0,0 +1,35 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W09] Warning: Found unquoted splice expression + ╭─[data/unquoted_splices.nix:7:3] + │ + 7 │ ${x} + · ──┬─ + · ╰─── Consider quoting this splice expression +───╯ +[W09] Warning: Found unquoted splice expression + ╭─[data/unquoted_splices.nix:8:3] + │ + 8 │ ${toString (x + y)} + · ─────────┬───────── + · ╰─────────── Consider quoting this splice expression +───╯ +[W09] Warning: Found unquoted splice expression + ╭─[data/unquoted_splices.nix:9:5] + │ + 9 │ a.${toString x} + · ──────┬────── + · ╰──────── Consider quoting this splice expression +───╯ +[W09] Warning: Found unquoted splice expression + ╭─[data/unquoted_splices.nix:12:3] + │ + 12 │ ╭─▶ ${ + 14 │ ├─▶ } + · │ + · ╰───────── Consider quoting this splice expression +────╯ + diff --git a/bin/tests/snapshots/main__unquoted_uri.snap b/bin/tests/snapshots/main__unquoted_uri.snap new file mode 100644 index 0000000..2f0e5a9 --- /dev/null +++ b/bin/tests/snapshots/main__unquoted_uri.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W12] Warning: Found unquoted URI expression + ╭─[data/unquoted_uri.nix:1:1] + │ + 1 │ github:nerdypepper/statix + · ────────────┬──────────── + · ╰────────────── Consider quoting this URI expression +───╯ + diff --git a/bin/tests/snapshots/main__useless_parens.snap b/bin/tests/snapshots/main__useless_parens.snap new file mode 100644 index 0000000..d44176e --- /dev/null +++ b/bin/tests/snapshots/main__useless_parens.snap @@ -0,0 +1,48 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:16:3] + │ + 16 │ (null) + · ───┬── + · ╰──── Useless parentheses around body of let expression +────╯ +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:4:9] + │ + 4 │ b = ("hello"); + · ────┬──── + · ╰────── Useless parentheses around value in binding +───╯ +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:5:9] + │ + 5 │ c = (d); + · ─┬─ + · ╰─── Useless parentheses around value in binding +───╯ +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:6:9] + │ + 6 │ e = ({ f = 2; }); + · ──────┬───── + · ╰─────── Useless parentheses around value in binding +───╯ +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:10:7] + │ + 10 │ g = (1 + 2); + · ───┬─── + · ╰───── Useless parentheses around value in binding +────╯ +[W08] Warning: These parentheses can be omitted + ╭─[data/useless_parens.nix:11:7] + │ + 11 │ h = ({ inherit i; }); + · ────────┬─────── + · ╰───────── Useless parentheses around value in binding +────╯ + diff --git a/flake.nix b/flake.nix index 3b9d011..b166817 100644 --- a/flake.nix +++ b/flake.nix @@ -93,11 +93,12 @@ "clippy" "rust-src" ]; + inherit (fenix.packages."${system}") rust-analyzer; in - with pkgs; - mkShell rec { + pkgs.mkShell { nativeBuildInputs = [ - cargo-watch + pkgs.cargo-watch + pkgs.cargo-insta rust-analyzer toolchain ]; diff --git a/lib/src/lints/useless_parens.rs b/lib/src/lints/useless_parens.rs index 45d80ae..dccc717 100644 --- a/lib/src/lints/useless_parens.rs +++ b/lib/src/lints/useless_parens.rs @@ -3,7 +3,7 @@ use crate::{Diagnostic, Metadata, Report, Rule, Suggestion}; use if_chain::if_chain; use macros::lint; use rnix::{ - types::{KeyValue, Paren, ParsedType, TypedNode, Wrapper}, + types::{KeyValue, LetIn, Paren, ParsedType, TypedNode, Wrapper}, NodeOrToken, SyntaxElement, SyntaxKind, }; @@ -71,7 +71,7 @@ fn do_thing(parsed_type_node: ParsedType) -> Option { if let Some(inner) = value_in_parens.inner(); then { let at = value_range; - let message = "Useless parentheses around value in `let` binding"; + let message = "Useless parentheses around value in binding"; let replacement = inner; Some(Diagnostic::suggest(at, message, Suggestion::new(at, replacement))) } else { @@ -98,7 +98,11 @@ fn do_thing(parsed_type_node: ParsedType) -> Option { // ensure that we don't lint inside let-in statements // we already lint such cases in previous match stmt - if KeyValue::cast(father_node).is_none(); + if KeyValue::cast(father_node.clone()).is_none(); + + // ensure that we don't lint inside let-bodies + // if this primitive is a let-body, we have already linted it + if LetIn::cast(father_node).is_none(); if let Some(inner_node) = paren_expr.inner(); if let Some(parsed_inner) = ParsedType::cast(inner_node); diff --git a/vfs/src/lib.rs b/vfs/src/lib.rs index 8b5df79..cd6cc03 100644 --- a/vfs/src/lib.rs +++ b/vfs/src/lib.rs @@ -7,7 +7,7 @@ use std::{ use indexmap::IndexSet; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] -pub struct FileId(u32); +pub struct FileId(pub u32); #[derive(Debug, Default)] pub struct Interner { -- cgit v1.2.3