}
}
+struct UsePlacementFinder {
+ target_module: NodeId,
+ span: Option<Span>,
+}
+
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
+ fn visit_mod(
+ &mut self,
+ module: &'tcx ast::Mod,
+ _: Span,
+ _: &[ast::Attribute],
+ node_id: NodeId,
+ ) {
+ if self.span.is_some() {
+ return;
+ }
+ if node_id != self.target_module {
+ visit::walk_mod(self, module);
+ return;
+ }
+ // find a use statement
+ for item in &module.items {
+ match item.node {
+ ItemKind::Use(..) => {
+ // don't suggest placing a use before the prelude
+ // import or other generated ones
+ if item.span == DUMMY_SP {
+ let mut span = item.span;
+ span.hi = span.lo;
+ self.span = Some(span);
+ return;
+ }
+ },
+ // don't place use before extern crate
+ ItemKind::ExternCrate(_) => {}
+ // but place them before the first other item
+ _ => if self.span.map_or(true, |span| item.span < span ) {
+ let mut span = item.span;
+ span.hi = span.lo;
+ self.span = Some(span);
+ },
+ }
+ }
+ assert!(self.span.is_some(), "a file can't have no items and emit suggestions");
+ }
+}
+
impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
fn visit_item(&mut self, item: &'tcx Item) {
self.resolve_item(item);
struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
+struct UseError<'a> {
+ err: DiagnosticBuilder<'a>,
+ /// Attach `use` statements for these candidates
+ candidates: Vec<ImportSuggestion>,
+ /// The node id of the module to place the use statements in
+ node_id: NodeId,
+ /// Whether the diagnostic should state that it's "better"
+ better: bool,
+}
+
struct AmbiguityError<'a> {
span: Span,
name: Name,
extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
pub make_glob_map: bool,
- // Maps imports to the names of items actually imported (this actually maps
- // all imports, but only glob imports are actually interesting).
+ /// Maps imports to the names of items actually imported (this actually maps
+ /// all imports, but only glob imports are actually interesting).
pub glob_map: GlobMap,
used_imports: FxHashSet<(NodeId, Namespace)>,
pub maybe_unused_trait_imports: NodeSet,
+ /// privacy errors are delayed until the end in order to deduplicate them
privacy_errors: Vec<PrivacyError<'a>>,
+ /// ambiguity errors are delayed for deduplication
ambiguity_errors: Vec<AmbiguityError<'a>>,
+ /// `use` injections are delayed for better placement and deduplication
+ use_injections: Vec<UseError<'a>>,
+
gated_errors: FxHashSet<Span>,
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
+ use_injections: Vec::new(),
gated_errors: FxHashSet(),
disallowed_shadowing: Vec::new(),
ImportResolver { resolver: self }.finalize_imports();
self.current_module = self.graph_root;
self.finalize_current_module_macro_resolutions();
+
visit::walk_crate(self, krate);
check_unused::check_crate(self, krate);
- self.report_errors();
+ self.report_errors(krate);
self.crate_loader.postprocess(krate);
}
__diagnostic_used!(E0411);
err.code("E0411".into());
err.span_label(span, "`Self` is only available in traits and impls");
- return err;
+ return (err, Vec::new());
}
if is_self_value(path, ns) {
__diagnostic_used!(E0424);
err.code("E0424".into());
err.span_label(span, format!("`self` value is only available in \
methods with `self` parameter"));
- return err;
+ return (err, Vec::new());
}
// Try to lookup the name in more relaxed fashion for better error reporting.
let ident = *path.last().unwrap();
let candidates = this.lookup_import_candidates(ident.node.name, ns, is_expected);
- if !candidates.is_empty() {
- let mut module_span = this.current_module.span;
- module_span.hi = module_span.lo;
- // Report import candidates as help and proceed searching for labels.
- show_candidates(&mut err, module_span, &candidates, def.is_some());
- } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
+ if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates =
this.lookup_import_candidates(ident.node.name, ns, is_enum_variant);
let mut enum_candidates = enum_candidates.iter()
format!("Self::{}", path_str));
}
}
- return err;
+ return (err, candidates);
}
}
match (def, source) {
(Def::Macro(..), _) => {
err.span_label(span, format!("did you mean `{}!(...)`?", path_str));
- return err;
+ return (err, candidates);
}
(Def::TyAlias(..), PathSource::Trait) => {
err.span_label(span, "type aliases cannot be used for traits");
- return err;
+ return (err, candidates);
}
(Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
ExprKind::Field(_, ident) => {
err.span_label(parent.span, format!("did you mean `{}::{}`?",
path_str, ident.node));
- return err;
+ return (err, candidates);
}
ExprKind::MethodCall(ref segment, ..) => {
err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
path_str, segment.identifier));
- return err;
+ return (err, candidates);
}
_ => {}
},
}
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
- return err;
+ return (err, candidates);
}
_ => {}
}
err.span_label(base_span, fallback_label);
this.type_ascription_suggestion(&mut err, base_span);
}
- err
+ (err, candidates)
};
let report_errors = |this: &mut Self, def: Option<Def>| {
- report_errors(this, def).emit();
+ let (err, candidates) = report_errors(this, def);
+ let def_id = this.current_module.normal_ancestor_id;
+ let node_id = this.definitions.as_local_node_id(def_id).unwrap();
+ let better = def.is_some();
+ this.use_injections.push(UseError { err, candidates, node_id, better });
err_path_resolution()
};
vis.is_accessible_from(module.normal_ancestor_id, self)
}
- fn report_errors(&mut self) {
+ fn report_errors(&mut self, krate: &Crate) {
self.report_shadowing_errors();
+ self.report_with_use_injections(krate);
let mut reported_spans = FxHashSet();
for &AmbiguityError { span, name, b1, b2, lexical, legacy } in &self.ambiguity_errors {
}
}
+ fn report_with_use_injections(&mut self, krate: &Crate) {
+ for UseError { mut err, candidates, node_id, better } in self.use_injections.drain(..) {
+ let mut finder = UsePlacementFinder {
+ target_module: node_id,
+ span: None,
+ };
+ visit::walk_crate(&mut finder, krate);
+ if !candidates.is_empty() {
+ let span = finder.span.expect("did not find module");
+ show_candidates(&mut err, span, &candidates, better);
+ }
+ err.emit();
+ }
+ }
+
fn report_shadowing_errors(&mut self) {
for (ident, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) {
self.resolve_legacy_scope(scope, ident, true);