Only allow {declare,impl}_lint_pass macros for implementing LintPass

This commit is contained in:
flip1995 2019-06-13 15:49:33 +02:00
parent 7d0a952e46
commit 37f09cb237
No known key found for this signature in database
GPG key ID: 693086869D506637
4 changed files with 57 additions and 11 deletions

View file

@ -9,6 +9,7 @@ use errors::Applicability;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use syntax::ast::{Ident, Item, ItemKind}; use syntax::ast::{Ident, Item, ItemKind};
use syntax::symbol::{sym, Symbol}; use syntax::symbol::{sym, Symbol};
use syntax_pos::ExpnInfo;
declare_lint! { declare_lint! {
pub DEFAULT_HASH_TYPES, pub DEFAULT_HASH_TYPES,
@ -225,19 +226,32 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
impl EarlyLintPass for LintPassImpl { impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node { 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 let Some(last) = lint_pass.path.segments.last() { if last.ident.name == sym::LintPass {
if last.ident.as_str() == "LintPass" { match &lint_pass.path.span.ctxt().outer_expn_info() {
cx.struct_span_lint( Some(info) if is_lint_pass_expansion(info) => {}
LINT_PASS_IMPL_WITHOUT_MACRO, _ => {
lint_pass.path.span, cx.struct_span_lint(
"implementing `LintPass` by hand", LINT_PASS_IMPL_WITHOUT_MACRO,
) lint_pass.path.span,
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") "implementing `LintPass` by hand",
.emit(); )
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
.emit();
}
} }
} }
} }
} }
} }
} }
fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool {
if expn_info.format.name() == sym::impl_lint_pass {
true
} else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() {
info.format.name() == sym::declare_lint_pass
} else {
false
}
}

View file

@ -214,6 +214,7 @@ symbols! {
custom_inner_attributes, custom_inner_attributes,
custom_test_frameworks, custom_test_frameworks,
c_variadic, c_variadic,
declare_lint_pass,
decl_macro, decl_macro,
Default, Default,
default_lib_allocator, default_lib_allocator,
@ -324,6 +325,7 @@ symbols! {
if_while_or_patterns, if_while_or_patterns,
ignore, ignore,
impl_header_lifetime_elision, impl_header_lifetime_elision,
impl_lint_pass,
impl_trait_in_bindings, impl_trait_in_bindings,
import_shadowing, import_shadowing,
index, index,
@ -365,6 +367,7 @@ symbols! {
link_llvm_intrinsics, link_llvm_intrinsics,
link_name, link_name,
link_section, link_section,
LintPass,
lint_reasons, lint_reasons,
literal, literal,
local_inner_macros, local_inner_macros,

View file

@ -26,6 +26,24 @@ impl LintPass for Foo { //~ERROR implementing `LintPass` by hand
} }
} }
macro_rules! custom_lint_pass_macro {
() => {
struct Custom;
impl LintPass for Custom { //~ERROR implementing `LintPass` by hand
fn get_lints(&self) -> LintArray {
lint_array!(TEST_LINT)
}
fn name(&self) -> &'static str {
"Custom"
}
}
};
}
custom_lint_pass_macro!();
struct Bar; struct Bar;
impl_lint_pass!(Bar => [TEST_LINT]); impl_lint_pass!(Bar => [TEST_LINT]);

View file

@ -11,5 +11,16 @@ LL | #![deny(lint_pass_impl_without_macro)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: try using `declare_lint_pass!` or `impl_lint_pass!` instead = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead
error: aborting due to previous error error: implementing `LintPass` by hand
--> $DIR/lint_pass_impl_without_macro.rs:33:14
|
LL | impl LintPass for Custom {
| ^^^^^^^^
...
LL | custom_lint_pass_macro!();
| -------------------------- in this macro invocation
|
= help: try using `declare_lint_pass!` or `impl_lint_pass!` instead
error: aborting due to 2 previous errors