Skip to content

Commit cf628b1

Browse files
committed
move to types group
1 parent 28f9f53 commit cf628b1

File tree

7 files changed

+98
-86
lines changed

7 files changed

+98
-86
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
9595
* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
9696
* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns)
9797
* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn)
98+
* [`null_pointer_optimization`](https://rust-lang.github.io/rust-clippy/master/index.html#null_pointer_optimization)
9899

99100

100101
## `msrv`

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
485485
crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
486486
crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
487487
crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
488-
crate::null_pointer_optimization::NULL_POINTER_OPTIMIZATION_INFO,
489488
crate::octal_escapes::OCTAL_ESCAPES_INFO,
490489
crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
491490
crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,
@@ -625,6 +624,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
625624
crate::types::BORROWED_BOX_INFO,
626625
crate::types::BOX_COLLECTION_INFO,
627626
crate::types::LINKEDLIST_INFO,
627+
crate::types::NULL_POINTER_OPTIMIZATION_INFO,
628628
crate::types::OPTION_OPTION_INFO,
629629
crate::types::RC_BUFFER_INFO,
630630
crate::types::RC_MUTEX_INFO,

clippy_lints/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ mod non_expressive_names;
242242
mod non_octal_unix_permissions;
243243
mod non_send_fields_in_send_ty;
244244
mod nonstandard_macro_braces;
245-
mod null_pointer_optimization;
246245
mod octal_escapes;
247246
mod only_used_in_recursion;
248247
mod operators;
@@ -1061,9 +1060,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10611060
Box::new(single_call_fn::SingleCallFn {
10621061
avoid_breaking_exported_api,
10631062
def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
1064-
store.register_late_pass(move |_| {
1065-
Box::new(null_pointer_optimization::NullPointerOptimization {
1066-
avoid_breaking_exported_api,
10671063
})
10681064
});
10691065
// add lints here, do not remove this comment, it's used in `new_lint`

clippy_lints/src/null_pointer_optimization.rs

Lines changed: 0 additions & 70 deletions
This file was deleted.

clippy_lints/src/types/mod.rs

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod borrowed_box;
22
mod box_collection;
33
mod linked_list;
4+
mod null_pointer_optimization;
45
mod option_option;
56
mod rc_buffer;
67
mod rc_mutex;
@@ -303,13 +304,50 @@ declare_clippy_lint! {
303304
"usage of `Rc<Mutex<T>>`"
304305
}
305306

307+
declare_clippy_lint! {
308+
/// ### What it does
309+
/// Checks for `C<Option<T>>` where `C` is a type that has
310+
/// [null pointer optimization](https://doc.rust-lang.org/core/option/#representation).
311+
///
312+
/// Note: There are some cases where `C<Option<T>>` is necessary, like getting a
313+
/// `&mut Option<T>` from a `Box<Option<T>>`. This is not possible with `Option<Box<T>>` without
314+
/// unstable features, currently.
315+
///
316+
/// ### Why is this bad?
317+
/// It's slower, as `Option` can use `null` as `None`, instead of adding another layer of
318+
/// indirection.
319+
///
320+
/// ### Example
321+
/// ```rust
322+
/// struct MyWrapperType<T>(Box<Option<T>>);
323+
/// ```
324+
/// Use instead:
325+
/// ```rust
326+
/// struct MyWrapperType<T>(Option<Box<T>>);
327+
/// ```
328+
#[clippy::version = "1.72.0"]
329+
pub NULL_POINTER_OPTIMIZATION,
330+
perf,
331+
"checks for `C<Option<T>>` where `C` is a type that has null pointer optimization"
332+
}
306333
pub struct Types {
307334
vec_box_size_threshold: u64,
308335
type_complexity_threshold: u64,
309336
avoid_breaking_exported_api: bool,
310337
}
311338

312-
impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
339+
impl_lint_pass!(Types => [
340+
BOX_COLLECTION,
341+
VEC_BOX,
342+
OPTION_OPTION,
343+
LINKEDLIST,
344+
BORROWED_BOX,
345+
REDUNDANT_ALLOCATION,
346+
RC_BUFFER,
347+
RC_MUTEX,
348+
TYPE_COMPLEXITY,
349+
NULL_POINTER_OPTIMIZATION,
350+
]);
313351

314352
impl<'tcx> LateLintPass<'tcx> for Types {
315353
fn check_fn(
@@ -349,10 +387,11 @@ impl<'tcx> LateLintPass<'tcx> for Types {
349387
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
350388

351389
match item.kind {
352-
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
390+
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) | ItemKind::TyAlias(ty, _) => self.check_ty(
353391
cx,
354392
ty,
355393
CheckTyContext {
394+
is_in_ty_alias: matches!(item.kind, ItemKind::TyAlias(..)),
356395
is_exported,
357396
..CheckTyContext::default()
358397
},
@@ -476,7 +515,10 @@ impl Types {
476515
return;
477516
}
478517

479-
if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
518+
if !context.is_nested_call
519+
&& !context.is_in_ty_alias
520+
&& type_complexity::check(cx, hir_ty, self.type_complexity_threshold)
521+
{
480522
return;
481523
}
482524

@@ -492,13 +534,16 @@ impl Types {
492534
// in `clippy_lints::utils::conf.rs`
493535

494536
let mut triggered = false;
495-
triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
496-
triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
497-
triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
498-
triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
499-
triggered |= option_option::check(cx, hir_ty, qpath, def_id);
500-
triggered |= linked_list::check(cx, hir_ty, def_id);
501-
triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id);
537+
if !context.is_in_ty_alias {
538+
triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
539+
triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
540+
triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
541+
triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
542+
triggered |= option_option::check(cx, hir_ty, qpath, def_id);
543+
triggered |= linked_list::check(cx, hir_ty, def_id);
544+
triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id);
545+
}
546+
triggered |= null_pointer_optimization::check(cx, hir_ty, qpath, res);
502547

503548
if triggered {
504549
return;
@@ -580,6 +625,7 @@ impl Types {
580625
#[allow(clippy::struct_excessive_bools)]
581626
#[derive(Clone, Copy, Default)]
582627
struct CheckTyContext {
628+
is_in_ty_alias: bool,
583629
is_in_trait_impl: bool,
584630
/// `true` for types on local variables.
585631
is_local: bool,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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, QPath, Ty, TyKind,
5+
};
6+
use rustc_lint::LateContext;
7+
8+
use super::NULL_POINTER_OPTIMIZATION;
9+
10+
pub(super) fn check(cx: &LateContext<'_>, ty: &Ty<'_>, qpath: &QPath<'_>, res: Res) -> bool {
11+
if let Res::Def(DefKind::Struct, def_id) = res {
12+
if !(is_lang_item_or_ctor(cx, def_id, LangItem::OwnedBox) || match_def_path(cx, def_id, &paths::PTR_NON_NULL)) {
13+
return false;
14+
}
15+
16+
if let Some(args) = last_path_segment(qpath).args
17+
&& let GenericArg::Type(option_ty) = args.args[0]
18+
&& let TyKind::Path(option_qpath) = option_ty.kind
19+
&& let res = cx.qpath_res(&option_qpath, option_ty.hir_id)
20+
&& let Res::Def(.., def_id) = res
21+
&& is_lang_item_or_ctor(cx, def_id, LangItem::Option)
22+
{
23+
let outer_ty = last_path_segment(qpath).ident.name;
24+
span_lint_and_help(
25+
cx,
26+
NULL_POINTER_OPTIMIZATION,
27+
ty.span,
28+
&format!("usage of `{outer_ty}<Option<T>>`"),
29+
None,
30+
&format!("consider using `Option<{outer_ty}<T>>` instead, as it will grant better performance. For more information, see\n\
31+
https://doc.rust-lang.org/core/option/#representation"),
32+
);
33+
34+
return true;
35+
}
36+
}
37+
38+
false
39+
}

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ define_Conf! {
289289
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
290290
/// ```
291291
(arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
292-
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
292+
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NULL_POINTER_OPTIMIZATION.
293293
///
294294
/// Suppress lints whenever the suggested change would cause breakage for other crates.
295295
(avoid_breaking_exported_api: bool = true),

0 commit comments

Comments
 (0)