Skip to content

Commit a56f4b4

Browse files
committed
Extracted lint reason parsing for reusability
1 parent 9066544 commit a56f4b4

File tree

1 file changed

+62
-36
lines changed

1 file changed

+62
-36
lines changed

compiler/rustc_lint/src/levels.rs

+62-36
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::context::{CheckLintNameResult, LintStore};
22
use crate::late::unerased_lint_store;
33
use rustc_ast as ast;
44
use rustc_ast::unwrap_or;
5+
use rustc_ast::NestedMetaItem;
56
use rustc_ast_pretty::pprust;
67
use rustc_data_structures::fx::FxHashMap;
78
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -247,44 +248,18 @@ impl<'s> LintLevelsBuilder<'s> {
247248

248249
// Before processing the lint names, look for a reason (RFC 2383)
249250
// at the end.
250-
let mut reason = None;
251251
let tail_li = &metas[metas.len() - 1];
252-
if let Some(item) = tail_li.meta_item() {
253-
match item.kind {
254-
ast::MetaItemKind::Word => {} // actual lint names handled later
255-
ast::MetaItemKind::NameValue(ref name_value) => {
256-
if item.path == sym::reason {
257-
// FIXME (#55112): issue unused-attributes lint if we thereby
258-
// don't have any lint names (`#[level(reason = "foo")]`)
259-
if let ast::LitKind::Str(rationale, _) = name_value.kind {
260-
if !self.sess.features_untracked().lint_reasons {
261-
feature_err(
262-
&self.sess.parse_sess,
263-
sym::lint_reasons,
264-
item.span,
265-
"lint reasons are experimental",
266-
)
267-
.emit();
268-
}
269-
reason = Some(rationale);
270-
} else {
271-
bad_attr(name_value.span)
272-
.span_label(name_value.span, "reason must be a string literal")
273-
.emit();
274-
}
275-
// found reason, reslice meta list to exclude it
276-
metas.pop().unwrap();
277-
} else {
278-
bad_attr(item.span)
279-
.span_label(item.span, "bad attribute argument")
280-
.emit();
281-
}
282-
}
283-
ast::MetaItemKind::List(_) => {
284-
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
285-
}
252+
let reason = match try_parse_reason_metadata(tail_li, self.sess) {
253+
ParseLintReasonResult::Ok(reason) => {
254+
metas.pop().unwrap();
255+
Some(reason)
286256
}
287-
}
257+
ParseLintReasonResult::MalformedReason => {
258+
metas.pop().unwrap();
259+
None
260+
}
261+
ParseLintReasonResult::NotFound => None,
262+
};
288263

289264
for li in metas {
290265
let sp = li.span();
@@ -568,6 +543,57 @@ impl<'s> LintLevelsBuilder<'s> {
568543
}
569544
}
570545

546+
pub(crate) enum ParseLintReasonResult {
547+
/// The reason was found and is returned as part of this value.
548+
Ok(Symbol),
549+
/// Indicates that the reason field was found but was malformed.
550+
MalformedReason,
551+
/// The checked item is not a reason field.
552+
NotFound,
553+
}
554+
555+
pub(crate) fn try_parse_reason_metadata(
556+
item: &NestedMetaItem,
557+
sess: &Session,
558+
) -> ParseLintReasonResult {
559+
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
560+
if let Some(item) = item.meta_item() {
561+
match item.kind {
562+
ast::MetaItemKind::Word => {} // actual lint names handled later
563+
ast::MetaItemKind::NameValue(ref name_value) => {
564+
if item.path == sym::reason {
565+
// FIXME (#55112): issue unused-attributes lint if we thereby
566+
// don't have any lint names (`#[level(reason = "foo")]`)
567+
if let ast::LitKind::Str(rationale, _) = name_value.kind {
568+
if !sess.features_untracked().lint_reasons {
569+
feature_err(
570+
&sess.parse_sess,
571+
sym::lint_reasons,
572+
item.span,
573+
"lint reasons are experimental",
574+
)
575+
.emit();
576+
}
577+
return ParseLintReasonResult::Ok(rationale);
578+
} else {
579+
bad_attr(name_value.span)
580+
.span_label(name_value.span, "reason must be a string literal")
581+
.emit();
582+
return ParseLintReasonResult::MalformedReason;
583+
}
584+
} else {
585+
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
586+
}
587+
}
588+
ast::MetaItemKind::List(_) => {
589+
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
590+
}
591+
}
592+
}
593+
594+
ParseLintReasonResult::NotFound
595+
}
596+
571597
pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool {
572598
if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) {
573599
return true;

0 commit comments

Comments
 (0)