| // Copyright (c) 2012, 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. |
| |
| // @dart = 2.6 |
| |
| part of dart.core; |
| |
| /** |
| * Representation of the invocation of a member on an object. |
| * |
| * This is the type of objects passed to [Object.noSuchMethod] when |
| * an object doesn't support the member invocation that was attempted |
| * on it. |
| */ |
| abstract class Invocation { |
| Invocation(); |
| |
| /** |
| * Creates an invocation corresponding to a method invocation. |
| * |
| * The method invocation has no type arguments. |
| * If the named arguments are omitted, they default to no named arguments. |
| */ |
| factory Invocation.method( |
| Symbol memberName, Iterable<Object> positionalArguments, |
| [Map<Symbol, Object> namedArguments]) => |
| _Invocation.method(memberName, null, positionalArguments, namedArguments); |
| |
| /** |
| * Creates an invocation corresponding to a generic method invocation. |
| * |
| * If [typeArguments] is `null` or empty, the constructor is equivalent to |
| * calling [Invocation.method] with the remaining arguments. |
| * All the individual type arguments must be non-null. |
| * |
| * If the named arguments are omitted, they default to no named arguments. |
| */ |
| factory Invocation.genericMethod(Symbol memberName, |
| Iterable<Type> typeArguments, Iterable<Object> positionalArguments, |
| [Map<Symbol, Object> namedArguments]) => |
| _Invocation.method( |
| memberName, typeArguments, positionalArguments, namedArguments); |
| |
| /** |
| * Creates an invocation corresponding to a getter invocation. |
| */ |
| factory Invocation.getter(Symbol name) = _Invocation.getter; |
| |
| /** |
| * Creates an invocation corresponding to a setter invocation. |
| * |
| * This constructor accepts any [Symbol] as [memberName], but remember that |
| * *actual setter names* end in `=`, so the invocation corresponding |
| * to `object.member = value` is |
| * ```dart |
| * Invocation.setter(const Symbol("member="), value) |
| * ``` |
| */ |
| factory Invocation.setter(Symbol memberName, Object argument) = |
| _Invocation.setter; |
| |
| /** The name of the invoked member. */ |
| Symbol get memberName; |
| |
| /** |
| * An unmodifiable view of the type arguments of the call. |
| * |
| * If the member is a getter, setter or operator, |
| * the type argument list is always empty. |
| */ |
| List<Type> get typeArguments => const <Type>[]; |
| |
| /** |
| * An unmodifiable view of the positional arguments of the call. |
| * |
| * If the member is a getter, the positional arguments list is |
| * always empty. |
| */ |
| List<dynamic> get positionalArguments; |
| |
| /** |
| * An unmodifiable view of the named arguments of the call. |
| * |
| * If the member is a getter, setter or operator, |
| * the named arguments map is always empty. |
| */ |
| Map<Symbol, dynamic> get namedArguments; |
| |
| /** Whether the invocation was a method call. */ |
| bool get isMethod; |
| |
| /** |
| * Whether the invocation was a getter call. |
| * If so, all three types of arguments lists are empty. |
| */ |
| bool get isGetter; |
| |
| /** |
| * Whether the invocation was a setter call. |
| * |
| * If so, [positionalArguments] has exactly one positional |
| * argument, [namedArguments] is empty, and typeArguments is |
| * empty. |
| */ |
| bool get isSetter; |
| |
| /** Whether the invocation was a getter or a setter call. */ |
| bool get isAccessor => isGetter || isSetter; |
| } |
| |
| /** Implementation of [Invocation] used by its factory constructors. */ |
| class _Invocation implements Invocation { |
| final Symbol memberName; |
| final List<Type> typeArguments; |
| // Positional arguments is `null` for getters only. |
| final List<Object> _positional; |
| // Named arguments is `null` for accessors only. |
| final Map<Symbol, Object> _named; |
| |
| _Invocation.method(this.memberName, Iterable<Type> types, |
| Iterable<Object> positional, Map<Symbol, Object> named) |
| : typeArguments = _ensureNonNullTypes(_makeUnmodifiable<Type>(types)), |
| _positional = _makeUnmodifiable<Object>(positional) ?? const <Object>[], |
| _named = (named == null || named.isEmpty) |
| ? const <Symbol, Object>{} |
| : Map<Symbol, Object>.unmodifiable(named); |
| |
| _Invocation.getter(this.memberName) |
| : typeArguments = const <Type>[], |
| _positional = null, |
| _named = null; |
| |
| _Invocation.setter(this.memberName, Object argument) |
| : typeArguments = const <Type>[], |
| _positional = List<Object>.unmodifiable([argument]), |
| _named = null; |
| |
| List<dynamic> get positionalArguments => _positional ?? const <Object>[]; |
| |
| Map<Symbol, dynamic> get namedArguments => _named ?? const <Symbol, Object>{}; |
| |
| bool get isMethod => _named != null; |
| bool get isGetter => _positional == null; |
| bool get isSetter => _positional != null && _named == null; |
| bool get isAccessor => _named == null; |
| |
| /// Checks that the elements of [types] are not null. |
| static List<Type> _ensureNonNullTypes(List<Type> types) { |
| if (types == null) return const <Type>[]; |
| for (int i = 0; i < types.length; i++) { |
| if (types[i] == null) { |
| throw ArgumentError( |
| "Type arguments must be non-null, was null at index $i."); |
| } |
| } |
| return types; |
| } |
| |
| static List<T> _makeUnmodifiable<T>(Iterable<T> elements) { |
| if (elements == null) return null; |
| return List<T>.unmodifiable(elements); |
| } |
| } |