Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dff9ee1

Browse files
committedMay 15, 2018
rustc: Fix crate lint for single-item paths
This commit fixes recommending the `crate` prefix when migrating to 2018 for paths that look like `use foo;` or `use {bar, baz}` Closes #50660
1 parent 3e955a0 commit dff9ee1

File tree

8 files changed

+287
-47
lines changed

8 files changed

+287
-47
lines changed
 

‎src/librustc/lint/builtin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ declare_lint! {
261261
}
262262

263263
declare_lint! {
264-
pub ABSOLUTE_PATH_STARTING_WITH_MODULE,
264+
pub ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
265265
Allow,
266266
"fully qualified paths that start with a module name \
267267
instead of `crate`, `self`, or an extern crate name"
@@ -328,7 +328,7 @@ impl LintPass for HardwiredLints {
328328
TYVAR_BEHIND_RAW_POINTER,
329329
ELIDED_LIFETIME_IN_PATH,
330330
BARE_TRAIT_OBJECT,
331-
ABSOLUTE_PATH_STARTING_WITH_MODULE,
331+
ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
332332
UNSTABLE_NAME_COLLISION,
333333
)
334334
}

‎src/librustc_lint/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ extern crate rustc_target;
4040
extern crate syntax_pos;
4141

4242
use rustc::lint;
43-
use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_STARTING_WITH_MODULE};
43+
use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE};
4444
use rustc::session;
4545
use rustc::util;
4646

@@ -282,7 +282,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
282282
// standard library, and thus should never be removed or changed to an error.
283283
},
284284
FutureIncompatibleInfo {
285-
id: LintId::of(ABSOLUTE_PATH_STARTING_WITH_MODULE),
285+
id: LintId::of(ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE),
286286
reference: "issue TBD",
287287
edition: Some(Edition::Edition2018),
288288
},
@@ -321,4 +321,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
321321
"converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
322322
store.register_removed("resolve_trait_on_defaulted_unit",
323323
"converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
324+
store.register_removed("absolute_path_starting_with_module",
325+
"renamed to `absolute_path_not_starting_with_crate`");
324326
}

‎src/librustc_resolve/lib.rs

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3232,6 +3232,7 @@ impl<'a> Resolver<'a> {
32323232
-> PathResult<'a> {
32333233
let mut module = None;
32343234
let mut allow_super = true;
3235+
let mut second_binding = None;
32353236

32363237
for (i, &ident) in path.iter().enumerate() {
32373238
debug!("resolve_path ident {} {:?}", i, ident);
@@ -3321,7 +3322,9 @@ impl<'a> Resolver<'a> {
33213322
.map(MacroBinding::binding)
33223323
} else {
33233324
match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
3325+
// we found a locally-imported or available item/module
33243326
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
3327+
// we found a local variable or type param
33253328
Some(LexicalScopeBinding::Def(def))
33263329
if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
33273330
return PathResult::NonModule(PathResolution::with_unresolved_segments(
@@ -3334,13 +3337,22 @@ impl<'a> Resolver<'a> {
33343337

33353338
match binding {
33363339
Ok(binding) => {
3340+
if i == 1 {
3341+
second_binding = Some(binding);
3342+
}
33373343
let def = binding.def();
33383344
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
33393345
if let Some(next_module) = binding.module() {
33403346
module = Some(next_module);
33413347
} else if def == Def::Err {
33423348
return PathResult::NonModule(err_path_resolution());
33433349
} else if opt_ns.is_some() && (is_last || maybe_assoc) {
3350+
self.lint_if_path_starts_with_module(
3351+
node_id,
3352+
path,
3353+
path_span,
3354+
second_binding,
3355+
);
33443356
return PathResult::NonModule(PathResolution::with_unresolved_segments(
33453357
def, path.len() - i - 1
33463358
));
@@ -3349,33 +3361,6 @@ impl<'a> Resolver<'a> {
33493361
format!("Not a module `{}`", ident),
33503362
is_last);
33513363
}
3352-
3353-
if let Some(id) = node_id {
3354-
if i == 1 && self.session.features_untracked().crate_in_paths
3355-
&& !self.session.rust_2018() {
3356-
let prev_name = path[0].name;
3357-
if prev_name == keywords::Extern.name() ||
3358-
prev_name == keywords::CrateRoot.name() {
3359-
let mut is_crate = false;
3360-
if let NameBindingKind::Import { directive: d, .. } = binding.kind {
3361-
if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
3362-
is_crate = true;
3363-
}
3364-
}
3365-
3366-
if !is_crate {
3367-
let diag = lint::builtin::BuiltinLintDiagnostics
3368-
::AbsPathWithModule(path_span);
3369-
self.session.buffer_lint_with_diagnostic(
3370-
lint::builtin::ABSOLUTE_PATH_STARTING_WITH_MODULE,
3371-
id, path_span,
3372-
"Absolute paths must start with `self`, `super`, \
3373-
`crate`, or an external crate name in the 2018 edition",
3374-
diag);
3375-
}
3376-
}
3377-
}
3378-
}
33793364
}
33803365
Err(Undetermined) => return PathResult::Indeterminate,
33813366
Err(Determined) => {
@@ -3408,9 +3393,77 @@ impl<'a> Resolver<'a> {
34083393
}
34093394
}
34103395

3396+
self.lint_if_path_starts_with_module(node_id, path, path_span, second_binding);
3397+
34113398
PathResult::Module(module.unwrap_or(self.graph_root))
34123399
}
34133400

3401+
fn lint_if_path_starts_with_module(&self,
3402+
id: Option<NodeId>,
3403+
path: &[Ident],
3404+
path_span: Span,
3405+
second_binding: Option<&NameBinding>) {
3406+
let id = match id {
3407+
Some(id) => id,
3408+
None => return,
3409+
};
3410+
3411+
let first_name = match path.get(0) {
3412+
Some(ident) => ident.name,
3413+
None => return,
3414+
};
3415+
3416+
// We're only interested in `use` paths which should start with
3417+
// `{{root}}` or `extern` currently.
3418+
if first_name != keywords::Extern.name() && first_name != keywords::CrateRoot.name() {
3419+
return
3420+
}
3421+
3422+
match path.get(1) {
3423+
// If this import looks like `crate::...` it's already good
3424+
Some(name) if name.name == keywords::Crate.name() => return,
3425+
// Otherwise go below to see if it's an extern crate
3426+
Some(_) => {}
3427+
// If the path has length one (and it's `CrateRoot` most likely)
3428+
// then we don't know whether we're gonna be importing a crate or an
3429+
// item in our crate. Defer this lint to elsewhere
3430+
None => return,
3431+
}
3432+
3433+
// If the first element of our path was actually resolved to an
3434+
// `ExternCrate` (also used for `crate::...`) then no need to issue a
3435+
// warning, this looks all good!
3436+
if let Some(binding) = second_binding {
3437+
if let NameBindingKind::Import { directive: d, .. } = binding.kind {
3438+
if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
3439+
return
3440+
}
3441+
}
3442+
}
3443+
3444+
self.lint_path_starts_with_module(id, path_span);
3445+
}
3446+
3447+
fn lint_path_starts_with_module(&self, id: NodeId, span: Span) {
3448+
// In the 2018 edition this lint is a hard error, so nothing to do
3449+
if self.session.rust_2018() {
3450+
return
3451+
}
3452+
// In the 2015 edition there's no use in emitting lints unless the
3453+
// crate's already enabled the feature that we're going to suggest
3454+
if !self.session.features_untracked().crate_in_paths {
3455+
return
3456+
}
3457+
let diag = lint::builtin::BuiltinLintDiagnostics
3458+
::AbsPathWithModule(span);
3459+
self.session.buffer_lint_with_diagnostic(
3460+
lint::builtin::ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
3461+
id, span,
3462+
"absolute paths must start with `self`, `super`, \
3463+
`crate`, or an external crate name in the 2018 edition",
3464+
diag);
3465+
}
3466+
34143467
// Resolve a local definition, potentially adjusting for closures.
34153468
fn adjust_local_def(&mut self,
34163469
ns: Namespace,

‎src/librustc_resolve/resolve_imports.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
640640
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
641641
self.current_module = directive.parent;
642642
let ImportDirective { ref module_path, span, .. } = *directive;
643+
let mut warn_if_binding_comes_from_local_crate = false;
643644

644645
// FIXME: Last path segment is treated specially in import resolution, so extern crate
645646
// mode for absolute paths needs some special support for single-segment imports.
@@ -653,6 +654,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
653654
return Some((directive.span,
654655
"cannot glob-import all possible crates".to_string()));
655656
}
657+
GlobImport { .. } if self.session.features_untracked().extern_absolute_paths => {
658+
self.lint_path_starts_with_module(directive.id, span);
659+
}
656660
SingleImport { source, target, .. } => {
657661
let crate_root = if source.name == keywords::Crate.name() &&
658662
module_path[0].name != keywords::Extern.name() {
@@ -676,6 +680,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
676680
self.populate_module_if_necessary(crate_root);
677681
Some(crate_root)
678682
} else {
683+
warn_if_binding_comes_from_local_crate = true;
679684
None
680685
};
681686

@@ -870,6 +875,26 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
870875
}
871876
}
872877

878+
if warn_if_binding_comes_from_local_crate {
879+
let mut warned = false;
880+
self.per_ns(|this, ns| {
881+
let binding = match result[ns].get().ok() {
882+
Some(b) => b,
883+
None => return
884+
};
885+
if let NameBindingKind::Import { directive: d, .. } = binding.kind {
886+
if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
887+
return
888+
}
889+
}
890+
if warned {
891+
return
892+
}
893+
warned = true;
894+
this.lint_path_starts_with_module(directive.id, span);
895+
});
896+
}
897+
873898
// Record what this import resolves to for later uses in documentation,
874899
// this may resolve to either a value or a type, but for documentation
875900
// purposes it's good enough to just favor one over the other.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2018 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+
pub fn foo() {}

‎src/test/ui/edition-lint-paths.fixed

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2018 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+
// aux-build:edition-lint-paths.rs
12+
// run-rustfix
13+
14+
#![feature(rust_2018_preview)]
15+
#![deny(absolute_path_not_starting_with_crate)]
16+
#![allow(unused)]
17+
18+
extern crate edition_lint_paths;
19+
20+
pub mod foo {
21+
use edition_lint_paths;
22+
use crate::bar::Bar;
23+
//~^ ERROR absolute
24+
//~| WARN this was previously accepted
25+
use super::bar::Bar2;
26+
use crate::bar::Bar3;
27+
28+
use crate::bar;
29+
//~^ ERROR absolute
30+
//~| WARN this was previously accepted
31+
use crate::{bar as something_else};
32+
33+
use {crate::Bar as SomethingElse, crate::main};
34+
//~^ ERROR absolute
35+
//~| WARN this was previously accepted
36+
//~| ERROR absolute
37+
//~| WARN this was previously accepted
38+
39+
use crate::{Bar as SomethingElse2, main as another_main};
40+
41+
pub fn test() {
42+
}
43+
}
44+
45+
use crate::bar::Bar;
46+
//~^ ERROR absolute
47+
//~| WARN this was previously accepted
48+
49+
pub mod bar {
50+
use edition_lint_paths as foo;
51+
pub struct Bar;
52+
pub type Bar2 = Bar;
53+
pub type Bar3 = Bar;
54+
}
55+
56+
mod baz {
57+
use crate::*;
58+
//~^ ERROR absolute
59+
//~| WARN this was previously accepted
60+
}
61+
62+
fn main() {
63+
let x = crate::bar::Bar;
64+
//~^ ERROR absolute
65+
//~| WARN this was previously accepted
66+
let x = bar::Bar;
67+
let x = ::crate::bar::Bar;
68+
let x = self::bar::Bar;
69+
foo::test();
70+
71+
{
72+
use edition_lint_paths as bar;
73+
edition_lint_paths::foo();
74+
bar::foo();
75+
::edition_lint_paths::foo();
76+
}
77+
}

‎src/test/ui/edition-lint-paths.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,70 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(crate_in_paths)]
12-
#![deny(absolute_path_starting_with_module)]
11+
// aux-build:edition-lint-paths.rs
12+
// run-rustfix
13+
14+
#![feature(rust_2018_preview)]
15+
#![deny(absolute_path_not_starting_with_crate)]
1316
#![allow(unused)]
1417

18+
extern crate edition_lint_paths;
19+
1520
pub mod foo {
21+
use edition_lint_paths;
1622
use ::bar::Bar;
17-
//~^ ERROR Absolute
23+
//~^ ERROR absolute
1824
//~| WARN this was previously accepted
1925
use super::bar::Bar2;
2026
use crate::bar::Bar3;
21-
}
2227

28+
use bar;
29+
//~^ ERROR absolute
30+
//~| WARN this was previously accepted
31+
use crate::{bar as something_else};
32+
33+
use {Bar as SomethingElse, main};
34+
//~^ ERROR absolute
35+
//~| WARN this was previously accepted
36+
//~| ERROR absolute
37+
//~| WARN this was previously accepted
38+
39+
use crate::{Bar as SomethingElse2, main as another_main};
40+
41+
pub fn test() {
42+
}
43+
}
2344

2445
use bar::Bar;
25-
//~^ ERROR Absolute
46+
//~^ ERROR absolute
2647
//~| WARN this was previously accepted
2748

2849
pub mod bar {
50+
use edition_lint_paths as foo;
2951
pub struct Bar;
3052
pub type Bar2 = Bar;
3153
pub type Bar3 = Bar;
3254
}
3355

56+
mod baz {
57+
use *;
58+
//~^ ERROR absolute
59+
//~| WARN this was previously accepted
60+
}
61+
3462
fn main() {
3563
let x = ::bar::Bar;
36-
//~^ ERROR Absolute
64+
//~^ ERROR absolute
3765
//~| WARN this was previously accepted
3866
let x = bar::Bar;
3967
let x = ::crate::bar::Bar;
4068
let x = self::bar::Bar;
69+
foo::test();
70+
71+
{
72+
use edition_lint_paths as bar;
73+
edition_lint_paths::foo();
74+
bar::foo();
75+
::edition_lint_paths::foo();
76+
}
4177
}

‎src/test/ui/edition-lint-paths.stderr

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,70 @@
1-
error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
2-
--> $DIR/edition-lint-paths.rs:16:9
1+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
2+
--> $DIR/edition-lint-paths.rs:22:9
33
|
44
LL | use ::bar::Bar;
55
| ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
66
|
77
note: lint level defined here
8-
--> $DIR/edition-lint-paths.rs:12:9
8+
--> $DIR/edition-lint-paths.rs:15:9
99
|
10-
LL | #![deny(absolute_path_starting_with_module)]
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
LL | #![deny(absolute_path_not_starting_with_crate)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
1313
= note: for more information, see issue TBD
1414

15-
error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
16-
--> $DIR/edition-lint-paths.rs:24:5
15+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
16+
--> $DIR/edition-lint-paths.rs:28:9
17+
|
18+
LL | use bar;
19+
| ^^^ help: use `crate`: `crate::bar`
20+
|
21+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
22+
= note: for more information, see issue TBD
23+
24+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
25+
--> $DIR/edition-lint-paths.rs:33:10
26+
|
27+
LL | use {Bar as SomethingElse, main};
28+
| ^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::Bar as SomethingElse`
29+
|
30+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
31+
= note: for more information, see issue TBD
32+
33+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
34+
--> $DIR/edition-lint-paths.rs:33:32
35+
|
36+
LL | use {Bar as SomethingElse, main};
37+
| ^^^^ help: use `crate`: `crate::main`
38+
|
39+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
40+
= note: for more information, see issue TBD
41+
42+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
43+
--> $DIR/edition-lint-paths.rs:45:5
1744
|
1845
LL | use bar::Bar;
1946
| ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
2047
|
2148
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
2249
= note: for more information, see issue TBD
2350

24-
error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
25-
--> $DIR/edition-lint-paths.rs:35:13
51+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
52+
--> $DIR/edition-lint-paths.rs:57:9
53+
|
54+
LL | use *;
55+
| ^ help: use `crate`: `crate::*`
56+
|
57+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
58+
= note: for more information, see issue TBD
59+
60+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
61+
--> $DIR/edition-lint-paths.rs:63:13
2662
|
2763
LL | let x = ::bar::Bar;
2864
| ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
2965
|
3066
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
3167
= note: for more information, see issue TBD
3268

33-
error: aborting due to 3 previous errors
69+
error: aborting due to 7 previous errors
3470

0 commit comments

Comments
 (0)
Please sign in to comment.