Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 30 additions & 18 deletions clippy_lints/src/functions/ref_option.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
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::is_type_diagnostic_item;
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 as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{FnDecl, HirId};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty};
use rustc_hir::{self as hir, FnDecl, HirId};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{self, Mutability, Ty};
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, sym};

fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
&& is_type_diagnostic_item(cx, *opt_ty, sym::Option)
&& let ty::Adt(_, opt_gen_args) = opt_ty.kind()
&& let [gen_arg] = opt_gen_args.as_slice()
&& let GenericArgKind::Type(gen_ty) = gen_arg.kind()
fn check_ty<'a>(cx: &LateContext<'a>, param: &hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
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
&& let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
Expand All @@ -27,6 +24,7 @@ fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a
args: [hir::GenericArg::Type(opt_ty)],
..
}) = last.args
&& !is_from_proc_macro(cx, param)
{
let lifetime = snippet(cx, lifetime.ident.span, "..");
fixes.push((
Expand Down Expand Up @@ -67,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 {
Expand All @@ -100,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);
}
}
Expand All @@ -112,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();
Expand Down
114 changes: 114 additions & 0 deletions tests/ui-toml/ref_option/ref_option.all.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//@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

#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
#![warn(clippy::ref_option)]

fn opt_u8(a: Option<&u8>) {}
//~^ ref_option
fn opt_gen<T>(a: Option<&T>) {}
//~^ ref_option
fn opt_string(a: std::option::Option<&String>) {}
//~^ ref_option
fn ret_u8<'a>(p: &'a str) -> Option<&'a u8> {
//~^ ref_option
panic!()
}
fn ret_u8_static() -> Option<&'static u8> {
//~^ ref_option
panic!()
}
fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
//~^ ref_option
fn ret_box<'a>() -> Option<&'a Box<u8>> {
//~^ ref_option
panic!()
}

pub fn pub_opt_string(a: Option<&String>) {}
//~[all]^ ref_option
pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
//~[all]^ ref_option

pub struct PubStruct;

impl PubStruct {
pub fn pub_opt_params(&self, a: Option<&()>) {}
//~[all]^ ref_option
pub fn pub_opt_ret(&self) -> Option<&String> {
//~[all]^ ref_option
panic!()
}

fn private_opt_params(&self, a: Option<&()>) {}
//~^ ref_option
fn private_opt_ret(&self) -> Option<&String> {
//~^ ref_option
panic!()
}
}

// valid, don't change
fn mut_u8(a: &mut Option<u8>) {}
pub fn pub_mut_u8(a: &mut Option<String>) {}

// might be good to catch in the future
fn mut_u8_ref(a: &mut &Option<u8>) {}
pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
fn lambdas() {
// Not handled for now, not sure if we should
let x = |a: &Option<String>| {};
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() {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/ref_option/ref_option.rs:8:1
--> tests/ui-toml/ref_option/ref_option.rs:9:1
|
LL | fn opt_u8(a: &Option<u8>) {}
| ^^^^^^^^^^^^^-----------^^^^
Expand All @@ -10,26 +10,26 @@ 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/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>) {}
| ^^^^^^^^^^^^^^^^^----------^^^^
| |
| help: change this to: `Option<&T>`

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/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>) {}
| ^^^^^^^^^^^^^^^^^----------------------------^^^^
| |
| help: change this to: `std::option::Option<&String>`

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/ref_option/ref_option.rs:14:1
--> tests/ui-toml/ref_option/ref_option.rs:15:1
|
LL | fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
| ^ -------------- help: change this to: `Option<&'a u8>`
LL | fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
| ^ -------------- help: change this to: `Option<&'a u8>`
| _|
| |
LL | |
Expand All @@ -38,10 +38,10 @@ LL | | }
| |_^

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/ref_option/ref_option.rs:18:1
--> tests/ui-toml/ref_option/ref_option.rs:19:1
|
LL | fn ret_string_static() -> &'static Option<u8> {
| ^ ------------------- help: change this to: `Option<&'static u8>`
LL | fn ret_u8_static() -> &'static Option<u8> {
| ^ ------------------- help: change this to: `Option<&'static u8>`
| _|
| |
LL | |
Expand All @@ -50,7 +50,7 @@ LL | | }
| |_^

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/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>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -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/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>>`
Expand All @@ -74,15 +74,15 @@ LL | | }
| |_^

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/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>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
| |
| help: change this to: `Option<&String>`

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/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>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -94,47 +94,15 @@ 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/ref_option/ref_option.rs:35:5
|
LL | fn pub_trait_opt(&self, a: &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/ref_option/ref_option.rs:37:5
|
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/ref_option/ref_option.rs:42:5
|
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/ref_option/ref_option.rs:44:5
|
LL | fn trait_ret(&self) -> &Option<String>;
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^
| |
| help: change this to: `Option<&String>`

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/ref_option/ref_option.rs:51:5
--> tests/ui-toml/ref_option/ref_option.rs:38:5
|
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/ref_option/ref_option.rs:53: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>`
Expand All @@ -146,15 +114,15 @@ LL | | }
| |_____^

error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
--> tests/ui/ref_option/ref_option.rs:58:5
--> tests/ui-toml/ref_option/ref_option.rs:45:5
|
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/ref_option/ref_option.rs:60: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>`
Expand All @@ -165,5 +133,5 @@ LL | | panic!()
LL | | }
| |_____^

error: aborting due to 17 previous errors
error: aborting due to 13 previous errors

Loading