rustc_lint/
disallowed_pass_by_ref.rs1use rustc_attr_ir::find_attr;
2use rustc_hir::def::Res;
3use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
4use rustc_lint_defs::{declare_lint_pass, declare_tool_lint};
5use rustc_middle::ty;
6
7use crate::diagnostics::DisallowedPassByRefDiag;
8use crate::{LateContext, LateLintPass, LintContext};
9
10#[doc =
r" The `disallowed_pass_by_ref` lint detects if types marked with `#[rustc_pass_by_value]` are"]
#[doc =
r" passed by reference. Types with this marker are usually thin wrappers around references, so"]
#[doc =
r" there is no benefit to an extra layer of indirection. (Example: `Ty` which is a reference"]
#[doc = r" to an `Interned<TyKind>`)"]
pub static DISALLOWED_PASS_BY_REF: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: &"rustc::DISALLOWED_PASS_BY_REF",
default_level: ::rustc_lint_defs::Warn,
desc: "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
edition_lint_opts: None,
report_in_external_macro: true,
future_incompatible: None,
is_externally_loaded: true,
crate_level_only: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_tool_lint! {
11 pub rustc::DISALLOWED_PASS_BY_REF,
16 Warn,
17 "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
18 report_in_external_macro: true
19}
20
21pub struct DisallowedPassByRef;
#[automatically_derived]
impl ::core::marker::Copy for DisallowedPassByRef { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DisallowedPassByRef { }
#[automatically_derived]
impl ::core::clone::Clone for DisallowedPassByRef {
#[inline]
fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for DisallowedPassByRef {
fn name(&self) -> &'static str { "DisallowedPassByRef" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[DISALLOWED_PASS_BY_REF]))
}
}
impl DisallowedPassByRef {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[DISALLOWED_PASS_BY_REF]))
}
}declare_lint_pass!(DisallowedPassByRef => [DISALLOWED_PASS_BY_REF]);
22
23impl<'tcx> LateLintPass<'tcx> for DisallowedPassByRef {
24 fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
25 match &ty.kind {
26 TyKind::Ref(_, inner_ty, hir::Mutability::Not) => {
27 if cx.tcx.trait_impl_of_assoc(ty.hir_id.owner.to_def_id()).is_some() {
28 return;
29 }
30 if let Some(t) = path_for_rustc_pass_by_value(cx, inner_ty) {
31 cx.emit_span_lint(
32 DISALLOWED_PASS_BY_REF,
33 ty.span,
34 DisallowedPassByRefDiag { ty: t, suggestion: ty.span },
35 );
36 }
37 }
38 _ => {}
39 }
40 }
41}
42
43fn path_for_rustc_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
44 if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
45 match path.res {
46 Res::Def(_, def_id) if {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &cx.tcx)
{
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcPassByValue) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(cx.tcx, def_id, RustcPassByValue) => {
47 let name = cx.tcx.item_ident(def_id);
48 let path_segment = path.segments.last().unwrap();
49 return Some(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", name,
gen_args(cx, path_segment)))
})format!("{}{}", name, gen_args(cx, path_segment)));
50 }
51 Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
52 if let ty::Adt(adt, args) =
53 cx.tcx.type_of(did).instantiate_identity().skip_norm_wip().kind()
54 {
55 if {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(adt.did(), &cx.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcPassByValue) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(cx.tcx, adt.did(), RustcPassByValue) {
56 return Some(cx.tcx.def_path_str_with_args(adt.did(), args));
57 }
58 }
59 }
60 _ => (),
61 }
62 }
63
64 None
65}
66
67fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
68 if let Some(args) = &segment.args {
69 let params = args
70 .args
71 .iter()
72 .map(|arg| match arg {
73 GenericArg::Lifetime(lt) => lt.to_string(),
74 GenericArg::Type(ty) => {
75 cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
76 }
77 GenericArg::Const(c) => {
78 cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into())
79 }
80 GenericArg::Infer(_) => String::from("_"),
81 })
82 .collect::<Vec<_>>();
83
84 if !params.is_empty() {
85 return ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}>", params.join(", ")))
})format!("<{}>", params.join(", "));
86 }
87 }
88
89 String::new()
90}