blob: 7d28cea9dfd633242c9d5fe71c07016fc5e5420f [file] [log] [blame]
// 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.
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(types),
_positional = positional == null
? const <Object?>[]
: List<Object?>.unmodifiable(positional),
_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(Iterable<Type>? types) {
if (types == null) return const <Type>[];
List<Type> typeArguments = List<Type>.unmodifiable(types);
for (int i = 0; i < typeArguments.length; i++) {
if (typeArguments[i] == null) {
throw ArgumentError.value(types, "types",
"Type arguments must be non-null, was null at index $i.");
}
}
return typeArguments;
}
}