lints: &'a mut [LateLintPassObject],
}
+#[cfg_attr(not(stage0), allow(lint_pass_impl_without_macro))]
impl LintPass for LateLintPassObjects<'_> {
fn name(&self) -> &'static str {
panic!()
lints: &'a mut [EarlyLintPassObject],
}
+#[cfg_attr(not(stage0), allow(lint_pass_impl_without_macro))]
impl LintPass for EarlyLintPassObjects<'_> {
fn name(&self) -> &'static str {
panic!()
};
use errors::Applicability;
use rustc_data_structures::fx::FxHashMap;
-use syntax::ast::Ident;
+use syntax::ast::{Ident, Item, ItemKind};
use syntax::symbol::{sym, Symbol};
declare_lint! {
impl EarlyLintPass for DefaultHashTypes {
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
if let Some(replace) = self.map.get(&ident.name) {
- let msg = format!(
- "Prefer {} over {}, it has better performance",
- replace, ident
- );
+ let msg = format!("Prefer {} over {}, it has better performance", replace, ident);
let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
db.span_suggestion(
ident.span,
replace.to_string(),
Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
);
- db.note(&format!(
- "a `use rustc_data_structures::fx::{}` may be necessary",
- replace
- ))
- .emit();
+ db.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
+ .emit();
}
}
}
}
}
}
- TyKind::Rptr(
- _,
- MutTy {
- ty: inner_ty,
- mutbl: Mutability::MutImmutable,
- },
- ) => {
+ TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::MutImmutable }) => {
if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) {
if cx.tcx.impl_trait_ref(impl_did).is_some() {
return;
String::new()
}
+
+declare_lint! {
+ pub LINT_PASS_IMPL_WITHOUT_MACRO,
+ Allow,
+ "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
+}
+
+declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
+
+impl EarlyLintPass for LintPassImpl {
+ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+ if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node {
+ if !lint_pass.path.span.ctxt().outer_expn_info().is_some() {
+ if let Some(last) = lint_pass.path.segments.last() {
+ if last.ident.as_str() == "LintPass" {
+ cx.struct_span_lint(
+ LINT_PASS_IMPL_WITHOUT_MACRO,
+ lint_pass.path.span,
+ "implementing `LintPass` by hand",
+ )
+ .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
+ .emit();
+ }
+ }
+ }
+ }
+ }
+}
pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) {
store.register_early_pass(sess, false, false, box DefaultHashTypes::new());
+ store.register_early_pass(sess, false, false, box LintPassImpl);
store.register_late_pass(sess, false, false, false, box TyTyKind);
store.register_group(
sess,
vec![
LintId::of(DEFAULT_HASH_TYPES),
LintId::of(USAGE_OF_TY_TYKIND),
+ LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
LintId::of(TY_PASS_BY_REFERENCE),
LintId::of(USAGE_OF_QUALIFIED_TY),
],
--- /dev/null
+// compile-flags: -Z unstable-options
+
+#![feature(rustc_private)]
+#![deny(lint_pass_impl_without_macro)]
+
+extern crate rustc;
+
+use rustc::lint::{LintArray, LintPass};
+use rustc::{declare_lint, declare_lint_pass, impl_lint_pass, lint_array};
+
+declare_lint! {
+ pub TEST_LINT,
+ Allow,
+ "test"
+}
+
+struct Foo;
+
+impl LintPass for Foo { //~ERROR implementing `LintPass` by hand
+ fn get_lints(&self) -> LintArray {
+ lint_array!(TEST_LINT)
+ }
+
+ fn name(&self) -> &'static str {
+ "Foo"
+ }
+}
+
+struct Bar;
+
+impl_lint_pass!(Bar => [TEST_LINT]);
+
+declare_lint_pass!(Baz => [TEST_LINT]);
+
+fn main() {}
--- /dev/null
+error: implementing `LintPass` by hand
+ --> $DIR/lint_pass_impl_without_macro.rs:19:6
+ |
+LL | impl LintPass for Foo {
+ | ^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint_pass_impl_without_macro.rs:4:9
+ |
+LL | #![deny(lint_pass_impl_without_macro)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead
+
+error: aborting due to previous error
+