@@ -66,8 +66,6 @@ public class AstAnalyzer {
6666 private static final ImmutableSet <String > BUILTIN_FUNCTIONS_WITHOUT_SIDEEFFECTS =
6767 ImmutableSet .of (
6868 "Object" , "Array" , "String" , "Number" , "BigInt" , "Boolean" , "RegExp" , "Error" );
69- private static final ImmutableSet <String > OBJECT_METHODS_WITHOUT_SIDEEFFECTS =
70- ImmutableSet .of ("toString" , "valueOf" );
7169 private static final ImmutableSet <String > REGEXP_METHODS = ImmutableSet .of ("test" , "exec" );
7270 private static final ImmutableSet <String > STRING_REGEXP_METHODS =
7371 ImmutableSet .of ("match" , "replace" , "search" , "split" );
@@ -163,9 +161,12 @@ boolean functionCallHasSideEffects(Node callNode) {
163161 return false ;
164162 }
165163 } else if (callee .isGetProp () || callee .isOptChainGetProp ()) {
166- if (callNode .hasOneChild ()
167- && assumeKnownBuiltinsArePure
168- && OBJECT_METHODS_WITHOUT_SIDEEFFECTS .contains (callee .getString ())) {
164+ String method = callee .getString ();
165+ if (assumeKnownBuiltinsArePure
166+ && ("valueOf" .equals (method )
167+ ? callNode .hasOneChild ()
168+ : "toString" .equals (method )
169+ && (callNode .hasOneChild () || callNode .hasTwoChildren ()))) {
169170 return false ;
170171 }
171172
@@ -181,7 +182,7 @@ boolean functionCallHasSideEffects(Node callNode) {
181182 && callee .getFirstChild ().isName ()
182183 && callee .isQualifiedName ()
183184 && callee .getFirstChild ().getString ().equals ("Math" )) {
184- switch (callee . getString () ) {
185+ switch (method ) {
185186 case "abs" ,
186187 "acos" ,
187188 "acosh" ,
@@ -226,13 +227,12 @@ boolean functionCallHasSideEffects(Node callNode) {
226227 }
227228
228229 if (!hasRegexpGlobalReferences && assumeKnownBuiltinsArePure ) {
229- if (callee .getFirstChild ().isRegExp () && REGEXP_METHODS .contains (callee . getString () )) {
230+ if (callee .getFirstChild ().isRegExp () && REGEXP_METHODS .contains (method )) {
230231 return false ;
231232 } else if (isTypedAsString (callee .getFirstChild ())) {
232233 // Unlike regexs, string methods don't need to be hosted on a string literal
233234 // to avoid leaking mutating global state changes, it is just necessary that
234235 // the regex object can't be referenced.
235- String method = callee .getString ();
236236 Node param = callee .getNext ();
237237 if (param != null ) {
238238 if (param .isStringLit ()) {
0 commit comments