rustc_lint: Stop creating a fake ast::Crate for running early lints

Add a trait generalizing over the crate root and freshly loaded modules instead
This also makes node IDs used for pre-expansion linting more precise
This commit is contained in:
Vadim Petrochenkov 2021-12-07 18:28:12 +08:00
parent 9c70b6d11b
commit 05cd75504b
5 changed files with 85 additions and 26 deletions

View file

@ -959,8 +959,9 @@ pub struct ExpansionData {
pub is_trailing_mac: bool, pub is_trailing_mac: bool,
} }
type OnExternModLoaded<'a> = type OnExternModLoaded<'a> = Option<
Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>; &'a dyn Fn(NodeId, Vec<Attribute>, Vec<P<Item>>, Symbol) -> (Vec<Attribute>, Vec<P<Item>>),
>;
/// One of these is made during expansion and incrementally updated as we go; /// One of these is made during expansion and incrementally updated as we go;
/// when a macro expansion occurs, the resulting nodes have the `backtrace() /// when a macro expansion occurs, the resulting nodes have the `backtrace()

View file

@ -1108,7 +1108,12 @@ impl InvocationCollectorNode for P<ast::Item> {
); );
if let Some(extern_mod_loaded) = ecx.extern_mod_loaded { if let Some(extern_mod_loaded) = ecx.extern_mod_loaded {
(attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); (attrs, items) = extern_mod_loaded(
ecx.current_expansion.lint_node_id,
attrs,
items,
ident.name,
);
} }
*mod_kind = ModKind::Loaded(items, Inline::No, inner_span); *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);

View file

@ -3,7 +3,7 @@ use crate::proc_macro_decls;
use crate::util; use crate::util;
use rustc_ast::mut_visit::MutVisitor; use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::{self as ast, visit, DUMMY_NODE_ID}; use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck; use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::traits::CodegenBackend;
@ -14,7 +14,7 @@ use rustc_errors::{Applicability, ErrorReported, PResult};
use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate; use rustc_hir::Crate;
use rustc_lint::LintStore; use rustc_lint::{EarlyCheckNode, LintStore};
use rustc_metadata::creader::CStore; use rustc_metadata::creader::CStore;
use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena; use rustc_middle::arena::Arena;
@ -34,7 +34,7 @@ use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind; use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session}; use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Symbol};
use rustc_span::{FileName, MultiSpan}; use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use rustc_typeck as typeck; use rustc_typeck as typeck;
@ -233,11 +233,11 @@ pub fn register_plugins<'a>(
Ok((krate, lint_store)) Ok((krate, lint_store))
} }
fn pre_expansion_lint( fn pre_expansion_lint<'a>(
sess: &Session, sess: &Session,
lint_store: &LintStore, lint_store: &LintStore,
registered_tools: &RegisteredTools, registered_tools: &RegisteredTools,
check_node: &ast::Crate, check_node: impl EarlyCheckNode<'a>,
node_name: &str, node_name: &str,
) { ) {
sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
@ -322,10 +322,15 @@ pub fn configure_and_expand(
}; };
let registered_tools = resolver.registered_tools().clone(); let registered_tools = resolver.registered_tools().clone();
let extern_mod_loaded = |ident: Ident, attrs, items, span| { let extern_mod_loaded = |node_id, attrs: Vec<_>, items: Vec<_>, name: Symbol| {
let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false }; pre_expansion_lint(
pre_expansion_lint(sess, lint_store, &registered_tools, &krate, ident.name.as_str()); sess,
(krate.attrs, krate.items) lint_store,
&registered_tools,
(node_id, &*attrs, &*items),
name.as_str(),
);
(attrs, items)
}; };
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded)); let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
@ -507,7 +512,7 @@ pub fn lower_to_hir<'res, 'tcx>(
resolver.registered_tools(), resolver.registered_tools(),
lint_buffer, lint_buffer,
rustc_lint::BuiltinCombinedEarlyLintPass::new(), rustc_lint::BuiltinCombinedEarlyLintPass::new(),
&krate, &*krate,
) )
}); });

View file

@ -16,9 +16,10 @@
use crate::context::{EarlyContext, LintContext, LintStore}; use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use crate::passes::{EarlyLintPass, EarlyLintPassObject};
use rustc_ast as ast; use rustc_ast::ptr::P;
use rustc_ast::visit as ast_visit; use rustc_ast::visit::{self as ast_visit, Visitor};
use rustc_ast::AstLike; use rustc_ast::AstLike;
use rustc_ast::{self as ast, walk_list};
use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::RegisteredTools;
use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
use rustc_session::Session; use rustc_session::Session;
@ -32,7 +33,7 @@ macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
$cx.pass.$f(&$cx.context, $($args),*); $cx.pass.$f(&$cx.context, $($args),*);
}) } }) }
struct EarlyContextAndPass<'a, T: EarlyLintPass> { pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
context: EarlyContext<'a>, context: EarlyContext<'a>,
pass: T, pass: T,
} }
@ -326,14 +327,65 @@ macro_rules! early_lint_pass_impl {
crate::early_lint_methods!(early_lint_pass_impl, []); crate::early_lint_methods!(early_lint_pass_impl, []);
fn early_lint_node( /// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
/// This trait generalizes over those nodes.
pub trait EarlyCheckNode<'a>: Copy {
fn id(self) -> ast::NodeId;
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b;
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b;
}
impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
fn id(self) -> ast::NodeId {
ast::CRATE_NODE_ID
}
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b,
{
&self.attrs
}
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b,
{
run_early_pass!(cx, check_crate, self);
ast_visit::walk_crate(cx, self);
run_early_pass!(cx, check_crate_post, self);
}
}
impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) {
fn id(self) -> ast::NodeId {
self.0
}
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b,
{
self.1
}
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b,
{
walk_list!(cx, visit_attribute, self.1);
walk_list!(cx, visit_item, self.2);
}
}
fn early_lint_node<'a>(
sess: &Session, sess: &Session,
warn_about_weird_lints: bool, warn_about_weird_lints: bool,
lint_store: &LintStore, lint_store: &LintStore,
registered_tools: &RegisteredTools, registered_tools: &RegisteredTools,
buffered: LintBuffer, buffered: LintBuffer,
pass: impl EarlyLintPass, pass: impl EarlyLintPass,
check_node: &ast::Crate, check_node: impl EarlyCheckNode<'a>,
) -> LintBuffer { ) -> LintBuffer {
let mut cx = EarlyContextAndPass { let mut cx = EarlyContextAndPass {
context: EarlyContext::new( context: EarlyContext::new(
@ -346,22 +398,18 @@ fn early_lint_node(
pass, pass,
}; };
cx.with_lint_attrs(ast::CRATE_NODE_ID, &check_node.attrs, |cx| { cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
run_early_pass!(cx, check_crate, check_node);
ast_visit::walk_crate(cx, check_node);
run_early_pass!(cx, check_crate_post, check_node);
});
cx.context.buffered cx.context.buffered
} }
pub fn check_ast_node( pub fn check_ast_node<'a>(
sess: &Session, sess: &Session,
pre_expansion: bool, pre_expansion: bool,
lint_store: &LintStore, lint_store: &LintStore,
registered_tools: &RegisteredTools, registered_tools: &RegisteredTools,
lint_buffer: Option<LintBuffer>, lint_buffer: Option<LintBuffer>,
builtin_lints: impl EarlyLintPass, builtin_lints: impl EarlyLintPass,
check_node: &ast::Crate, check_node: impl EarlyCheckNode<'a>,
) { ) {
let passes = let passes =
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };

View file

@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{intravisit, HirId, CRATE_HIR_ID}; use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::LevelAndSource; use rustc_middle::lint::LevelAndSource;
use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::LintDiagnosticBuilder;