|
1 | | -use clippy_utils::diagnostics::{span_lint, span_lint_hir}; |
2 | | -use rustc_hir::def_id::DefId; |
3 | | -use rustc_hir::{self as hir, Attribute, find_attr}; |
4 | | -use rustc_lint::{LateContext, LateLintPass, LintContext}; |
5 | | -use rustc_middle::ty::AssocContainer; |
| 1 | +use clippy_utils::diagnostics::span_lint; |
| 2 | +use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, OwnerId, TraitFn, TraitItem, TraitItemKind, find_attr}; |
| 3 | +use rustc_lint::{LateContext, LateLintPass}; |
6 | 4 | use rustc_session::config::CrateType; |
7 | 5 | use rustc_session::declare_lint_pass; |
8 | 6 | use rustc_span::Span; |
@@ -66,134 +64,41 @@ declare_clippy_lint! { |
66 | 64 |
|
67 | 65 | declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); |
68 | 66 |
|
69 | | -fn check_missing_inline_attrs( |
70 | | - cx: &LateContext<'_>, |
71 | | - attrs: &[Attribute], |
72 | | - sp: Span, |
73 | | - desc: &'static str, |
74 | | - hir_id: Option<hir::HirId>, |
75 | | -) { |
76 | | - if !find_attr!(attrs, Inline(..)) { |
77 | | - let msg = format!("missing `#[inline]` for {desc}"); |
78 | | - if let Some(hir_id) = hir_id { |
79 | | - span_lint_hir(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, hir_id, sp, msg); |
80 | | - } else { |
81 | | - span_lint(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, msg); |
82 | | - } |
| 67 | +fn check(cx: &LateContext<'_>, item: OwnerId, sp: Span) { |
| 68 | + if cx.effective_visibilities.is_exported(item.def_id) |
| 69 | + && !find_attr!(cx.tcx.hir_attrs(item.into()), Inline(..)) |
| 70 | + // Rust `inline` doesn't mean anything with external linkage. |
| 71 | + && !cx.tcx.codegen_fn_attrs(item.def_id).contains_extern_indicator() |
| 72 | + && !cx.tcx.crate_types().iter().any(|&t| matches!(t, CrateType::ProcMacro)) |
| 73 | + && !sp.in_external_macro(cx.tcx.sess.source_map()) |
| 74 | + { |
| 75 | + span_lint( |
| 76 | + cx, |
| 77 | + MISSING_INLINE_IN_PUBLIC_ITEMS, |
| 78 | + sp, |
| 79 | + "missing `#[inline]` on a publicly callable function", |
| 80 | + ); |
83 | 81 | } |
84 | 82 | } |
85 | 83 |
|
86 | 84 | impl<'tcx> LateLintPass<'tcx> for MissingInline { |
87 | | - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { |
88 | | - if it.span.in_external_macro(cx.sess().source_map()) { |
89 | | - return; |
90 | | - } |
91 | | - |
92 | | - if cx |
93 | | - .tcx |
94 | | - .crate_types() |
95 | | - .iter() |
96 | | - .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) |
97 | | - { |
98 | | - return; |
99 | | - } |
100 | | - |
101 | | - if !cx.effective_visibilities.is_exported(it.owner_id.def_id) { |
102 | | - return; |
103 | | - } |
104 | | - match it.kind { |
105 | | - hir::ItemKind::Fn { .. } => { |
106 | | - if fn_is_externally_exported(cx, it.owner_id.to_def_id()) { |
107 | | - return; |
108 | | - } |
109 | | - |
110 | | - let desc = "a function"; |
111 | | - let attrs = cx.tcx.hir_attrs(it.hir_id()); |
112 | | - check_missing_inline_attrs(cx, attrs, it.span, desc, None); |
113 | | - }, |
114 | | - hir::ItemKind::Trait { items: trait_items, .. } => { |
115 | | - // note: we need to check if the trait is exported so we can't use |
116 | | - // `LateLintPass::check_trait_item` here. |
117 | | - for &tit in trait_items { |
118 | | - let tit_ = cx.tcx.hir_trait_item(tit); |
119 | | - match tit_.kind { |
120 | | - hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {}, |
121 | | - hir::TraitItemKind::Fn(..) => { |
122 | | - if cx.tcx.defaultness(tit.owner_id).has_value() { |
123 | | - // trait method with default body needs inline in case |
124 | | - // an impl is not provided |
125 | | - let desc = "a default trait method"; |
126 | | - let item = cx.tcx.hir_trait_item(tit); |
127 | | - let attrs = cx.tcx.hir_attrs(item.hir_id()); |
128 | | - check_missing_inline_attrs(cx, attrs, item.span, desc, Some(tit.hir_id())); |
129 | | - } |
130 | | - }, |
131 | | - } |
132 | | - } |
133 | | - }, |
134 | | - hir::ItemKind::Const(..) |
135 | | - | hir::ItemKind::Enum(..) |
136 | | - | hir::ItemKind::Macro(..) |
137 | | - | hir::ItemKind::Mod(..) |
138 | | - | hir::ItemKind::Static(..) |
139 | | - | hir::ItemKind::Struct(..) |
140 | | - | hir::ItemKind::TraitAlias(..) |
141 | | - | hir::ItemKind::GlobalAsm { .. } |
142 | | - | hir::ItemKind::TyAlias(..) |
143 | | - | hir::ItemKind::Union(..) |
144 | | - | hir::ItemKind::ExternCrate(..) |
145 | | - | hir::ItemKind::ForeignMod { .. } |
146 | | - | hir::ItemKind::Impl { .. } |
147 | | - | hir::ItemKind::Use(..) => {}, |
| 85 | + fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { |
| 86 | + if let ItemKind::Fn { .. } = it.kind { |
| 87 | + check(cx, it.owner_id, it.span); |
148 | 88 | } |
149 | 89 | } |
150 | 90 |
|
151 | | - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { |
152 | | - if impl_item.span.in_external_macro(cx.sess().source_map()) |
153 | | - || cx |
154 | | - .tcx |
155 | | - .crate_types() |
156 | | - .iter() |
157 | | - .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) |
| 91 | + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { |
| 92 | + if let TraitItemKind::Fn(_, f) = item.kind |
| 93 | + && let TraitFn::Provided(_) = f |
158 | 94 | { |
159 | | - return; |
| 95 | + check(cx, item.owner_id, item.span); |
160 | 96 | } |
| 97 | + } |
161 | 98 |
|
162 | | - // If the item being implemented is not exported, then we don't need #[inline] |
163 | | - if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) { |
164 | | - return; |
165 | | - } |
166 | | - |
167 | | - let desc = match impl_item.kind { |
168 | | - hir::ImplItemKind::Fn(..) => "a method", |
169 | | - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return, |
170 | | - }; |
171 | | - |
172 | | - let assoc_item = cx.tcx.associated_item(impl_item.owner_id); |
173 | | - let container_id = assoc_item.container_id(cx.tcx); |
174 | | - let trait_def_id = match assoc_item.container { |
175 | | - AssocContainer::Trait => Some(container_id), |
176 | | - AssocContainer::TraitImpl(_) => Some(cx.tcx.impl_trait_id(container_id)), |
177 | | - AssocContainer::InherentImpl => None, |
178 | | - }; |
179 | | - |
180 | | - if let Some(trait_def_id) = trait_def_id |
181 | | - && trait_def_id.is_local() |
182 | | - && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) |
183 | | - { |
184 | | - // If a trait is being implemented for an item, and the |
185 | | - // trait is not exported, we don't need #[inline] |
186 | | - return; |
| 99 | + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { |
| 100 | + if let ImplItemKind::Fn(..) = item.kind { |
| 101 | + check(cx, item.owner_id, item.span); |
187 | 102 | } |
188 | | - |
189 | | - let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); |
190 | | - check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None); |
191 | 103 | } |
192 | 104 | } |
193 | | - |
194 | | -/// Checks if this function is externally exported, where #[inline] wouldn't have the desired effect |
195 | | -/// and a rustc warning would be triggered, see #15301 |
196 | | -fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { |
197 | | - let attrs = cx.tcx.codegen_fn_attrs(def_id); |
198 | | - attrs.contains_extern_indicator() |
199 | | -} |
0 commit comments