Skip to content

Commit 093d4d1

Browse files
committed
new lint null_pointer_optimization
1 parent 588c1ab commit 093d4d1

File tree

6 files changed

+167
-0
lines changed

6 files changed

+167
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5120,6 +5120,7 @@ Released 2018-09-13
51205120
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
51215121
[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
51225122
[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
5123+
[`null_pointer_optimization`]: https://rust-lang.github.io/rust-clippy/master/index.html#null_pointer_optimization
51235124
[`obfuscated_if_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#obfuscated_if_else
51245125
[`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes
51255126
[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
501501
crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
502502
crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
503503
crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
504+
crate::null_pointer_optimization::NULL_POINTER_OPTIMIZATION_INFO,
504505
crate::octal_escapes::OCTAL_ESCAPES_INFO,
505506
crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
506507
crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ mod non_expressive_names;
246246
mod non_octal_unix_permissions;
247247
mod non_send_fields_in_send_ty;
248248
mod nonstandard_macro_braces;
249+
mod null_pointer_optimization;
249250
mod octal_escapes;
250251
mod only_used_in_recursion;
251252
mod operators;
@@ -1070,6 +1071,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10701071
Box::new(single_call_fn::SingleCallFn {
10711072
avoid_breaking_exported_api,
10721073
def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
1074+
store.register_late_pass(move |_| {
1075+
Box::new(null_pointer_optimization::NullPointerOptimization {
1076+
avoid_breaking_exported_api,
10731077
})
10741078
});
10751079
let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_strings;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use clippy_utils::{diagnostics::span_lint_and_help, is_lang_item_or_ctor, last_path_segment, match_def_path, paths};
2+
use rustc_hir::{
3+
def::{DefKind, Res},
4+
GenericArg, LangItem, Ty, TyKind,
5+
};
6+
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_session::{declare_tool_lint, impl_lint_pass};
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
/// Checks for `T<Option<U>>` where `T` is a type that has
12+
/// [null pointer optimization](https://doc.rust-lang.org/core/option/#representation).
13+
///
14+
/// ### Why is this bad?
15+
/// It's slower, as `Option` can use `null` as `None`, instead of adding another layer of
16+
/// indirection.
17+
///
18+
/// ### Example
19+
/// ```rust
20+
/// struct MyWrapperType<T>(Box<Option<T>>);
21+
/// ```
22+
/// Use instead:
23+
/// ```rust
24+
/// struct MyWrapperType<T>(Option<Box<T>>);
25+
/// ```
26+
#[clippy::version = "1.72.0"]
27+
pub NULL_POINTER_OPTIMIZATION,
28+
perf,
29+
"checks for `U<Option<T>>` where `U` is a type that has null pointer optimization"
30+
}
31+
impl_lint_pass!(NullPointerOptimization => [NULL_POINTER_OPTIMIZATION]);
32+
33+
#[derive(Clone, Copy)]
34+
pub struct NullPointerOptimization {
35+
pub avoid_breaking_exported_api: bool,
36+
}
37+
38+
impl LateLintPass<'_> for NullPointerOptimization {
39+
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
40+
if let TyKind::Path(qpath) = ty.kind
41+
&& let res = cx.qpath_res(&qpath, ty.hir_id)
42+
&& let Res::Def(DefKind::Struct, def_id) = res
43+
{
44+
if !(is_lang_item_or_ctor(cx, def_id, LangItem::OwnedBox)
45+
|| match_def_path(cx, def_id, &paths::PTR_NON_NULL))
46+
{
47+
return;
48+
}
49+
50+
if let Some(args) = last_path_segment(&qpath).args
51+
&& let GenericArg::Type(option_ty) = args.args[0]
52+
&& let TyKind::Path(option_qpath) = option_ty.kind
53+
&& let res = cx.qpath_res(&option_qpath, option_ty.hir_id)
54+
&& let Res::Def(.., def_id) = res
55+
&& is_lang_item_or_ctor(cx, def_id, LangItem::Option)
56+
{
57+
let outer_ty = last_path_segment(&qpath).ident.name;
58+
span_lint_and_help(
59+
cx,
60+
NULL_POINTER_OPTIMIZATION,
61+
ty.span,
62+
&format!("usage of `{outer_ty}<Option<T>>`"),
63+
None,
64+
&format!("consider using `Option<{outer_ty}<T>>` instead, as it will grant better performance. For more information, see\n\
65+
https://doc.rust-lang.org/core/option/#representation"),
66+
);
67+
}
68+
}
69+
}
70+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(clippy::boxed_local, unused)]
2+
#![warn(clippy::null_pointer_optimization)]
3+
#![no_main]
4+
5+
use std::ptr::NonNull;
6+
7+
type A<T> = Box<Option<T>>;
8+
9+
fn a<T>(a: Box<Option<T>>) {}
10+
11+
// lint at `type A<T>`, but not here.
12+
fn a_ty_alias<T>(a: A<T>) {}
13+
14+
fn b(b: String) {}
15+
16+
fn c<T>(c: NonNull<Option<T>>) {}
17+
18+
fn g<T>(e: Option<Box<Option<T>>>) {}
19+
20+
struct H<T>(Box<Option<T>>);
21+
22+
enum I<T> {
23+
J(Box<Option<T>>),
24+
}
25+
26+
// do not lint
27+
28+
struct D<T>(Option<T>);
29+
30+
fn d<T>(d: D<T>) {}
31+
32+
fn e<T>(e: Option<NonNull<T>>) {}
33+
34+
fn f<T>(e: Option<Box<T>>) {}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
error: usage of `Box<Option<T>>`
2+
--> $DIR/null_pointer_optimization.rs:7:13
3+
|
4+
LL | type A<T> = Box<Option<T>>;
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= help: consider using `Option<Box<T>>` instead, as it will grant better performance. For more information, see
8+
https://doc.rust-lang.org/core/option/#representation
9+
= note: `-D clippy::null-pointer-optimization` implied by `-D warnings`
10+
11+
error: usage of `Box<Option<T>>`
12+
--> $DIR/null_pointer_optimization.rs:9:12
13+
|
14+
LL | fn a<T>(a: Box<Option<T>>) {}
15+
| ^^^^^^^^^^^^^^
16+
|
17+
= help: consider using `Option<Box<T>>` instead, as it will grant better performance. For more information, see
18+
https://doc.rust-lang.org/core/option/#representation
19+
20+
error: usage of `NonNull<Option<T>>`
21+
--> $DIR/null_pointer_optimization.rs:16:12
22+
|
23+
LL | fn c<T>(c: NonNull<Option<T>>) {}
24+
| ^^^^^^^^^^^^^^^^^^
25+
|
26+
= help: consider using `Option<NonNull<T>>` instead, as it will grant better performance. For more information, see
27+
https://doc.rust-lang.org/core/option/#representation
28+
29+
error: usage of `Box<Option<T>>`
30+
--> $DIR/null_pointer_optimization.rs:18:19
31+
|
32+
LL | fn g<T>(e: Option<Box<Option<T>>>) {}
33+
| ^^^^^^^^^^^^^^
34+
|
35+
= help: consider using `Option<Box<T>>` instead, as it will grant better performance. For more information, see
36+
https://doc.rust-lang.org/core/option/#representation
37+
38+
error: usage of `Box<Option<T>>`
39+
--> $DIR/null_pointer_optimization.rs:20:13
40+
|
41+
LL | struct H<T>(Box<Option<T>>);
42+
| ^^^^^^^^^^^^^^
43+
|
44+
= help: consider using `Option<Box<T>>` instead, as it will grant better performance. For more information, see
45+
https://doc.rust-lang.org/core/option/#representation
46+
47+
error: usage of `Box<Option<T>>`
48+
--> $DIR/null_pointer_optimization.rs:23:7
49+
|
50+
LL | J(Box<Option<T>>),
51+
| ^^^^^^^^^^^^^^
52+
|
53+
= help: consider using `Option<Box<T>>` instead, as it will grant better performance. For more information, see
54+
https://doc.rust-lang.org/core/option/#representation
55+
56+
error: aborting due to 6 previous errors
57+

0 commit comments

Comments
 (0)