diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7885bdfb12c..d9a198f8243 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2519,6 +2519,7 @@ Released 2018-09-13
 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
+[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 78a95b00403..7e12e9be4aa 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -356,6 +356,7 @@ mod unicode;
 mod unit_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
+mod unnecessary_self_imports;
 mod unnecessary_sort_by;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
@@ -963,6 +964,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         unit_types::UNIT_CMP,
         unnamed_address::FN_ADDRESS_COMPARISONS,
         unnamed_address::VTABLE_ADDRESS_COMPARISONS,
+        unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
         unnecessary_sort_by::UNNECESSARY_SORT_BY,
         unnecessary_wraps::UNNECESSARY_WRAPS,
         unnested_or_patterns::UNNESTED_OR_PATTERNS,
@@ -1048,6 +1050,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
     store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
     store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
 
     let msrv = conf.msrv.as_ref().and_then(|s| {
         parse_msrv(s, None, None).or_else(|| {
@@ -1320,6 +1323,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(strings::STRING_TO_STRING),
         LintId::of(strings::STR_TO_STRING),
         LintId::of(types::RC_BUFFER),
+        LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
         LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
         LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
         LintId::of(write::PRINT_STDERR),
diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs
index 6a52de4f713..64e9dc85466 100644
--- a/clippy_lints/src/modulo_arithmetic.rs
+++ b/clippy_lints/src/modulo_arithmetic.rs
@@ -4,7 +4,7 @@ use clippy_utils::sext;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self};
+use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::fmt::Display;
 
diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs
new file mode 100644
index 00000000000..48c54d79cf1
--- /dev/null
+++ b/clippy_lints/src/unnecessary_self_imports.rs
@@ -0,0 +1,67 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use if_chain::if_chain;
+use rustc_ast::{Item, ItemKind, UseTreeKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::kw;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for imports ending in `::{self}`.
+    ///
+    /// **Why is this bad?** In most cases, this can be written much more cleanly by omitting `::{self}`.
+    ///
+    /// **Known problems:** Removing `::{self}` will cause any non-module items at the same path to also be imported.
+    /// This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt
+    /// to detect this scenario and that is why it is a restriction lint.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::io::{self};
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::io;
+    /// ```
+    pub UNNECESSARY_SELF_IMPORTS,
+    restriction,
+    "imports ending in `::{self}`, which can be omitted"
+}
+
+declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]);
+
+impl EarlyLintPass for UnnecessarySelfImports {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if_chain! {
+            if let ItemKind::Use(use_tree) = &item.kind;
+            if let UseTreeKind::Nested(nodes) = &use_tree.kind;
+            if let [(self_tree, _)] = &**nodes;
+            if let [self_seg] = &*self_tree.prefix.segments;
+            if self_seg.ident.name == kw::SelfLower;
+            if let Some(last_segment) = use_tree.prefix.segments.last();
+
+            then {
+                span_lint_and_then(
+                    cx,
+                    UNNECESSARY_SELF_IMPORTS,
+                    item.span,
+                    "import ending with `::{self}`",
+                    |diag| {
+                        diag.span_suggestion(
+                            last_segment.span().with_hi(item.span.hi()),
+                            "consider omitting `::{self}`",
+                            format!(
+                                "{}{};",
+                                last_segment.ident,
+                                if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {}", alias) } else { String::new() },
+                            ),
+                            Applicability::MaybeIncorrect,
+                        );
+                        diag.note("this will slightly change semantics; any non-module items at the same path will also be imported");
+                    },
+                );
+            }
+        }
+    }
+}
diff --git a/tests/ui/unnecessary_self_imports.fixed b/tests/ui/unnecessary_self_imports.fixed
new file mode 100644
index 00000000000..1185eaa1d55
--- /dev/null
+++ b/tests/ui/unnecessary_self_imports.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+#![warn(clippy::unnecessary_self_imports)]
+#![allow(unused_imports, dead_code)]
+
+use std::collections::hash_map::{self, *};
+use std::fs as alias;
+use std::io::{self, Read};
+use std::rc;
+
+fn main() {}
diff --git a/tests/ui/unnecessary_self_imports.rs b/tests/ui/unnecessary_self_imports.rs
new file mode 100644
index 00000000000..56bfbc09402
--- /dev/null
+++ b/tests/ui/unnecessary_self_imports.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+#![warn(clippy::unnecessary_self_imports)]
+#![allow(unused_imports, dead_code)]
+
+use std::collections::hash_map::{self, *};
+use std::fs::{self as alias};
+use std::io::{self, Read};
+use std::rc::{self};
+
+fn main() {}
diff --git a/tests/ui/unnecessary_self_imports.stderr b/tests/ui/unnecessary_self_imports.stderr
new file mode 100644
index 00000000000..83a5618c983
--- /dev/null
+++ b/tests/ui/unnecessary_self_imports.stderr
@@ -0,0 +1,23 @@
+error: import ending with `::{self}`
+  --> $DIR/unnecessary_self_imports.rs:6:1
+   |
+LL | use std::fs::{self as alias};
+   | ^^^^^^^^^--------------------
+   |          |
+   |          help: consider omitting `::{self}`: `fs as alias;`
+   |
+   = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings`
+   = note: this will slightly change semantics; any non-module items at the same path will also be imported
+
+error: import ending with `::{self}`
+  --> $DIR/unnecessary_self_imports.rs:8:1
+   |
+LL | use std::rc::{self};
+   | ^^^^^^^^^-----------
+   |          |
+   |          help: consider omitting `::{self}`: `rc;`
+   |
+   = note: this will slightly change semantics; any non-module items at the same path will also be imported
+
+error: aborting due to 2 previous errors
+