fix(ref_option): don't lint in external and proc-macros

This commit is contained in:
Ada Alakbarova 2025-09-13 01:24:18 +02:00
parent 25cf36ac78
commit b901ba725e
No known key found for this signature in database
9 changed files with 230 additions and 36 deletions

View file

@ -1,18 +1,19 @@
use crate::functions::REF_OPTION;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_trait_impl_item;
use clippy_utils::source::snippet;
use clippy_utils::ty::option_arg_ty;
use clippy_utils::{is_from_proc_macro, is_trait_impl_item};
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{self as hir, FnDecl, HirId};
use rustc_lint::LateContext;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{self, Mutability, Ty};
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
fn check_ty<'a>(cx: &LateContext<'a>, param: &hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
if !param.span.in_external_macro(cx.sess().source_map())
&& let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
&& let Some(gen_ty) = option_arg_ty(cx, *opt_ty)
&& !gen_ty.is_ref()
// Need to gen the original spans, so first parsing mid, and hir parsing afterward
@ -23,6 +24,7 @@ fn check_ty<'a>(cx: &LateContext<'a>, param: &hir::Ty<'a>, param_ty: Ty<'a>, fix
args: [hir::GenericArg::Type(opt_ty)],
..
}) = last.args
&& !is_from_proc_macro(cx, param)
{
let lifetime = snippet(cx, lifetime.ident.span, "..");
fixes.push((
@ -63,21 +65,24 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
#[allow(clippy::too_many_arguments)]
pub(crate) fn check_fn<'a>(
cx: &LateContext<'a>,
kind: FnKind<'_>,
kind: FnKind<'a>,
decl: &FnDecl<'a>,
span: Span,
hir_id: HirId,
def_id: LocalDefId,
body: &hir::Body<'_>,
body: &hir::Body<'a>,
avoid_breaking_exported_api: bool,
) {
if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
if span.in_external_macro(cx.sess().source_map()) {
return;
}
if let FnKind::Closure = kind {
// Compute the span of the closure parameters + return type if set
let span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
let inputs_output_span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
if decl.inputs.is_empty() {
out_ty.span
} else {
@ -96,9 +101,18 @@ pub(crate) fn check_fn<'a>(
};
let sig = args.as_closure().sig().skip_binder();
check_fn_sig(cx, decl, span, sig);
if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
return;
}
check_fn_sig(cx, decl, inputs_output_span, sig);
} else if !is_trait_impl_item(cx, hir_id) {
let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
return;
}
check_fn_sig(cx, decl, span, sig);
}
}
@ -108,8 +122,10 @@ pub(super) fn check_trait_item<'a>(
trait_item: &hir::TraitItem<'a>,
avoid_breaking_exported_api: bool,
) {
if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
if !trait_item.span.in_external_macro(cx.sess().source_map())
&& let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
&& !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id))
&& !is_from_proc_macro(cx, trait_item)
{
let def_id = trait_item.owner_id.def_id;
let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();

View file

@ -1,3 +1,4 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: private all
//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
@ -62,4 +63,52 @@ fn lambdas() {
let x = |a: &Option<String>| -> &Option<String> { panic!() };
}
pub mod external {
proc_macros::external!(
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
pub mod proc_macros {
proc_macros::with_span!(
span
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
fn main() {}

View file

@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:8:1
--> tests/ui-toml/ref_option/ref_option.rs:9:1
|
LL | fn opt_u8(a: &Option<u8>) {}
| ^^^^^^^^^^^^^-----------^^^^
@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:10:1
--> tests/ui-toml/ref_option/ref_option.rs:11:1
|
LL | fn opt_gen<T>(a: &Option<T>) {}
| ^^^^^^^^^^^^^^^^^----------^^^^
@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
| help: change this to: `Option<&T>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:12:1
--> tests/ui-toml/ref_option/ref_option.rs:13:1
|
LL | fn opt_string(a: &std::option::Option<String>) {}
| ^^^^^^^^^^^^^^^^^----------------------------^^^^
@ -26,7 +26,7 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
| help: change this to: `std::option::Option<&String>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:14:1
--> tests/ui-toml/ref_option/ref_option.rs:15:1
|
LL | fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
| ^ -------------- help: change this to: `Option<&'a u8>`
@ -38,7 +38,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:18:1
--> tests/ui-toml/ref_option/ref_option.rs:19:1
|
LL | fn ret_u8_static() -> &'static Option<u8> {
| ^ ------------------- help: change this to: `Option<&'static u8>`
@ -50,7 +50,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:22:1
--> tests/ui-toml/ref_option/ref_option.rs:23:1
|
LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
|
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:24:1
--> tests/ui-toml/ref_option/ref_option.rs:25:1
|
LL | fn ret_box<'a>() -> &'a Option<Box<u8>> {
| ^ ------------------- help: change this to: `Option<&'a Box<u8>>`
@ -74,7 +74,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:29:1
--> tests/ui-toml/ref_option/ref_option.rs:30:1
|
LL | pub fn pub_opt_string(a: &Option<String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@ -82,7 +82,7 @@ LL | pub fn pub_opt_string(a: &Option<String>) {}
| help: change this to: `Option<&String>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:31:1
--> tests/ui-toml/ref_option/ref_option.rs:32:1
|
LL | pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -94,7 +94,7 @@ LL + pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
|
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:37:5
--> tests/ui-toml/ref_option/ref_option.rs:38:5
|
LL | pub fn pub_opt_params(&self, a: &Option<()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@ -102,7 +102,7 @@ LL | pub fn pub_opt_params(&self, a: &Option<()>) {}
| help: change this to: `Option<&()>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:39:5
--> tests/ui-toml/ref_option/ref_option.rs:40:5
|
LL | pub fn pub_opt_ret(&self) -> &Option<String> {
| ^ --------------- help: change this to: `Option<&String>`
@ -114,7 +114,7 @@ LL | | }
| |_____^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:44:5
--> tests/ui-toml/ref_option/ref_option.rs:45:5
|
LL | fn private_opt_params(&self, a: &Option<()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@ -122,7 +122,7 @@ LL | fn private_opt_params(&self, a: &Option<()>) {}
| help: change this to: `Option<&()>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:46:5
--> tests/ui-toml/ref_option/ref_option.rs:47:5
|
LL | fn private_opt_ret(&self) -> &Option<String> {
| ^ --------------- help: change this to: `Option<&String>`

View file

@ -1,3 +1,4 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: private all
//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
@ -62,4 +63,52 @@ fn lambdas() {
let x = |a: &Option<String>| -> &Option<String> { panic!() };
}
pub mod external {
proc_macros::external!(
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
pub mod proc_macros {
proc_macros::with_span!(
span
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
fn main() {}

View file

@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:8:1
--> tests/ui-toml/ref_option/ref_option.rs:9:1
|
LL | fn opt_u8(a: &Option<u8>) {}
| ^^^^^^^^^^^^^-----------^^^^
@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:10:1
--> tests/ui-toml/ref_option/ref_option.rs:11:1
|
LL | fn opt_gen<T>(a: &Option<T>) {}
| ^^^^^^^^^^^^^^^^^----------^^^^
@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
| help: change this to: `Option<&T>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:12:1
--> tests/ui-toml/ref_option/ref_option.rs:13:1
|
LL | fn opt_string(a: &std::option::Option<String>) {}
| ^^^^^^^^^^^^^^^^^----------------------------^^^^
@ -26,7 +26,7 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
| help: change this to: `std::option::Option<&String>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:14:1
--> tests/ui-toml/ref_option/ref_option.rs:15:1
|
LL | fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
| ^ -------------- help: change this to: `Option<&'a u8>`
@ -38,7 +38,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:18:1
--> tests/ui-toml/ref_option/ref_option.rs:19:1
|
LL | fn ret_u8_static() -> &'static Option<u8> {
| ^ ------------------- help: change this to: `Option<&'static u8>`
@ -50,7 +50,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:22:1
--> tests/ui-toml/ref_option/ref_option.rs:23:1
|
LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
|
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:24:1
--> tests/ui-toml/ref_option/ref_option.rs:25:1
|
LL | fn ret_box<'a>() -> &'a Option<Box<u8>> {
| ^ ------------------- help: change this to: `Option<&'a Box<u8>>`
@ -74,7 +74,7 @@ LL | | }
| |_^
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:44:5
--> tests/ui-toml/ref_option/ref_option.rs:45:5
|
LL | fn private_opt_params(&self, a: &Option<()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@ -82,7 +82,7 @@ LL | fn private_opt_params(&self, a: &Option<()>) {}
| help: change this to: `Option<&()>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option.rs:46:5
--> tests/ui-toml/ref_option/ref_option.rs:47:5
|
LL | fn private_opt_ret(&self) -> &Option<String> {
| ^ --------------- help: change this to: `Option<&String>`

View file

@ -1,3 +1,4 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: private all
//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
@ -62,4 +63,52 @@ fn lambdas() {
let x = |a: &Option<String>| -> &Option<String> { panic!() };
}
pub mod external {
proc_macros::external!(
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
pub mod proc_macros {
proc_macros::with_span!(
span
fn opt_u8(a: &Option<u8>) {}
fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
panic!()
}
pub fn pub_opt_u8(a: &Option<u8>) {}
pub struct PubStruct;
impl PubStruct {
pub fn pub_opt_params(&self, a: &Option<()>) {}
pub fn pub_opt_ret(&self) -> &Option<String> {
panic!()
}
fn private_opt_params(&self, a: &Option<()>) {}
fn private_opt_ret(&self) -> &Option<String> {
panic!()
}
}
);
}
fn main() {}

View file

@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:9:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:10:5
|
LL | fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
@ -10,7 +10,7 @@ LL | fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:11:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:12:5
|
LL | fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
@ -18,7 +18,7 @@ LL | fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
| help: change this to: `Option<&Vec<u8>>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:16:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
|
LL | fn trait_opt(&self, a: &Option<String>);
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@ -26,7 +26,7 @@ LL | fn trait_opt(&self, a: &Option<String>);
| help: change this to: `Option<&String>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:18:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
|
LL | fn trait_ret(&self) -> &Option<String>;
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^

View file

@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:16:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
|
LL | fn trait_opt(&self, a: &Option<String>);
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@ -10,7 +10,7 @@ LL | fn trait_opt(&self, a: &Option<String>);
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui-toml/ref_option/ref_option_traits.rs:18:5
--> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
|
LL | fn trait_ret(&self) -> &Option<String>;
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^

View file

@ -1,4 +1,5 @@
//@no-rustfix: fixes are only done to traits, not the impls
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: private all
//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
@ -37,4 +38,34 @@ impl PrivateTrait for PrivateStruct {
}
}
pub mod external {
proc_macros::external!(
pub trait PubTrait {
fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
}
trait PrivateTrait {
fn trait_opt(&self, a: &Option<String>);
fn trait_ret(&self) -> &Option<String>;
}
);
}
pub mod proc_macros {
proc_macros::with_span!(
span
pub trait PubTrait {
fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
}
trait PrivateTrait {
fn trait_opt(&self, a: &Option<String>);
fn trait_ret(&self) -> &Option<String>;
}
);
}
fn main() {}