]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #50665 - alexcrichton:fix-single-item-path-warnings, r=oli-obk
authorbors <bors@rust-lang.org>
Thu, 17 May 2018 05:00:14 +0000 (05:00 +0000)
committerbors <bors@rust-lang.org>
Thu, 17 May 2018 05:00:14 +0000 (05:00 +0000)
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

src/librustc/lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/test/ui/auxiliary/edition-lint-paths.rs [new file with mode: 0644]
src/test/ui/edition-lint-paths.fixed [new file with mode: 0644]
src/test/ui/edition-lint-paths.rs
src/test/ui/edition-lint-paths.stderr

index 4f015ed1ce161c5163c7b1fe8b61306e91f606f9..5ebea52f3c5ad9a8e2d09ab6076554c0de27821f 100644 (file)
 }
 
 declare_lint! {
-    pub ABSOLUTE_PATH_STARTING_WITH_MODULE,
+    pub ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
     Allow,
     "fully qualified paths that start with a module name \
      instead of `crate`, `self`, or an extern crate name"
@@ -328,7 +328,7 @@ fn get_lints(&self) -> LintArray {
             TYVAR_BEHIND_RAW_POINTER,
             ELIDED_LIFETIME_IN_PATH,
             BARE_TRAIT_OBJECT,
-            ABSOLUTE_PATH_STARTING_WITH_MODULE,
+            ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
             UNSTABLE_NAME_COLLISION,
         )
     }
index ae44ea6b65b9ac596f6b39a8dee13be8a8e7b87b..0ae133640fad9feb93bd68ce0faec1a271cbaa4b 100644 (file)
@@ -40,7 +40,7 @@
 extern crate syntax_pos;
 
 use rustc::lint;
-use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_STARTING_WITH_MODULE};
+use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE};
 use rustc::session;
 use rustc::util;
 
@@ -283,7 +283,7 @@ macro_rules! add_lint_group {
             //       standard library, and thus should never be removed or changed to an error.
         },
         FutureIncompatibleInfo {
-            id: LintId::of(ABSOLUTE_PATH_STARTING_WITH_MODULE),
+            id: LintId::of(ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE),
             reference: "issue TBD",
             edition: Some(Edition::Edition2018),
         },
@@ -322,4 +322,6 @@ macro_rules! add_lint_group {
         "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
     store.register_removed("resolve_trait_on_defaulted_unit",
         "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
+    store.register_removed("absolute_path_starting_with_module",
+        "renamed to `absolute_path_not_starting_with_crate`");
 }
index d2934bc9ee8acc10ebddc9e19c62a33bef8225c5..5a5f5ce2e3862ced35e702215ad345e9eff85919 100644 (file)
@@ -3232,6 +3232,7 @@ fn resolve_path(&mut self,
                     -> PathResult<'a> {
         let mut module = None;
         let mut allow_super = true;
+        let mut second_binding = None;
 
         for (i, &ident) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?}", i, ident);
@@ -3321,7 +3322,9 @@ fn resolve_path(&mut self,
                     .map(MacroBinding::binding)
             } else {
                 match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
+                    // we found a locally-imported or available item/module
                     Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
+                    // we found a local variable or type param
                     Some(LexicalScopeBinding::Def(def))
                             if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
                         return PathResult::NonModule(PathResolution::with_unresolved_segments(
@@ -3334,6 +3337,9 @@ fn resolve_path(&mut self,
 
             match binding {
                 Ok(binding) => {
+                    if i == 1 {
+                        second_binding = Some(binding);
+                    }
                     let def = binding.def();
                     let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
                     if let Some(next_module) = binding.module() {
@@ -3341,6 +3347,12 @@ fn resolve_path(&mut self,
                     } else if def == Def::Err {
                         return PathResult::NonModule(err_path_resolution());
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
+                        self.lint_if_path_starts_with_module(
+                            node_id,
+                            path,
+                            path_span,
+                            second_binding,
+                        );
                         return PathResult::NonModule(PathResolution::with_unresolved_segments(
                             def, path.len() - i - 1
                         ));
@@ -3349,33 +3361,6 @@ fn resolve_path(&mut self,
                                                   format!("Not a module `{}`", ident),
                                                   is_last);
                     }
-
-                    if let Some(id) = node_id {
-                        if i == 1 && self.session.features_untracked().crate_in_paths
-                                  && !self.session.rust_2018() {
-                            let prev_name = path[0].name;
-                            if prev_name == keywords::Extern.name() ||
-                               prev_name == keywords::CrateRoot.name() {
-                                let mut is_crate = false;
-                                if let NameBindingKind::Import { directive: d, .. } = binding.kind {
-                                    if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
-                                        is_crate = true;
-                                    }
-                                }
-
-                                if !is_crate {
-                                    let diag = lint::builtin::BuiltinLintDiagnostics
-                                                   ::AbsPathWithModule(path_span);
-                                    self.session.buffer_lint_with_diagnostic(
-                                        lint::builtin::ABSOLUTE_PATH_STARTING_WITH_MODULE,
-                                        id, path_span,
-                                        "Absolute paths must start with `self`, `super`, \
-                                        `crate`, or an external crate name in the 2018 edition",
-                                        diag);
-                                }
-                            }
-                        }
-                    }
                 }
                 Err(Undetermined) => return PathResult::Indeterminate,
                 Err(Determined) => {
@@ -3408,9 +3393,77 @@ fn resolve_path(&mut self,
             }
         }
 
+        self.lint_if_path_starts_with_module(node_id, path, path_span, second_binding);
+
         PathResult::Module(module.unwrap_or(self.graph_root))
     }
 
+    fn lint_if_path_starts_with_module(&self,
+                                       id: Option<NodeId>,
+                                       path: &[Ident],
+                                       path_span: Span,
+                                       second_binding: Option<&NameBinding>) {
+        let id = match id {
+            Some(id) => id,
+            None => return,
+        };
+
+        let first_name = match path.get(0) {
+            Some(ident) => ident.name,
+            None => return,
+        };
+
+        // We're only interested in `use` paths which should start with
+        // `{{root}}` or `extern` currently.
+        if first_name != keywords::Extern.name() && first_name != keywords::CrateRoot.name() {
+            return
+        }
+
+        match path.get(1) {
+            // If this import looks like `crate::...` it's already good
+            Some(name) if name.name == keywords::Crate.name() => return,
+            // Otherwise go below to see if it's an extern crate
+            Some(_) => {}
+            // If the path has length one (and it's `CrateRoot` most likely)
+            // then we don't know whether we're gonna be importing a crate or an
+            // item in our crate. Defer this lint to elsewhere
+            None => return,
+        }
+
+        // If the first element of our path was actually resolved to an
+        // `ExternCrate` (also used for `crate::...`) then no need to issue a
+        // warning, this looks all good!
+        if let Some(binding) = second_binding {
+            if let NameBindingKind::Import { directive: d, .. } = binding.kind {
+                if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
+                    return
+                }
+            }
+        }
+
+        self.lint_path_starts_with_module(id, path_span);
+    }
+
+    fn lint_path_starts_with_module(&self, id: NodeId, span: Span) {
+        // In the 2018 edition this lint is a hard error, so nothing to do
+        if self.session.rust_2018() {
+            return
+        }
+        // In the 2015 edition there's no use in emitting lints unless the
+        // crate's already enabled the feature that we're going to suggest
+        if !self.session.features_untracked().crate_in_paths {
+            return
+        }
+        let diag = lint::builtin::BuiltinLintDiagnostics
+            ::AbsPathWithModule(span);
+        self.session.buffer_lint_with_diagnostic(
+            lint::builtin::ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
+            id, span,
+            "absolute paths must start with `self`, `super`, \
+            `crate`, or an external crate name in the 2018 edition",
+            diag);
+    }
+
     // Resolve a local definition, potentially adjusting for closures.
     fn adjust_local_def(&mut self,
                         ns: Namespace,
index 6a5a31a885fb9855c880239da9df6a23358da1cc..09c421fba47b1abb5140bc962e5a10181e688434 100644 (file)
@@ -640,6 +640,7 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
     fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
         self.current_module = directive.parent;
         let ImportDirective { ref module_path, span, .. } = *directive;
+        let mut warn_if_binding_comes_from_local_crate = false;
 
         // FIXME: Last path segment is treated specially in import resolution, so extern crate
         // mode for absolute paths needs some special support for single-segment imports.
@@ -653,6 +654,9 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
                     return Some((directive.span,
                                  "cannot glob-import all possible crates".to_string()));
                 }
+                GlobImport { .. } if self.session.features_untracked().extern_absolute_paths => {
+                    self.lint_path_starts_with_module(directive.id, span);
+                }
                 SingleImport { source, target, .. } => {
                     let crate_root = if source.name == keywords::Crate.name() &&
                                         module_path[0].name != keywords::Extern.name() {
@@ -676,6 +680,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
                         self.populate_module_if_necessary(crate_root);
                         Some(crate_root)
                     } else {
+                        warn_if_binding_comes_from_local_crate = true;
                         None
                     };
 
@@ -870,6 +875,26 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
             }
         }
 
+        if warn_if_binding_comes_from_local_crate {
+            let mut warned = false;
+            self.per_ns(|this, ns| {
+                let binding = match result[ns].get().ok() {
+                    Some(b) => b,
+                    None => return
+                };
+                if let NameBindingKind::Import { directive: d, .. } = binding.kind {
+                    if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
+                        return
+                    }
+                }
+                if warned {
+                    return
+                }
+                warned = true;
+                this.lint_path_starts_with_module(directive.id, span);
+            });
+        }
+
         // Record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
diff --git a/src/test/ui/auxiliary/edition-lint-paths.rs b/src/test/ui/auxiliary/edition-lint-paths.rs
new file mode 100644 (file)
index 0000000..cc17a9b
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn foo() {}
diff --git a/src/test/ui/edition-lint-paths.fixed b/src/test/ui/edition-lint-paths.fixed
new file mode 100644 (file)
index 0000000..9975a6d
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:edition-lint-paths.rs
+// run-rustfix
+
+#![feature(rust_2018_preview)]
+#![deny(absolute_path_not_starting_with_crate)]
+#![allow(unused)]
+
+extern crate edition_lint_paths;
+
+pub mod foo {
+    use edition_lint_paths;
+    use crate::bar::Bar;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    use super::bar::Bar2;
+    use crate::bar::Bar3;
+
+    use crate::bar;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    use crate::{bar as something_else};
+
+    use {crate::Bar as SomethingElse, crate::main};
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    //~| ERROR absolute
+    //~| WARN this was previously accepted
+
+    use crate::{Bar as SomethingElse2, main as another_main};
+
+    pub fn test() {
+    }
+}
+
+use crate::bar::Bar;
+//~^ ERROR absolute
+//~| WARN this was previously accepted
+
+pub mod bar {
+    use edition_lint_paths as foo;
+    pub struct Bar;
+    pub type Bar2 = Bar;
+    pub type Bar3 = Bar;
+}
+
+mod baz {
+    use crate::*;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+}
+
+fn main() {
+    let x = crate::bar::Bar;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    let x = bar::Bar;
+    let x = ::crate::bar::Bar;
+    let x = self::bar::Bar;
+    foo::test();
+
+    {
+        use edition_lint_paths as bar;
+        edition_lint_paths::foo();
+        bar::foo();
+        ::edition_lint_paths::foo();
+    }
+}
index 0b49e72ccd94c4d57279a657eb799cdcd1b36475..6cc3295a4d95bbb9988e09662d47952cb0a08435 100644 (file)
@@ -8,34 +8,70 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(crate_in_paths)]
-#![deny(absolute_path_starting_with_module)]
+// aux-build:edition-lint-paths.rs
+// run-rustfix
+
+#![feature(rust_2018_preview)]
+#![deny(absolute_path_not_starting_with_crate)]
 #![allow(unused)]
 
+extern crate edition_lint_paths;
+
 pub mod foo {
+    use edition_lint_paths;
     use ::bar::Bar;
-    //~^ ERROR Absolute
+    //~^ ERROR absolute
     //~| WARN this was previously accepted
     use super::bar::Bar2;
     use crate::bar::Bar3;
-}
 
+    use bar;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    use crate::{bar as something_else};
+
+    use {Bar as SomethingElse, main};
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+    //~| ERROR absolute
+    //~| WARN this was previously accepted
+
+    use crate::{Bar as SomethingElse2, main as another_main};
+
+    pub fn test() {
+    }
+}
 
 use bar::Bar;
-//~^ ERROR Absolute
+//~^ ERROR absolute
 //~| WARN this was previously accepted
 
 pub mod bar {
+    use edition_lint_paths as foo;
     pub struct Bar;
     pub type Bar2 = Bar;
     pub type Bar3 = Bar;
 }
 
+mod baz {
+    use *;
+    //~^ ERROR absolute
+    //~| WARN this was previously accepted
+}
+
 fn main() {
     let x = ::bar::Bar;
-    //~^ ERROR Absolute
+    //~^ ERROR absolute
     //~| WARN this was previously accepted
     let x = bar::Bar;
     let x = ::crate::bar::Bar;
     let x = self::bar::Bar;
+    foo::test();
+
+    {
+        use edition_lint_paths as bar;
+        edition_lint_paths::foo();
+        bar::foo();
+        ::edition_lint_paths::foo();
+    }
 }
index 509527e03743c7bec5d0bebac7deca9d8ee99846..1588e242f2283e4afe9e6764224fb4a4769cbabf 100644 (file)
@@ -1,19 +1,46 @@
-error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:16:9
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:22:9
    |
 LL |     use ::bar::Bar;
    |         ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
    |
 note: lint level defined here
-  --> $DIR/edition-lint-paths.rs:12:9
+  --> $DIR/edition-lint-paths.rs:15:9
    |
-LL | #![deny(absolute_path_starting_with_module)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(absolute_path_not_starting_with_crate)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue TBD
 
-error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:24:5
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:28:9
+   |
+LL |     use bar;
+   |         ^^^ help: use `crate`: `crate::bar`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue TBD
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:33:10
+   |
+LL |     use {Bar as SomethingElse, main};
+   |          ^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::Bar as SomethingElse`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue TBD
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:33:32
+   |
+LL |     use {Bar as SomethingElse, main};
+   |                                ^^^^ help: use `crate`: `crate::main`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue TBD
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:45:5
    |
 LL | use bar::Bar;
    |     ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -21,8 +48,17 @@ LL | use bar::Bar;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue TBD
 
-error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:35:13
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:57:9
+   |
+LL |     use *;
+   |         ^ help: use `crate`: `crate::*`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue TBD
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:63:13
    |
 LL |     let x = ::bar::Bar;
    |             ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -30,5 +66,5 @@ LL |     let x = ::bar::Bar;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue TBD
 
-error: aborting due to 3 previous errors
+error: aborting due to 7 previous errors