Skip to content

Commit 3a4c16c

Browse files
committed
Optimizing the code and modify the error message
1 parent 1ac33ad commit 3a4c16c

File tree

5 files changed

+260
-157
lines changed

5 files changed

+260
-157
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ extern crate rustc_session;
5555
extern crate rustc_span;
5656
extern crate rustc_target;
5757
extern crate rustc_trait_selection;
58+
extern crate smallvec;
5859
extern crate thin_vec;
5960

6061
#[macro_use]
Lines changed: 32 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_utils::consts::{ConstEvalCtxt, Constant};
2-
use clippy_utils::diagnostics::span_lint_and_sugg;
3-
use clippy_utils::source::snippet;
2+
use clippy_utils::diagnostics::span_lint_and_then;
43
use rustc_errors::Applicability;
54
use rustc_hir::{Expr, ExprKind, QPath, Ty, TyKind};
65
use rustc_lint::LateContext;
76
use rustc_span::sym;
7+
use smallvec::SmallVec;
88

99
use super::IP_CONSTANT;
1010

@@ -16,109 +16,37 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
1616
},
1717
p,
1818
)) = func.kind
19-
&& p.ident.as_str() == "new"
19+
&& p.ident.name == sym::new
2020
&& let Some(func_def_id) = func_path.res.opt_def_id()
21-
&& (cx.tcx.is_diagnostic_item(sym::Ipv4Addr, func_def_id)
22-
|| cx.tcx.is_diagnostic_item(sym::Ipv6Addr, func_def_id))
23-
&& let Some(constant_name) = is_ipaddr_constants(cx, args)
21+
&& matches!(
22+
cx.tcx.get_diagnostic_name(func_def_id),
23+
Some(sym::Ipv4Addr | sym::Ipv6Addr)
24+
)
25+
&& let Some(args) = args
26+
.iter()
27+
.map(|arg| {
28+
if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) {
29+
u8::try_from(constant).ok()
30+
} else {
31+
None
32+
}
33+
})
34+
.collect::<Option<SmallVec<[u8; 8]>>>()
2435
{
25-
let sugg_snip = format!(
26-
"{}::{}",
27-
snippet(cx, func_path.span, cx.tcx.def_path_str(func_def_id).as_str()),
28-
constant_name
29-
);
30-
31-
span_lint_and_sugg(
32-
cx,
33-
IP_CONSTANT,
34-
expr.span,
35-
format!("use `{sugg_snip}` instead"),
36-
"try",
37-
sugg_snip,
38-
Applicability::MachineApplicable,
39-
);
36+
let constant_name = match args.as_slice() {
37+
[0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0] => "UNSPECIFIED",
38+
[127, 0, 0, 1] | [0, 0, 0, 0, 0, 0, 0, 1] => "LOCALHOST",
39+
[255, 255, 255, 255] => "BROADCAST",
40+
_ => return,
41+
};
42+
43+
span_lint_and_then(cx, IP_CONSTANT, expr.span, "hand-coded well-known IP address", |diag| {
44+
diag.span_suggestion_verbose(
45+
expr.span.with_lo(p.ident.span.lo()),
46+
"use",
47+
constant_name,
48+
Applicability::MachineApplicable,
49+
);
50+
});
4051
}
4152
}
42-
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> {
100-
if args.len() != 4 && args.len() != 8 {
101-
return None;
102-
}
103-
104-
// Extract integer constants from arguments
105-
let mut constants = Vec::new();
106-
for arg in args {
107-
if let Some(Constant::Int(constant)) = ConstEvalCtxt::new(cx).eval(arg) {
108-
constants.push(constant);
109-
} else {
110-
return None;
111-
}
112-
}
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
120-
}
121-
}
122-
123-
current_node.constant_name
124-
}

0 commit comments

Comments
 (0)