From b5e01baa2530f2277816fd660e8db5d1ab379a19 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 16 Sep 2023 22:38:06 +0200 Subject: [PATCH] API: Add `HasSpan` and `HasNodeId` traits and review changes <3 --- marker_adapter/src/context.rs | 14 +- marker_api/src/ast/common/id.rs | 62 ++++ marker_api/src/ast/common/span.rs | 39 ++- marker_api/src/ast/expr.rs | 30 +- marker_api/src/ast/expr/lit_expr.rs | 2 +- marker_api/src/ast/item.rs | 38 ++- marker_api/src/ast/item/adt_item.rs | 29 +- marker_api/src/ast/stmt.rs | 21 +- marker_api/src/context.rs | 85 +++--- marker_api/src/diagnostic.rs | 272 +++++++----------- marker_api/src/lib.rs | 2 + marker_api/src/prelude.rs | 5 + marker_lints/src/lib.rs | 4 +- .../tests/ui/diag_msg_uppercase_start.rs | 4 +- marker_rustc_driver/src/context.rs | 11 +- .../src/conversion/rustc/common.rs | 21 +- marker_uilints/src/lib.rs | 6 +- marker_uilints/src/utils.rs | 2 +- 18 files changed, 327 insertions(+), 320 deletions(-) diff --git a/marker_adapter/src/context.rs b/marker_adapter/src/context.rs index 1abc47ca..5b39909a 100644 --- a/marker_adapter/src/context.rs +++ b/marker_adapter/src/context.rs @@ -2,16 +2,12 @@ #![allow(clippy::needless_lifetimes)] use marker_api::{ - ast::{ - item::{Body, ItemKind}, - ty::SemTyKind, - BodyId, ExpnId, ExpnInfo, ExprId, FileInfo, FilePos, ItemId, Span, SpanId, SpanPos, SpanSource, SymbolId, - TyDefId, - }, + ast::{ty::SemTyKind, ExpnId, ExpnInfo, ExprId, FileInfo, FilePos, SpanId, SpanPos, SpanSource, SymbolId}, context::DriverCallbacks, - diagnostic::{Diagnostic, EmissionNodeId}, + diagnostic::Diagnostic, ffi::{self, FfiOption}, lint::{Level, Lint}, + prelude::*, }; /// ### Safety @@ -59,7 +55,7 @@ impl<'ast> DriverContextWrapper<'ast> { // False positive because `EmissionNode` are non-exhaustive #[allow(improper_ctypes_definitions)] -extern "C" fn lint_level_at<'ast>(data: &'ast (), lint: &'static Lint, node: EmissionNodeId) -> Level { +extern "C" fn lint_level_at<'ast>(data: &'ast (), lint: &'static Lint, node: NodeId) -> Level { unsafe { as_driver_cx(data) }.lint_level_at(lint, node) } @@ -129,7 +125,7 @@ unsafe fn as_driver_cx<'ast>(data: &'ast ()) -> &'ast dyn DriverContext<'ast> { } pub trait DriverContext<'ast> { - fn lint_level_at(&'ast self, lint: &'static Lint, node: EmissionNodeId) -> Level; + fn lint_level_at(&'ast self, lint: &'static Lint, node: NodeId) -> Level; fn emit_diag(&'ast self, diag: &Diagnostic<'_, 'ast>); fn item(&'ast self, api_id: ItemId) -> Option>; diff --git a/marker_api/src/ast/common/id.rs b/marker_api/src/ast/common/id.rs index ad760332..8a27feff 100644 --- a/marker_api/src/ast/common/id.rs +++ b/marker_api/src/ast/common/id.rs @@ -39,6 +39,8 @@ macro_rules! new_id { use new_id; +use crate::private::Sealed; + new_id!( /// This ID uniquely identifies a crate during linting. pub CrateId: u32 @@ -144,3 +146,63 @@ new_id! { /// This ID uniquely identifies a statement during linting. pub StmtId: u64 } + +#[repr(C)] +#[non_exhaustive] +#[derive(Debug, Clone, Copy)] +pub enum NodeId { + Expr(ExprId), + Item(ItemId), + Stmt(StmtId), + Body(BodyId), + Field(FieldId), + Variant(VariantId), +} + +macro_rules! impl_into_node_id_for { + ($variant:ident, $ty:ty) => { + impl From<$ty> for NodeId { + fn from(value: $ty) -> Self { + NodeId::$variant(value) + } + } + + impl From<&$ty> for NodeId { + fn from(value: &$ty) -> Self { + NodeId::$variant(*value) + } + } + }; +} + +impl_into_node_id_for!(Expr, ExprId); +impl_into_node_id_for!(Item, ItemId); +impl_into_node_id_for!(Stmt, StmtId); +impl_into_node_id_for!(Body, BodyId); +impl_into_node_id_for!(Field, FieldId); +impl_into_node_id_for!(Variant, VariantId); + +pub trait HasNodeId: Sealed { + /// Returns the [`NodeId`] of the identifiable node + fn node_id(&self) -> NodeId; +} + +impl HasNodeId for &N { + fn node_id(&self) -> NodeId { + (*self).node_id() + } +} + +macro_rules! impl_identifiable_for { + ($ty:ty$(, use $data_trait:path)?) => { + impl<'ast> $crate::ast::HasNodeId for $ty { + fn node_id(&self) -> $crate::ast::NodeId { + $( + use $data_trait; + )* + self.id().into() + } + } + }; +} +pub(crate) use impl_identifiable_for; diff --git a/marker_api/src/ast/common/span.rs b/marker_api/src/ast/common/span.rs index 2921d8ca..27d699c5 100644 --- a/marker_api/src/ast/common/span.rs +++ b/marker_api/src/ast/common/span.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::{context::with_cx, diagnostic::Applicability, ffi}; +use crate::{context::with_cx, diagnostic::Applicability, ffi, private::Sealed}; use super::{ExpnId, MacroId, SpanId, SpanSrcId, SymbolId}; @@ -386,6 +386,13 @@ impl<'ast> Span<'ast> { } } +impl<'ast> HasSpan<'ast> for Span<'ast> { + fn span(&self) -> &Span<'ast> { + self + } +} +impl Sealed for Span<'_> {} + #[cfg(feature = "driver-api")] impl<'ast> Span<'ast> { #[must_use] @@ -509,11 +516,14 @@ impl<'ast> Ident<'ast> { pub fn name(&self) -> &str { with_cx(self, |cx| cx.symbol_str(self.sym)) } +} - pub fn span(&self) -> &Span<'ast> { +impl<'ast> HasSpan<'ast> for Ident<'ast> { + fn span(&self) -> &Span<'ast> { with_cx(self, |cx| cx.span(self.span)) } } +impl<'ast> crate::private::Sealed for Ident<'ast> {} #[cfg(feature = "driver-api")] impl<'ast> Ident<'ast> { @@ -570,3 +580,28 @@ impl_ident_eq_for!( std::ffi::OsString, std::borrow::Cow<'_, str> ); + +/// A trait for nodes, that provide a [`Span`]. +pub trait HasSpan<'ast>: Sealed { + /// This returns the [`Span`] of the implementing AST node. + fn span(&self) -> &Span<'ast>; +} + +/// This macro implements the [`HasSpan`] trait for data types, that provide a +/// `span()` method. +macro_rules! impl_spanned_for { + ($ty:ty) => { + impl<'ast> $crate::ast::HasSpan<'ast> for $ty { + fn span(&self) -> &$crate::ast::Span<'ast> { + self.span() + } + } + }; +} +pub(crate) use impl_spanned_for; + +impl<'ast, N: HasSpan<'ast>> HasSpan<'ast> for &N { + fn span(&self) -> &Span<'ast> { + (*self).span() + } +} diff --git a/marker_api/src/ast/expr.rs b/marker_api/src/ast/expr.rs index fd75f276..70641f9a 100644 --- a/marker_api/src/ast/expr.rs +++ b/marker_api/src/ast/expr.rs @@ -1,6 +1,6 @@ use crate::{prelude::EmissionNode, private::Sealed, CtorBlocker}; -use super::{ty::SemTyKind, ExprId, Span, SpanId}; +use super::{ty::SemTyKind, ExprId, HasNodeId, HasSpan, Span, SpanId}; use std::{fmt::Debug, marker::PhantomData}; @@ -27,16 +27,10 @@ pub use unstable_expr::*; /// /// This trait is only meant to be implemented inside this crate. The `Sealed` /// super trait prevents external implementations. -pub trait ExprData<'ast>: Debug + Sealed -where - for<'a> &'a Self: EmissionNode<'ast>, -{ +pub trait ExprData<'ast>: Debug + EmissionNode<'ast> + HasSpan<'ast> + HasNodeId + Sealed { /// Returns the [`ExprId`] of this expression. fn id(&self) -> ExprId; - /// Returns the [`Span`] of this expression. - fn span(&self) -> &Span<'ast>; - /// Returns the semantic type of this expression. fn ty(&self) -> SemTyKind<'ast>; @@ -96,9 +90,9 @@ impl<'ast> ExprKind<'ast> { impl_expr_kind_fn!(ExprKind: precedence() -> ExprPrecedence); } +crate::ast::impl_spanned_for!(ExprKind<'ast>); +crate::ast::impl_identifiable_for!(ExprKind<'ast>); impl Sealed for ExprKind<'_> {} -crate::diagnostic::impl_emission_node_for_node!(ExprKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&ExprKind<'ast>); #[repr(C)] #[non_exhaustive] @@ -122,9 +116,9 @@ impl<'ast> LitExprKind<'ast> { impl_expr_kind_fn!(LitExprKind: precedence() -> ExprPrecedence); } +crate::ast::impl_spanned_for!(LitExprKind<'ast>); +crate::ast::impl_identifiable_for!(LitExprKind<'ast>); impl Sealed for LitExprKind<'_> {} -crate::diagnostic::impl_emission_node_for_node!(LitExprKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&LitExprKind<'ast>); impl<'ast> From> for ExprKind<'ast> { fn from(value: LitExprKind<'ast>) -> Self { @@ -322,10 +316,6 @@ macro_rules! impl_expr_data { self.data.id } - fn span(&self) -> &crate::ast::Span<'ast> { - $crate::context::with_cx(self, |cx| cx.span(self.data.span)) - } - fn ty(&self) -> $crate::ast::ty::SemTyKind<'ast> { $crate::context::with_cx(self, |cx| cx.expr_ty(self.data.id)) } @@ -337,8 +327,14 @@ macro_rules! impl_expr_data { } } + impl<'ast> $crate::ast::HasSpan<'ast> for $self_ty { + fn span(&self) -> &crate::ast::Span<'ast> { + $crate::context::with_cx(self, |cx| cx.span(self.data.span)) + } + } + $crate::ast::impl_identifiable_for!($self_ty, use $crate::ast::expr::ExprData); + impl<'ast> $crate::private::Sealed for $self_ty {} - $crate::diagnostic::impl_emission_node_for_node!(&$self_ty, use super::ExprData); impl<'ast> From<&'ast $self_ty> for $crate::ast::expr::ExprKind<'ast> { fn from(from: &'ast $self_ty) -> Self { diff --git a/marker_api/src/ast/expr/lit_expr.rs b/marker_api/src/ast/expr/lit_expr.rs index ea73a911..7d0e0b5c 100644 --- a/marker_api/src/ast/expr/lit_expr.rs +++ b/marker_api/src/ast/expr/lit_expr.rs @@ -62,7 +62,7 @@ impl<'ast> CharLitExpr<'ast> { /// can be hardware-dependent. For exact value checks, it might be better to check /// the written float literal by getting the code snipped from the expression span. /// See: -/// * [`ExprData::span()`](`super::ExprData::span`) +/// * [`HasSpan::span()`](`super::HasSpan::span`) /// * [`Span::snippet()`](`crate::ast::Span::snippet`) /// /// All integer literals are unsigned, negative numbers have a unary negation diff --git a/marker_api/src/ast/item.rs b/marker_api/src/ast/item.rs index 7d8874e6..a71c7c29 100644 --- a/marker_api/src/ast/item.rs +++ b/marker_api/src/ast/item.rs @@ -5,7 +5,7 @@ use crate::private::Sealed; use crate::CtorBlocker; use super::expr::ExprKind; -use super::{Ident, ItemId, Span, SpanId}; +use super::{HasNodeId, HasSpan, Ident, ItemId, Span, SpanId}; // Item implementations mod extern_crate_item; @@ -37,18 +37,11 @@ pub use unstable_item::*; /// /// This trait is only meant to be implemented inside this crate. The `Sealed` /// super trait prevents external implementations. -pub trait ItemData<'ast>: Debug + Sealed -where - for<'a> &'a Self: EmissionNode<'ast>, -{ +pub trait ItemData<'ast>: Debug + EmissionNode<'ast> + HasSpan<'ast> + HasNodeId + Sealed { /// Returns the [`ItemId`] of this item. This is a unique identifier used for comparison /// and to request items from the [`AstContext`](`crate::context::AstContext`). fn id(&self) -> ItemId; - /// The [`Span`] of the entire item. This span should be used for general item related - /// diagnostics. - fn span(&self) -> &Span<'ast>; - /// The [`Visibility`] of this item. fn visibility(&self) -> &Visibility<'ast>; @@ -97,8 +90,9 @@ impl<'ast> ItemKind<'ast> { impl_item_type_fn!(ItemKind: attrs() -> ()); } -crate::diagnostic::impl_emission_node_for_node!(ItemKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&ItemKind<'ast>); +crate::ast::impl_spanned_for!(ItemKind<'ast>); +crate::ast::impl_identifiable_for!(ItemKind<'ast>); +impl<'ast> crate::private::Sealed for ItemKind<'ast> {} #[non_exhaustive] #[derive(Debug, Copy, Clone)] @@ -118,8 +112,9 @@ impl<'ast> AssocItemKind<'ast> { // FIXME: Potentially add a field to the items to optionally store the owner id } -crate::diagnostic::impl_emission_node_for_node!(AssocItemKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&AssocItemKind<'ast>); +crate::ast::impl_spanned_for!(AssocItemKind<'ast>); +crate::ast::impl_identifiable_for!(AssocItemKind<'ast>); +impl<'ast> crate::private::Sealed for AssocItemKind<'ast> {} impl<'ast> From> for ItemKind<'ast> { fn from(value: AssocItemKind<'ast>) -> Self { @@ -147,8 +142,9 @@ impl<'ast> ExternItemKind<'ast> { impl_item_type_fn!(ExternItemKind: as_item() -> ItemKind<'ast>); } -crate::diagnostic::impl_emission_node_for_node!(ExternItemKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&ExternItemKind<'ast>); +crate::ast::impl_spanned_for!(ExternItemKind<'ast>); +crate::ast::impl_identifiable_for!(ExternItemKind<'ast>); +impl<'ast> crate::private::Sealed for ExternItemKind<'ast> {} impl<'ast> From> for ItemKind<'ast> { fn from(value: ExternItemKind<'ast>) -> Self { @@ -206,10 +202,6 @@ macro_rules! impl_item_data { self.data.id } - fn span(&self) -> &crate::ast::Span<'ast> { - $crate::context::with_cx(self, |cx| cx.span(self.data.span)) - } - fn visibility(&self) -> &crate::ast::item::Visibility<'ast> { &self.data.vis } @@ -225,8 +217,14 @@ macro_rules! impl_item_data { fn attrs(&self) {} } + impl<'ast> $crate::ast::HasSpan<'ast> for $self_name<'ast> { + fn span(&self) -> &crate::ast::Span<'ast> { + $crate::context::with_cx(self, |cx| cx.span(self.data.span)) + } + } + + $crate::ast::impl_identifiable_for!($self_name<'ast>, use $crate::ast::item::ItemData); impl $crate::private::Sealed for $self_name<'_> {} - $crate::diagnostic::impl_emission_node_for_node!(&$self_name<'ast>, use super::ItemData); impl<'ast> From<&'ast $self_name<'ast>> for crate::ast::item::ItemKind<'ast> { fn from(value: &'ast $self_name<'ast>) -> Self { diff --git a/marker_api/src/ast/item/adt_item.rs b/marker_api/src/ast/item/adt_item.rs index fd7d0403..adf39d68 100644 --- a/marker_api/src/ast/item/adt_item.rs +++ b/marker_api/src/ast/item/adt_item.rs @@ -1,6 +1,7 @@ use crate::ast::expr::ConstExpr; use crate::ast::generic::SynGenericParams; use crate::ast::ty::SynTyKind; +use crate::ast::HasSpan; use crate::ast::{FieldId, Span, SpanId, SymbolId, VariantId}; use crate::context::with_cx; use crate::ffi::{FfiOption, FfiSlice}; @@ -159,19 +160,20 @@ impl<'ast> EnumVariant<'ast> { } } - /// The [`Span`] of the entire item. This span should be used for general item related - /// diagnostics. - pub fn span(&self) -> &Span<'ast> { - with_cx(self, |cx| cx.span(self.span)) - } - /// The discriminant of this variant, if one has been defined pub fn discriminant(&self) -> Option<&ConstExpr<'ast>> { self.discriminant.get() } } -crate::diagnostic::impl_emission_node_for_node!(&EnumVariant<'ast>); +impl<'ast> HasSpan<'ast> for EnumVariant<'ast> { + fn span(&self) -> &Span<'ast> { + with_cx(self, |cx| cx.span(self.span)) + } +} + +crate::ast::impl_identifiable_for!(EnumVariant<'ast>); +impl<'ast> crate::private::Sealed for EnumVariant<'ast> {} #[cfg(feature = "driver-api")] impl<'ast> EnumVariant<'ast> { @@ -312,16 +314,17 @@ impl<'ast> Field<'ast> { self.ty } - /// The [`Span`] of the entire item. This span should be used for general item related - /// diagnostics. - pub fn span(&self) -> &Span<'ast> { + // FIXME(xFrednet): Add `fn attrs() -> ??? {}`, see rust-marker/marker#51 +} + +impl<'ast> HasSpan<'ast> for Field<'ast> { + fn span(&self) -> &Span<'ast> { with_cx(self, |cx| cx.span(self.span)) } - - // FIXME(xFrednet): Add `fn attrs() -> ??? {}`, see rust-marker/marker#51 } -crate::diagnostic::impl_emission_node_for_node!(&Field<'ast>); +crate::ast::impl_identifiable_for!(Field<'ast>); +impl<'ast> crate::private::Sealed for Field<'ast> {} #[cfg(feature = "driver-api")] impl<'ast> Field<'ast> { diff --git a/marker_api/src/ast/stmt.rs b/marker_api/src/ast/stmt.rs index b9f4040f..c1f69b2b 100644 --- a/marker_api/src/ast/stmt.rs +++ b/marker_api/src/ast/stmt.rs @@ -3,18 +3,15 @@ use std::marker::PhantomData; use crate::{ffi::FfiOption, private::Sealed}; -use super::{expr::ExprKind, item::ItemKind, pat::PatKind, ty::SynTyKind, Span, SpanId, StmtId}; +use super::{expr::ExprKind, item::ItemKind, pat::PatKind, ty::SynTyKind, HasNodeId, HasSpan, Span, SpanId, StmtId}; /// This trait combines methods, which all statements have in common. /// /// This trait is only meant to be implemented inside this crate. The `Sealed` /// super trait prevents external implementations. -pub trait StmtData<'ast>: Debug + Sealed { - /// Returns the [`SpanId`] of this statement +pub trait StmtData<'ast>: Debug + HasSpan<'ast> + HasNodeId + Sealed { + /// Returns the [`StmtId`] of this statement fn id(&self) -> StmtId; - - /// Returns the [`Span`] of this statement. - fn span(&self) -> &Span<'ast>; } #[repr(C)] @@ -51,8 +48,9 @@ impl<'ast> StmtKind<'ast> { pub fn attrs(&self) {} } -crate::diagnostic::impl_emission_node_for_node!(StmtKind<'ast>); -crate::diagnostic::impl_emission_node_for_node!(&StmtKind<'ast>); +crate::ast::impl_spanned_for!(StmtKind<'ast>); +crate::ast::impl_identifiable_for!(StmtKind<'ast>); +impl<'ast> crate::private::Sealed for StmtKind<'ast> {} #[repr(C)] #[derive(Debug)] @@ -76,12 +74,16 @@ macro_rules! impl_stmt_data { fn id(&self) -> crate::ast::StmtId { self.data.id } + } + impl<'ast> $crate::ast::HasSpan<'ast> for $self_ty { fn span(&self) -> &crate::ast::Span<'ast> { $crate::context::with_cx(self, |cx| cx.span(self.data.span)) } } + $crate::ast::impl_identifiable_for!($self_ty, use StmtData); + impl<'ast> From<&'ast $self_ty> for $crate::ast::stmt::StmtKind<'ast> { fn from(from: &'ast $self_ty) -> Self { $crate::ast::stmt::StmtKind::$enum_name(from) @@ -131,7 +133,6 @@ impl<'ast> LetStmt<'ast> { } impl_stmt_data!(LetStmt<'ast>, Let); -crate::diagnostic::impl_emission_node_for_node!(LetStmt<'ast>); #[repr(C)] #[derive(Debug)] @@ -148,7 +149,6 @@ impl<'ast> ExprStmt<'ast> { } impl_stmt_data!(ExprStmt<'ast>, Expr); -crate::diagnostic::impl_emission_node_for_node!(ExprStmt<'ast>); #[repr(C)] #[derive(Debug)] @@ -165,4 +165,3 @@ impl<'ast> ItemStmt<'ast> { } impl_stmt_data!(ItemStmt<'ast>, Item); -crate::diagnostic::impl_emission_node_for_node!(ItemStmt<'ast>); diff --git a/marker_api/src/context.rs b/marker_api/src/context.rs index e13f718f..318f978a 100644 --- a/marker_api/src/context.rs +++ b/marker_api/src/context.rs @@ -8,10 +8,10 @@ use crate::{ ast::{ item::{Body, ItemKind}, ty::SemTyKind, - BodyId, ExpnId, ExpnInfo, ExprId, FileInfo, FilePos, ItemId, Span, SpanId, SpanPos, SpanSource, SymbolId, - TyDefId, + BodyId, ExpnId, ExpnInfo, ExprId, FileInfo, FilePos, HasNodeId, ItemId, NodeId, Span, SpanId, SpanPos, + SpanSource, SymbolId, TyDefId, }, - diagnostic::{Diagnostic, DiagnosticBuilder, EmissionNode, EmissionNodeId}, + diagnostic::{Diagnostic, DiagnosticBuilder, EmissionNode}, ffi, lint::{Level, Lint, MacroReport}, }; @@ -101,23 +101,27 @@ impl<'ast> AstContext<'ast> { } impl<'ast> AstContext<'ast> { - pub fn lint_level_at(&self, lint: &'static Lint, node: impl EmissionNode<'ast>) -> Level { - self.driver.call_lint_level_at(lint, node.emission_node_id()) + pub fn lint_level_at(&self, lint: &'static Lint, node: impl HasNodeId) -> Level { + self.driver.call_lint_level_at(lint, node.node_id()) } /// This function is used to emit a lint. /// /// Every lint emission, is bound to one specific node in the AST. This - /// node is used to check the lint level and as the main [`Span`] of the - /// diagnostic message. See [`EmissionNode`] for more information. + /// node is used to check the lint level and is the default [`Span`] of + /// the diagnostic message. See [`EmissionNode`] for more information. + /// The [`Span`] can be overwritten with [`DiagnosticBuilder::span`]. /// - /// The lint message, will be the main message at the start of the created - /// diagnostic. This message and all messages emitted as part of the created - /// diagnostic should start with a lower letter, according to [rustc's dev guide]. + /// The message parameter, will be the main message of the created diagnostic. + /// This message and all messages emitted as part of the created diagnostic + /// should start with a lower letter, according to [rustc's dev guide]. /// /// The function will return a [`DiagnosticBuilder`] which can be used to decorate - /// the diagnostic message, with notes and help messages. The diagnostic message will - /// be emitted when the builder instance is dropped. + /// the diagnostic message, with notes and help messages. These customizations can + /// be moved into a conditional closure, to improve performance under some circumstances. + /// See [`DiagnosticBuilder::decorate`] for more information. + /// + /// The diagnostic message will be emitted when the builder instance is dropped. /// /// [rustc's dev guide]: /// @@ -125,11 +129,11 @@ impl<'ast> AstContext<'ast> { /// /// ``` /// # use marker_api::prelude::*; - /// # marker_api::declare_lint!( + /// # marker_api::declare_lint!{ /// # /// Dummy /// # LINT, /// # Warn, - /// # ); + /// # } /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) { /// cx.emit_lint(LINT, node, ""); /// # } @@ -138,7 +142,7 @@ impl<'ast> AstContext<'ast> { /// The code above will roughly generate the following error message: /// /// ```text - /// warning: <-- The message that is set by this function + /// warning: <-- The message that is set by this function /// --> path/file.rs:1:1 /// | /// 1 | node @@ -150,19 +154,17 @@ impl<'ast> AstContext<'ast> { /// /// ``` /// # use marker_api::prelude::*; - /// # marker_api::declare_lint!( + /// # marker_api::declare_lint!{ /// # /// Dummy /// # LINT, /// # Warn, - /// # ); + /// # } /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) { - /// cx - /// .emit_lint(LINT, node, "") - /// .help(""); + /// cx.emit_lint(LINT, node, "").help(""); /// # } /// ``` /// - /// The [`DiagnosticBuilder::help`] call will add a help message like this: + /// The [`DiagnosticBuilder::help`] will add a help message like this: /// /// ```text /// warning: @@ -171,34 +173,31 @@ impl<'ast> AstContext<'ast> { /// 1 | node /// | ^^^^ /// | - /// = help: <-- The added help message + /// = help: <-- The added help message /// ``` /// /// ## Example 3 /// - /// Creating suggestions can impact the performance. The - /// [`DiagnosticBuilder::decorate`] function can be used, to only add more - /// context to the lint emission if it will actually be emitted. This will - /// save performance, when the lint is allowed at the [`EmissionNode`] + /// Adding a help message using [`DiagnosticBuilder::decorate`]: /// /// ``` /// # use marker_api::prelude::*; - /// # marker_api::declare_lint!( + /// # marker_api::declare_lint!{ /// # /// Dummy /// # LINT, /// # Warn, - /// # ); + /// # } /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) { /// cx.emit_lint(LINT, node, "").decorate(|diag| { - /// // This closure is only called, if the lint is enabled. Here you - /// // can create a beautiful help message. + /// // This closure is only called, if the diagnostic will be emitted. + /// // Here you can create a beautiful help message. /// diag.help(""); /// }); /// # } /// ``` /// /// This will create the same help message as in example 2, but it will be faster - /// if the lint is enabled. The emitted message would look like this: + /// if the lint is suppressed. The emitted message would look like this: /// ```text /// warning: /// --> path/file.rs:1:1 @@ -206,28 +205,24 @@ impl<'ast> AstContext<'ast> { /// 1 | node /// | ^^^^ /// | - /// = help: <-- The added help message + /// = help: <-- The added help message /// ``` - #[allow(clippy::needless_pass_by_value)] // `&impl ToString` pub fn emit_lint( &self, lint: &'static Lint, node: impl EmissionNode<'ast>, - msg: impl ToString, + msg: impl Into, ) -> DiagnosticBuilder<'ast> { - let id = node.emission_node_id(); - let Some(span) = node.emission_span(self) else { - // If the `Span` is none, we can't emit a diagnostic message for it. - return DiagnosticBuilder::new_dummy(lint, id); - }; + let id = node.node_id(); + let span = node.span(); if matches!(lint.report_in_macro, MacroReport::No) && span.is_from_expansion() { - return DiagnosticBuilder::new_dummy(lint, id); + return DiagnosticBuilder::dummy(); } - if self.lint_level_at(lint, node) == Level::Allow { - return DiagnosticBuilder::new_dummy(lint, id); + if self.lint_level_at(lint, &node) == Level::Allow { + return DiagnosticBuilder::dummy(); } - DiagnosticBuilder::new(lint, id, msg.to_string(), span) + DiagnosticBuilder::new(lint, id, msg.into(), span.clone()) } pub(crate) fn emit_diagnostic<'a>(&self, diag: &'a Diagnostic<'a, 'ast>) { @@ -339,7 +334,7 @@ struct DriverCallbacks<'ast> { // can't call them in safe Rust passing a &() pointer. This will trigger UB. // Lint emission and information - pub lint_level_at: extern "C" fn(&'ast (), &'static Lint, EmissionNodeId) -> Level, + pub lint_level_at: extern "C" fn(&'ast (), &'static Lint, NodeId) -> Level, pub emit_diag: for<'a> extern "C" fn(&'ast (), &'a Diagnostic<'a, 'ast>), // Public utility @@ -360,7 +355,7 @@ struct DriverCallbacks<'ast> { } impl<'ast> DriverCallbacks<'ast> { - fn call_lint_level_at(&self, lint: &'static Lint, node: EmissionNodeId) -> Level { + fn call_lint_level_at(&self, lint: &'static Lint, node: NodeId) -> Level { (self.lint_level_at)(self.driver_context, lint, node) } diff --git a/marker_api/src/diagnostic.rs b/marker_api/src/diagnostic.rs index 308b44b1..a450b8f7 100644 --- a/marker_api/src/diagnostic.rs +++ b/marker_api/src/diagnostic.rs @@ -4,70 +4,51 @@ use std::fmt::Debug; use crate::{ - ast::{ExprId, FieldId, ItemId, Span, StmtId, VariantId}, + ast::{HasNodeId, NodeId, Span}, context::{with_cx, AstContext}, ffi::{FfiSlice, FfiStr}, lint::Lint, + prelude::HasSpan, }; /// This builder creates the diagnostic object which will be emitted by the driver. /// The documentation will showcase the messages in rustc's console emission style, /// the actual display depends on the driver. pub struct DiagnosticBuilder<'ast> { + /// This field will be `Some` if the created diagnostic will be emitted, otherwise + /// it'll be `None`. See [`DiagnosticBuilder::decorate`] for more information, when the + /// lint might be suppressed. + inner: Option>, +} + +struct DiagnosticBuilderInner<'ast> { lint: &'static Lint, - node: EmissionNodeId, + node: NodeId, msg: String, - span: Option>, + span: Span<'ast>, parts: Vec>>, - /// This flag indicates, if the diagnostic messages should actually be emitted - /// at the end. This might be false, if the lint is allowed at the emission location. - emit_lint: bool, } -#[allow(clippy::needless_pass_by_value)] // `&impl ToString` doesn't work impl<'ast> DiagnosticBuilder<'ast> { - pub(crate) fn new_dummy(lint: &'static Lint, node: EmissionNodeId) -> Self { - Self { - lint, - node, - msg: String::new(), - span: None, - parts: vec![], - emit_lint: false, - } + /// Creates a new dummy builder, which basically makes all operations a noop + pub(crate) fn dummy() -> Self { + Self { inner: None } } - pub(crate) fn new(lint: &'static Lint, node: EmissionNodeId, msg: String, span: Span<'ast>) -> Self { + pub(crate) fn new(lint: &'static Lint, node: NodeId, msg: String, span: Span<'ast>) -> Self { Self { - lint, - msg, - node, - span: Some(span), - parts: vec![], - emit_lint: true, - } - } - - /// This function sets the main message of this diagnostic message. - /// - /// From rustc a lint emission would look like this: - /// ```text - /// warning: <-- The message that is set by this function - /// --> path/file.rs:1:1 - /// | - /// 1 | expression - /// | ^^^^^^^^^^ - /// | - /// ``` - pub fn set_main_message(&mut self, msg: impl ToString) -> &mut Self { - if self.emit_lint { - self.msg = msg.to_string(); + inner: Some(DiagnosticBuilderInner { + lint, + msg, + node, + span, + parts: vec![], + }), } - self } - /// This function sets the main [`Span`] of this diagnostic message. - /// [`AstContext::emit_lint`] will by default use the span of the given + /// This function sets the main [`Span`] of the created diagnostic. + /// [`AstContext::emit_lint`] will by default use the [`Span`] of the given /// [`EmissionNode`]. /// /// From rustc a lint emission would look like this: @@ -79,9 +60,9 @@ impl<'ast> DiagnosticBuilder<'ast> { /// | ^^^^ <-- The main span set by this function /// | /// ``` - pub fn set_main_span(&mut self, span: &Span<'ast>) -> &mut Self { - if self.emit_lint { - self.span = Some(span.clone()); + pub fn span(&mut self, span: &Span<'ast>) -> &mut Self { + if let Some(inner) = self.inner.as_mut() { + inner.span = span.clone(); } self @@ -102,9 +83,9 @@ impl<'ast> DiagnosticBuilder<'ast> { /// ``` /// /// [`Self::span_note`] can be used to highlight a relevant [`Span`]. - pub fn note(&mut self, msg: impl ToString) -> &mut Self { - if self.emit_lint { - self.parts.push(DiagnosticPart::Note { msg: msg.to_string() }); + pub fn note(&mut self, msg: impl Into) -> &mut Self { + if let Some(inner) = self.inner.as_mut() { + inner.parts.push(DiagnosticPart::Note { msg: msg.into() }); } self @@ -130,10 +111,10 @@ impl<'ast> DiagnosticBuilder<'ast> { /// ``` /// /// [`Self::note`] can be used to add text notes without a span. - pub fn span_note(&mut self, msg: impl ToString, span: &Span<'ast>) -> &mut Self { - if self.emit_lint { - self.parts.push(DiagnosticPart::NoteSpan { - msg: msg.to_string(), + pub fn span_note(&mut self, msg: impl Into, span: &Span<'ast>) -> &mut Self { + if let Some(inner) = self.inner.as_mut() { + inner.parts.push(DiagnosticPart::NoteSpan { + msg: msg.into(), span: span.clone(), }); } @@ -157,9 +138,9 @@ impl<'ast> DiagnosticBuilder<'ast> { /// /// [`Self::span_help`] can be used to highlight a relevant [`Span`]. /// [`Self::span_suggestion`] can be used to add a help message with a suggestion. - pub fn help(&mut self, msg: impl ToString) -> &mut Self { - if self.emit_lint { - self.parts.push(DiagnosticPart::Help { msg: msg.to_string() }); + pub fn help(&mut self, msg: impl Into) -> &mut Self { + if let Some(inner) = self.inner.as_mut() { + inner.parts.push(DiagnosticPart::Help { msg: msg.into() }); } self @@ -186,10 +167,10 @@ impl<'ast> DiagnosticBuilder<'ast> { /// /// [`Self::help`] can be used to add a text help message without a [`Span`]. /// [`Self::span_suggestion`] can be used to add a help message with a suggestion. - pub fn span_help(&mut self, msg: impl ToString, span: &Span<'ast>) -> &mut Self { - if self.emit_lint { - self.parts.push(DiagnosticPart::HelpSpan { - msg: msg.to_string(), + pub fn span_help(&mut self, msg: impl Into, span: &Span<'ast>) -> &mut Self { + if let Some(inner) = self.inner.as_mut() { + inner.parts.push(DiagnosticPart::HelpSpan { + msg: msg.into(), span: span.clone(), }); } @@ -215,64 +196,91 @@ impl<'ast> DiagnosticBuilder<'ast> { /// explanation is required. pub fn span_suggestion( &mut self, - msg: impl ToString, + msg: impl Into, span: &Span<'ast>, - suggestion: impl ToString, + suggestion: impl Into, app: Applicability, ) -> &mut Self { - if self.emit_lint { - self.parts.push(DiagnosticPart::Suggestion { - msg: msg.to_string(), + if let Some(inner) = self.inner.as_mut() { + inner.parts.push(DiagnosticPart::Suggestion { + msg: msg.into(), span: span.clone(), - sugg: suggestion.to_string(), + sugg: suggestion.into(), app, }); } + self } - /// This function takes a closure, that is only executed, if the created - /// diagnostic is actually emitted in the end. This is useful for crafting - /// suggestions. Having them in a conditional closure will speedup the - /// linting process if the lint is allowed at a given location. + /// The `decorate` parameter accepts a closure, that is only executed, when the + /// lint will actually be emitted in the end. Having them in a conditional closure + /// will speedup the linting process if the lint is suppressed. + /// + /// A lint emission might be suppressed, if the lint is allowed at the + /// [`EmissionNode`] or if the [`MacroReport`](crate::lint::MacroReport) level + /// specified in the [`Lint`] isn't sufficient for context of the [`EmissionNode`]. /// /// ``` /// # use marker_api::prelude::*; - /// # marker_api::declare_lint!( + /// # marker_api::declare_lint!{ /// # /// Dummy /// # LINT, /// # Warn, - /// # ); + /// # }; /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) { /// cx.emit_lint(LINT, node, "").decorate(|diag| { - /// // This closure is only called, if the lint is enabled. Here you - /// // can create a beautiful help message. + /// // This closure is only called, if the diagnostic will be emitted. + /// // Here you can create a beautiful help message. /// diag.help(""); /// }); /// # } /// ``` + /// + /// You can also checkout [`DiagnosticBuilder::done()`] to use a closure, without + /// curly brackets. pub fn decorate(&mut self, decorate: F) -> &mut Self where F: FnOnce(&mut DiagnosticBuilder<'ast>), { - if self.emit_lint { + if self.inner.is_some() { decorate(self); } + self } + /// This function simply consumes the builder reference, which allows simpler + /// use in closures. The following closures for [`DiagnosticBuilder::decorate`] + /// are equivalent: + /// + /// ``` + /// # use marker_api::prelude::*; + /// # marker_api::declare_lint!{ + /// # /// Dummy + /// # LINT, + /// # Warn, + /// # } + /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) { + /// // Without `done()` + /// cx.emit_lint(LINT, node, "").decorate(|diag| { + /// diag.help(""); + /// }); + /// + /// // With `done()` + /// cx.emit_lint(LINT, node, "").decorate(|diag| diag.help("").done()); + /// # } + /// ``` + pub fn done(&self) {} + pub(crate) fn emit<'builder>(&'builder self, cx: &AstContext<'ast>) { - if self.emit_lint { - let parts: Vec<_> = self.parts.iter().map(DiagnosticPart::to_ffi_part).collect(); - let span = self - .span - .as_ref() - .expect("always Some, if `DiagnosticBuilder::emit_lint` is true"); + if let Some(inner) = &self.inner { + let parts: Vec<_> = inner.parts.iter().map(DiagnosticPart::to_ffi_part).collect(); let diag = Diagnostic { - lint: self.lint, - msg: self.msg.as_str().into(), - node: self.node, - span, + lint: inner.lint, + msg: inner.msg.as_str().into(), + node: inner.node, + span: &inner.span, parts: parts.as_slice().into(), }; cx.emit_diagnostic(&diag); @@ -289,97 +297,9 @@ impl<'ast> Drop for DiagnosticBuilder<'ast> { /// Every lint emission is bound to a specific node. The node is used to /// determine the lint level and [`Span`] that is used for the main diagnostic /// message. -/// -/// This trait is implemented for most AST nodes and node ids. When given the option, -/// it's better to use the node directly, as the id might require some callbacks into -/// the driver to fetch the actual node. -// -// FIXME(xFrednet): This trait should also be implemented for all ids that implement -// `Into`. However, for this we first need to add more methods to fetch -// nodes by id, to provide a valid implementation for `emission_span`. -// -// The `Copy` super trait is not necessary, but it allows us to simply use `impl EmissionNode`, -// without triggering `clippy::needless_pass_by_value`. Marker could use `&impl EmissionNode` -// instead, but then these functions would complain about values of type `*Kind` and require the -// user to add a reference to the value. Just using `impl EmissionNode` feels better to me. -pub trait EmissionNode<'ast>: Debug + Copy { - /// The [`EmissionNodeId`] which is used to determine the lint level and - /// where the lint is emitted. - fn emission_node_id(&self) -> EmissionNodeId; - - /// The [`Span`] which will be used for a lint emission, if it's not overwritten by - /// [`DiagnosticBuilder::set_main_span`]. - /// - /// The [`AstContext`] can be used to fetch the [`Span`], if this is implemented on - /// a id. - fn emission_span(&self, _cx: &AstContext<'ast>) -> Option>; -} - -macro_rules! impl_emission_node_for_node { - ($ty:ty$(, use $data_trait:path)?) => { - impl<'ast> $crate::diagnostic::EmissionNode<'ast> for $ty { - fn emission_node_id(&self) -> $crate::diagnostic::EmissionNodeId { - $( - use $data_trait; - )* - self.id().into() - } - - fn emission_span(&self, _cx: &$crate::AstContext<'ast>) -> Option<$crate::ast::Span<'ast>> { - $( - use $data_trait; - )* - Some(self.span().clone()) - } - } - }; -} -pub(crate) use impl_emission_node_for_node; - -impl<'ast> EmissionNode<'ast> for crate::ast::ItemId { - fn emission_node_id(&self) -> EmissionNodeId { - self.into() - } - - fn emission_span(&self, cx: &AstContext<'ast>) -> Option> { - cx.item(*self).map(|x| x.span().clone()) - } -} - -/// This is the id of an [`EmissionNode`]. It can be used to determine the -/// lint level and to emit a lint. -#[repr(C)] -#[non_exhaustive] -#[derive(Debug, Clone, Copy)] -pub enum EmissionNodeId { - Expr(ExprId), - Item(ItemId), - Stmt(StmtId), - Field(FieldId), - Variant(VariantId), -} - -macro_rules! impl_into_emission_node_id_for { - ($variant:ident, $ty:ty) => { - impl From<$ty> for EmissionNodeId { - fn from(value: $ty) -> Self { - EmissionNodeId::$variant(value) - } - } - - impl From<&$ty> for EmissionNodeId { - fn from(value: &$ty) -> Self { - EmissionNodeId::$variant(*value) - } - } - }; -} +pub trait EmissionNode<'ast>: Debug + HasSpan<'ast> + HasNodeId {} -impl_into_emission_node_id_for!(Expr, ExprId); -impl_into_emission_node_id_for!(Item, ItemId); -impl_into_emission_node_id_for!(Stmt, StmtId); -impl_into_emission_node_id_for!(Field, FieldId); -impl_into_emission_node_id_for!(Variant, VariantId); +impl<'ast, N: Debug + HasSpan<'ast> + HasNodeId> EmissionNode<'ast> for N {} #[repr(C)] #[non_exhaustive] @@ -464,7 +384,7 @@ pub enum Applicability { pub(crate) struct Diagnostic<'builder, 'ast> { pub lint: &'static Lint, pub msg: FfiStr<'builder>, - pub node: EmissionNodeId, + pub node: NodeId, pub span: &'builder Span<'ast>, pub parts: FfiSlice<'builder, DiagnosticPart, &'builder Span<'ast>>>, } diff --git a/marker_api/src/lib.rs b/marker_api/src/lib.rs index e85271bc..b6bb0427 100644 --- a/marker_api/src/lib.rs +++ b/marker_api/src/lib.rs @@ -46,6 +46,8 @@ pub(crate) mod private { /// /// See: [Sealed traits](https://rust-lang.github.io/api-guidelines/future-proofing.html) pub trait Sealed {} + + impl Sealed for &N {} } /// This struct blocks the construction of enum variants, similar to the `#[non_exhaustive]` diff --git a/marker_api/src/prelude.rs b/marker_api/src/prelude.rs index 32db6ca1..4ed02090 100644 --- a/marker_api/src/prelude.rs +++ b/marker_api/src/prelude.rs @@ -8,8 +8,13 @@ pub use crate::ast::item::ItemData; pub use crate::ast::pat::PatData; pub use crate::ast::stmt::StmtData; pub use crate::ast::ty::SynTyData; +pub use crate::ast::HasNodeId; +pub use crate::ast::HasSpan; pub use crate::diagnostic::EmissionNode; +// IDs +pub use crate::ast::{BodyId, ExprId, FieldId, GenericId, ItemId, NodeId, StmtId, TyDefId, VarId, VariantId}; + // Common types pub use crate::ast::expr::ExprKind; pub use crate::ast::item::Body; diff --git a/marker_lints/src/lib.rs b/marker_lints/src/lib.rs index 19c61991..32805fa2 100644 --- a/marker_lints/src/lib.rs +++ b/marker_lints/src/lib.rs @@ -7,7 +7,7 @@ use marker_api::{ LintPass, LintPassInfo, LintPassInfoBuilder, }; -marker_api::declare_lint!( +marker_api::declare_lint! { /// ### What it does /// Diagnostic messages should start with lower case letter according to /// [rustc's dev guide]. @@ -15,7 +15,7 @@ marker_api::declare_lint!( /// [rustc's dev guide]: DIAG_MSG_UPPERCASE_START, Warn, -); +} #[derive(Debug, Default)] struct MarkerLintsLintPass; diff --git a/marker_lints/tests/ui/diag_msg_uppercase_start.rs b/marker_lints/tests/ui/diag_msg_uppercase_start.rs index f6679339..248781bd 100644 --- a/marker_lints/tests/ui/diag_msg_uppercase_start.rs +++ b/marker_lints/tests/ui/diag_msg_uppercase_start.rs @@ -2,11 +2,11 @@ extern crate marker_api; use marker_api::{ast::expr::ExprKind, context::AstContext}; -marker_api::declare_lint!( +marker_api::declare_lint!{ /// Dummy DUMMY, Warn, -); +} pub fn accept_message<'ast>(cx: &AstContext<'ast>, expr: ExprKind<'ast>) { cx.emit_lint(DUMMY, expr, "x <-- this is cool"); diff --git a/marker_rustc_driver/src/context.rs b/marker_rustc_driver/src/context.rs index 1aecbc98..af3a00a9 100644 --- a/marker_rustc_driver/src/context.rs +++ b/marker_rustc_driver/src/context.rs @@ -2,13 +2,10 @@ use std::cell::{OnceCell, RefCell}; use marker_adapter::context::{DriverContext, DriverContextWrapper}; use marker_api::{ - ast::{ - item::{Body, ItemKind}, - BodyId, ExprId, ItemId, Span, SpanId, SymbolId, TyDefId, - }, - context::AstContext, - diagnostic::{Diagnostic, EmissionNodeId}, + ast::{SpanId, SymbolId}, + diagnostic::Diagnostic, lint::{Level, Lint}, + prelude::*, }; use rustc_hash::FxHashMap; use rustc_hir as hir; @@ -74,7 +71,7 @@ impl<'ast, 'tcx> RustcContext<'ast, 'tcx> { } impl<'ast, 'tcx: 'ast> DriverContext<'ast> for RustcContext<'ast, 'tcx> { - fn lint_level_at(&'ast self, api_lint: &'static Lint, node: EmissionNodeId) -> Level { + fn lint_level_at(&'ast self, api_lint: &'static Lint, node: NodeId) -> Level { if let Some(id) = self.rustc_converter.try_to_hir_id_from_emission_node(node) { let lint = self.rustc_converter.to_lint(api_lint); let level = self.rustc_cx.lint_level_at_node(lint, id).0; diff --git a/marker_rustc_driver/src/conversion/rustc/common.rs b/marker_rustc_driver/src/conversion/rustc/common.rs index 396ccce1..e75b6c14 100644 --- a/marker_rustc_driver/src/conversion/rustc/common.rs +++ b/marker_rustc_driver/src/conversion/rustc/common.rs @@ -1,12 +1,10 @@ use std::mem::{size_of, transmute}; use marker_api::{ - ast::{ - BodyId, CrateId, ExpnId, ExprId, FieldId, GenericId, ItemId, Span, SpanId, SpanPos, SpanSrcId, StmtId, - SymbolId, TyDefId, VarId, VariantId, - }, - diagnostic::{Applicability, EmissionNodeId}, + ast::{CrateId, ExpnId, SpanId, SpanPos, SpanSrcId, SymbolId}, + diagnostic::Applicability, lint::Level, + prelude::*, }; use rustc_hir as hir; @@ -130,13 +128,14 @@ impl<'ast, 'tcx> RustcConverter<'ast, 'tcx> { } #[must_use] - pub fn try_to_hir_id_from_emission_node(&self, node: EmissionNodeId) -> Option { + pub fn try_to_hir_id_from_emission_node(&self, node: NodeId) -> Option { let def_id = match node { - EmissionNodeId::Expr(id) => return Some(self.to_hir_id(id)), - EmissionNodeId::Item(id) => self.to_def_id(id), - EmissionNodeId::Stmt(id) => return Some(self.to_hir_id(id)), - EmissionNodeId::Field(id) => return Some(self.to_hir_id(id)), - EmissionNodeId::Variant(id) => self.to_def_id(id), + NodeId::Expr(id) => return Some(self.to_hir_id(id)), + NodeId::Item(id) => self.to_def_id(id), + NodeId::Stmt(id) => return Some(self.to_hir_id(id)), + NodeId::Body(id) => return Some(self.to_body_id(id).hir_id), + NodeId::Field(id) => return Some(self.to_hir_id(id)), + NodeId::Variant(id) => self.to_def_id(id), _ => unreachable!(), }; diff --git a/marker_uilints/src/lib.rs b/marker_uilints/src/lib.rs index d3ae18ea..edc4086b 100644 --- a/marker_uilints/src/lib.rs +++ b/marker_uilints/src/lib.rs @@ -119,7 +119,7 @@ impl LintPass for TestLintPass { Some(name) if name.starts_with("PrintMe") || name.starts_with("PRINT_ME") || name.starts_with("print_me") ) { cx.emit_lint(TEST_LINT, item, "printing item").decorate(|diag| { - diag.set_main_span(item.ident().unwrap().span()); + diag.span(item.ident().unwrap().span()); diag.note(format!("{item:#?}")); }); } @@ -131,7 +131,7 @@ impl LintPass for TestLintPass { ) { cx.emit_lint(TEST_LINT, item, "printing item with body") .decorate(|diag| { - diag.set_main_span(item.ident().unwrap().span()); + diag.span(item.ident().unwrap().span()); diag.note(format!("Item: {item:#?}")); diag.note(format!("Body: {:#?}", cx.body(func.body_id().unwrap()))); }); @@ -210,7 +210,7 @@ fn check_static_item<'ast>(cx: &'ast AstContext<'ast>, item: &'ast StaticItem<'a let name = name.name(); if name.starts_with("PRINT_TYPE") { cx.emit_lint(TEST_LINT, item, "printing type for").decorate(|diag| { - diag.set_main_span(item.ty().span()); + diag.span(item.ty().span()); }); eprintln!("{:#?}\n\n", item.ty()); } else if name.starts_with("FIND_ITEM") { diff --git a/marker_uilints/src/utils.rs b/marker_uilints/src/utils.rs index 8e45cd27..585dd3f2 100644 --- a/marker_uilints/src/utils.rs +++ b/marker_uilints/src/utils.rs @@ -22,7 +22,7 @@ pub fn check_item<'ast>(cx: &'ast AstContext<'ast>, item: ItemKind<'ast>) { format!("testing `contains_return` -> {res}"), ) .decorate(|diag| { - diag.set_main_span(ident.span()); + diag.span(ident.span()); }); } }