@@ -1049,6 +1049,11 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10491049 return ;
10501050 }
10511051
1052+ // Check decorators - they execute at definition time
1053+ for decorator in & class. decorators {
1054+ decorator. visit_with ( self ) ;
1055+ }
1056+
10521057 // Check the extends clause - this is evaluated at definition time
10531058 if let Some ( super_class) = & class. super_class {
10541059 super_class. visit_with ( self ) ;
@@ -1073,6 +1078,10 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10731078 }
10741079 // Check static properties - they execute at definition time
10751080 ClassMember :: ClassProp ( class_prop) if class_prop. is_static => {
1081+ // Check decorators - they execute at definition time
1082+ for decorator in & class_prop. decorators {
1083+ decorator. visit_with ( self ) ;
1084+ }
10761085 // Check the property key (for computed properties)
10771086 class_prop. key . visit_with ( self ) ;
10781087 // Check the initializer - static property initializers execute at definition time
@@ -1082,6 +1091,10 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10821091 }
10831092 // Check computed property keys for all members
10841093 ClassMember :: Method ( method) => {
1094+ // Check decorators - they execute at definition time
1095+ for decorator in & method. function . decorators {
1096+ decorator. visit_with ( self ) ;
1097+ }
10851098 method. key . visit_with ( self ) ;
10861099 // Method bodies don't execute at definition time
10871100 }
@@ -1090,26 +1103,46 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10901103 // Constructor body doesn't execute at definition time
10911104 }
10921105 ClassMember :: PrivateMethod ( private_method) => {
1106+ // Check decorators - they execute at definition time
1107+ for decorator in & private_method. function . decorators {
1108+ decorator. visit_with ( self ) ;
1109+ }
10931110 private_method. key . visit_with ( self ) ;
10941111 // Method bodies don't execute at definition time
10951112 }
10961113 ClassMember :: ClassProp ( class_prop) => {
1114+ // Check decorators - they execute at definition time
1115+ for decorator in & class_prop. decorators {
1116+ decorator. visit_with ( self ) ;
1117+ }
10971118 // For non-static properties, only check the key
10981119 class_prop. key . visit_with ( self ) ;
10991120 // Instance property initializers don't execute at definition time
11001121 }
11011122 ClassMember :: PrivateProp ( private_prop) => {
1123+ // Check decorators - they execute at definition time
1124+ for decorator in & private_prop. decorators {
1125+ decorator. visit_with ( self ) ;
1126+ }
11021127 private_prop. key . visit_with ( self ) ;
11031128 // Instance property initializers don't execute at definition time
11041129 }
11051130 ClassMember :: AutoAccessor ( auto_accessor) if auto_accessor. is_static => {
1131+ // Check decorators - they execute at definition time
1132+ for decorator in & auto_accessor. decorators {
1133+ decorator. visit_with ( self ) ;
1134+ }
11061135 // Static auto accessors execute at definition time
11071136 auto_accessor. key . visit_with ( self ) ;
11081137 if let Some ( value) = & auto_accessor. value {
11091138 value. visit_with ( self ) ;
11101139 }
11111140 }
11121141 ClassMember :: AutoAccessor ( auto_accessor) => {
1142+ // Check decorators - they execute at definition time
1143+ for decorator in & auto_accessor. decorators {
1144+ decorator. visit_with ( self ) ;
1145+ }
11131146 // Non-static auto accessors only check the key
11141147 auto_accessor. key . visit_with ( self ) ;
11151148 }
@@ -1122,6 +1155,17 @@ impl<'a> Visit for SideEffectVisitor<'a> {
11221155 }
11231156 }
11241157
1158+ fn visit_decorator ( & mut self , _decorator : & Decorator ) {
1159+ if self . has_side_effects {
1160+ return ;
1161+ }
1162+
1163+ // Decorators always have side effects because they are function calls
1164+ // that execute at class/member definition time, even if they're just
1165+ // identifier references (e.g., @decorator is equivalent to calling decorator())
1166+ self . mark_side_effect ( ) ;
1167+ }
1168+
11251169 fn visit_pat ( & mut self , pat : & Pat ) {
11261170 if self . has_side_effects {
11271171 return ;
@@ -1197,6 +1241,7 @@ mod tests {
11971241 & fm,
11981242 Syntax :: Es ( EsSyntax {
11991243 jsx : true ,
1244+ decorators : true ,
12001245 ..Default :: default ( )
12011246 } ) ,
12021247 EsVersion :: latest ( ) ,
@@ -2193,4 +2238,62 @@ mod tests {
21932238 test_destructure_default_pure_annotation,
21942239 "const { foo = /*#__PURE__*/ compute() } = obj;"
21952240 ) ;
2241+
2242+ // ==================== Phase 14: Decorator Side Effects ====================
2243+
2244+ // Class decorator has side effects (executes at definition time)
2245+ side_effects ! (
2246+ test_class_decorator,
2247+ r#"
2248+ @decorator
2249+ class Foo {}
2250+ "#
2251+ ) ;
2252+
2253+ // Method decorator has side effects
2254+ side_effects ! (
2255+ test_method_decorator,
2256+ r#"
2257+ class Foo {
2258+ @decorator
2259+ method() {}
2260+ }
2261+ "#
2262+ ) ;
2263+
2264+ // Property decorator has side effects
2265+ side_effects ! (
2266+ test_property_decorator,
2267+ r#"
2268+ class Foo {
2269+ @decorator
2270+ prop = 1;
2271+ }
2272+ "#
2273+ ) ;
2274+
2275+ // Multiple decorators
2276+ side_effects ! (
2277+ test_multiple_decorators,
2278+ r#"
2279+ @decorator1
2280+ @decorator2
2281+ class Foo {
2282+ @propDecorator
2283+ prop = 1;
2284+
2285+ @methodDecorator
2286+ method() {}
2287+ }
2288+ "#
2289+ ) ;
2290+
2291+ // Decorator with arguments
2292+ side_effects ! (
2293+ test_decorator_with_args,
2294+ r#"
2295+ @decorator(config())
2296+ class Foo {}
2297+ "#
2298+ ) ;
21962299}
0 commit comments