about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src/attributes/confusables.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src/attributes/confusables.rs')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs65
1 files changed, 51 insertions, 14 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index 2ced759fd88..6cff952fcf2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -1,21 +1,58 @@
-//! Parsing and validation of builtin attributes
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
 
-use rustc_ast::MetaItemInner;
-use rustc_ast::attr::AttributeExt;
-use rustc_span::Symbol;
+use super::{AcceptMapping, AttributeParser};
+use crate::context::FinalizeContext;
+use crate::session_diagnostics;
 
-/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names.
-pub fn parse_confusables(attr: &impl AttributeExt) -> Option<Vec<Symbol>> {
-    let metas = attr.meta_item_list()?;
+#[derive(Default)]
+pub(crate) struct ConfusablesParser {
+    confusables: ThinVec<Symbol>,
+    first_span: Option<Span>,
+}
+
+impl AttributeParser for ConfusablesParser {
+    const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
+        let Some(list) = args.list() else {
+            // FIXME(jdonszelmann): error when not a list? Bring validation code here.
+            //       NOTE: currently subsequent attributes are silently ignored using
+            //       tcx.get_attr().
+            return;
+        };
+
+        if list.is_empty() {
+            cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
+        }
+
+        for param in list.mixed() {
+            let span = param.span();
 
-    let mut candidates = Vec::new();
+            let Some(lit) = param.lit() else {
+                cx.emit_err(session_diagnostics::IncorrectMetaItem {
+                    span,
+                    suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
+                        lo: span.shrink_to_lo(),
+                        hi: span.shrink_to_hi(),
+                    }),
+                });
+                continue;
+            };
 
-    for meta in metas {
-        let MetaItemInner::Lit(meta_lit) = meta else {
+            this.confusables.push(lit.symbol);
+        }
+
+        this.first_span.get_or_insert(cx.attr_span);
+    })];
+
+    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        if self.confusables.is_empty() {
             return None;
-        };
-        candidates.push(meta_lit.symbol);
-    }
+        }
 
-    Some(candidates)
+        Some(AttributeKind::Confusables {
+            symbols: self.confusables,
+            first_span: self.first_span.unwrap(),
+        })
+    }
 }