diff options
author | Akshay <[email protected]> | 2021-09-13 17:50:25 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-09-13 17:50:25 +0100 |
commit | 4152367f5dee2a70ff49f4aff4040d5d433b8e44 (patch) | |
tree | fea606b3121702ae2f714f51697135e3c7b9a9ee | |
parent | 7a3c3822ba4a368b0475bc5de89ced78fa8b3cb5 (diff) |
add demo lint: bool_comparison
-rw-r--r-- | Cargo.lock | 179 | ||||
-rw-r--r-- | lib/Cargo.toml | 4 | ||||
-rw-r--r-- | lib/src/lib.rs | 50 | ||||
-rw-r--r-- | lib/src/lints.rs | 2 | ||||
-rw-r--r-- | lib/src/lints/bool_comparison.rs | 78 |
5 files changed, 308 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..73188a4 --- /dev/null +++ b/Cargo.lock | |||
@@ -0,0 +1,179 @@ | |||
1 | # This file is automatically @generated by Cargo. | ||
2 | # It is not intended for manual editing. | ||
3 | version = 3 | ||
4 | |||
5 | [[package]] | ||
6 | name = "ariadne" | ||
7 | version = "0.1.3" | ||
8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
9 | checksum = "7080ae01b2f0c312065d4914cd0f0de045eb8832e9415b355106a6cff3073cb4" | ||
10 | dependencies = [ | ||
11 | "yansi", | ||
12 | ] | ||
13 | |||
14 | [[package]] | ||
15 | name = "autocfg" | ||
16 | version = "1.0.1" | ||
17 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
18 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" | ||
19 | |||
20 | [[package]] | ||
21 | name = "bin" | ||
22 | version = "0.1.0" | ||
23 | dependencies = [ | ||
24 | "ariadne", | ||
25 | "lib", | ||
26 | ] | ||
27 | |||
28 | [[package]] | ||
29 | name = "cbitset" | ||
30 | version = "0.2.0" | ||
31 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
32 | checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b" | ||
33 | dependencies = [ | ||
34 | "num-traits", | ||
35 | ] | ||
36 | |||
37 | [[package]] | ||
38 | name = "countme" | ||
39 | version = "2.0.4" | ||
40 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
41 | checksum = "328b822bdcba4d4e402be8d9adb6eebf269f969f8eadef977a553ff3c4fbcb58" | ||
42 | |||
43 | [[package]] | ||
44 | name = "hashbrown" | ||
45 | version = "0.9.1" | ||
46 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
47 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" | ||
48 | |||
49 | [[package]] | ||
50 | name = "if_chain" | ||
51 | version = "1.0.2" | ||
52 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
53 | checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" | ||
54 | |||
55 | [[package]] | ||
56 | name = "lazy_static" | ||
57 | version = "1.4.0" | ||
58 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
59 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||
60 | |||
61 | [[package]] | ||
62 | name = "lib" | ||
63 | version = "0.1.0" | ||
64 | dependencies = [ | ||
65 | "if_chain", | ||
66 | "lazy_static", | ||
67 | "macros", | ||
68 | "rnix", | ||
69 | ] | ||
70 | |||
71 | [[package]] | ||
72 | name = "macros" | ||
73 | version = "0.1.0" | ||
74 | dependencies = [ | ||
75 | "proc-macro2", | ||
76 | "quote", | ||
77 | "syn", | ||
78 | ] | ||
79 | |||
80 | [[package]] | ||
81 | name = "memoffset" | ||
82 | version = "0.6.4" | ||
83 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
84 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" | ||
85 | dependencies = [ | ||
86 | "autocfg", | ||
87 | ] | ||
88 | |||
89 | [[package]] | ||
90 | name = "num-traits" | ||
91 | version = "0.2.14" | ||
92 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
93 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" | ||
94 | dependencies = [ | ||
95 | "autocfg", | ||
96 | ] | ||
97 | |||
98 | [[package]] | ||
99 | name = "proc-macro2" | ||
100 | version = "1.0.29" | ||
101 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
102 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" | ||
103 | dependencies = [ | ||
104 | "unicode-xid", | ||
105 | ] | ||
106 | |||
107 | [[package]] | ||
108 | name = "quote" | ||
109 | version = "1.0.9" | ||
110 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
111 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" | ||
112 | dependencies = [ | ||
113 | "proc-macro2", | ||
114 | ] | ||
115 | |||
116 | [[package]] | ||
117 | name = "rnix" | ||
118 | version = "0.9.0" | ||
119 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
120 | checksum = "1b37f8af07a0354606141df076458660af7e22238e4117a041c21c548080addd" | ||
121 | dependencies = [ | ||
122 | "cbitset", | ||
123 | "rowan", | ||
124 | "smol_str", | ||
125 | ] | ||
126 | |||
127 | [[package]] | ||
128 | name = "rowan" | ||
129 | version = "0.12.6" | ||
130 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
131 | checksum = "a1b36e449f3702f3b0c821411db1cbdf30fb451726a9456dce5dabcd44420043" | ||
132 | dependencies = [ | ||
133 | "countme", | ||
134 | "hashbrown", | ||
135 | "memoffset", | ||
136 | "rustc-hash", | ||
137 | "text-size", | ||
138 | ] | ||
139 | |||
140 | [[package]] | ||
141 | name = "rustc-hash" | ||
142 | version = "1.1.0" | ||
143 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
144 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | ||
145 | |||
146 | [[package]] | ||
147 | name = "smol_str" | ||
148 | version = "0.1.18" | ||
149 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
150 | checksum = "b203e79e90905594272c1c97c7af701533d42adaab0beb3859018e477d54a3b0" | ||
151 | |||
152 | [[package]] | ||
153 | name = "syn" | ||
154 | version = "1.0.76" | ||
155 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
156 | checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" | ||
157 | dependencies = [ | ||
158 | "proc-macro2", | ||
159 | "quote", | ||
160 | "unicode-xid", | ||
161 | ] | ||
162 | |||
163 | [[package]] | ||
164 | name = "text-size" | ||
165 | version = "1.1.0" | ||
166 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
167 | checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" | ||
168 | |||
169 | [[package]] | ||
170 | name = "unicode-xid" | ||
171 | version = "0.2.2" | ||
172 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
173 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" | ||
174 | |||
175 | [[package]] | ||
176 | name = "yansi" | ||
177 | version = "0.5.0" | ||
178 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
179 | checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" | ||
diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 49e2e49..e371c5d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml | |||
@@ -6,3 +6,7 @@ edition = "2018" | |||
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
7 | 7 | ||
8 | [dependencies] | 8 | [dependencies] |
9 | rnix = "0.9.0" | ||
10 | if_chain = "1.0" | ||
11 | macros = { path = "../macros" } | ||
12 | lazy_static = "1.0" | ||
diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 31e1bb2..537f4b3 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs | |||
@@ -1,7 +1,47 @@ | |||
1 | #[cfg(test)] | 1 | pub mod lints; |
2 | mod tests { | 2 | |
3 | #[test] | 3 | use rnix::{SyntaxElement, SyntaxKind, TextRange}; |
4 | fn it_works() { | 4 | use std::ops::Deref; |
5 | assert_eq!(2 + 2, 4); | 5 | |
6 | pub trait Rule { | ||
7 | fn validate(&self, node: &SyntaxElement) -> Option<Diagnostic>; | ||
8 | } | ||
9 | |||
10 | #[derive(Debug)] | ||
11 | pub struct Diagnostic { | ||
12 | pub at: TextRange, | ||
13 | pub message: String, | ||
14 | } | ||
15 | |||
16 | impl Diagnostic { | ||
17 | pub fn new(at: TextRange, message: String) -> Self { | ||
18 | Self { at, message } | ||
6 | } | 19 | } |
7 | } | 20 | } |
21 | |||
22 | pub trait Metadata { | ||
23 | fn name(&self) -> &str; | ||
24 | fn note(&self) -> &str; | ||
25 | fn match_with(&self, with: &SyntaxKind) -> bool; | ||
26 | } | ||
27 | |||
28 | pub trait Lint: Metadata + Rule + Send + Sync {} | ||
29 | |||
30 | // #[macro_export] | ||
31 | // macro_rules! lint_map { | ||
32 | // ($($s:ident),*,) => { | ||
33 | // lint_map($($s),*); | ||
34 | // } | ||
35 | // ($($s:ident),*) => { | ||
36 | // use ::std::collections::HashMap; | ||
37 | // use rnix::SyntaxKind; | ||
38 | // $( | ||
39 | // mod $s; | ||
40 | // )* | ||
41 | // ::lazy_static::lazy_static! { | ||
42 | // pub static ref RULES: HashMap<SyntaxKind, &'static Box<dyn $crate::Lint>> = { | ||
43 | // vec![$(&*$s::LINT,)*] | ||
44 | // } | ||
45 | // } | ||
46 | // } | ||
47 | // } | ||
diff --git a/lib/src/lints.rs b/lib/src/lints.rs new file mode 100644 index 0000000..b0df71b --- /dev/null +++ b/lib/src/lints.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | pub mod bool_comparison; | ||
2 | pub mod with_list; | ||
diff --git a/lib/src/lints/bool_comparison.rs b/lib/src/lints/bool_comparison.rs new file mode 100644 index 0000000..4476b31 --- /dev/null +++ b/lib/src/lints/bool_comparison.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | use crate::{Diagnostic, Lint, Metadata, Rule}; | ||
2 | |||
3 | use if_chain::if_chain; | ||
4 | use macros::lint; | ||
5 | use rnix::{ | ||
6 | types::{BinOp, BinOpKind, Ident, TokenWrapper, TypedNode}, | ||
7 | NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, | ||
8 | }; | ||
9 | |||
10 | #[lint( | ||
11 | name = "bool_comparison", | ||
12 | note = "Unnecessary comparison with boolean", | ||
13 | match_with = "SyntaxKind::NODE_BIN_OP" | ||
14 | )] | ||
15 | struct BoolComparison; | ||
16 | |||
17 | impl Rule for BoolComparison { | ||
18 | fn validate(&self, node: &SyntaxElement) -> Option<Diagnostic> { | ||
19 | if_chain! { | ||
20 | if let NodeOrToken::Node(bin_op_node) = node; | ||
21 | if let Some(bin_expr) = BinOp::cast(bin_op_node.clone()); | ||
22 | if let Some(lhs) = bin_expr.lhs(); | ||
23 | if let Some(rhs) = bin_expr.rhs(); | ||
24 | |||
25 | if let BinOpKind::Equal | BinOpKind::NotEqual = bin_expr.operator(); | ||
26 | let (non_bool_side, bool_side) = if is_boolean_ident(&lhs) { | ||
27 | (rhs, lhs) | ||
28 | } else if is_boolean_ident(&rhs) { | ||
29 | (lhs, rhs) | ||
30 | } else { | ||
31 | return None | ||
32 | }; | ||
33 | then { | ||
34 | let at = node.text_range(); | ||
35 | let message = format!( | ||
36 | "Comparing `{}` with boolean literal `{}`", | ||
37 | non_bool_side, | ||
38 | bool_side | ||
39 | ); | ||
40 | dbg!(Some(Diagnostic::new(at, message))) | ||
41 | } else { | ||
42 | None | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // not entirely accurate, underhanded nix programmers might write `true = false` | ||
49 | fn is_boolean_ident(node: &SyntaxNode) -> bool { | ||
50 | if let Some(ident_expr) = Ident::cast(node.clone()) { | ||
51 | ident_expr.as_str() == "true" || ident_expr.as_str() == "false" | ||
52 | } else { | ||
53 | false | ||
54 | } | ||
55 | } | ||
56 | |||
57 | // #[cfg(test)] | ||
58 | // mod tests { | ||
59 | // use super::*; | ||
60 | // use rnix::{parser, WalkEvent}; | ||
61 | // | ||
62 | // #[test] | ||
63 | // fn trivial() { | ||
64 | // let src = r#" | ||
65 | // a == true | ||
66 | // "#; | ||
67 | // let parsed = rnix::parse(src).as_result().ok().unwrap(); | ||
68 | // let _ = parsed | ||
69 | // .node() | ||
70 | // .preorder_with_tokens() | ||
71 | // .filter_map(|event| match event { | ||
72 | // WalkEvent::Enter(t) => Some(t), | ||
73 | // _ => None, | ||
74 | // }) | ||
75 | // .map(|node| BoolComparison.validate(&node)) | ||
76 | // .collect::<Vec<_>>(); | ||
77 | // } | ||
78 | // } | ||