Skip to content

Commit

Permalink
Suggest correct raw identifier in case of typo
Browse files Browse the repository at this point in the history
  • Loading branch information
olegnn committed Feb 10, 2020
1 parent 85ffd44 commit 477dac3
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 40 deletions.
62 changes: 31 additions & 31 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ type Res = def::Res<ast::NodeId>;
crate type Suggestion = (Vec<(Span, String)>, String, Applicability);

crate struct TypoSuggestion {
pub candidate: Symbol,
pub candidate: Ident,
pub res: Res,
}

impl TypoSuggestion {
crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
crate fn from_res(candidate: Ident, res: Res) -> TypoSuggestion {
TypoSuggestion { candidate, res }
}
}
Expand Down Expand Up @@ -107,7 +107,7 @@ impl<'a> Resolver<'a> {
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
if filter_fn(res) {
names.push(TypoSuggestion::from_res(key.ident.name, res));
names.push(TypoSuggestion::from_res(key.ident, res));
}
}
}
Expand Down Expand Up @@ -509,7 +509,7 @@ impl<'a> Resolver<'a> {
.get(&expn_id)
.into_iter()
.flatten()
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
.map(|ident| TypoSuggestion::from_res(*ident, res)),
);
}
}
Expand All @@ -525,11 +525,9 @@ impl<'a> Resolver<'a> {
false,
false,
) {
suggestions.extend(
ext.helper_attrs
.iter()
.map(|name| TypoSuggestion::from_res(*name, res)),
);
suggestions.extend(ext.helper_attrs.iter().map(|name| {
TypoSuggestion::from_res(Ident::new(*name, derive.span), res)
}));
}
}
}
Expand All @@ -538,8 +536,7 @@ impl<'a> Resolver<'a> {
if let LegacyScope::Binding(legacy_binding) = legacy_scope {
let res = legacy_binding.binding.res();
if filter_fn(res) {
suggestions
.push(TypoSuggestion::from_res(legacy_binding.ident.name, res))
suggestions.push(TypoSuggestion::from_res(legacy_binding.ident, res))
}
}
}
Expand All @@ -557,40 +554,40 @@ impl<'a> Resolver<'a> {
suggestions.extend(
this.registered_attrs
.iter()
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
.map(|ident| TypoSuggestion::from_res(*ident, res)),
);
}
}
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(
|(name, binding)| {
let res = binding.res();
filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
let span = binding.span;
filter_fn(res)
.then_some(TypoSuggestion::from_res(Ident::new(*name, span), res))
},
));
}
Scope::BuiltinAttrs => {
let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
if filter_fn(res) {
suggestions.extend(
BUILTIN_ATTRIBUTES
.iter()
.map(|(name, ..)| TypoSuggestion::from_res(*name, res)),
);
suggestions.extend(BUILTIN_ATTRIBUTES.iter().map(|(name, ..)| {
TypoSuggestion::from_res(Ident::with_dummy_span(*name), res)
}));
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res))
filter_fn(res).then_some(TypoSuggestion::from_res(*ident, res))
}));
}
Scope::ToolPrelude => {
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
suggestions.extend(
this.registered_tools
.iter()
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
.map(|ident| TypoSuggestion::from_res(*ident, res)),
);
}
Scope::StdLibPrelude => {
Expand All @@ -608,7 +605,8 @@ impl<'a> Resolver<'a> {
let primitive_types = &this.primitive_type_table.primitive_types;
suggestions.extend(primitive_types.iter().flat_map(|(name, prim_ty)| {
let res = Res::PrimTy(*prim_ty);
filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
filter_fn(res)
.then_some(TypoSuggestion::from_res(Ident::with_dummy_span(*name), res))
}))
}
}
Expand All @@ -620,12 +618,12 @@ impl<'a> Resolver<'a> {
suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());

match find_best_match_for_name(
suggestions.iter().map(|suggestion| &suggestion.candidate),
suggestions.iter().map(|suggestion| &suggestion.candidate.name),
&ident.as_str(),
None,
) {
Some(found) if found != ident.name => {
suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
suggestions.into_iter().find(|suggestion| suggestion.candidate.name == found)
}
_ => None,
}
Expand Down Expand Up @@ -805,7 +803,7 @@ impl<'a> Resolver<'a> {
) -> bool {
if let Some(suggestion) = suggestion {
// We shouldn't suggest underscore.
if suggestion.candidate == kw::Underscore {
if suggestion.candidate.name == kw::Underscore {
return false;
}

Expand All @@ -814,12 +812,6 @@ impl<'a> Resolver<'a> {
suggestion.res.article(),
suggestion.res.descr()
);
err.span_suggestion(
span,
&msg,
suggestion.candidate.to_string(),
Applicability::MaybeIncorrect,
);
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
LOCAL_CRATE => self.definitions.opt_span(def_id),
_ => Some(
Expand All @@ -828,16 +820,24 @@ impl<'a> Resolver<'a> {
.def_span(self.cstore().get_span_untracked(def_id, self.session)),
),
});
let candidate = def_span
.as_ref()
.map(|span| Ident::new(suggestion.candidate.name, *span))
.unwrap_or(suggestion.candidate);

err.span_suggestion(span, &msg, candidate.to_string(), Applicability::MaybeIncorrect);

if let Some(span) = def_span {
err.span_label(
span,
&format!(
"similarly named {} `{}` defined here",
suggestion.res.descr(),
suggestion.candidate.as_str(),
candidate.to_string(),
),
);
}

return true;
}
false
Expand Down
21 changes: 12 additions & 9 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
// Locals and type parameters
for (ident, &res) in &rib.bindings {
if filter_fn(res) {
names.push(TypoSuggestion::from_res(ident.name, res));
names.push(TypoSuggestion::from_res(*ident, res));
}
}
// Items in scope
Expand All @@ -672,7 +672,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
);

if filter_fn(crate_mod) {
Some(TypoSuggestion::from_res(ident.name, crate_mod))
Some(TypoSuggestion::from_res(*ident, crate_mod))
} else {
None
}
Expand All @@ -689,11 +689,14 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
}
// Add primitive types to the mix
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
names.extend(
self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
}),
)
names.extend(self.r.primitive_type_table.primitive_types.iter().map(
|(name, prim_ty)| {
TypoSuggestion::from_res(
Ident::with_dummy_span(*name),
Res::PrimTy(*prim_ty),
)
},
))
}
} else {
// Search in module.
Expand All @@ -712,12 +715,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());

match find_best_match_for_name(
names.iter().map(|suggestion| &suggestion.candidate),
names.iter().map(|suggestion| &suggestion.candidate.name),
&name.as_str(),
None,
) {
Some(found) if found != name => {
names.into_iter().find(|suggestion| suggestion.candidate == found)
names.into_iter().find(|suggestion| suggestion.candidate.name == found)
}
_ => None,
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/span/issue-68962.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn r#fn() {}

fn main() {
let r#final = 1;

// Should correctly suggest variable defined using raw identifier.
fina; //~ ERROR cannot find value

// Should correctly suggest function defined using raw identifier.
f(); //~ ERROR cannot find function
}
18 changes: 18 additions & 0 deletions src/test/ui/span/issue-68962.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0425]: cannot find value `fina` in this scope
--> $DIR/issue-68962.rs:7:5
|
LL | fina;
| ^^^^ help: a local variable with a similar name exists: `r#final`

error[E0425]: cannot find function `f` in this scope
--> $DIR/issue-68962.rs:10:5
|
LL | fn r#fn() {}
| ------------ similarly named function `r#fn` defined here
...
LL | f();
| ^ help: a function with a similar name exists: `r#fn`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0425`.

0 comments on commit 477dac3

Please sign in to comment.