Skip to content

Commit f0c88b1

Browse files
committed
Use tree-based structure matching instead of loop
1 parent 8e20f97 commit f0c88b1

File tree

5 files changed

+125
-30
lines changed

5 files changed

+125
-30
lines changed

clippy_lints/src/methods/ip_constant.rs

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@ use rustc_span::sym;
88

99
use super::IP_CONSTANT;
1010

11-
static IPV4V6_CONSTANTS: &[(&[u128], &str)] = &[
12-
// Ipv4
13-
(&[127, 0, 0, 1], "LOCALHOST"),
14-
(&[255, 255, 255, 255], "BROADCAST"),
15-
(&[0, 0, 0, 0], "UNSPECIFIED"),
16-
// Ipv6
17-
(&[0, 0, 0, 0, 0, 0, 0, 1], "LOCALHOST"),
18-
(&[0, 0, 0, 0, 0, 0, 0, 0], "UNSPECIFIED"),
19-
];
20-
2111
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) {
2212
if let ExprKind::Path(QPath::TypeRelative(
2313
Ty {
@@ -30,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
3020
&& let Some(func_def_id) = func_path.res.opt_def_id()
3121
&& (cx.tcx.is_diagnostic_item(sym::Ipv4Addr, func_def_id)
3222
|| cx.tcx.is_diagnostic_item(sym::Ipv6Addr, func_def_id))
33-
&& let Some(constant_name) = is_ipv4v6_constants(cx, args)
23+
&& let Some(constant_name) = is_ipaddr_constants(cx, args)
3424
{
3525
let sugg_snip = format!(
3626
"{}::{}",
@@ -50,7 +40,63 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
5040
}
5141
}
5242

53-
fn is_ipv4v6_constants(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<&'static str> {
43+
struct Node {
44+
children: &'static [(u128, Node)],
45+
constant_name: Option<&'static str>,
46+
}
47+
48+
impl Node {
49+
const fn new(children: &'static [(u128, Node)], constant_name: Option<&'static str>) -> Self {
50+
Self {
51+
children,
52+
constant_name,
53+
}
54+
}
55+
56+
const fn leaf(constant_name: &'static str) -> Self {
57+
Self {
58+
children: &[],
59+
constant_name: Some(constant_name),
60+
}
61+
}
62+
}
63+
64+
// Tree structure for IP constants
65+
#[rustfmt::skip]
66+
static IPADDR_CONSTANTS_TREE: Node = Node::new(&[
67+
(127, Node::new(&[
68+
(0, Node::new(&[
69+
(0, Node::new(&[
70+
(1, Node::leaf("LOCALHOST")) // IPv4 127.0.0.1
71+
], None))
72+
], None))
73+
], None)),
74+
(255, Node::new(&[
75+
(255, Node::new(&[
76+
(255, Node::new(&[
77+
(255, Node::leaf("BROADCAST")) // IPv4 255.255.255.255
78+
], None))
79+
], None))
80+
], None)),
81+
(0, Node::new(&[
82+
(0, Node::new(&[
83+
(0, Node::new(&[
84+
(0, Node::new(&[
85+
(0, Node::new(&[
86+
(0, Node::new(&[
87+
(0, Node::new(&[
88+
(0, Node::leaf("UNSPECIFIED")), // IPv6 ::
89+
(1, Node::leaf("LOCALHOST")) // IPv6 ::1
90+
], None))
91+
], None))
92+
], None))
93+
], Some("UNSPECIFIED"))) // IPv4 0.0.0.0
94+
], None))
95+
], None))
96+
], None)),
97+
], None);
98+
99+
fn is_ipaddr_constants(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<&'static str> {
54100
if args.len() != 4 && args.len() != 8 {
55101
return None;
56102
}
@@ -64,12 +110,15 @@ fn is_ipv4v6_constants(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<&'stat
64110
return None;
65111
}
66112
}
67-
// Check against known IP constants
68-
for (pattern, name) in IPV4V6_CONSTANTS {
69-
if pattern.len() == constants.len() && pattern.iter().eq(constants.iter()) {
70-
return Some(name);
113+
114+
let mut current_node = &IPADDR_CONSTANTS_TREE;
115+
for value in constants {
116+
if let Some((_, next_node)) = current_node.children.iter().find(|(val, _)| *val == value) {
117+
current_node = next_node;
118+
} else {
119+
return None; // Early termination on mismatch
71120
}
72121
}
73122

74-
None
123+
current_node.constant_name
75124
}

tests/ui/ip_constant.fixed

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,17 @@ fn macro_test() {
102102
// no lint
103103
}
104104

105+
include!("ip_constant_included.rs");
106+
107+
fn external_constant_test() {
108+
use std::net::{Ipv4Addr, Ipv6Addr};
109+
110+
let _ = Ipv4Addr::LOCALHOST;
111+
//~^ ip_constant
112+
113+
let _ = Ipv6Addr::LOCALHOST;
114+
}
115+
105116
fn main() {
106-
literal_test1();
107-
literal_test2();
108-
literal_test3();
109-
const_test1();
110-
const_test2();
111-
macro_test();
117+
// UI Test
112118
}

tests/ui/ip_constant.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,27 @@ fn macro_test() {
122122
// no lint
123123
}
124124

125+
include!("ip_constant_included.rs");
126+
127+
fn external_constant_test() {
128+
use std::net::{Ipv4Addr, Ipv6Addr};
129+
130+
let _ = Ipv4Addr::new(EXTERNAL_CONST_U8_127, 0, 0, 1);
131+
//~^ ip_constant
132+
133+
let _ = Ipv6Addr::new(
134+
//~^ ip_constant
135+
EXTERNAL_CONST_U16_0,
136+
0,
137+
0,
138+
0,
139+
0,
140+
0,
141+
0,
142+
1,
143+
);
144+
}
145+
125146
fn main() {
126-
literal_test1();
127-
literal_test2();
128-
literal_test3();
129-
const_test1();
130-
const_test2();
131-
macro_test();
147+
// UI Test
132148
}

tests/ui/ip_constant.stderr

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,24 @@ error: use `Ipv6Addr::LOCALHOST` instead
165165
LL | let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1);
166166
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv6Addr::LOCALHOST`
167167

168-
error: aborting due to 25 previous errors
168+
error: use `Ipv4Addr::LOCALHOST` instead
169+
--> tests/ui/ip_constant.rs:130:13
170+
|
171+
LL | let _ = Ipv4Addr::new(EXTERNAL_CONST_U8_127, 0, 0, 1);
172+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
173+
174+
error: use `Ipv6Addr::LOCALHOST` instead
175+
--> tests/ui/ip_constant.rs:133:13
176+
|
177+
LL | let _ = Ipv6Addr::new(
178+
| _____________^
179+
LL | |
180+
LL | | EXTERNAL_CONST_U16_0,
181+
LL | | 0,
182+
... |
183+
LL | | 1,
184+
LL | | );
185+
| |_____^ help: try: `Ipv6Addr::LOCALHOST`
186+
187+
error: aborting due to 27 previous errors
169188

tests/ui/ip_constant_included.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//@only-target: NOWAY
2+
3+
const EXTERNAL_CONST_U8_127: u8 = 127;
4+
5+
const EXTERNAL_CONST_U16_0: u16 = 0;

0 commit comments

Comments
 (0)