Skip to content

Commit 3b385d6

Browse files
Copilotsapphi-red
andcommitted
Add comprehensive tests for typeof guard patterns in side effect analysis
Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
1 parent aff837d commit 3b385d6

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,3 +832,68 @@ fn test_object_with_to_primitive_related_properties_overridden() {
832832
test("+{ ...{ valueOf() { return Symbol() } } }", true);
833833
test("+{ ...{ [Symbol.toPrimitive]() { return Symbol() } } }", true);
834834
}
835+
836+
#[test]
837+
fn test_typeof_guard_patterns() {
838+
// Test patterns with global variables that should be side-effect-free
839+
// when properly guarded with typeof checks
840+
841+
// Logical AND patterns - typeof x !== 'undefined' && x
842+
test_with_global_variables("typeof x !== 'undefined' && x", vec!["x".to_string()], false);
843+
test_with_global_variables("typeof x != 'undefined' && x", vec!["x".to_string()], false);
844+
test_with_global_variables("'undefined' !== typeof x && x", vec!["x".to_string()], false);
845+
test_with_global_variables("'undefined' != typeof x && x", vec!["x".to_string()], false);
846+
847+
// Logical OR patterns - typeof x === 'undefined' || x
848+
test_with_global_variables("typeof x === 'undefined' || x", vec!["x".to_string()], false);
849+
test_with_global_variables("typeof x == 'undefined' || x", vec!["x".to_string()], false);
850+
test_with_global_variables("'undefined' === typeof x || x", vec!["x".to_string()], false);
851+
test_with_global_variables("'undefined' == typeof x || x", vec!["x".to_string()], false);
852+
853+
// String comparison patterns - typeof x < 'u' && x
854+
test_with_global_variables("typeof x < 'u' && x", vec!["x".to_string()], false);
855+
test_with_global_variables("typeof x <= 'u' && x", vec!["x".to_string()], false);
856+
test_with_global_variables("'u' > typeof x && x", vec!["x".to_string()], false);
857+
test_with_global_variables("'u' >= typeof x && x", vec!["x".to_string()], false);
858+
859+
// Conditional patterns - typeof x === 'undefined' ? fallback : x
860+
test_with_global_variables("typeof x === 'undefined' ? 0 : x", vec!["x".to_string()], false);
861+
test_with_global_variables("typeof x == 'undefined' ? 0 : x", vec!["x".to_string()], false);
862+
test_with_global_variables("'undefined' === typeof x ? 0 : x", vec!["x".to_string()], false);
863+
test_with_global_variables("'undefined' == typeof x ? 0 : x", vec!["x".to_string()], false);
864+
865+
// Conditional patterns - typeof x !== 'undefined' ? x : fallback
866+
test_with_global_variables("typeof x !== 'undefined' ? x : 0", vec!["x".to_string()], false);
867+
test_with_global_variables("typeof x != 'undefined' ? x : 0", vec!["x".to_string()], false);
868+
test_with_global_variables("'undefined' !== typeof x ? x : 0", vec!["x".to_string()], false);
869+
test_with_global_variables("'undefined' != typeof x ? x : 0", vec!["x".to_string()], false);
870+
871+
// These should still have side effects because the fallback/other expressions have side effects
872+
test_with_global_variables("typeof x !== 'undefined' && (x + foo())", vec!["x".to_string()], true);
873+
test_with_global_variables("typeof x === 'undefined' || (x + foo())", vec!["x".to_string()], true);
874+
test_with_global_variables("typeof x === 'undefined' ? foo() : x", vec!["x".to_string()], true);
875+
test_with_global_variables("typeof x !== 'undefined' ? x : foo()", vec!["x".to_string()], true);
876+
877+
// These should still have side effects because the guard condition itself has side effects
878+
test_with_global_variables("typeof foo() !== 'undefined' && x", vec!["x".to_string()], true);
879+
test_with_global_variables("typeof foo() === 'undefined' || x", vec!["x".to_string()], true);
880+
test_with_global_variables("typeof foo() === 'undefined' ? 0 : x", vec!["x".to_string()], true);
881+
882+
// These should still have side effects because the variable name doesn't match
883+
test_with_global_variables("typeof y !== 'undefined' && x", vec!["x".to_string(), "y".to_string()], true);
884+
test_with_global_variables("typeof y === 'undefined' || x", vec!["x".to_string(), "y".to_string()], true);
885+
test_with_global_variables("typeof y === 'undefined' ? 0 : x", vec!["x".to_string(), "y".to_string()], true);
886+
887+
// Test that accessing non-global variables is side-effect-free
888+
test("localVar", false);
889+
890+
// These should be side-effect-free when the variable is not declared as global
891+
// because such variables are treated as having no side effects when accessed
892+
test("typeof localVar !== 'undefined' && localVar", false);
893+
test("typeof localVar === 'undefined' || localVar", false);
894+
test("typeof localVar === 'undefined' ? 0 : localVar", false);
895+
896+
// Test multiple variables
897+
test_with_global_variables("typeof x !== 'undefined' && typeof y !== 'undefined' && x && y", vec!["x".to_string(), "y".to_string()], true); // Still has side effects because both x and y are accessed
898+
test_with_global_variables("typeof x !== 'undefined' && x", vec!["x".to_string(), "y".to_string()], false);
899+
}

0 commit comments

Comments
 (0)