|
3 | 3 |
|
4 | 4 | use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy}; |
5 | 5 | use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak}; |
6 | | -use crate::{ModuleKind, NameBinding, PathResult, Segment, ToNameBinding}; |
7 | | -use crate::{ModuleOrUniformRoot, KNOWN_TOOLS}; |
| 6 | +use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; |
8 | 7 | use crate::Namespace::*; |
9 | 8 | use crate::resolve_imports::ImportResolver; |
10 | 9 | use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; |
11 | 10 | use rustc::hir::def_id; |
12 | 11 | use rustc::middle::stability; |
| 12 | +use rustc::session::Session; |
| 13 | +use rustc::util::nodemap::FxHashSet; |
13 | 14 | use rustc::{ty, lint, span_bug}; |
14 | 15 | use syntax::ast::{self, NodeId, Ident}; |
15 | | -use syntax::attr::StabilityLevel; |
| 16 | +use syntax::attr::{self, StabilityLevel}; |
16 | 17 | use syntax::edition::Edition; |
17 | 18 | use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; |
18 | 19 | use syntax::feature_gate::GateIssue; |
@@ -93,6 +94,45 @@ fn fast_print_path(path: &ast::Path) -> Symbol { |
93 | 94 | } |
94 | 95 | } |
95 | 96 |
|
| 97 | +fn registered_idents( |
| 98 | + sess: &Session, |
| 99 | + attrs: &[ast::Attribute], |
| 100 | + attr_name: Symbol, |
| 101 | + descr: &str, |
| 102 | +) -> FxHashSet<Ident> { |
| 103 | + let mut registered = FxHashSet::default(); |
| 104 | + for attr in attr::filter_by_name(attrs, attr_name) { |
| 105 | + for nested_meta in attr.meta_item_list().unwrap_or_default() { |
| 106 | + match nested_meta.ident() { |
| 107 | + Some(ident) => if let Some(old_ident) = registered.replace(ident) { |
| 108 | + let msg = format!("{} `{}` was already registered", descr, ident); |
| 109 | + sess.struct_span_err(ident.span, &msg) |
| 110 | + .span_label(old_ident.span, "already registered here").emit(); |
| 111 | + } |
| 112 | + None => { |
| 113 | + let msg = format!("`{}` only accepts identifiers", attr_name); |
| 114 | + let span = nested_meta.span(); |
| 115 | + sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit(); |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + } |
| 120 | + registered |
| 121 | +} |
| 122 | + |
| 123 | +crate fn registered_attrs_and_tools( |
| 124 | + sess: &Session, |
| 125 | + attrs: &[ast::Attribute], |
| 126 | +) -> (FxHashSet<Ident>, FxHashSet<Ident>) { |
| 127 | + let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute"); |
| 128 | + let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool"); |
| 129 | + // We implicitly add `rustfmt` and `clippy` to known tools, |
| 130 | + // but it's not an error to register them explicitly. |
| 131 | + let predefined_tools = [sym::clippy, sym::rustfmt]; |
| 132 | + registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); |
| 133 | + (registered_attrs, registered_tools) |
| 134 | +} |
| 135 | + |
96 | 136 | impl<'a> base::Resolver for Resolver<'a> { |
97 | 137 | fn next_node_id(&mut self) -> NodeId { |
98 | 138 | self.session.next_node_id() |
@@ -531,6 +571,15 @@ impl<'a> Resolver<'a> { |
531 | 571 | Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), |
532 | 572 | } |
533 | 573 | } |
| 574 | + Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() { |
| 575 | + Some(ident) => { |
| 576 | + let binding = (Res::NonMacroAttr(NonMacroAttrKind::Registered), |
| 577 | + ty::Visibility::Public, ident.span, ExpnId::root()) |
| 578 | + .to_name_binding(this.arenas); |
| 579 | + Ok((binding, Flags::PRELUDE)) |
| 580 | + } |
| 581 | + None => Err(Determinacy::Determined) |
| 582 | + } |
534 | 583 | Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() { |
535 | 584 | Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)), |
536 | 585 | None => Err(Determinacy::determined( |
@@ -560,12 +609,14 @@ impl<'a> Resolver<'a> { |
560 | 609 | this.graph_root.unexpanded_invocations.borrow().is_empty() |
561 | 610 | )), |
562 | 611 | } |
563 | | - Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) { |
564 | | - let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, ExpnId::root()) |
565 | | - .to_name_binding(this.arenas); |
566 | | - Ok((binding, Flags::PRELUDE)) |
567 | | - } else { |
568 | | - Err(Determinacy::Determined) |
| 612 | + Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() { |
| 613 | + Some(ident) => { |
| 614 | + let binding = (Res::ToolMod, |
| 615 | + ty::Visibility::Public, ident.span, ExpnId::root()) |
| 616 | + .to_name_binding(this.arenas); |
| 617 | + Ok((binding, Flags::PRELUDE)) |
| 618 | + } |
| 619 | + None => Err(Determinacy::Determined) |
569 | 620 | } |
570 | 621 | Scope::StdLibPrelude => { |
571 | 622 | let mut result = Err(Determinacy::Determined); |
|
0 commit comments