Skip to content

Commit

Permalink
feat(ast,parser): parse TSTypeAnnotations on AccessorProperty (#5179
Browse files Browse the repository at this point in the history
)

Closes #5177

While making this, I noticed an uncaught parse error for accessors: accessors cannot be optional. I'll add a fix for this in an up-stack PR.
  • Loading branch information
DonIsaac committed Aug 25, 2024
1 parent 1d01aa3 commit c2fa725
Show file tree
Hide file tree
Showing 17 changed files with 367 additions and 179 deletions.
6 changes: 6 additions & 0 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2277,8 +2277,14 @@ pub struct AccessorProperty<'a> {
pub key: PropertyKey<'a>,
/// Initialized value in the declaration, if present.
pub value: Option<Expression<'a>>,
/// Property was declared with a computed key
pub computed: bool,
/// Property was declared with a `static` modifier
pub r#static: bool,
/// Type annotation on the property.
///
/// Will only ever be [`Some`] for TypeScript files.
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
}

#[ast(visit)]
Expand Down
6 changes: 4 additions & 2 deletions crates/oxc_ast/src/generated/assert_layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ const _: () = {
assert!(size_of::<AccessorPropertyType>() == 1usize);
assert!(align_of::<AccessorPropertyType>() == 1usize);

assert!(size_of::<AccessorProperty>() == 88usize);
assert!(size_of::<AccessorProperty>() == 96usize);
assert!(align_of::<AccessorProperty>() == 8usize);
assert!(offset_of!(AccessorProperty, r#type) == 0usize);
assert!(offset_of!(AccessorProperty, span) == 4usize);
Expand All @@ -696,6 +696,7 @@ const _: () = {
assert!(offset_of!(AccessorProperty, value) == 64usize);
assert!(offset_of!(AccessorProperty, computed) == 80usize);
assert!(offset_of!(AccessorProperty, r#static) == 81usize);
assert!(offset_of!(AccessorProperty, type_annotation) == 88usize);

assert!(size_of::<ImportExpression>() == 56usize);
assert!(align_of::<ImportExpression>() == 8usize);
Expand Down Expand Up @@ -2091,7 +2092,7 @@ const _: () = {
assert!(size_of::<AccessorPropertyType>() == 1usize);
assert!(align_of::<AccessorPropertyType>() == 1usize);

assert!(size_of::<AccessorProperty>() == 48usize);
assert!(size_of::<AccessorProperty>() == 52usize);
assert!(align_of::<AccessorProperty>() == 4usize);
assert!(offset_of!(AccessorProperty, r#type) == 0usize);
assert!(offset_of!(AccessorProperty, span) == 4usize);
Expand All @@ -2100,6 +2101,7 @@ const _: () = {
assert!(offset_of!(AccessorProperty, value) == 36usize);
assert!(offset_of!(AccessorProperty, computed) == 44usize);
assert!(offset_of!(AccessorProperty, r#static) == 45usize);
assert!(offset_of!(AccessorProperty, type_annotation) == 48usize);

assert!(size_of::<ImportExpression>() == 32usize);
assert!(align_of::<ImportExpression>() == 4usize);
Expand Down
74 changes: 57 additions & 17 deletions crates/oxc_ast/src/generated/ast_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6494,10 +6494,11 @@ impl<'a> AstBuilder<'a> {
/// - decorators: Decorators applied to the accessor property.
/// - key: The expression used to declare the property.
/// - value: Initialized value in the declaration, if present.
/// - computed
/// - r#static
/// - computed: Property was declared with a computed key
/// - r#static: Property was declared with a `static` modifier
/// - type_annotation: Type annotation on the property.
#[inline]
pub fn class_element_accessor_property(
pub fn class_element_accessor_property<T1>(
self,
r#type: AccessorPropertyType,
span: Span,
Expand All @@ -6506,10 +6507,21 @@ impl<'a> AstBuilder<'a> {
value: Option<Expression<'a>>,
computed: bool,
r#static: bool,
) -> ClassElement<'a> {
ClassElement::AccessorProperty(self.alloc(
self.accessor_property(r#type, span, decorators, key, value, computed, r#static),
))
type_annotation: T1,
) -> ClassElement<'a>
where
T1: IntoIn<'a, Option<Box<'a, TSTypeAnnotation<'a>>>>,
{
ClassElement::AccessorProperty(self.alloc(self.accessor_property(
r#type,
span,
decorators,
key,
value,
computed,
r#static,
type_annotation,
)))
}

/// Convert a [`AccessorProperty`] into a [`ClassElement::AccessorProperty`]
Expand Down Expand Up @@ -7057,10 +7069,11 @@ impl<'a> AstBuilder<'a> {
/// - decorators: Decorators applied to the accessor property.
/// - key: The expression used to declare the property.
/// - value: Initialized value in the declaration, if present.
/// - computed
/// - r#static
/// - computed: Property was declared with a computed key
/// - r#static: Property was declared with a `static` modifier
/// - type_annotation: Type annotation on the property.
#[inline]
pub fn accessor_property(
pub fn accessor_property<T1>(
self,
r#type: AccessorPropertyType,
span: Span,
Expand All @@ -7069,8 +7082,21 @@ impl<'a> AstBuilder<'a> {
value: Option<Expression<'a>>,
computed: bool,
r#static: bool,
) -> AccessorProperty<'a> {
AccessorProperty { r#type, span, decorators, key, value, computed, r#static }
type_annotation: T1,
) -> AccessorProperty<'a>
where
T1: IntoIn<'a, Option<Box<'a, TSTypeAnnotation<'a>>>>,
{
AccessorProperty {
r#type,
span,
decorators,
key,
value,
computed,
r#static,
type_annotation: type_annotation.into_in(self.allocator),
}
}

/// Builds a [`AccessorProperty`] and stores it in the memory arena.
Expand All @@ -7083,10 +7109,11 @@ impl<'a> AstBuilder<'a> {
/// - decorators: Decorators applied to the accessor property.
/// - key: The expression used to declare the property.
/// - value: Initialized value in the declaration, if present.
/// - computed
/// - r#static
/// - computed: Property was declared with a computed key
/// - r#static: Property was declared with a `static` modifier
/// - type_annotation: Type annotation on the property.
#[inline]
pub fn alloc_accessor_property(
pub fn alloc_accessor_property<T1>(
self,
r#type: AccessorPropertyType,
span: Span,
Expand All @@ -7095,9 +7122,22 @@ impl<'a> AstBuilder<'a> {
value: Option<Expression<'a>>,
computed: bool,
r#static: bool,
) -> Box<'a, AccessorProperty<'a>> {
type_annotation: T1,
) -> Box<'a, AccessorProperty<'a>>
where
T1: IntoIn<'a, Option<Box<'a, TSTypeAnnotation<'a>>>>,
{
Box::new_in(
self.accessor_property(r#type, span, decorators, key, value, computed, r#static),
self.accessor_property(
r#type,
span,
decorators,
key,
value,
computed,
r#static,
type_annotation,
),
self.allocator,
)
}
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_ast/src/generated/derive_clone_in.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,7 @@ impl<'old_alloc, 'new_alloc> CloneIn<'new_alloc> for AccessorProperty<'old_alloc
value: self.value.clone_in(allocator),
computed: self.computed.clone_in(allocator),
r#static: self.r#static.clone_in(allocator),
type_annotation: self.type_annotation.clone_in(allocator),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_ast/src/generated/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3110,6 +3110,9 @@ pub mod walk {
if let Some(value) = &it.value {
visitor.visit_expression(value);
}
if let Some(type_annotation) = &it.type_annotation {
visitor.visit_ts_type_annotation(type_annotation);
}
}

#[inline]
Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_ast/src/generated/visit_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3253,6 +3253,9 @@ pub mod walk_mut {
if let Some(value) = &mut it.value {
visitor.visit_expression(value);
}
if let Some(type_annotation) = &mut it.type_annotation {
visitor.visit_ts_type_annotation(type_annotation);
}
}

#[inline]
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_isolated_declarations/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ impl<'a> IsolatedDeclarations<'a> {
None,
property.computed,
property.r#static,
// SAFETY: `ast.copy` is unsound! We need to fix.
unsafe { self.ast.copy(&property.type_annotation) },
);
elements.push(new_element);
}
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_parser/src/js/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ impl<'a> ParserImpl<'a> {
}

if accessor {
self.parse_ts_type_annotation()?;
self.parse_class_accessor_property(span, key, computed, r#static, r#abstract).map(Some)
} else if self.at(Kind::LParen) || self.at(Kind::LAngle) || r#async || generator {
// LAngle for start of type parameters `foo<T>`
Expand Down Expand Up @@ -479,6 +478,8 @@ impl<'a> ParserImpl<'a> {
r#static: bool,
r#abstract: bool,
) -> Result<ClassElement<'a>> {
let type_annotation =
if self.ts_enabled() { self.parse_ts_type_annotation()? } else { None };
let value =
self.eat(Kind::Eq).then(|| self.parse_assignment_expression_or_higher()).transpose()?;
let r#type = if r#abstract {
Expand All @@ -496,6 +497,7 @@ impl<'a> ParserImpl<'a> {
value,
computed,
r#static,
type_annotation,
))
}
}
17 changes: 17 additions & 0 deletions crates/oxc_semantic/tests/integration/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@ fn test_class_with_type_parameter() {
tester.has_symbol("B").has_number_of_references(0).test();
}

#[test]
fn test_class_with_accessor() {
SemanticTester::ts(
"
type T = 1;
abstract class Foo {
accessor prop: T;
}
",
)
.has_some_symbol("T")
.has_number_of_references(1)
.has_number_of_references_where(1, Reference::is_type)
.test();
}

#[test]
fn test_ts_mapped_type() {
let tester = SemanticTester::ts(
Expand Down
Loading

0 comments on commit c2fa725

Please sign in to comment.