mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
fix(transformer/typescript): typescript syntax within SimpleAssignmentTarget with MemberExpressions is not stripped (#4920)
close: #4870 I added the `move_identifier_reference` and `move_member_expression` methods used to take ownership in `ast_builder_impl`. This way can let us get rid of `ast.copy`. Another possible approach is to add `get_expression_owner` to `SimpleAssignmentTarget` and a `get_inner_expression_owner` method to `Expression`. And add an `into_xxxxx` method for `inherit_variants` macro The implementation looks like this ```rs let Some(expression) = self.get_expression_owner() else { return; } match expr.get_inner_expression_owner() { Expression::Identifier(ident) => { *target = self.ctx.ast.simple_assignment_target_from_identifier_reference(ident); } inner_expr @ match_member_expression!(Expression) => { *target = SimpleAssignmentTarget::from( inner_expr.into_member_expression() ); } _ => (), } ```
This commit is contained in:
parent
508644a34e
commit
248a757b34
4 changed files with 67 additions and 7 deletions
|
|
@ -69,6 +69,16 @@ impl<'a> AstBuilder<'a> {
|
|||
unsafe { std::mem::transmute_copy(src) }
|
||||
}
|
||||
|
||||
/// Moves the identifier reference out by replacing it with a dummy identifier reference.
|
||||
#[inline]
|
||||
pub fn move_identifier_reference(
|
||||
self,
|
||||
expr: &mut IdentifierReference<'a>,
|
||||
) -> IdentifierReference<'a> {
|
||||
let dummy = self.identifier_reference(expr.span(), "");
|
||||
mem::replace(expr, dummy)
|
||||
}
|
||||
|
||||
/// Moves the expression out by replacing it with a null expression.
|
||||
#[inline]
|
||||
pub fn move_expression(self, expr: &mut Expression<'a>) -> Expression<'a> {
|
||||
|
|
@ -76,6 +86,18 @@ impl<'a> AstBuilder<'a> {
|
|||
mem::replace(expr, null_expr)
|
||||
}
|
||||
|
||||
/// Moves the member expression out by replacing it with a dummy expression.
|
||||
#[inline]
|
||||
pub fn move_member_expression(self, expr: &mut MemberExpression<'a>) -> MemberExpression<'a> {
|
||||
let dummy = self.member_expression_computed(
|
||||
expr.span(),
|
||||
self.expression_null_literal(expr.span()),
|
||||
self.expression_null_literal(expr.span()),
|
||||
false,
|
||||
);
|
||||
mem::replace(expr, dummy)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn move_statement(self, stmt: &mut Statement<'a>) -> Statement<'a> {
|
||||
let empty_stmt = self.empty_statement(stmt.span());
|
||||
|
|
|
|||
|
|
@ -216,6 +216,20 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_inner_expression_mut(&mut self) -> &mut Expression<'a> {
|
||||
match self {
|
||||
Expression::ParenthesizedExpression(expr) => expr.expression.get_inner_expression_mut(),
|
||||
Expression::TSAsExpression(expr) => expr.expression.get_inner_expression_mut(),
|
||||
Expression::TSSatisfiesExpression(expr) => expr.expression.get_inner_expression_mut(),
|
||||
Expression::TSInstantiationExpression(expr) => {
|
||||
expr.expression.get_inner_expression_mut()
|
||||
}
|
||||
Expression::TSNonNullExpression(expr) => expr.expression.get_inner_expression_mut(),
|
||||
Expression::TSTypeAssertion(expr) => expr.expression.get_inner_expression_mut(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_identifier_reference(&self) -> bool {
|
||||
matches!(self, Expression::Identifier(_))
|
||||
}
|
||||
|
|
@ -632,6 +646,17 @@ impl<'a> SimpleAssignmentTarget<'a> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_expression_mut(&mut self) -> Option<&mut Expression<'a>> {
|
||||
match self {
|
||||
Self::TSAsExpression(expr) => Some(&mut expr.expression),
|
||||
Self::TSSatisfiesExpression(expr) => Some(&mut expr.expression),
|
||||
Self::TSNonNullExpression(expr) => Some(&mut expr.expression),
|
||||
Self::TSTypeAssertion(expr) => Some(&mut expr.expression),
|
||||
Self::TSInstantiationExpression(expr) => Some(&mut expr.expression),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArrayAssignmentTarget<'a> {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::{cell::Cell, rc::Rc};
|
|||
|
||||
use oxc_allocator::Vec as ArenaVec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_semantic::SymbolFlags;
|
||||
use oxc_span::{Atom, GetSpan, Span, SPAN};
|
||||
use oxc_syntax::{
|
||||
|
|
@ -222,11 +223,24 @@ impl<'a> TypeScriptAnnotations<'a> {
|
|||
}
|
||||
|
||||
pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) {
|
||||
if let Some(expr) = target.get_expression() {
|
||||
if let Expression::Identifier(ident) = expr.get_inner_expression() {
|
||||
// SAFETY: `ast.copy` is unsound! We need to fix.
|
||||
let ident = unsafe { self.ctx.ast.copy(ident) };
|
||||
*target = SimpleAssignmentTarget::AssignmentTargetIdentifier(ident);
|
||||
if let Some(expr) = target.get_expression_mut() {
|
||||
match expr.get_inner_expression_mut() {
|
||||
// `foo!++` to `foo++`
|
||||
Expression::Identifier(ident) => {
|
||||
*target = self.ctx.ast.simple_assignment_target_from_identifier_reference(
|
||||
self.ctx.ast.move_identifier_reference(ident),
|
||||
);
|
||||
}
|
||||
// `foo.bar!++` to `foo.bar++`
|
||||
inner_expr @ match_member_expression!(Expression) => {
|
||||
*target = SimpleAssignmentTarget::from(
|
||||
self.ctx.ast.move_member_expression(inner_expr.to_member_expression_mut()),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// This should be never hit until more syntax is added to the JavaScript/TypeScrips
|
||||
self.ctx.error(OxcDiagnostic::error("Cannot strip out typescript syntax if SimpleAssignmentTarget is not an IdentifierReference or MemberExpression"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ commit: d8086f14
|
|||
|
||||
transformer_typescript Summary:
|
||||
AST Parsed : 6456/6456 (100.00%)
|
||||
Positive Passed: 6452/6456 (99.94%)
|
||||
Positive Passed: 6453/6456 (99.95%)
|
||||
Mismatch: "compiler/constEnumNamespaceReferenceCausesNoImport2.ts"
|
||||
Mismatch: "compiler/incrementOnNullAssertion.ts"
|
||||
Mismatch: "conformance/externalModules/typeOnly/exportDeclaration.ts"
|
||||
Mismatch: "conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx"
|
||||
|
|
|
|||
Loading…
Reference in a new issue