|  | // Copyright (c) 2023, 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. | 
|  |  | 
|  | /// Handling of static weak references. | 
|  |  | 
|  | import 'package:kernel/ast.dart'; | 
|  | import 'package:kernel/core_types.dart' show CoreTypes; | 
|  |  | 
|  | import '../codes/cfe_codes.dart' | 
|  | show | 
|  | messageWeakReferenceNotStatic, | 
|  | messageWeakReferenceNotOneArgument, | 
|  | messageWeakReferenceReturnTypeNotNullable, | 
|  | messageWeakReferenceMismatchReturnAndArgumentTypes, | 
|  | messageWeakReferenceTargetNotStaticTearoff, | 
|  | messageWeakReferenceTargetHasParameters; | 
|  | import 'constant_evaluator.dart' show ErrorReporter; | 
|  |  | 
|  | /// Recognizes and validates static weak references. | 
|  | /// Intrinsic method for static weak references can be | 
|  | /// declared using `@pragma('weak-tearoff-reference')`. | 
|  | class StaticWeakReferences { | 
|  | static const String weakTearoffReferencePragma = 'weak-tearoff-reference'; | 
|  |  | 
|  | // Coverage-ignore(suite): Not run. | 
|  | static bool isWeakReference(StaticInvocation node) => | 
|  | node.target.hasWeakTearoffReferencePragma; | 
|  |  | 
|  | static bool isAnnotatedWithWeakReferencePragma( | 
|  | Annotatable node, CoreTypes coreTypes) { | 
|  | for (Expression annotation in node.annotations) { | 
|  | if (annotation is ConstantExpression) { | 
|  | Constant constant = annotation.constant; | 
|  | if (constant is InstanceConstant) { | 
|  | if (constant.classNode == coreTypes.pragmaClass) { | 
|  | Constant? name = | 
|  | constant.fieldValues[coreTypes.pragmaName.fieldReference]; | 
|  | if (name is StringConstant) { | 
|  | if (name.value == weakTearoffReferencePragma) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Coverage-ignore(suite): Not run. | 
|  | static void validateWeakReferenceUse( | 
|  | StaticInvocation node, ErrorReporter errorReporter) { | 
|  | final Arguments arguments = node.arguments; | 
|  | if (arguments.positional.length != 1 || arguments.named.isNotEmpty) { | 
|  | errorReporter.report(messageWeakReferenceNotOneArgument.withLocation( | 
|  | node.location!.file, node.fileOffset, 1)); | 
|  | return; | 
|  | } | 
|  | final Expression arg = arguments.positional.single; | 
|  | if (arg is ConstantExpression) { | 
|  | final Constant constant = arg.constant; | 
|  | if (constant is StaticTearOffConstant) { | 
|  | final Procedure target = constant.target; | 
|  | if (target.isStatic) { | 
|  | final FunctionNode function = target.function; | 
|  | if (function.positionalParameters.isNotEmpty || | 
|  | function.namedParameters.isNotEmpty || | 
|  | function.typeParameters.isNotEmpty) { | 
|  | errorReporter.report(messageWeakReferenceTargetHasParameters | 
|  | .withLocation(node.location!.file, node.fileOffset, 1)); | 
|  | } | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | errorReporter.report(messageWeakReferenceTargetNotStaticTearoff | 
|  | .withLocation(node.location!.file, node.fileOffset, 1)); | 
|  | } | 
|  |  | 
|  | // Coverage-ignore(suite): Not run. | 
|  | static void validateWeakReferenceDeclaration( | 
|  | Annotatable node, ErrorReporter errorReporter) { | 
|  | if (node is! Procedure || | 
|  | !node.isStatic || | 
|  | node.kind != ProcedureKind.Method) { | 
|  | errorReporter.report(messageWeakReferenceNotStatic.withLocation( | 
|  | node.location!.file, node.fileOffset, 1)); | 
|  | return; | 
|  | } | 
|  | final FunctionNode function = node.function; | 
|  | if (function.positionalParameters.length != 1 || | 
|  | function.requiredParameterCount != 1 || | 
|  | function.namedParameters.isNotEmpty) { | 
|  | errorReporter.report(messageWeakReferenceNotOneArgument.withLocation( | 
|  | node.location!.file, node.fileOffset, 1)); | 
|  | return; | 
|  | } | 
|  | final DartType returnType = function.returnType; | 
|  | if (returnType.nullability != Nullability.nullable) { | 
|  | errorReporter.report(messageWeakReferenceReturnTypeNotNullable | 
|  | .withLocation(node.location!.file, node.fileOffset, 1)); | 
|  | } | 
|  | if (returnType != function.positionalParameters.single.type) { | 
|  | errorReporter.report(messageWeakReferenceMismatchReturnAndArgumentTypes | 
|  | .withLocation(node.location!.file, node.fileOffset, 1)); | 
|  | } | 
|  | node.hasWeakTearoffReferencePragma = true; | 
|  | } | 
|  |  | 
|  | // Coverage-ignore(suite): Not run. | 
|  | // Returns argument expression of the weak reference. | 
|  | // Assumes weak reference is valid. | 
|  | static Expression getWeakReferenceArgument(StaticInvocation node) { | 
|  | assert(isWeakReference(node)); | 
|  | return node.arguments.positional.single; | 
|  | } | 
|  |  | 
|  | // Coverage-ignore(suite): Not run. | 
|  | // Returns target method of the weak reference. | 
|  | // Assumes weak reference is valid. | 
|  | static Procedure getWeakReferenceTarget(StaticInvocation node) { | 
|  | final Expression arg = getWeakReferenceArgument(node); | 
|  | return ((arg as ConstantExpression).constant as StaticTearOffConstant) | 
|  | .target; | 
|  | } | 
|  | } |