Version 3.10.0-236.0.dev Merge 36991474d1c0047e393c88bc06cbad817837704d into dev
diff --git a/DEPS b/DEPS index 74626fe..2bf8784 100644 --- a/DEPS +++ b/DEPS
@@ -163,9 +163,9 @@ # meant to be downloaded by users for local testing. You can self-service # update these by following the go/dart-engprod/browsers.md instructions. "download_chrome": False, - "chrome_tag": "141.0.7390.16", + "chrome_tag": "141.0.7390.30", "download_firefox": False, - "firefox_tag": "142.0.1", + "firefox_tag": "143.0.1", # Emscripten is used in dart2wasm tests. "download_emscripten": False,
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index 7a4a4b2..a8fcf9f 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -3497,6 +3497,8 @@ The fix is to remove `Function` from where it's referenced. WarningCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE: status: hasFix +WarningCode.DEPRECATED_OPTIONAL: + status: needsEvaluation WarningCode.DEPRECATED_SUBCLASS: status: hasFix WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT: @@ -3576,6 +3578,7 @@ status: hasFix WarningCode.INVALID_AWAIT_NOT_REQUIRED_ANNOTATION: status: needsFix + notes: The fix is to remove the annotation. WarningCode.INVALID_DEPRECATED_EXTEND_ANNOTATION: status: needsFix notes: The fix is to remove the annotation. @@ -3588,6 +3591,9 @@ WarningCode.INVALID_DEPRECATED_MIXIN_ANNOTATION: status: needsFix notes: The fix is to remove the annotation. +WarningCode.INVALID_DEPRECATED_OPTIONAL_ANNOTATION: + status: needsFix + notes: The fix is to remove the annotation. WarningCode.INVALID_DEPRECATED_SUBCLASS_ANNOTATION: status: needsFix notes: The fix is to remove the annotation.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart index 4142226..a051574 100644 --- a/pkg/analyzer/lib/dart/element/element.dart +++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -3159,8 +3159,8 @@ /// Whether the receiver has an annotation of the form `@awaitNotRequired`. bool get hasAwaitNotRequired; - /// Whether the receiver has an annotation of the form `@deprecated` - /// or `@Deprecated('..')`. + /// Whether the receiver has an annotation of the form `@deprecated`, + /// `@Deprecated('..')`, or any other `Deprecated` constructor. bool get hasDeprecated; /// Whether the receiver has an annotation of the form `@doNotStore`.
diff --git a/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart b/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart index 307e2c3..091aaf2 100644 --- a/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart +++ b/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart
@@ -991,6 +991,7 @@ WarningCode.deprecatedMixin, WarningCode.deprecatedMixinFunction, WarningCode.deprecatedNewInCommentReference, + WarningCode.deprecatedOptional, WarningCode.deprecatedSubclass, WarningCode.docDirectiveArgumentWrongFormat, WarningCode.docDirectiveHasExtraArguments, @@ -1026,6 +1027,7 @@ WarningCode.invalidDeprecatedImplementAnnotation, WarningCode.invalidDeprecatedInstantiateAnnotation, WarningCode.invalidDeprecatedMixinAnnotation, + WarningCode.invalidDeprecatedOptionalAnnotation, WarningCode.invalidDeprecatedSubclassAnnotation, WarningCode.invalidExportOfInternalElement, WarningCode.invalidExportOfInternalElementIndirectly,
diff --git a/pkg/analyzer/lib/src/error/annotation_verifier.dart b/pkg/analyzer/lib/src/error/annotation_verifier.dart index cad886b..f2bb9e8 100644 --- a/pkg/analyzer/lib/src/error/annotation_verifier.dart +++ b/pkg/analyzer/lib/src/error/annotation_verifier.dart
@@ -121,25 +121,27 @@ assert(element.isDeprecated); switch (element.deprecationKind) { case 'extend': - _checkDeprecatedExtend(node, node.parent); + _checkDeprecatedExtend(node); case 'implement': - _checkDeprecatedImplement(node, node.parent); + _checkDeprecatedImplement(node); case 'instantiate': - _checkDeprecatedInstantiate(node, node.parent); + _checkDeprecatedInstantiate(node); case 'mixin': - _checkDeprecatedMixin(node, node.parent); + _checkDeprecatedMixin(node); + case 'optional': + _checkDeprecatedOptional(node); case 'subclass': - _checkDeprecatedSubclass(node, node.parent); + _checkDeprecatedSubclass(node); } } - void _checkDeprecatedExtend(Annotation node, AstNode parent) { + void _checkDeprecatedExtend(Annotation node) { Element? declaredElement; - if (parent + if (node.parent case ClassDeclaration(:var declaredFragment) || ClassTypeAlias(:var declaredFragment)) { declaredElement = declaredFragment!.element; - } else if (parent is GenericTypeAlias) { + } else if (node.parent case GenericTypeAlias parent) { declaredElement = parent.type.type?.element; } @@ -157,15 +159,15 @@ ); } - void _checkDeprecatedImplement(Annotation node, AstNode parent) { + void _checkDeprecatedImplement(Annotation node) { Element? declaredElement; - if (parent + if (node.parent case ClassDeclaration(:var declaredFragment) || ClassTypeAlias(:var declaredFragment)) { declaredElement = declaredFragment!.element; - } else if (parent is MixinDeclaration) { + } else if (node.parent case MixinDeclaration parent) { declaredElement = parent.declaredFragment!.element; - } else if (parent is GenericTypeAlias) { + } else if (node.parent case GenericTypeAlias parent) { declaredElement = parent.type.type?.element; } @@ -185,13 +187,13 @@ ); } - void _checkDeprecatedInstantiate(Annotation node, AstNode parent) { + void _checkDeprecatedInstantiate(Annotation node) { Element? declaredElement; - if (parent + if (node.parent case ClassDeclaration(:var declaredFragment) || ClassTypeAlias(:var declaredFragment)) { declaredElement = declaredFragment!.element; - } else if (parent is GenericTypeAlias) { + } else if (node.parent case GenericTypeAlias parent) { declaredElement = parent.type.type?.element; } @@ -208,7 +210,8 @@ ); } - void _checkDeprecatedMixin(Annotation node, AstNode parent) { + void _checkDeprecatedMixin(Annotation node) { + var parent = node.parent; if (parent is ClassDeclaration && parent.declaredFragment!.element.isPublic && parent.mixinKeyword != null) { @@ -221,15 +224,48 @@ ); } - void _checkDeprecatedSubclass(Annotation node, AstNode parent) { + void _checkDeprecatedOptional(Annotation node) { + var parent = node.parent; + if (parent is FormalParameter) { + FormalParameterList parameterList; + if (parent.parent case FormalParameterList parent2) { + parameterList = parent2; + } else if (parent.parent case DefaultFormalParameter( + parent: FormalParameterList parent2, + )) { + parameterList = parent2; + } else { + // We shouldn't get here; if we do, don't report the annotation. + return; + } + + // This annotation is only valid on method declarations, constructor + // declarations, and top-level function declarations. + var isValidFunction = + parameterList.parent is MethodDeclaration || + parameterList.parent is ConstructorDeclaration || + (parameterList.parent is FunctionExpression && + parameterList.parent?.parent is FunctionDeclaration && + parameterList.parent?.parent?.parent is CompilationUnit); + + if (parent.isOptional && isValidFunction) return; + } + + _diagnosticReporter.atNode( + node.name, + WarningCode.invalidDeprecatedOptionalAnnotation, + ); + } + + void _checkDeprecatedSubclass(Annotation node) { Element? declaredElement; - if (parent + if (node.parent case ClassDeclaration(:var declaredFragment) || ClassTypeAlias(:var declaredFragment)) { declaredElement = declaredFragment!.element; - } else if (parent is MixinDeclaration) { + } else if (node.parent case MixinDeclaration parent) { declaredElement = parent.declaredFragment!.element; - } else if (parent is GenericTypeAlias) { + } else if (node.parent case GenericTypeAlias parent) { declaredElement = parent.type.type?.element; }
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart index 42776bd..077353b 100644 --- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart +++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -337,12 +337,21 @@ void visitDotShorthandConstructorInvocation( DotShorthandConstructorInvocation node, ) { + _deprecatedFunctionalityVerifier.dotShorthandConstructorInvocation(node); _deprecatedMemberUseVerifier.dotShorthandConstructorInvocation(node); _checkForLiteralConstructorUseInDotShorthand(node); super.visitDotShorthandConstructorInvocation(node); } @override + void visitDotShorthandInvocation(DotShorthandInvocation node) { + _deprecatedFunctionalityVerifier.dotShorthandInvocation(node); + // TODO(srawlins): I imagine we need to check with + // `_deprecatedMemberUseVerifier` here... + super.visitDotShorthandInvocation(node); + } + + @override void visitEnumDeclaration(EnumDeclaration node) { _deprecatedMemberUseVerifier.pushElement(node.declaredFragment!.element); _deprecatedFunctionalityVerifier.enumDeclaration(node); @@ -577,6 +586,7 @@ covariant InstanceCreationExpressionImpl node, ) { _deprecatedMemberUseVerifier.instanceCreationExpression(node); + _deprecatedFunctionalityVerifier.instanceCreationExpression(node); _nullSafeApiVerifier.instanceCreation(node); _checkForLiteralConstructorUse(node); super.visitInstanceCreationExpression(node); @@ -655,6 +665,7 @@ @override void visitMethodInvocation(covariant MethodInvocationImpl node) { _deprecatedMemberUseVerifier.methodInvocation(node); + _deprecatedFunctionalityVerifier.methodInvocation(node); _errorHandlerVerifier.verifyMethodInvocation(node); _nullSafeApiVerifier.methodInvocation(node); super.visitMethodInvocation(node);
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index 3935606..de3a668 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -10905,6 +10905,19 @@ ); /// Parameters: + /// Object parameterName: the name of the parameter + static const WarningTemplate< + LocatableDiagnostic Function({required Object parameterName}) + > + deprecatedOptional = WarningTemplate( + 'DEPRECATED_OPTIONAL', + "Omitting an argument for the '{0}' parameter is deprecated.", + correctionMessage: "Try passing an argument for '{0}'.", + withArguments: _withArgumentsDeprecatedOptional, + expectedTypes: [ExpectedType.object], + ); + + /// Parameters: /// Object typeName: the name of the type static const WarningTemplate< LocatableDiagnostic Function({required Object typeName}) @@ -11394,6 +11407,21 @@ expectedTypes: [], ); + /// This warning is generated anywhere where `@Deprecated.optional` + /// annotates something other than an optional parameter. + /// + /// No parameters. + static const WarningWithoutArguments invalidDeprecatedOptionalAnnotation = + WarningWithoutArguments( + 'INVALID_DEPRECATED_OPTIONAL_ANNOTATION', + "The annotation '@Deprecated.optional' can only be applied to optional " + "parameters.", + correctionMessage: + "Try removing the '@Deprecated.optional' annotation.", + hasPublishedDocs: true, + expectedTypes: [], + ); + /// No parameters. static const WarningWithoutArguments invalidDeprecatedSubclassAnnotation = WarningWithoutArguments( @@ -12987,6 +13015,12 @@ return LocatableDiagnosticImpl(deprecatedMixin, [typeName]); } + static LocatableDiagnostic _withArgumentsDeprecatedOptional({ + required Object parameterName, + }) { + return LocatableDiagnosticImpl(deprecatedOptional, [parameterName]); + } + static LocatableDiagnostic _withArgumentsDeprecatedSubclass({ required Object typeName, }) {
diff --git a/pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart b/pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart index c952c87..c7997c8 100644 --- a/pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart +++ b/pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart
@@ -43,11 +43,54 @@ } } + void dotShorthandConstructorInvocation( + DotShorthandConstructorInvocation node, + ) { + var element = node.constructorName.element; + if (element is! ExecutableElement) return; + _checkForDeprecatedOptional( + element: element, + argumentList: node.argumentList, + errorNode: node.constructorName, + ); + } + + void dotShorthandInvocation(DotShorthandInvocation node) { + var element = node.memberName.element; + if (element is! ExecutableElement) return; + _checkForDeprecatedOptional( + element: element, + argumentList: node.argumentList, + errorNode: node.memberName, + ); + } + void enumDeclaration(EnumDeclaration node) { _checkForDeprecatedImplement(node.implementsClause?.interfaces); _checkForDeprecatedMixin(node.withClause); } + void instanceCreationExpression(InstanceCreationExpression node) { + var constructor = node.constructorName.element; + if (constructor == null) return; + _checkForDeprecatedOptional( + element: constructor, + argumentList: node.argumentList, + errorNode: node.constructorName, + ); + } + + void methodInvocation(MethodInvocation node) { + var method = node.methodName.element; + if (method is! ExecutableElement) return; + if (method is LocalFunctionElement) return; + _checkForDeprecatedOptional( + element: method, + argumentList: node.argumentList, + errorNode: node.methodName, + ); + } + void mixinDeclaration(MixinDeclaration node) { _checkForDeprecatedImplement(node.implementsClause?.interfaces); // Not technically "implementing," but is similar enough for @@ -117,6 +160,28 @@ } } + void _checkForDeprecatedOptional({ + required ExecutableElement element, + required ArgumentList argumentList, + required AstNode errorNode, + }) { + var omittedParameters = element.formalParameters.toList(); + for (var argument in argumentList.arguments) { + var parameter = argument.correspondingParameter; + if (parameter == null) continue; + omittedParameters.remove(parameter); + } + for (var parameter in omittedParameters) { + if (parameter.isDeprecatedWithKind('optional')) { + _diagnosticReporter.atNode( + errorNode, + WarningCode.deprecatedOptional, + arguments: [parameter.name ?? '<unknown>'], + ); + } + } + } + void _checkForDeprecatedSubclass(List<NamedType>? namedTypes) { if (namedTypes == null) return; for (var namedType in namedTypes) {
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart index 0537301..d1bf1fa 100644 --- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart +++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -322,10 +322,11 @@ const Deprecated.instantiate([this.message]) : _kind = _DeprecationKind.instantiate; const Deprecated.mixin([this.message]) : _kind = _DeprecationKind.mixin; + const Deprecated.optional([this.message]) : _kind = _DeprecationKind.optional; } enum _DeprecationKind { - use, implement, extend, subclass, instantiate, mixin; + use, implement, extend, subclass, instantiate, mixin, optional; } class pragma { @@ -737,10 +738,9 @@ @Since('2.9') abstract final class Handle implements NativeType {} -@Since('2.12') abstract base class Opaque implements NativeType {} -final class Void implements NativeType {} +abstract final class Void implements NativeType {} final class Int8 implements SizedNativeType { const Int8(); @@ -813,22 +813,26 @@ final class Pointer<T extends NativeType> implements SizedNativeType { external factory Pointer.fromAddress(int ptr); - static Pointer<NativeFunction<T>> fromFunction<T extends Function>( - @DartRepresentationOf("T") Function f, - [Object exceptionalReturn]) {} + external static Pointer<NativeFunction<T>> fromFunction<T extends Function>( + @DartRepresentationOf('T') Function f, [ + Object? exceptionalReturn, + ]); external Pointer<U> cast<U extends NativeType>(); - } final Pointer<Never> nullptr = Pointer.fromAddress(0); -class NativeCallable<T extends Function> { - NativeCallable.isolateLocal( - @DartRepresentationOf("T") Function callback, - {Object? exceptionalReturn}) {} +@Since('3.1') +abstract final class NativeCallable<T extends Function> { + factory NativeCallable.isolateLocal( + @DartRepresentationOf("T") Function callback, { + Object? exceptionalReturn, + }) => throw 0; - NativeCallable.listener(@DartRepresentationOf("T") Function callback) {} + factory NativeCallable.listener( + @DartRepresentationOf("T") Function callback, + ) => throw 0; Pointer<NativeFunction<T>> get nativeFunction; @@ -840,7 +844,7 @@ external DF asFunction<DF extends Function>({bool isLeaf = false}); } -abstract final class _Compound implements NativeType {} +final class _Compound implements NativeType {} abstract base class Struct extends _Compound implements SizedNativeType { @Since('3.4') @@ -864,15 +868,16 @@ const Packed(this.memberAlignment); } -abstract final class DynamicLibrary { - external factory DynamicLibrary.open(String name); - +final class DynamicLibrary { + external factory DynamicLibrary.open(String path); external Pointer<T> lookup<T extends NativeType>(String symbolName); } extension DynamicLibraryExtension on DynamicLibrary { external F lookupFunction<T extends Function, F extends Function>( - String symbolName, {bool isLeaf:false}); + String symbolName, { + bool isLeaf = false, + }); } abstract final class NativeFunction<T extends Function> implements NativeType {} @@ -990,30 +995,25 @@ @Since('2.19') final class Native<T> { final String? symbol; - final String? asset; + final String? assetId; final bool isLeaf; - const Native({ - this.asset, - this.isLeaf: false, - this.symbol, - }); + const Native({this.assetId, this.isLeaf = false, this.symbol}); + @Since('3.3') external static Pointer<T> addressOf<T extends NativeType>( - @DartRepresentationOf('T') Object object); + @DartRepresentationOf('T') Object native, + ); } +@Since('2.19') final class DefaultAsset { final String id; const DefaultAsset(this.id); } -final class Asset { - final String asset; - const Asset(this.asset); -} - -final class Abi { +@Since('2.16') +class Abi { static const androidArm = _androidArm; static const androidArm64 = _androidArm64; static const androidIA32 = _androidIA32;
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 846bdec..38a8268 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml
@@ -24150,6 +24150,59 @@ problemMessage: "Mixing in 'Function' is deprecated." correctionMessage: "Try removing 'Function' from the 'with' clause." hasPublishedDocs: true + DEPRECATED_OPTIONAL: + parameters: + Object parameterName: the name of the parameter + problemMessage: "Omitting an argument for the '#parameterName' parameter is deprecated." + correctionMessage: Try passing an argument for '#parameterName'. + hasPublishedDocs: false + documentation: |- + #### Description + + The analyzer produces this diagnostic when an argument is omitted for an + optional parameter annotated with `@Deprecated.optional`. This annotation + indicates that omitting an argument for the parameter is deprecated, and + the parameter will soon become required. + + #### Example + + Given a library `p` that defines a function with an optional parameter + annotated with `@Deprecated.optional`: + + ```dart + %uri="package:p/p.dart" + void f({@Deprecated.optional() int a = 0}) {} + ``` + + The following code produces this diagnostic, because the invocation + doesn't pass a value for the parameter `a`: + + ```dart + import 'package:p/p.dart'; + + void g() { + [!f!](); + } + ``` + + #### Common fixes + + Follow any specific instructions provided in the `@Deprecated.optional` + annotation. + + If no instructions are present, pass an appropriate argument for the + corresponding parameter: + + + ```dart + import 'package:p/p.dart'; + + void g() { + f(a: 0); + } + ``` + + Using the default value will preserve the current behavior of the code. DEPRECATED_NEW_IN_COMMENT_REFERENCE: parameters: none problemMessage: "Using the 'new' keyword in a comment reference is deprecated." @@ -25065,9 +25118,9 @@ The analyzer produces this diagnostic when anything other than an extendable class is annotated with - Deprecated.extend. An extendable class is a - class not declared with the `interface`, `final`, or `sealed` keywords, - and with at least one public generative constructor. + @Deprecated.extend. An extendable class is a class that isn't declared + with the `interface`, `final`, or `sealed` keywords and also has at least + one public generative constructor. #### Example @@ -25098,9 +25151,8 @@ The analyzer produces this diagnostic when anything other than an implementable class or mixin is annotated with - Deprecated.implement. An implementable - class or mixin is one not declared with the `base`, `final`, or `sealed` - keywords. + @Deprecated.implement. An implementable class or mixin is one not declared + with the `base`, `final`, or `sealed` keywords. #### Example @@ -25128,7 +25180,7 @@ #### Description The analyzer produces this diagnostic when anything other than an - instantiable class is annotated with Deprecated.instantiate. An + instantiable class is annotated with @Deprecated.instantiate. An instantiable class is one not declared with the `abstract` or `sealed` keywords, and with at least one public, generative constructor. @@ -25157,11 +25209,13 @@ comment: |- This warning is generated anywhere where `@Deprecated.mixin` annotates something other than a mixin class. + # TODO(srawlins): link Deprecated.mixin below with: + # [`Deprecated.mixin`][meta-deprecated-mixin] documentation: |- #### Description - The analyzer produces this diagnostic when anything other than a - mixin class is annotated with Deprecated.mixin. + The analyzer produces this diagnostic when the `@Deprecated.mixin` + annotation is applied to a declaration that isn't a mixin class. #### Example @@ -25180,6 +25234,42 @@ ```dart class C {} ``` + INVALID_DEPRECATED_OPTIONAL_ANNOTATION: + parameters: none + problemMessage: "The annotation '@Deprecated.optional' can only be applied to optional parameters." + correctionMessage: Try removing the '@Deprecated.optional' annotation. + hasPublishedDocs: true + comment: |- + This warning is generated anywhere where `@Deprecated.optional` + annotates something other than an optional parameter. + # TODO(srawlins): link Deprecated.optional below with: + # [`Deprecated.optional`][meta-deprecated-optional] + documentation: |- + #### Description + + The analyzer produces this diagnostic when the `@Deprecated.optional` + annotation is applied to a parameter that isn't an optional parameter. The + annotation must not be used on a parameter in a local function, an + anonymous function, a function-typed parameter, or a typedef. It is only + valid on optional parameters in a top-level function, a method, or a + constructor. + + #### Example + + The following code produces this diagnostic because the annotation is on a + required parameter: + + ```dart + void f(@[!Deprecated.optional!]() int p) {} + ``` + + #### Common fixes + + Remove the annotation: + + ```dart + void f(int p) {} + ``` INVALID_DEPRECATED_SUBCLASS_ANNOTATION: parameters: none problemMessage: "The annotation '@Deprecated.subclass' can only be applied to subclassable classes and mixins." @@ -25192,7 +25282,7 @@ The analyzer produces this diagnostic when anything other than a subclassable class or mixin is annotated with - Deprecated.subclass. A subclassable + @Deprecated.subclass. A subclassable class is a class not declared with the `final` or `sealed` keywords. A subclassable mixin is a mixin not declared with the `base` keyword.
diff --git a/pkg/analyzer/test/src/diagnostics/deprecated_optional_test.dart b/pkg/analyzer/test/src/diagnostics/deprecated_optional_test.dart new file mode 100644 index 0000000..f0c0f68 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/deprecated_optional_test.dart
@@ -0,0 +1,150 @@ +// Copyright (c) 2025, 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/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(DeprecatedOptionalTest); + }); +} + +@reflectiveTest +class DeprecatedOptionalTest extends PubPackageResolutionTest { + test_argumentGiven() async { + await assertNoErrorsInCode(r''' +void f([@Deprecated.optional() int? p]) {} + +void g() { + f(1); +} +'''); + } + + test_argumentGiven_named() async { + await assertNoErrorsInCode(r''' +void f({@Deprecated.optional() int? p}) {} + +void g() { + f(p: 1); +} +'''); + } + + test_argumentOmitted() async { + await assertErrorsInCode( + r''' +void f([@Deprecated.optional() int? p]) {} + +void g() { + f(); +} +''', + [error(WarningCode.deprecatedOptional, 57, 1)], + ); + } + + test_argumentOmitted_dotShorthand() async { + await assertErrorsInCode( + r''' +class C { + static C m({@Deprecated.optional() int? p}) => C(); +} + +C f() { + return .m(); +} +''', + [error(WarningCode.deprecatedOptional, 85, 1)], + ); + } + + test_argumentOmitted_dotShorthandConstructor() async { + await assertErrorsInCode( + r''' +class C { + C({@Deprecated.optional() int? p}); +} + +C f() { + return .new(); +} +''', + [error(WarningCode.deprecatedOptional, 69, 3)], + ); + } + + test_argumentOmitted_instanceCreation() async { + await assertErrorsInCode( + r''' +class C { + C([@Deprecated.optional() int? p]); +} + +void f() { + C(); +} +''', + [error(WarningCode.deprecatedOptional, 64, 1)], + ); + } + + test_argumentOmitted_methodInvocation() async { + await assertErrorsInCode( + r''' +class C { + void m({@Deprecated.optional() int? p}) {} +} + +void f(C c) { + c.m(); +} +''', + [error(WarningCode.deprecatedOptional, 76, 1)], + ); + } + + test_argumentOmitted_named() async { + await assertErrorsInCode( + r''' +void f({@Deprecated.optional() int? p}) {} + +void g() { + f(); +} +''', + [error(WarningCode.deprecatedOptional, 57, 1)], + ); + } + + test_argumentOmitted_override() async { + await assertNoErrorsInCode(r''' +class C { + void m({@Deprecated.optional() int? p}) {} +} + +class D extends C { + @override + void m({int? p}) {} +} + +void g(D d) { + d.m(); +} +'''); + } + + test_noAnnotation() async { + await assertNoErrorsInCode(r''' +void f([int? p]) {} + +void g() { + f(); +} +'''); + } +}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_deprecated_optional_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_deprecated_optional_annotation_test.dart new file mode 100644 index 0000000..0b3cbac --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/invalid_deprecated_optional_annotation_test.dart
@@ -0,0 +1,143 @@ +// Copyright (c) 2025, 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/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(InvalidDeprecatedOptionalAnnotationTest); + }); +} + +@reflectiveTest +class InvalidDeprecatedOptionalAnnotationTest extends PubPackageResolutionTest { + test_function() async { + await assertErrorsInCode( + r''' +@Deprecated.optional() +void f([int p = 0]) {} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 1, 19)], + ); + } + + test_parameter_ofConstructor() async { + await assertNoErrorsInCode(r''' +class C { + C([@Deprecated.optional() int? p]); +} +'''); + } + + test_parameter_ofFunctionParameter() async { + await assertErrorsInCode( + r''' +void f(void cb([@Deprecated.optional() int? p])) { + cb(); +} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 17, 19)], + ); + } + + test_parameter_ofFunctionTypedParameter() async { + await assertErrorsInCode( + r''' +void f(void Function([@Deprecated.optional() int? p]) cb) { + cb(); +} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 23, 19)], + ); + } + + test_parameter_ofLocalFunction() async { + await assertErrorsInCode( + r''' +void f() { + void g([@Deprecated.optional() int? p]) {} + g(); +} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 22, 19)], + ); + } + + test_parameter_ofMethod() async { + await assertNoErrorsInCode(r''' +class C { + void m([@Deprecated.optional() int? p]) {} +} +'''); + } + + test_parameter_ofTypedef() async { + await assertErrorsInCode( + r''' +typedef Cb = void Function([@Deprecated.optional() int? p]); +void f(Cb cb) { + cb(); +} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 29, 19)], + ); + } + + test_parameter_optionalNamedWithDefault() async { + await assertNoErrorsInCode(r''' +void f( + {@Deprecated.optional() int p = 0} +) {} +'''); + } + + test_parameter_optionalNamedWithoutDefault() async { + await assertNoErrorsInCode(r''' +void f( + {@Deprecated.optional() int? p} +) {} +'''); + } + + test_parameter_optionalPositionalWithDefault() async { + await assertNoErrorsInCode(r''' +void f( + [@Deprecated.optional() int p = 0] +) {} +'''); + } + + test_parameter_optionalPositionalWithoutDefault() async { + await assertNoErrorsInCode(r''' +void f( + [@Deprecated.optional() int? p] +) {} +'''); + } + + test_parameter_requiredNamed() async { + await assertErrorsInCode( + r''' +void f( + {@Deprecated.optional() required int? p} +) {} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 12, 19)], + ); + } + + test_parameter_requiredPositional() async { + await assertErrorsInCode( + r''' +void f( + @Deprecated.optional() int? p +) {} +''', + [error(WarningCode.invalidDeprecatedOptionalAnnotation, 11, 19)], + ); + } +}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 9f78786..0d15860 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -190,6 +190,7 @@ import 'deprecated_member_use_test.dart' as deprecated_member_use; import 'deprecated_mixin_function_test.dart' as deprecated_mixin_function; import 'deprecated_mixin_test.dart' as deprecated_mixin; +import 'deprecated_optional_test.dart' as deprecated_optional; import 'deprecated_subclass_test.dart' as deprecated_subclass; import 'doc_directive_argument_wrong_format_test.dart' as doc_directive_argument_wrong_format; @@ -448,6 +449,8 @@ as invalid_deprecated_instantiate_annotation; import 'invalid_deprecated_mixin_annotation_test.dart' as invalid_deprecated_mixin_annotation; +import 'invalid_deprecated_optional_annotation_test.dart' + as invalid_deprecated_optional_annotation; import 'invalid_deprecated_subclass_annotation_test.dart' as invalid_deprecated_subclass_annotation; import 'invalid_do_not_submit_test.dart' as invalid_do_not_submit; @@ -1082,6 +1085,7 @@ deprecated_member_use.main(); deprecated_mixin_function.main(); deprecated_mixin.main(); + deprecated_optional.main(); deprecated_subclass.main(); doc_directive_argument_wrong_format.main(); doc_directive_has_extra_arguments.main(); @@ -1241,6 +1245,7 @@ invalid_deprecated_implement_annotation.main(); invalid_deprecated_instantiate_annotation.main(); invalid_deprecated_mixin_annotation.main(); + invalid_deprecated_optional_annotation.main(); invalid_deprecated_subclass_annotation.main(); invalid_do_not_submit.main(); invalid_exception_value.main();
diff --git a/tools/VERSION b/tools/VERSION index 4c1c86e..d83511d 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 3 MINOR 10 PATCH 0 -PRERELEASE 235 +PRERELEASE 236 PRERELEASE_PATCH 0