Rust: refactor pre_emit! and post_emit! to a trait

This commit is contained in:
Paolo Tranquilli
2025-06-24 09:19:22 +02:00
parent e5cb639e28
commit d0c7550119
8 changed files with 369 additions and 459 deletions

View File

@@ -1,4 +1,4 @@
use super::mappings::{AddressableAst, AddressableHir, PathAst};
use super::mappings::{AddressableAst, AddressableHir, Emission, PathAst};
use crate::generated::{self};
use crate::rust_analyzer::FileSemanticInformation;
use crate::trap::{DiagnosticSeverity, TrapFile, TrapId};
@@ -22,121 +22,165 @@ use ra_ap_syntax::{
ast,
};
#[macro_export]
macro_rules! pre_emit {
(Item, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion($node) {
return Some(label.into());
}
};
(AssocItem, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
return Some(label.into());
}
};
(ExternItem, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
return Some(label.into());
}
};
(Meta, $self:ident, $node:ident) => {
// rust-analyzer doesn't expand macros in this context
$self.macro_context_depth += 1;
};
($($_:tt)*) => {};
impl Emission<ast::Item> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::Item) -> Option<Label<generated::Item>> {
self.prepare_item_expansion(node).map(Into::into)
}
fn post_emit(&mut self, node: &ast::Item, label: Label<generated::Item>) {
self.emit_item_expansion(node, label);
}
}
// TODO: remove the mannually written Label conversions. These can be auto-generated by
// changing the base class of AssocItem from AstNode to Item
impl From<crate::trap::Label<generated::AssocItem>> for crate::trap::Label<generated::Item> {
fn from(value: crate::trap::Label<generated::AssocItem>) -> Self {
impl Emission<ast::AssocItem> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::AssocItem) -> Option<Label<generated::AssocItem>> {
self.prepare_item_expansion(&node.clone().into())
.map(Into::into)
}
fn post_emit(&mut self, node: &ast::AssocItem, label: Label<generated::AssocItem>) {
self.emit_item_expansion(&node.clone().into(), label.into());
}
}
impl Emission<ast::ExternItem> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::ExternItem) -> Option<Label<generated::ExternItem>> {
self.prepare_item_expansion(&node.clone().into())
.map(Into::into)
}
fn post_emit(&mut self, node: &ast::ExternItem, label: Label<generated::ExternItem>) {
self.emit_item_expansion(&node.clone().into(), label.into());
}
}
impl Emission<ast::Meta> for Translator<'_> {
fn pre_emit(&mut self, _node: &ast::Meta) -> Option<Label<generated::Meta>> {
self.macro_context_depth += 1;
None
}
fn post_emit(&mut self, _node: &ast::Meta, _label: Label<generated::Meta>) {
self.macro_context_depth -= 1;
}
}
impl Emission<ast::Fn> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Fn, label: Label<generated::Function>) {
self.emit_function_has_implementation(node, label);
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Struct> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Struct, label: Label<generated::Struct>) {
self.emit_derive_expansion(node, label);
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Enum> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Enum, label: Label<generated::Enum>) {
self.emit_derive_expansion(node, label);
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Union> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Union, label: Label<generated::Union>) {
self.emit_derive_expansion(node, label);
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Trait> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Trait, label: Label<generated::Trait>) {
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Module> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Module, label: Label<generated::Module>) {
self.extract_canonical_origin(node, label.into());
}
}
impl Emission<ast::Variant> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Variant, label: Label<generated::Variant>) {
self.extract_canonical_origin_of_enum_variant(node, label);
}
}
impl Emission<ast::PathExpr> for Translator<'_> {
fn post_emit(&mut self, node: &ast::PathExpr, label: Label<generated::PathExpr>) {
self.extract_path_canonical_destination(node, label.into());
}
}
impl Emission<ast::RecordExpr> for Translator<'_> {
fn post_emit(&mut self, node: &ast::RecordExpr, label: Label<generated::StructExpr>) {
self.extract_path_canonical_destination(node, label.into());
}
}
impl Emission<ast::PathPat> for Translator<'_> {
fn post_emit(&mut self, node: &ast::PathPat, label: Label<generated::PathPat>) {
self.extract_path_canonical_destination(node, label.into());
}
}
impl Emission<ast::RecordPat> for Translator<'_> {
fn post_emit(&mut self, node: &ast::RecordPat, label: Label<generated::StructPat>) {
self.extract_path_canonical_destination(node, label.into());
}
}
impl Emission<ast::TupleStructPat> for Translator<'_> {
fn post_emit(&mut self, node: &ast::TupleStructPat, label: Label<generated::TupleStructPat>) {
self.extract_path_canonical_destination(node, label.into());
}
}
impl Emission<ast::MethodCallExpr> for Translator<'_> {
fn post_emit(&mut self, node: &ast::MethodCallExpr, label: Label<generated::MethodCallExpr>) {
self.extract_method_canonical_destination(node, label);
}
}
impl Emission<ast::PathSegment> for Translator<'_> {
fn post_emit(&mut self, node: &ast::PathSegment, label: Label<generated::PathSegment>) {
self.extract_types_from_path_segment(node, label);
}
}
impl Emission<ast::Const> for Translator<'_> {
fn post_emit(&mut self, node: &ast::Const, label: Label<generated::Const>) {
self.emit_const_has_implementation(node, label);
}
}
impl Emission<ast::MacroCall> for Translator<'_> {
fn post_emit(&mut self, node: &ast::MacroCall, label: Label<generated::MacroCall>) {
self.extract_macro_call_expanded(node, label);
}
}
// TODO: remove the manually written Label conversions. These can be auto-generated by
// ch
// anging the base class of AssocItem from AstNode to Item
impl From<Label<generated::AssocItem>> for Label<generated::Item> {
fn from(value: Label<generated::AssocItem>) -> Self {
// SAFETY: this is safe because every concrete instance of `@assoc_item` is also an instance of `@item`
unsafe { Self::from_untyped(value.as_untyped()) }
}
}
// TODO: remove the mannually written Label conversions. These can be auto-generated by
// TODO: remove the manually written Label conversions. These can be auto-generated by
// changing the base class of ExternItem from AstNode to Item
impl From<crate::trap::Label<generated::ExternItem>> for crate::trap::Label<generated::Item> {
fn from(value: crate::trap::Label<generated::ExternItem>) -> Self {
impl From<Label<generated::ExternItem>> for Label<generated::Item> {
fn from(value: Label<generated::ExternItem>) -> Self {
// SAFETY: this is safe because every concrete instance of `@extern_item` is also an instance of `@item`
unsafe { Self::from_untyped(value.as_untyped()) }
}
}
#[macro_export]
macro_rules! post_emit {
(Meta, $self:ident, $node:ident, $label:ident) => {
$self.macro_context_depth -= 1;
};
(MacroCall, $self:ident, $node:ident, $label:ident) => {
$self.extract_macro_call_expanded($node, $label);
};
(Function, $self:ident, $node:ident, $label:ident) => {
$self.emit_function_has_implementation($node, $label);
$self.extract_canonical_origin($node, $label.into());
};
(Trait, $self:ident, $node:ident, $label:ident) => {
$self.extract_canonical_origin($node, $label.into());
};
(Struct, $self:ident, $node:ident, $label:ident) => {
$self.emit_derive_expansion($node, $label);
$self.extract_canonical_origin($node, $label.into());
};
(Enum, $self:ident, $node:ident, $label:ident) => {
$self.emit_derive_expansion($node, $label);
$self.extract_canonical_origin($node, $label.into());
};
(Union, $self:ident, $node:ident, $label:ident) => {
$self.emit_derive_expansion($node, $label);
$self.extract_canonical_origin($node, $label.into());
};
(Module, $self:ident, $node:ident, $label:ident) => {
$self.extract_canonical_origin($node, $label.into());
};
(Variant, $self:ident, $node:ident, $label:ident) => {
$self.extract_canonical_origin_of_enum_variant($node, $label);
};
(Item, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion($node, $label);
};
(AssocItem, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion(
&$node.clone().into(),
From::<Label<generated::AssocItem>>::from($label),
);
};
(ExternItem, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion(
&$node.clone().into(),
From::<Label<generated::ExternItem>>::from($label),
);
};
// TODO canonical origin of other items
(PathExpr, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
};
(StructExpr, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
};
(PathPat, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
};
(StructPat, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
};
(TupleStructPat, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
};
(MethodCallExpr, $self:ident, $node:ident, $label:ident) => {
$self.extract_method_canonical_destination($node, $label);
};
(PathSegment, $self:ident, $node:ident, $label:ident) => {
$self.extract_types_from_path_segment($node, $label.into());
};
(Const, $self:ident, $node:ident, $label:ident) => {
$self.emit_const_has_implementation($node, $label);
};
($($_:tt)*) => {};
}
// see https://github.com/tokio-rs/tracing/issues/2730
macro_rules! dispatch_to_tracing {
@@ -497,6 +541,17 @@ impl<'a> Translator<'a> {
);
}
}
pub(crate) fn emit_else_branch(
&mut self,
node: &ast::ElseBranch,
) -> Option<Label<generated::Expr>> {
match node {
ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).map(Into::into),
ast::ElseBranch::Block(inner) => self.emit_block_expr(inner).map(Into::into),
}
}
fn canonical_path_from_type(&self, ty: Type) -> Option<String> {
let sema = self.semantics.as_ref().unwrap();
// rust-analyzer doesn't provide a type enum directly

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,20 @@
use crate::trap::{Label, TrapClass};
use ra_ap_hir::{Enum, Function, HasContainer, Module, Semantics, Struct, Trait, Union};
use ra_ap_ide_db::RootDatabase;
use ra_ap_syntax::{AstNode, ast, ast::RangeItem};
pub(crate) trait HasTrapClass: AstNode {
type TrapClass: TrapClass;
}
pub(crate) trait Emission<T: HasTrapClass> {
fn pre_emit(&mut self, _node: &T) -> Option<Label<T::TrapClass>> {
None
}
fn post_emit(&mut self, _node: &T, _label: Label<T::TrapClass>) {}
}
pub(crate) trait TextValue {
fn try_get_text(&self) -> Option<String>;
}