|  | // 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:analyzer/dart/element/element2.dart'; | 
|  | import 'package:analyzer/dart/element/type.dart'; | 
|  | import 'package:analyzer/error/listener.dart'; | 
|  | import 'package:analyzer/src/dart/ast/ast.dart'; | 
|  | import 'package:analyzer/src/dart/ast/extensions.dart'; | 
|  | import 'package:analyzer/src/dart/element/type.dart'; | 
|  | import 'package:analyzer/src/dart/element/type_system.dart'; | 
|  | import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart'; | 
|  | import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart'; | 
|  | import 'package:analyzer/src/dart/resolver/type_property_resolver.dart'; | 
|  | import 'package:analyzer/src/error/codes.dart'; | 
|  | import 'package:analyzer/src/error/nullable_dereference_verifier.dart'; | 
|  | import 'package:analyzer/src/generated/resolver.dart'; | 
|  |  | 
|  | /// Helper for resolving [FunctionExpressionInvocation]s. | 
|  | class FunctionExpressionInvocationResolver { | 
|  | final ResolverVisitor _resolver; | 
|  | final TypePropertyResolver _typePropertyResolver; | 
|  |  | 
|  | FunctionExpressionInvocationResolver({ | 
|  | required ResolverVisitor resolver, | 
|  | })  : _resolver = resolver, | 
|  | _typePropertyResolver = resolver.typePropertyResolver; | 
|  |  | 
|  | ErrorReporter get _errorReporter => _resolver.errorReporter; | 
|  |  | 
|  | ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver; | 
|  |  | 
|  | NullableDereferenceVerifier get _nullableDereferenceVerifier => | 
|  | _resolver.nullableDereferenceVerifier; | 
|  |  | 
|  | TypeSystemImpl get _typeSystem => _resolver.typeSystem; | 
|  |  | 
|  | void resolve(FunctionExpressionInvocationImpl node, | 
|  | List<WhyNotPromotedGetter> whyNotPromotedArguments, | 
|  | {required TypeImpl contextType}) { | 
|  | var function = node.function; | 
|  |  | 
|  | if (function is ExtensionOverrideImpl) { | 
|  | _resolveReceiverExtensionOverride(node, function, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | var receiverType = function.typeOrThrow; | 
|  | if (_checkForUseOfVoidResult(function, receiverType)) { | 
|  | _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | receiverType = _typeSystem.resolveToBound(receiverType); | 
|  | if (receiverType is FunctionTypeImpl) { | 
|  | _nullableDereferenceVerifier.expression( | 
|  | CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, | 
|  | function, | 
|  | ); | 
|  | _resolve(node, receiverType, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (identical(receiverType, NeverTypeImpl.instance)) { | 
|  | _errorReporter.atNode( | 
|  | function, | 
|  | WarningCode.RECEIVER_OF_TYPE_NEVER, | 
|  | ); | 
|  | _unresolved(node, NeverTypeImpl.instance, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | var result = _typePropertyResolver.resolve( | 
|  | receiver: function, | 
|  | receiverType: receiverType, | 
|  | name: MethodElement2.CALL_METHOD_NAME, | 
|  | propertyErrorEntity: function, | 
|  | nameErrorEntity: function, | 
|  | ); | 
|  | var callElement = result.getter2; | 
|  |  | 
|  | if (callElement == null) { | 
|  | if (result.needsGetterError) { | 
|  | _errorReporter.atNode( | 
|  | function, | 
|  | CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, | 
|  | ); | 
|  | } | 
|  | var type = result.isGetterInvalid | 
|  | ? InvalidTypeImpl.instance | 
|  | : DynamicTypeImpl.instance; | 
|  | _unresolved(node, type, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (callElement.kind != ElementKind.METHOD) { | 
|  | _errorReporter.atNode( | 
|  | function, | 
|  | CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, | 
|  | ); | 
|  | _unresolved(node, InvalidTypeImpl.instance, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | node.element = callElement; | 
|  | var rawType = callElement.type; | 
|  | _resolve(node, rawType, whyNotPromotedArguments, contextType: contextType); | 
|  | } | 
|  |  | 
|  | /// Check for situations where the result of a method or function is used, | 
|  | /// when it returns 'void'. Or, in rare cases, when other types of expressions | 
|  | /// are void, such as identifiers. | 
|  | /// | 
|  | /// See [CompileTimeErrorCode.USE_OF_VOID_RESULT]. | 
|  | /// | 
|  | // TODO(scheglov): this is duplicate | 
|  | bool _checkForUseOfVoidResult(Expression expression, DartType type) { | 
|  | if (!identical(type, VoidTypeImpl.instance)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (expression is MethodInvocation) { | 
|  | SimpleIdentifier methodName = expression.methodName; | 
|  | _errorReporter.atNode( | 
|  | methodName, | 
|  | CompileTimeErrorCode.USE_OF_VOID_RESULT, | 
|  | ); | 
|  | } else { | 
|  | _errorReporter.atNode( | 
|  | expression, | 
|  | CompileTimeErrorCode.USE_OF_VOID_RESULT, | 
|  | ); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void _resolve(FunctionExpressionInvocationImpl node, FunctionType rawType, | 
|  | List<WhyNotPromotedGetter> whyNotPromotedArguments, | 
|  | {required TypeImpl contextType}) { | 
|  | var returnType = FunctionExpressionInvocationInferrer( | 
|  | resolver: _resolver, | 
|  | node: node, | 
|  | argumentList: node.argumentList, | 
|  | whyNotPromotedArguments: whyNotPromotedArguments, | 
|  | contextType: contextType, | 
|  | ).resolveInvocation( | 
|  | // TODO(paulberry): eliminate this cast by changing the type of | 
|  | // `rawType`. | 
|  | rawType: rawType as FunctionTypeImpl); | 
|  |  | 
|  | node.recordStaticType(returnType, resolver: _resolver); | 
|  | } | 
|  |  | 
|  | void _resolveReceiverExtensionOverride( | 
|  | FunctionExpressionInvocationImpl node, | 
|  | ExtensionOverrideImpl function, | 
|  | List<WhyNotPromotedGetter> whyNotPromotedArguments, | 
|  | {required TypeImpl contextType}) { | 
|  | var result = _extensionResolver.getOverrideMember( | 
|  | function, | 
|  | MethodElement2.CALL_METHOD_NAME, | 
|  | ); | 
|  | var callElement = result.getter2; | 
|  | node.element = callElement; | 
|  |  | 
|  | if (callElement == null) { | 
|  | _errorReporter.atNode( | 
|  | function, | 
|  | CompileTimeErrorCode.INVOCATION_OF_EXTENSION_WITHOUT_CALL, | 
|  | arguments: [function.name.lexeme], | 
|  | ); | 
|  | return _unresolved( | 
|  | node, DynamicTypeImpl.instance, whyNotPromotedArguments, | 
|  | contextType: contextType); | 
|  | } | 
|  |  | 
|  | if (callElement.isStatic) { | 
|  | _errorReporter.atNode( | 
|  | node.argumentList, | 
|  | CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER, | 
|  | ); | 
|  | } | 
|  |  | 
|  | var rawType = callElement.type; | 
|  | _resolve(node, rawType, whyNotPromotedArguments, contextType: contextType); | 
|  | } | 
|  |  | 
|  | void _unresolved(FunctionExpressionInvocationImpl node, TypeImpl type, | 
|  | List<WhyNotPromotedGetter> whyNotPromotedArguments, | 
|  | {required TypeImpl contextType}) { | 
|  | _setExplicitTypeArgumentTypes(node); | 
|  | FunctionExpressionInvocationInferrer( | 
|  | resolver: _resolver, | 
|  | node: node, | 
|  | argumentList: node.argumentList, | 
|  | contextType: contextType, | 
|  | whyNotPromotedArguments: whyNotPromotedArguments) | 
|  | .resolveInvocation(rawType: null); | 
|  | node.staticInvokeType = type; | 
|  | node.recordStaticType(type, resolver: _resolver); | 
|  | } | 
|  |  | 
|  | /// Inference cannot be done, we still want to fill type argument types. | 
|  | static void _setExplicitTypeArgumentTypes( | 
|  | FunctionExpressionInvocationImpl node, | 
|  | ) { | 
|  | var typeArguments = node.typeArguments; | 
|  | if (typeArguments != null) { | 
|  | node.typeArgumentTypes = typeArguments.arguments | 
|  | .map((typeArgument) => typeArgument.typeOrThrow) | 
|  | .toList(); | 
|  | } else { | 
|  | node.typeArgumentTypes = const <TypeImpl>[]; | 
|  | } | 
|  | } | 
|  | } |