| // 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:front_end/src/codes/diagnostic.dart' as diag; | |
| import 'package:front_end/src/kernel/utils.dart' show isAnnotatedWithPragma; | |
| import 'package:kernel/ast.dart'; | |
| import 'package:kernel/core_types.dart' show CoreTypes; | |
| 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, | |
| ) => isAnnotatedWithPragma(node, coreTypes, weakTearoffReferencePragma); | |
| static void validateWeakReferenceUse( | |
| StaticInvocation node, | |
| ErrorReporter errorReporter, | |
| ) { | |
| final Arguments arguments = node.arguments; | |
| if (arguments.positional.length != 1 || arguments.named.isNotEmpty) { | |
| // Coverage-ignore-block(suite): Not run. | |
| errorReporter.report( | |
| diag.weakReferenceNotOneArgument.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 || | |
| // Coverage-ignore(suite): Not run. | |
| function.namedParameters.isNotEmpty || | |
| // Coverage-ignore(suite): Not run. | |
| function.typeParameters.isNotEmpty) { | |
| errorReporter.report( | |
| diag.weakReferenceTargetHasParameters.withLocation( | |
| node.location!.file, | |
| node.fileOffset, | |
| 1, | |
| ), | |
| ); | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| errorReporter.report( | |
| diag.weakReferenceTargetNotStaticTearoff.withLocation( | |
| node.location!.file, | |
| node.fileOffset, | |
| 1, | |
| ), | |
| ); | |
| } | |
| static void validateWeakReferenceDeclaration( | |
| Annotatable node, | |
| ErrorReporter errorReporter, | |
| ) { | |
| if (node is! Procedure || | |
| !node.isStatic || | |
| node.kind != ProcedureKind.Method) { | |
| errorReporter.report( | |
| diag.weakReferenceNotStatic.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( | |
| diag.weakReferenceNotOneArgument.withLocation( | |
| node.location!.file, | |
| node.fileOffset, | |
| 1, | |
| ), | |
| ); | |
| return; | |
| } | |
| final DartType returnType = function.returnType; | |
| if (returnType.nullability != Nullability.nullable) { | |
| errorReporter.report( | |
| diag.weakReferenceReturnTypeNotNullable.withLocation( | |
| node.location!.file, | |
| node.fileOffset, | |
| 1, | |
| ), | |
| ); | |
| } | |
| if (returnType != function.positionalParameters.single.type) { | |
| errorReporter.report( | |
| diag.weakReferenceMismatchReturnAndArgumentTypes.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; | |
| } | |
| } |