Skip to content

Commit 26af329

Browse files
committed
add new lint: localhost_hardcode
1 parent 5dccb10 commit 26af329

9 files changed

+277
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5937,6 +5937,7 @@ Released 2018-09-13
59375937
[`lint_groups_priority`]: https://rust-lang.github.io/rust-clippy/master/index.html#lint_groups_priority
59385938
[`literal_string_with_formatting_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#literal_string_with_formatting_args
59395939
[`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes
5940+
[`localhost_hardcode`]: https://rust-lang.github.io/rust-clippy/master/index.html#localhost_hardcode
59405941
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
59415942
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
59425943
[`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
260260
crate::literal_representation::UNREADABLE_LITERAL_INFO,
261261
crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
262262
crate::literal_string_with_formatting_args::LITERAL_STRING_WITH_FORMATTING_ARGS_INFO,
263+
crate::localhost_hardcode::LOCALHOST_HARDCODE_INFO,
263264
crate::loops::CHAR_INDICES_AS_BYTE_INDICES_INFO,
264265
crate::loops::EMPTY_LOOP_INFO,
265266
crate::loops::EXPLICIT_COUNTER_LOOP_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ mod lifetimes;
199199
mod lines_filter_map_ok;
200200
mod literal_representation;
201201
mod literal_string_with_formatting_args;
202+
mod localhost_hardcode;
202203
mod loops;
203204
mod macro_metavars_in_unsafe;
204205
mod macro_use;
@@ -946,5 +947,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
946947
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
947948
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
948949
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
950+
store.register_late_pass(|_| Box::new(localhost_hardcode::LocalhostHardcode));
949951
// add lints here, do not remove this comment, it's used in `new_lint`
950952
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::is_integer_const;
3+
use clippy_utils::source::SpanRangeExt;
4+
use rustc_errors::Applicability;
5+
use rustc_hir::{Expr, ExprKind, QPath};
6+
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_session::declare_lint_pass;
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
/// Detects hardcoded localhost IP addresses using `Ipv4Addr::new(127, 0, 0, 1)`.
12+
///
13+
/// ### Why is this bad?
14+
/// Using a hardcoded IP address `(127.0.0.1)` is less clear and maintainable than using the
15+
/// `Ipv4Addr::LOCALHOST` constant.
16+
///
17+
/// ### Example
18+
/// ```no_run
19+
/// use std::net::Ipv4Addr;
20+
/// let addr = Ipv4Addr::new(127, 0, 0, 1);
21+
/// ```
22+
/// Use instead:
23+
/// ```no_run
24+
/// use std::net::Ipv4Addr;
25+
/// let addr = Ipv4Addr::LOCALHOST;
26+
/// ```
27+
#[clippy::version = "1.89.0"]
28+
pub LOCALHOST_HARDCODE,
29+
style,
30+
"hardcoded localhost IP address"
31+
}
32+
declare_lint_pass!(LocalhostHardcode => [LOCALHOST_HARDCODE]);
33+
34+
fn is_localhost_hardcode(cx: &LateContext<'_>, args: &'_ [Expr<'_>]) -> bool {
35+
if args.len() == 4
36+
&& args.iter().enumerate().all(|(i, arg)| match i {
37+
0 => is_integer_const(cx, arg, 127),
38+
1 | 2 => is_integer_const(cx, arg, 0),
39+
3 => is_integer_const(cx, arg, 1),
40+
_ => false,
41+
})
42+
{
43+
return true;
44+
}
45+
false
46+
}
47+
48+
impl LateLintPass<'_> for LocalhostHardcode {
49+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
50+
// Ignore expressions from macro expansions
51+
if expr.span.from_expansion() {
52+
return;
53+
}
54+
55+
if let ExprKind::Call(func, args) = &expr.kind
56+
&& let ExprKind::Path(qpath) = &func.kind
57+
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
58+
&& "std::net::Ipv4Addr::new" == cx.tcx.def_path_str(def_id)
59+
&& is_localhost_hardcode(cx, args)
60+
// Get source text of the calling relative path for suggestion
61+
&& let QPath::TypeRelative(ty, _) = qpath
62+
&& let Some(ty_span) = ty.span.get_source_range(cx)
63+
&& let Some(ty_text) = ty_span.as_str()
64+
{
65+
let suggestion = format!("{ty_text}::LOCALHOST");
66+
67+
span_lint_and_sugg(
68+
cx,
69+
LOCALHOST_HARDCODE,
70+
expr.span,
71+
format!("use `{suggestion}` instead"),
72+
"try",
73+
suggestion,
74+
Applicability::MachineApplicable,
75+
);
76+
}
77+
}
78+
}

tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::await_holding_invalid_type)]
2+
#![allow(clippy::localhost_hardcode)]
23
use std::net::Ipv4Addr;
34

45
async fn bad() -> u32 {

tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: holding a disallowed type across an await point `std::string::String`
2-
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9
2+
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:6:9
33
|
44
LL | let _x = String::from("hello");
55
| ^^
@@ -9,13 +9,13 @@ LL | let _x = String::from("hello");
99
= help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]`
1010

1111
error: holding a disallowed type across an await point `std::net::Ipv4Addr`
12-
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:11:9
12+
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:12:9
1313
|
1414
LL | let x = Ipv4Addr::new(127, 0, 0, 1);
1515
| ^
1616

1717
error: holding a disallowed type across an await point `std::string::String`
18-
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:35:13
18+
--> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:36:13
1919
|
2020
LL | let _x = String::from("hi!");
2121
| ^^

tests/ui/localhost_hardcode.fixed

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![warn(clippy::localhost_hardcode)]
2+
#![allow(dead_code)]
3+
4+
fn literal_test1() {
5+
use std::net::Ipv4Addr;
6+
let _ = Ipv4Addr::LOCALHOST;
7+
//~^ localhost_hardcode
8+
}
9+
10+
fn literal_test2() {
11+
use std::net;
12+
let _ = net::Ipv4Addr::LOCALHOST;
13+
//~^ localhost_hardcode
14+
}
15+
16+
fn literal_test3() {
17+
let _ = std::net::Ipv4Addr::LOCALHOST;
18+
//~^ localhost_hardcode
19+
}
20+
21+
const CONSTANT_1: u8 = 127;
22+
const CONSTANT_2: u8 = 0;
23+
const CONSTANT_3: u8 = 0;
24+
const CONSTANT_4: u8 = 1;
25+
26+
fn const_test1() {
27+
use std::net::Ipv4Addr;
28+
let _ = Ipv4Addr::LOCALHOST;
29+
//~^ localhost_hardcode
30+
}
31+
32+
fn const_test2() {
33+
use std::net;
34+
let _ = net::Ipv4Addr::LOCALHOST;
35+
//~^ localhost_hardcode
36+
}
37+
38+
fn const_test3() {
39+
let _ = std::net::Ipv4Addr::LOCALHOST;
40+
//~^ localhost_hardcode
41+
}
42+
43+
fn const_test4() {
44+
use std::net::Ipv4Addr;
45+
let _ = Ipv4Addr::LOCALHOST;
46+
//~^ localhost_hardcode
47+
let _ = Ipv4Addr::LOCALHOST;
48+
//~^ localhost_hardcode
49+
let _ = Ipv4Addr::LOCALHOST;
50+
//~^ localhost_hardcode
51+
let _ = Ipv4Addr::LOCALHOST;
52+
//~^ localhost_hardcode
53+
}
54+
55+
fn main() {
56+
literal_test1();
57+
literal_test2();
58+
literal_test3();
59+
const_test1();
60+
const_test2();
61+
const_test3();
62+
const_test4();
63+
}

tests/ui/localhost_hardcode.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![warn(clippy::localhost_hardcode)]
2+
#![allow(dead_code)]
3+
4+
fn literal_test1() {
5+
use std::net::Ipv4Addr;
6+
let _ = Ipv4Addr::new(127, 0, 0, 1);
7+
//~^ localhost_hardcode
8+
}
9+
10+
fn literal_test2() {
11+
use std::net;
12+
let _ = net::Ipv4Addr::new(127, 0, 0, 1);
13+
//~^ localhost_hardcode
14+
}
15+
16+
fn literal_test3() {
17+
let _ = std::net::Ipv4Addr::new(127, 0, 0, 1);
18+
//~^ localhost_hardcode
19+
}
20+
21+
const CONSTANT_1: u8 = 127;
22+
const CONSTANT_2: u8 = 0;
23+
const CONSTANT_3: u8 = 0;
24+
const CONSTANT_4: u8 = 1;
25+
26+
fn const_test1() {
27+
use std::net::Ipv4Addr;
28+
let _ = Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
29+
//~^ localhost_hardcode
30+
}
31+
32+
fn const_test2() {
33+
use std::net;
34+
let _ = net::Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
35+
//~^ localhost_hardcode
36+
}
37+
38+
fn const_test3() {
39+
let _ = std::net::Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
40+
//~^ localhost_hardcode
41+
}
42+
43+
fn const_test4() {
44+
use std::net::Ipv4Addr;
45+
let _ = Ipv4Addr::new(126 + 1, 0, 0, 1);
46+
//~^ localhost_hardcode
47+
let _ = Ipv4Addr::new(126 + CONSTANT_4, 0, 0, 1);
48+
//~^ localhost_hardcode
49+
let _ = Ipv4Addr::new(127, 2 - 1 - CONSTANT_4, 0, 1);
50+
//~^ localhost_hardcode
51+
let _ = Ipv4Addr::new({ 127 }, 0, 0, 1);
52+
//~^ localhost_hardcode
53+
}
54+
55+
fn main() {
56+
literal_test1();
57+
literal_test2();
58+
literal_test3();
59+
const_test1();
60+
const_test2();
61+
const_test3();
62+
const_test4();
63+
}

tests/ui/localhost_hardcode.stderr

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
error: use `Ipv4Addr::LOCALHOST` instead
2+
--> tests/ui/localhost_hardcode.rs:6:13
3+
|
4+
LL | let _ = Ipv4Addr::new(127, 0, 0, 1);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
6+
|
7+
= note: `-D clippy::localhost-hardcode` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::localhost_hardcode)]`
9+
10+
error: use `net::Ipv4Addr::LOCALHOST` instead
11+
--> tests/ui/localhost_hardcode.rs:12:13
12+
|
13+
LL | let _ = net::Ipv4Addr::new(127, 0, 0, 1);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `net::Ipv4Addr::LOCALHOST`
15+
16+
error: use `std::net::Ipv4Addr::LOCALHOST` instead
17+
--> tests/ui/localhost_hardcode.rs:17:13
18+
|
19+
LL | let _ = std::net::Ipv4Addr::new(127, 0, 0, 1);
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::net::Ipv4Addr::LOCALHOST`
21+
22+
error: use `Ipv4Addr::LOCALHOST` instead
23+
--> tests/ui/localhost_hardcode.rs:28:13
24+
|
25+
LL | let _ = Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
27+
28+
error: use `net::Ipv4Addr::LOCALHOST` instead
29+
--> tests/ui/localhost_hardcode.rs:34:13
30+
|
31+
LL | let _ = net::Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `net::Ipv4Addr::LOCALHOST`
33+
34+
error: use `std::net::Ipv4Addr::LOCALHOST` instead
35+
--> tests/ui/localhost_hardcode.rs:39:13
36+
|
37+
LL | let _ = std::net::Ipv4Addr::new(CONSTANT_1, CONSTANT_2, CONSTANT_3, CONSTANT_4);
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::net::Ipv4Addr::LOCALHOST`
39+
40+
error: use `Ipv4Addr::LOCALHOST` instead
41+
--> tests/ui/localhost_hardcode.rs:45:13
42+
|
43+
LL | let _ = Ipv4Addr::new(126 + 1, 0, 0, 1);
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
45+
46+
error: use `Ipv4Addr::LOCALHOST` instead
47+
--> tests/ui/localhost_hardcode.rs:47:13
48+
|
49+
LL | let _ = Ipv4Addr::new(126 + CONSTANT_4, 0, 0, 1);
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
51+
52+
error: use `Ipv4Addr::LOCALHOST` instead
53+
--> tests/ui/localhost_hardcode.rs:49:13
54+
|
55+
LL | let _ = Ipv4Addr::new(127, 2 - 1 - CONSTANT_4, 0, 1);
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
57+
58+
error: use `Ipv4Addr::LOCALHOST` instead
59+
--> tests/ui/localhost_hardcode.rs:51:13
60+
|
61+
LL | let _ = Ipv4Addr::new({ 127 }, 0, 0, 1);
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ipv4Addr::LOCALHOST`
63+
64+
error: aborting due to 10 previous errors
65+

0 commit comments

Comments
 (0)