1 use rustc_errors
::Applicability
;
3 self as hir
, GenericArg
, GenericBounds
, GenericParamKind
, HirId
, Lifetime
, MutTy
, Mutability
, Node
, QPath
,
4 SyntheticTyParamKind
, TyKind
,
6 use rustc_lint
::LateContext
;
8 use if_chain
::if_chain
;
10 use crate::utils
::{match_path, paths, snippet, span_lint_and_sugg}
;
12 use super::BORROWED_BOX
;
14 pub(super) fn check(cx
: &LateContext
<'_
>, hir_ty
: &hir
::Ty
<'_
>, lt
: &Lifetime
, mut_ty
: &MutTy
<'_
>) -> bool
{
15 match mut_ty
.ty
.kind
{
16 TyKind
::Path(ref qpath
) => {
17 let hir_id
= mut_ty
.ty
.hir_id
;
18 let def
= cx
.qpath_res(qpath
, hir_id
);
20 if let Some(def_id
) = def
.opt_def_id();
21 if Some(def_id
) == cx
.tcx
.lang_items().owned_box();
22 if let QPath
::Resolved(None
, ref path
) = *qpath
;
23 if let [ref bx
] = *path
.segments
;
24 if let Some(ref params
) = bx
.args
;
25 if !params
.parenthesized
;
26 if let Some(inner
) = params
.args
.iter().find_map(|arg
| match arg
{
27 GenericArg
::Type(ty
) => Some(ty
),
31 if is_any_trait(inner
) {
32 // Ignore `Box<Any>` types; see issue #1884 for details.
36 let ltopt
= if lt
.is_elided() {
39 format
!("{} ", lt
.name
.ident().as_str())
42 if mut_ty
.mutbl
== Mutability
::Mut
{
43 // Ignore `&mut Box<T>` types; see issue #2907 for
48 // When trait objects or opaque types have lifetime or auto-trait bounds,
49 // we need to add parentheses to avoid a syntax error due to its ambiguity.
50 // Originally reported as the issue #3128.
51 let inner_snippet
= snippet(cx
, inner
.span
, "..");
52 let suggestion
= match &inner
.kind
{
53 TyKind
::TraitObject(bounds
, lt_bound
, _
) if bounds
.len() > 1 || !lt_bound
.is_elided() => {
54 format
!("&{}({})", ltopt
, &inner_snippet
)
57 if get_bounds_if_impl_trait(cx
, qpath
, inner
.hir_id
)
58 .map_or(false, |bounds
| bounds
.len() > 1) =>
60 format
!("&{}({})", ltopt
, &inner_snippet
)
62 _
=> format
!("&{}{}", ltopt
, &inner_snippet
),
68 "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
71 // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
72 // because the trait impls of it will break otherwise;
73 // and there may be other cases that result in invalid code.
74 // For example, type coercion doesn't work nicely.
75 Applicability
::Unspecified
,
86 // Returns true if given type is `Any` trait.
87 fn is_any_trait(t
: &hir
::Ty
<'_
>) -> bool
{
89 if let TyKind
::TraitObject(ref traits
, ..) = t
.kind
;
90 if !traits
.is_empty();
91 // Only Send/Sync can be used as additional traits, so it is enough to
92 // check only the first trait.
93 if match_path(&traits
[0].trait_ref
.path
, &paths
::ANY_TRAIT
);
102 fn get_bounds_if_impl_trait
<'tcx
>(cx
: &LateContext
<'tcx
>, qpath
: &QPath
<'_
>, id
: HirId
) -> Option
<GenericBounds
<'tcx
>> {
104 if let Some(did
) = cx
.qpath_res(qpath
, id
).opt_def_id();
105 if let Some(Node
::GenericParam(generic_param
)) = cx
.tcx
.hir().get_if_local(did
);
106 if let GenericParamKind
::Type { synthetic, .. }
= generic_param
.kind
;
107 if synthetic
== Some(SyntheticTyParamKind
::ImplTrait
);
109 Some(generic_param
.bounds
)