Skip to content

Commit 5dc91a7

Browse files
committed
Auto merge of #30064 - fhartwig:macro-suggestions, r=sanxiyn
Fixes #13677 This does the same sort of suggestion for misspelt macros that we already do for misspelt identifiers. Example. Compiling this program: ```rust macro_rules! foo { ($e:expr) => ( $e ) } fn main() { fob!("hello!"); } ``` gives the following error message: ``` /Users/mcp/temp/test.rs:7:5: 7:8 error: macro undefined: 'fob!' /Users/mcp/temp/test.rs:7 fob!("hello!"); ^~~ /Users/mcp/temp/test.rs:7:5: 7:8 help: did you mean `foo`? /Users/mcp/temp/test.rs:7 fob!("hello!"); ``` I had to move the levenshtein distance function into libsyntax for this. Maybe this should live somewhere else (some utility crate?), but I couldn't find a crate to put it in that is imported by libsyntax and the other rustc crates.
2 parents ca63650 + 4bb7cf1 commit 5dc91a7

File tree

8 files changed

+42
-8
lines changed

8 files changed

+42
-8
lines changed

src/librustc/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ pub mod util {
146146
pub mod common;
147147
pub mod ppaux;
148148
pub mod nodemap;
149-
pub mod lev_distance;
150149
pub mod num;
151150
pub mod fs;
152151
}

src/librustc_resolve/lib.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ use rustc::middle::privacy::*;
6262
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
6363
use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
6464
use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
65-
use rustc::util::lev_distance::lev_distance;
6665

6766
use syntax::ast;
6867
use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
@@ -72,6 +71,7 @@ use syntax::ext::mtwt;
7271
use syntax::parse::token::{self, special_names, special_idents};
7372
use syntax::ptr::P;
7473
use syntax::codemap::{self, Span, Pos};
74+
use syntax::util::lev_distance::{lev_distance, max_suggestion_distance};
7575

7676
use rustc_front::intravisit::{self, FnKind, Visitor};
7777
use rustc_front::hir;
@@ -3383,11 +3383,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
33833383
}
33843384
}
33853385

3386-
// As a loose rule to avoid obviously incorrect suggestions, clamp the
3387-
// maximum edit distance we will accept for a suggestion to one third of
3388-
// the typo'd name's length.
3389-
let max_distance = std::cmp::max(name.len(), 3) / 3;
3390-
3386+
let max_distance = max_suggestion_distance(name);
33913387
if !values.is_empty() && values[smallest] <= max_distance && name != &maybes[smallest][..] {
33923388

33933389
SuggestionType::Function(maybes[smallest].to_string())

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ use TypeAndSubsts;
110110
use lint;
111111
use util::common::{block_query, ErrorReported, indenter, loop_query};
112112
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
113-
use util::lev_distance::lev_distance;
114113

115114
use std::cell::{Cell, Ref, RefCell};
116115
use std::collections::{HashSet};
@@ -123,6 +122,7 @@ use syntax::codemap::{self, Span, Spanned};
123122
use syntax::owned_slice::OwnedSlice;
124123
use syntax::parse::token::{self, InternedString};
125124
use syntax::ptr::P;
125+
use syntax::util::lev_distance::lev_distance;
126126

127127
use rustc_front::intravisit::{self, Visitor};
128128
use rustc_front::hir;

src/libsyntax/ext/base.rs

+15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use parse::token;
2424
use parse::token::{InternedString, intern, str_to_ident};
2525
use ptr::P;
2626
use util::small_vector::SmallVector;
27+
use util::lev_distance::{lev_distance, max_suggestion_distance};
2728
use ext::mtwt;
2829
use fold::Folder;
2930

@@ -776,6 +777,20 @@ impl<'a> ExtCtxt<'a> {
776777
pub fn name_of(&self, st: &str) -> ast::Name {
777778
token::intern(st)
778779
}
780+
781+
pub fn suggest_macro_name(&mut self, name: &str, span: Span) {
782+
let mut min: Option<(Name, usize)> = None;
783+
let max_dist = max_suggestion_distance(name);
784+
for macro_name in self.syntax_env.names.iter() {
785+
let dist = lev_distance(name, &macro_name.as_str());
786+
if dist <= max_dist && (min.is_none() || min.unwrap().1 > dist) {
787+
min = Some((*macro_name, dist));
788+
}
789+
}
790+
if let Some((suggestion, _)) = min {
791+
self.fileline_help(span, &format!("did you mean `{}!`?", suggestion));
792+
}
793+
}
779794
}
780795

781796
/// Extract a string literal from the macro expanded version of `expr`,

src/libsyntax/ext/expand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
191191
pth.span,
192192
&format!("macro undefined: '{}!'",
193193
&extname));
194+
fld.cx.suggest_macro_name(&extname.as_str(), pth.span);
194195

195196
// let compilation continue
196197
None

src/libsyntax/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ macro_rules! panictry {
6565

6666
pub mod util {
6767
pub mod interner;
68+
pub mod lev_distance;
6869
pub mod node_count;
6970
pub mod parser;
7071
#[cfg(test)]

src/librustc/util/lev_distance.rs src/libsyntax/util/lev_distance.rs

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ pub fn lev_distance(me: &str, t: &str) -> usize {
4141
dcol[t_last + 1]
4242
}
4343

44+
pub fn max_suggestion_distance(name: &str) -> usize {
45+
use std::cmp::max;
46+
// As a loose rule to avoid obviously incorrect suggestions, clamp the
47+
// maximum edit distance we will accept for a suggestion to one third of
48+
// the typo'd name's length.
49+
max(name.len(), 3) / 3
50+
}
51+
4452
#[test]
4553
fn test_lev_distance() {
4654
use std::char::{ from_u32, MAX };
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
printlx!("oh noes!"); //~ ERROR macro undefined
13+
//~^ HELP did you mean `println!`?
14+
}

0 commit comments

Comments
 (0)