From 2ca3555c44ac7b98bb366e19ff891c4b4c4940e7 Mon Sep 17 00:00:00 2001 From: Lasse Reichstein Holst Nielsen Date: Tue, 5 May 2020 08:10:13 +0000 Subject: [PATCH] Allow `NoSuchMethodError.withInvocation` to accept any `Invocation`. Currently the VM only accepts an `_InvocationMirror` instance, not a user created `Invocation`. Fixes #33124 Bug: http://dartbug.com/33124 Change-Id: Ifdc95861cbe632bc317ca8d9fb92cf0d3ae600f0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/140100 Reviewed-by: Siva Annamalai Commit-Queue: Lasse R.H. Nielsen --- sdk/lib/_internal/vm/lib/errors_patch.dart | 337 ++++++++++-------- .../lib/_internal/vm/lib/errors_patch.dart | 336 +++++++++-------- ...uch_method_error_with_invocation_test.dart | 48 +++ ...uch_method_error_with_invocation_test.dart | 48 +++ 4 files changed, 488 insertions(+), 281 deletions(-) create mode 100644 tests/standalone/no_such_method_error_with_invocation_test.dart create mode 100644 tests/standalone_2/no_such_method_error_with_invocation_test.dart diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart index ee0d60823b7..1ffcfa13720 100644 --- a/sdk/lib/_internal/vm/lib/errors_patch.dart +++ b/sdk/lib/_internal/vm/lib/errors_patch.dart @@ -187,12 +187,12 @@ class NoSuchMethodError { List _existingArgumentNames; final Object _receiver; - final _InvocationMirror _invocation; + final Invocation _invocation; @patch NoSuchMethodError.withInvocation(Object receiver, Invocation invocation) : _receiver = receiver, - _invocation = invocation as _InvocationMirror; + _invocation = invocation; static void _throwNewInvocation(Object receiver, Invocation invocation) { throw new NoSuchMethodError.withInvocation(receiver, invocation); @@ -285,155 +285,210 @@ class NoSuchMethodError { @patch String toString() { // TODO(regis): Remove this null check once dart2js is updated. - if (_invocation == null) { + var invocation = _invocation; + if (invocation == null) { // Use deprecated version of toString. return _toStringDeprecated(); } - String memberName = - internal.Symbol.computeUnmangledName(_invocation.memberName); - var level = (_invocation._type >> _InvocationMirror._LEVEL_SHIFT) & - _InvocationMirror._LEVEL_MASK; - var kind = _invocation._type & _InvocationMirror._KIND_MASK; - if (kind == _InvocationMirror._LOCAL_VAR) { - return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; - } - - StringBuffer typeArgumentsBuf = null; - var typeArguments = _invocation.typeArguments; - if ((typeArguments != null) && (typeArguments.length > 0)) { - typeArgumentsBuf = new StringBuffer(); - typeArgumentsBuf.write("<"); - for (int i = 0; i < typeArguments.length; i++) { - if (i > 0) { - typeArgumentsBuf.write(", "); - } - typeArgumentsBuf.write(Error.safeToString(typeArguments[i])); + if (invocation is _InvocationMirror) { + String memberName = + internal.Symbol.computeUnmangledName(invocation.memberName); + var level = (invocation._type >> _InvocationMirror._LEVEL_SHIFT) & + _InvocationMirror._LEVEL_MASK; + var kind = invocation._type & _InvocationMirror._KIND_MASK; + if (kind == _InvocationMirror._LOCAL_VAR) { + return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; } - typeArgumentsBuf.write(">"); - } - StringBuffer argumentsBuf = new StringBuffer(); - var positionalArguments = _invocation.positionalArguments; - int argumentCount = 0; - if (positionalArguments != null) { - for (; argumentCount < positionalArguments.length; argumentCount++) { - if (argumentCount > 0) { - argumentsBuf.write(", "); - } - argumentsBuf - .write(Error.safeToString(positionalArguments[argumentCount])); - } - } - var namedArguments = _invocation.namedArguments; - if (namedArguments != null) { - namedArguments.forEach((Symbol key, var value) { - if (argumentCount > 0) { - argumentsBuf.write(", "); - } - argumentsBuf.write(internal.Symbol.computeUnmangledName(key)); - argumentsBuf.write(": "); - argumentsBuf.write(Error.safeToString(value)); - argumentCount++; - }); - } - String existingSig = - _existingMethodSignature(_receiver, memberName, _invocation._type); - String argsMsg = existingSig != null ? " with matching arguments" : ""; - String kindBuf; - if (kind >= 0 && kind < 5) { - kindBuf = (const [ - "method", - "getter", - "setter", - "getter or setter", - "variable" - ])[kind]; - } - - StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); - bool is_type_call = false; - switch (level) { - case _InvocationMirror._DYNAMIC: - { - if (_receiver == null) { - if (existingSig != null) { - msgBuf.writeln("The null object does not have a $kindBuf " - "'$memberName'$argsMsg."); - } else { - msgBuf.writeln("The $kindBuf '$memberName' was called on null."); - } - } else { - if (_receiver is _Closure) { - msgBuf.writeln("Closure call with mismatched arguments: " - "function '$memberName'"); - } else if (_receiver is _Type && memberName == "call") { - is_type_call = true; - String name = _receiver.toString(); - msgBuf.writeln("Attempted to use type '$name' as a function. " - "Since types do not define a method 'call', this is not " - "possible. Did you intend to call the $name constructor and " - "forget the 'new' operator?"); - } else { - msgBuf.writeln("Class '${_receiver.runtimeType}' has no instance " - "$kindBuf '$memberName'$argsMsg."); - } + StringBuffer typeArgumentsBuf = null; + var typeArguments = invocation.typeArguments; + if ((typeArguments != null) && (typeArguments.length > 0)) { + typeArgumentsBuf = new StringBuffer(); + typeArgumentsBuf.write("<"); + for (int i = 0; i < typeArguments.length; i++) { + if (i > 0) { + typeArgumentsBuf.write(", "); } - break; + typeArgumentsBuf.write(Error.safeToString(typeArguments[i])); } - case _InvocationMirror._SUPER: - { - msgBuf.writeln("Super class of class '${_receiver.runtimeType}' has " - "no instance $kindBuf '$memberName'$argsMsg."); - memberName = "super.$memberName"; - break; - } - case _InvocationMirror._STATIC: - { - msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg " - "declared in class '$_receiver'."); - break; - } - case _InvocationMirror._CONSTRUCTOR: - { - msgBuf.writeln("No constructor '$memberName'$argsMsg declared " - "in class '$_receiver'."); - memberName = "new $memberName"; - break; - } - case _InvocationMirror._TOP_LEVEL: - { - msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg " - "declared."); - break; - } - } - - if (level == _InvocationMirror._TOP_LEVEL) { - msgBuf.writeln("Receiver: top-level"); - } else { - msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}"); - } - - if (kind == _InvocationMirror._METHOD) { - String m = is_type_call ? "$_receiver" : "$memberName"; - msgBuf.write("Tried calling: $m"); - if (typeArgumentsBuf != null) { - msgBuf.write(typeArgumentsBuf); + typeArgumentsBuf.write(">"); } - msgBuf.write("($argumentsBuf)"); - } else if (argumentCount == 0) { - msgBuf.write("Tried calling: $memberName"); - } else if (kind == _InvocationMirror._SETTER) { - msgBuf.write("Tried calling: $memberName$argumentsBuf"); - } else { - msgBuf.write("Tried calling: $memberName = $argumentsBuf"); - } + StringBuffer argumentsBuf = new StringBuffer(); + var positionalArguments = invocation.positionalArguments; + int argumentCount = 0; + if (positionalArguments != null) { + for (; argumentCount < positionalArguments.length; argumentCount++) { + if (argumentCount > 0) { + argumentsBuf.write(", "); + } + argumentsBuf + .write(Error.safeToString(positionalArguments[argumentCount])); + } + } + var namedArguments = invocation.namedArguments; + if (namedArguments != null) { + namedArguments.forEach((Symbol key, var value) { + if (argumentCount > 0) { + argumentsBuf.write(", "); + } + argumentsBuf.write(internal.Symbol.computeUnmangledName(key)); + argumentsBuf.write(": "); + argumentsBuf.write(Error.safeToString(value)); + argumentCount++; + }); + } + String existingSig = + _existingMethodSignature(_receiver, memberName, invocation._type); + String argsMsg = existingSig != null ? " with matching arguments" : ""; - if (existingSig != null) { - msgBuf.write("\nFound: $memberName$existingSig"); - } + String kindBuf; + if (kind >= 0 && kind < 5) { + kindBuf = (const [ + "method", + "getter", + "setter", + "getter or setter", + "variable" + ])[kind]; + } - return msgBuf.toString(); + StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); + bool is_type_call = false; + switch (level) { + case _InvocationMirror._DYNAMIC: + { + if (_receiver == null) { + if (existingSig != null) { + msgBuf.writeln("The null object does not have a $kindBuf " + "'$memberName'$argsMsg."); + } else { + msgBuf + .writeln("The $kindBuf '$memberName' was called on null."); + } + } else { + if (_receiver is _Closure) { + msgBuf.writeln("Closure call with mismatched arguments: " + "function '$memberName'"); + } else if (_receiver is _Type && memberName == "call") { + is_type_call = true; + String name = _receiver.toString(); + msgBuf.writeln("Attempted to use type '$name' as a function. " + "Since types do not define a method 'call', this is not " + "possible. Did you intend to call the $name constructor and " + "forget the 'new' operator?"); + } else { + msgBuf + .writeln("Class '${_receiver.runtimeType}' has no instance " + "$kindBuf '$memberName'$argsMsg."); + } + } + break; + } + case _InvocationMirror._SUPER: + { + msgBuf + .writeln("Super class of class '${_receiver.runtimeType}' has " + "no instance $kindBuf '$memberName'$argsMsg."); + memberName = "super.$memberName"; + break; + } + case _InvocationMirror._STATIC: + { + msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg " + "declared in class '$_receiver'."); + break; + } + case _InvocationMirror._CONSTRUCTOR: + { + msgBuf.writeln("No constructor '$memberName'$argsMsg declared " + "in class '$_receiver'."); + memberName = "new $memberName"; + break; + } + case _InvocationMirror._TOP_LEVEL: + { + msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg " + "declared."); + break; + } + } + + if (level == _InvocationMirror._TOP_LEVEL) { + msgBuf.writeln("Receiver: top-level"); + } else { + msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}"); + } + + if (kind == _InvocationMirror._METHOD) { + String m = is_type_call ? "$_receiver" : "$memberName"; + msgBuf.write("Tried calling: $m"); + if (typeArgumentsBuf != null) { + msgBuf.write(typeArgumentsBuf); + } + msgBuf.write("($argumentsBuf)"); + } else if (argumentCount == 0) { + msgBuf.write("Tried calling: $memberName"); + } else if (kind == _InvocationMirror._SETTER) { + msgBuf.write("Tried calling: $memberName$argumentsBuf"); + } else { + msgBuf.write("Tried calling: $memberName = $argumentsBuf"); + } + + if (existingSig != null) { + msgBuf.write("\nFound: $memberName$existingSig"); + } + + return msgBuf.toString(); + } + return _toStringPlain(_receiver, invocation); + } + + /// Creates a string representation of an invocation. + /// + /// Used for situations where there is no extra information available + /// about the failed invocation than the [Invocation] object and receiver, + /// which includes errors created using [NoSuchMethodError.withInvocation]. + static String _toStringPlain(Object receiver, Invocation invocation) { + var name = _symbolToString(invocation.memberName); + var receiverType = "${receiver.runtimeType}"; + if (invocation.isAccessor) { + return "NoSuchMethodError: $receiverType has no $name ${invocation.isGetter ? "getter" : "setter"}"; + } + var buffer = StringBuffer("NoSuchMethodError")..write(": "); + buffer.write("$receiverType has no $name method accepting arguments "); + var separator = ""; + if (invocation.typeArguments.isNotEmpty) { + buffer.write("<"); + for (var type in invocation.typeArguments) { + buffer..write(separator)..write("_"); + separator = ", "; + } + buffer.write(">"); + separator = ""; + } + buffer.write("("); + for (var argument in invocation.positionalArguments) { + buffer..write(separator)..write("_"); + separator = ", "; + } + if (invocation.namedArguments.isNotEmpty) { + buffer..write(separator)..write("{"); + separator = ""; + for (var name in invocation.namedArguments.keys) { + buffer..write(separator)..write(_symbolToString(name))..write(": _"); + separator = ","; + } + buffer.write("}"); + } + buffer.write(")"); + return buffer.toString(); + } + + static String _symbolToString(Symbol symbol) { + if (symbol is internal.Symbol) { + return internal.Symbol.computeUnmangledName(symbol); + } + return "$symbol"; } // TODO(regis): Remove this function once dart2js is updated. diff --git a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart index 3a964d6a580..05983d7a616 100644 --- a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart +++ b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart @@ -184,13 +184,13 @@ class NoSuchMethodError { List? _existingArgumentNames; final Object _receiver; - final _InvocationMirror? _invocation; + final Invocation? _invocation; // Issue(dartbug.com/127160): Remove the cast to [_InvocationMirror]. @patch NoSuchMethodError.withInvocation(Object receiver, Invocation invocation) : _receiver = receiver, - _invocation = invocation as _InvocationMirror; + _invocation = invocation; static void _throwNewInvocation(Object receiver, Invocation invocation) { throw new NoSuchMethodError.withInvocation(receiver, invocation); @@ -288,152 +288,208 @@ class NoSuchMethodError { // Use deprecated version of toString. return _toStringDeprecated(); } - var internalName = localInvocation.memberName as internal.Symbol; - String memberName = internal.Symbol.computeUnmangledName(internalName); + if (localInvocation is _InvocationMirror) { + var internalName = localInvocation.memberName as internal.Symbol; + String memberName = internal.Symbol.computeUnmangledName(internalName); - var level = (localInvocation._type >> _InvocationMirror._LEVEL_SHIFT) & - _InvocationMirror._LEVEL_MASK; - var kind = localInvocation._type & _InvocationMirror._KIND_MASK; - if (kind == _InvocationMirror._LOCAL_VAR) { - return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; - } - - StringBuffer? typeArgumentsBuf = null; - final typeArguments = localInvocation.typeArguments; - if ((typeArguments != null) && (typeArguments.length > 0)) { - final argsBuf = new StringBuffer(); - argsBuf.write("<"); - for (int i = 0; i < typeArguments.length; i++) { - if (i > 0) { - argsBuf.write(", "); - } - argsBuf.write(Error.safeToString(typeArguments[i])); + var level = (localInvocation._type >> _InvocationMirror._LEVEL_SHIFT) & + _InvocationMirror._LEVEL_MASK; + var kind = localInvocation._type & _InvocationMirror._KIND_MASK; + if (kind == _InvocationMirror._LOCAL_VAR) { + return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; } - argsBuf.write(">"); - typeArgumentsBuf = argsBuf; - } - StringBuffer argumentsBuf = new StringBuffer(); - var positionalArguments = localInvocation.positionalArguments; - int argumentCount = 0; - if (positionalArguments != null) { - for (; argumentCount < positionalArguments.length; argumentCount++) { - if (argumentCount > 0) { - argumentsBuf.write(", "); - } - argumentsBuf - .write(Error.safeToString(positionalArguments[argumentCount])); - } - } - var namedArguments = localInvocation.namedArguments; - if (namedArguments != null) { - namedArguments.forEach((Symbol key, var value) { - if (argumentCount > 0) { - argumentsBuf.write(", "); - } - var internalName = key as internal.Symbol; - argumentsBuf.write(internal.Symbol.computeUnmangledName(internalName)); - argumentsBuf.write(": "); - argumentsBuf.write(Error.safeToString(value)); - argumentCount++; - }); - } - String? existingSig = - _existingMethodSignature(_receiver, memberName, localInvocation._type); - String argsMsg = existingSig != null ? " with matching arguments" : ""; - assert(kind >= 0 && kind < 5); - final String kindBuf = (const [ - "method", - "getter", - "setter", - "getter or setter", - "variable" - ])[kind]; - - StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); - bool isTypeCall = false; - switch (level) { - case _InvocationMirror._DYNAMIC: - { - if (_receiver == null) { - if (existingSig != null) { - msgBuf.writeln("The null object does not have a $kindBuf " - "'$memberName'$argsMsg."); - } else { - msgBuf.writeln("The $kindBuf '$memberName' was called on null."); - } - } else { - if (_receiver is _Closure) { - msgBuf.writeln("Closure call with mismatched arguments: " - "function '$memberName'"); - } else if (_receiver is _Type && memberName == "call") { - isTypeCall = true; - String name = _receiver.toString(); - msgBuf.writeln("Attempted to use type '$name' as a function. " - "Since types do not define a method 'call', this is not " - "possible. Did you intend to call the $name constructor and " - "forget the 'new' operator?"); - } else { - msgBuf.writeln("Class '${_receiver.runtimeType}' has no instance " - "$kindBuf '$memberName'$argsMsg."); - } + StringBuffer? typeArgumentsBuf = null; + final typeArguments = localInvocation.typeArguments; + if ((typeArguments != null) && (typeArguments.length > 0)) { + final argsBuf = new StringBuffer(); + argsBuf.write("<"); + for (int i = 0; i < typeArguments.length; i++) { + if (i > 0) { + argsBuf.write(", "); } - break; + argsBuf.write(Error.safeToString(typeArguments[i])); } - case _InvocationMirror._SUPER: - { - msgBuf.writeln("Super class of class '${_receiver.runtimeType}' has " - "no instance $kindBuf '$memberName'$argsMsg."); - memberName = "super.$memberName"; - break; - } - case _InvocationMirror._STATIC: - { - msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg " - "declared in class '$_receiver'."); - break; - } - case _InvocationMirror._CONSTRUCTOR: - { - msgBuf.writeln("No constructor '$memberName'$argsMsg declared " - "in class '$_receiver'."); - memberName = "new $memberName"; - break; - } - case _InvocationMirror._TOP_LEVEL: - { - msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg " - "declared."); - break; - } - } - - if (level == _InvocationMirror._TOP_LEVEL) { - msgBuf.writeln("Receiver: top-level"); - } else { - msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}"); - } - - if (kind == _InvocationMirror._METHOD) { - String m = isTypeCall ? "$_receiver" : "$memberName"; - msgBuf.write("Tried calling: $m"); - if (typeArgumentsBuf != null) { - msgBuf.write(typeArgumentsBuf); + argsBuf.write(">"); + typeArgumentsBuf = argsBuf; } - msgBuf.write("($argumentsBuf)"); - } else if (argumentCount == 0) { - msgBuf.write("Tried calling: $memberName"); - } else if (kind == _InvocationMirror._SETTER) { - msgBuf.write("Tried calling: $memberName$argumentsBuf"); - } else { - msgBuf.write("Tried calling: $memberName = $argumentsBuf"); - } + StringBuffer argumentsBuf = new StringBuffer(); + var positionalArguments = localInvocation.positionalArguments; + int argumentCount = 0; + if (positionalArguments != null) { + for (; argumentCount < positionalArguments.length; argumentCount++) { + if (argumentCount > 0) { + argumentsBuf.write(", "); + } + argumentsBuf + .write(Error.safeToString(positionalArguments[argumentCount])); + } + } + var namedArguments = localInvocation.namedArguments; + if (namedArguments != null) { + namedArguments.forEach((Symbol key, var value) { + if (argumentCount > 0) { + argumentsBuf.write(", "); + } + var internalName = key as internal.Symbol; + argumentsBuf + .write(internal.Symbol.computeUnmangledName(internalName)); + argumentsBuf.write(": "); + argumentsBuf.write(Error.safeToString(value)); + argumentCount++; + }); + } + String? existingSig = _existingMethodSignature( + _receiver, memberName, localInvocation._type); + String argsMsg = existingSig != null ? " with matching arguments" : ""; - if (existingSig != null) { - msgBuf.write("\nFound: $memberName$existingSig"); - } + assert(kind >= 0 && kind < 5); + final String kindBuf = (const [ + "method", + "getter", + "setter", + "getter or setter", + "variable" + ])[kind]; - return msgBuf.toString(); + StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); + bool isTypeCall = false; + switch (level) { + case _InvocationMirror._DYNAMIC: + { + if (_receiver == null) { + if (existingSig != null) { + msgBuf.writeln("The null object does not have a $kindBuf " + "'$memberName'$argsMsg."); + } else { + msgBuf + .writeln("The $kindBuf '$memberName' was called on null."); + } + } else { + if (_receiver is _Closure) { + msgBuf.writeln("Closure call with mismatched arguments: " + "function '$memberName'"); + } else if (_receiver is _Type && memberName == "call") { + isTypeCall = true; + String name = _receiver.toString(); + msgBuf.writeln("Attempted to use type '$name' as a function. " + "Since types do not define a method 'call', this is not " + "possible. Did you intend to call the $name constructor and " + "forget the 'new' operator?"); + } else { + msgBuf + .writeln("Class '${_receiver.runtimeType}' has no instance " + "$kindBuf '$memberName'$argsMsg."); + } + } + break; + } + case _InvocationMirror._SUPER: + { + msgBuf + .writeln("Super class of class '${_receiver.runtimeType}' has " + "no instance $kindBuf '$memberName'$argsMsg."); + memberName = "super.$memberName"; + break; + } + case _InvocationMirror._STATIC: + { + msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg " + "declared in class '$_receiver'."); + break; + } + case _InvocationMirror._CONSTRUCTOR: + { + msgBuf.writeln("No constructor '$memberName'$argsMsg declared " + "in class '$_receiver'."); + memberName = "new $memberName"; + break; + } + case _InvocationMirror._TOP_LEVEL: + { + msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg " + "declared."); + break; + } + } + + if (level == _InvocationMirror._TOP_LEVEL) { + msgBuf.writeln("Receiver: top-level"); + } else { + msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}"); + } + + if (kind == _InvocationMirror._METHOD) { + String m = isTypeCall ? "$_receiver" : "$memberName"; + msgBuf.write("Tried calling: $m"); + if (typeArgumentsBuf != null) { + msgBuf.write(typeArgumentsBuf); + } + msgBuf.write("($argumentsBuf)"); + } else if (argumentCount == 0) { + msgBuf.write("Tried calling: $memberName"); + } else if (kind == _InvocationMirror._SETTER) { + msgBuf.write("Tried calling: $memberName$argumentsBuf"); + } else { + msgBuf.write("Tried calling: $memberName = $argumentsBuf"); + } + + if (existingSig != null) { + msgBuf.write("\nFound: $memberName$existingSig"); + } + + return msgBuf.toString(); + } + return _toStringPlain(_receiver, localInvocation); + } + + /// Creates a string representation of an invocation. + /// + /// Used for situations where there is no extra information available + /// about the failed invocation than the [Invocation] object and receiver, + /// which includes errors created using [NoSuchMethodError.withInvocation]. + static String _toStringPlain(Object receiver, Invocation invocation) { + var name = _symbolToString(invocation.memberName); + var receiverType = "${receiver.runtimeType}"; + if (invocation.isAccessor) { + return "NoSuchMethodError: $receiverType has no $name " + "${invocation.isGetter ? "getter" : "setter"}"; + } + var buffer = StringBuffer("NoSuchMethodError")..write(": "); + buffer.write("$receiverType has no $name method accepting arguments "); + var separator = ""; + if (invocation.typeArguments.isNotEmpty) { + buffer.write("<"); + for (var type in invocation.typeArguments) { + buffer..write(separator)..write("_"); + separator = ", "; + } + buffer.write(">"); + separator = ""; + } + buffer.write("("); + for (var argument in invocation.positionalArguments) { + buffer..write(separator)..write("_"); + separator = ", "; + } + if (invocation.namedArguments.isNotEmpty) { + buffer..write(separator)..write("{"); + separator = ""; + for (var name in invocation.namedArguments.keys) { + buffer..write(separator)..write(_symbolToString(name))..write(": _"); + separator = ","; + } + buffer.write("}"); + } + buffer.write(")"); + return buffer.toString(); + } + + static String _symbolToString(Symbol symbol) { + if (symbol is internal.Symbol) { + return internal.Symbol.computeUnmangledName(symbol); + } + return "$symbol"; } // TODO(regis): Remove this function once dart2js is updated. diff --git a/tests/standalone/no_such_method_error_with_invocation_test.dart b/tests/standalone/no_such_method_error_with_invocation_test.dart new file mode 100644 index 00000000000..9d8dc17ccce --- /dev/null +++ b/tests/standalone/no_such_method_error_with_invocation_test.dart @@ -0,0 +1,48 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import "package:expect/expect.dart"; + +main() { + // Using withInvocation constructor. + var receiver = Object(); + { + var invocationGet = Invocation.getter(#foo); + var errorGet = NoSuchMethodError.withInvocation(receiver, invocationGet); + var errorString = errorGet.toString(); + Expect.isTrue(errorString.contains("foo"), "01: $errorString"); + Expect.isTrue(errorString.contains("getter"), "02: $errorString"); + } + { + var invocationSet = Invocation.setter(#foo, 42); + var error = NoSuchMethodError.withInvocation(receiver, invocationSet); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "03: $errorString"); + Expect.isTrue(errorString.contains("setter"), "04: $errorString"); + } + { + var invocationCall = Invocation.method(#foo, [42]); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "05: $errorString"); + Expect.isTrue(errorString.contains("method"), "06: $errorString"); + Expect.isTrue(errorString.contains("(_)"), "07: $errorString"); + } + { + var invocationCall = Invocation.method(#foo, [42], {#bar: 37}); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "08: $errorString"); + Expect.isTrue(errorString.contains("method"), "09: $errorString"); + Expect.isTrue(errorString.contains("(_, {bar: _})"), "10: $errorString"); + } + { + var invocationCall = Invocation.genericMethod(#foo, [int], [42]); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "11: $errorString"); + Expect.isTrue(errorString.contains("method"), "12: $errorString"); + Expect.isTrue(errorString.contains("<_>(_)"), "13: $errorString"); + } +} diff --git a/tests/standalone_2/no_such_method_error_with_invocation_test.dart b/tests/standalone_2/no_such_method_error_with_invocation_test.dart new file mode 100644 index 00000000000..9d8dc17ccce --- /dev/null +++ b/tests/standalone_2/no_such_method_error_with_invocation_test.dart @@ -0,0 +1,48 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import "package:expect/expect.dart"; + +main() { + // Using withInvocation constructor. + var receiver = Object(); + { + var invocationGet = Invocation.getter(#foo); + var errorGet = NoSuchMethodError.withInvocation(receiver, invocationGet); + var errorString = errorGet.toString(); + Expect.isTrue(errorString.contains("foo"), "01: $errorString"); + Expect.isTrue(errorString.contains("getter"), "02: $errorString"); + } + { + var invocationSet = Invocation.setter(#foo, 42); + var error = NoSuchMethodError.withInvocation(receiver, invocationSet); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "03: $errorString"); + Expect.isTrue(errorString.contains("setter"), "04: $errorString"); + } + { + var invocationCall = Invocation.method(#foo, [42]); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "05: $errorString"); + Expect.isTrue(errorString.contains("method"), "06: $errorString"); + Expect.isTrue(errorString.contains("(_)"), "07: $errorString"); + } + { + var invocationCall = Invocation.method(#foo, [42], {#bar: 37}); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "08: $errorString"); + Expect.isTrue(errorString.contains("method"), "09: $errorString"); + Expect.isTrue(errorString.contains("(_, {bar: _})"), "10: $errorString"); + } + { + var invocationCall = Invocation.genericMethod(#foo, [int], [42]); + var error = NoSuchMethodError.withInvocation(receiver, invocationCall); + var errorString = error.toString(); + Expect.isTrue(errorString.contains("foo"), "11: $errorString"); + Expect.isTrue(errorString.contains("method"), "12: $errorString"); + Expect.isTrue(errorString.contains("<_>(_)"), "13: $errorString"); + } +}