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 syntax::ast::{Ident, Item, ItemKind};
use syntax::symbol::{sym, Symbol};
use syntax_pos::ExpnInfo;
declare_lint! {
pub DEFAULT_HASH_TYPES,
@ -225,19 +226,32 @@ 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();
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
match &lint_pass.path.span.ctxt().outer_expn_info() {
Some(info) if is_lint_pass_expansion(info) => {}
_ => {
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();
}
}
}
}
}
}
}
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_test_frameworks,
c_variadic,
declare_lint_pass,
decl_macro,
Default,
default_lib_allocator,
@ -324,6 +325,7 @@ symbols! {
if_while_or_patterns,
ignore,
impl_header_lifetime_elision,
impl_lint_pass,
impl_trait_in_bindings,
import_shadowing,
index,
@ -365,6 +367,7 @@ symbols! {
link_llvm_intrinsics,
link_name,
link_section,
LintPass,
lint_reasons,
literal,
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;
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
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