1
1
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;
4
3
use rustc_errors:: Applicability ;
5
4
use rustc_hir:: { Expr , ExprKind , QPath , Ty , TyKind } ;
6
5
use rustc_lint:: LateContext ;
7
6
use rustc_span:: sym;
7
+ use smallvec:: SmallVec ;
8
8
9
9
use super :: IP_CONSTANT ;
10
10
@@ -16,109 +16,37 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
16
16
} ,
17
17
p,
18
18
) ) = func. kind
19
- && p. ident . as_str ( ) == " new"
19
+ && p. ident . name == sym :: new
20
20
&& 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 ] > > > ( )
24
35
{
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
+ } ) ;
40
51
}
41
52
}
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