blob: fff2325968cb4ad7ed79b41768d9f5c55947c5fc [file] [log] [blame]
// Copyright (c) 2021, 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:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/resolver/instance_creation_resolver_helper.dart';
import 'package:analyzer/src/generated/resolver.dart';
/// A resolver for [InstanceCreationExpression] nodes.
///
/// This resolver is responsible for rewriting a given
/// [InstanceCreationExpression] as a [MethodInvocation] if the parsed
/// [ConstructorName]'s `type` resolves to a [FunctionReference] or
/// [ConstructorReference], instead of a [NamedType].
class InstanceCreationExpressionResolver with InstanceCreationResolverMixin {
/// The resolver driving this participant.
final ResolverVisitor _resolver;
InstanceCreationExpressionResolver(this._resolver);
@override
ResolverVisitor get resolver => _resolver;
void resolve(InstanceCreationExpressionImpl node) {
// The parser can parse certain code as [InstanceCreationExpression] when it
// might be an invocation of a method on a [FunctionReference] or
// [ConstructorReference]. In such a case, it is this resolver's
// responsibility to rewrite. For example, given:
//
// a.m<int>.apply();
//
// the parser will give an InstanceCreationExpression (`a.m<int>.apply()`)
// with a name of `a.m<int>.apply` (ConstructorName) with a type of
// `a.m<int>` (TypeName with a name of `a.m` (PrefixedIdentifier) and
// typeArguments of `<int>`) and a name of `apply` (SimpleIdentifier). If
// `a.m<int>` is actually a function reference, then the
// InstanceCreationExpression needs to be rewritten as a MethodInvocation
// with a target of `a.m<int>` (a FunctionReference) and a name of `apply`.
if (node.keyword == null) {
var typeNameTypeArguments = node.constructorName.type.typeArguments;
if (typeNameTypeArguments != null) {
// This could be a method call on a function reference or a constructor
// reference.
_resolveWithTypeNameWithTypeArguments(node, typeNameTypeArguments);
return;
}
}
_resolveInstanceCreationExpression(node);
}
void _resolveInstanceCreationExpression(InstanceCreationExpressionImpl node) {
var whyNotPromotedList = <WhyNotPromotedGetter>[];
var constructorName = node.constructorName;
constructorName.accept(_resolver);
// Re-assign constructorName in case the node got replaced.
constructorName = node.constructorName;
var elementToInfer = _resolver.inferenceHelper.constructorElementToInfer(
constructorName: constructorName,
definingLibrary: _resolver.definingLibrary,
);
var typeName = constructorName.type;
var constructorElement = constructorName.staticElement;
var inferenceResult = inferArgumentTypes(
inferenceNode: node,
constructorElement: constructorElement,
elementToInfer: elementToInfer,
typeArguments: typeName.typeArguments,
arguments: node.argumentList,
errorNode: constructorName,
isConst: node.isConst);
if (inferenceResult != null) {
typeName.type = inferenceResult.constructedType;
constructorElement =
constructorName.staticElement = inferenceResult.constructorElement;
}
_resolver.analyzeArgumentList(
node.argumentList, constructorElement?.parameters,
whyNotPromotedList: whyNotPromotedList);
_resolver.elementResolver.visitInstanceCreationExpression(node);
_resolver.typeAnalyzer.visitInstanceCreationExpression(node);
_resolver.checkForArgumentTypesNotAssignableInList(
node.argumentList, whyNotPromotedList);
}
/// Resolve [node] which has a [NamedType] with type arguments (given as
/// [typeNameTypeArguments]).
///
/// The instance creation expression may actually be a method call on a
/// type-instantiated function reference or constructor reference.
void _resolveWithTypeNameWithTypeArguments(
InstanceCreationExpressionImpl node,
TypeArgumentListImpl typeNameTypeArguments,
) {
var typeNameName = node.constructorName.type.name;
if (typeNameName is SimpleIdentifierImpl) {
// TODO(srawlins): Lookup the name and potentially rewrite `node` as a
// [MethodInvocation].
_resolveInstanceCreationExpression(node);
return;
} else if (typeNameName is PrefixedIdentifierImpl) {
// TODO(srawlins): Lookup the name and potentially rewrite `node` as a
// [MethodInvocation].
_resolveInstanceCreationExpression(node);
} else {
assert(
false, 'Unexpected typeNameName type: ${typeNameName.runtimeType}');
_resolveInstanceCreationExpression(node);
}
}
}