|
4 | 4 | //! conflicts between multiple such attributes attached to the same
|
5 | 5 | //! item.
|
6 | 6 |
|
7 |
| -use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; |
| 7 | +use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; |
8 | 8 | use rustc_data_structures::fx::FxHashMap;
|
9 | 9 | use rustc_errors::{pluralize, struct_span_err, Applicability};
|
10 | 10 | use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
@@ -178,34 +178,7 @@ impl CheckAttrVisitor<'_> {
|
178 | 178 | check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
|
179 | 179 | }
|
180 | 180 |
|
181 |
| - // Warn on useless empty attributes. |
182 |
| - if matches!( |
183 |
| - attr.name_or_empty(), |
184 |
| - sym::macro_use |
185 |
| - | sym::allow |
186 |
| - | sym::warn |
187 |
| - | sym::deny |
188 |
| - | sym::forbid |
189 |
| - | sym::feature |
190 |
| - | sym::repr |
191 |
| - | sym::target_feature |
192 |
| - ) && attr.meta_item_list().map_or(false, |list| list.is_empty()) |
193 |
| - { |
194 |
| - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { |
195 |
| - lint.build("unused attribute") |
196 |
| - .span_suggestion( |
197 |
| - attr.span, |
198 |
| - "remove this attribute", |
199 |
| - String::new(), |
200 |
| - Applicability::MachineApplicable, |
201 |
| - ) |
202 |
| - .note(&format!( |
203 |
| - "attribute `{}` with an empty list has no effect", |
204 |
| - attr.name_or_empty() |
205 |
| - )) |
206 |
| - .emit(); |
207 |
| - }); |
208 |
| - } |
| 181 | + self.check_unused_attribute(hir_id, attr) |
209 | 182 | }
|
210 | 183 |
|
211 | 184 | if !is_valid {
|
@@ -1969,6 +1942,55 @@ impl CheckAttrVisitor<'_> {
|
1969 | 1942 | });
|
1970 | 1943 | }
|
1971 | 1944 | }
|
| 1945 | + |
| 1946 | + fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { |
| 1947 | + // Warn on useless empty attributes. |
| 1948 | + let note = if matches!( |
| 1949 | + attr.name_or_empty(), |
| 1950 | + sym::macro_use |
| 1951 | + | sym::allow |
| 1952 | + | sym::expect |
| 1953 | + | sym::warn |
| 1954 | + | sym::deny |
| 1955 | + | sym::forbid |
| 1956 | + | sym::feature |
| 1957 | + | sym::repr |
| 1958 | + | sym::target_feature |
| 1959 | + ) && attr.meta_item_list().map_or(false, |list| list.is_empty()) |
| 1960 | + { |
| 1961 | + format!( |
| 1962 | + "attribute `{}` with an empty list has no effect", |
| 1963 | + attr.name_or_empty() |
| 1964 | + ) |
| 1965 | + } else if matches!( |
| 1966 | + attr.name_or_empty(), |
| 1967 | + sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect |
| 1968 | + ) && let Some(meta) = attr.meta_item_list() |
| 1969 | + && meta.len() == 1 |
| 1970 | + && let Some(item) = meta[0].meta_item() |
| 1971 | + && let MetaItemKind::NameValue(_) = &item.kind |
| 1972 | + && item.path == sym::reason |
| 1973 | + { |
| 1974 | + format!( |
| 1975 | + "attribute `{}` without any lints has no effect", |
| 1976 | + attr.name_or_empty() |
| 1977 | + ) |
| 1978 | + } else { |
| 1979 | + return; |
| 1980 | + }; |
| 1981 | + |
| 1982 | + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { |
| 1983 | + lint.build("unused attribute") |
| 1984 | + .span_suggestion( |
| 1985 | + attr.span, |
| 1986 | + "remove this attribute", |
| 1987 | + String::new(), |
| 1988 | + Applicability::MachineApplicable, |
| 1989 | + ) |
| 1990 | + .note(¬e) |
| 1991 | + .emit(); |
| 1992 | + }); |
| 1993 | + } |
1972 | 1994 | }
|
1973 | 1995 |
|
1974 | 1996 | impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
|
0 commit comments