Skip to content

Commit 5b2a008

Browse files
srawlinsCommit Queue
authored andcommitted
Analyzer warnings: add support for @Deprecation.instantiate
Work towards #60504 * The annotation causes certain usage to generate a warning (+ tests). * Possible fixes for this new warning are offered (+ tests). * Placing the annotation on an invalid element generates a different warning (+ tests). Change-Id: I0ba88e2192efcc26615542fc773d306a31ac5449 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445361 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent dd0ac56 commit 5b2a008

File tree

12 files changed

+380
-14
lines changed

12 files changed

+380
-14
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,6 +3464,11 @@ WarningCode.DEPRECATED_IMPLEMENT:
34643464
status: hasFix
34653465
WarningCode.DEPRECATED_IMPLEMENTS_FUNCTION:
34663466
status: hasFix
3467+
WarningCode.DEPRECATED_INSTANTIATE:
3468+
status: noFix
3469+
notes: |-
3470+
The only fix would be to delete the whole instance creation expression, or
3471+
follow the directions in the deprecation message.
34673472
WarningCode.DEPRECATED_MIXIN_FUNCTION:
34683473
status: needsFix
34693474
notes: |-
@@ -3555,6 +3560,9 @@ WarningCode.INVALID_DEPRECATED_EXTEND_ANNOTATION:
35553560
WarningCode.INVALID_DEPRECATED_IMPLEMENT_ANNOTATION:
35563561
status: needsFix
35573562
notes: The fix is to remove the annotation.
3563+
WarningCode.INVALID_DEPRECATED_INSTANTIATE_ANNOTATION:
3564+
status: needsFix
3565+
notes: The fix is to remove the annotation.
35583566
WarningCode.INVALID_DEPRECATED_SUBCLASS_ANNOTATION:
35593567
status: needsFix
35603568
notes: The fix is to remove the annotation.

pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,7 @@ const List<DiagnosticCode> diagnosticCodeValues = [
984984
WarningCode.deprecatedExtendsFunction,
985985
WarningCode.deprecatedImplement,
986986
WarningCode.deprecatedImplementsFunction,
987+
WarningCode.deprecatedInstantiate,
987988
WarningCode.deprecatedMixinFunction,
988989
WarningCode.deprecatedNewInCommentReference,
989990
WarningCode.deprecatedSubclass,
@@ -1019,6 +1020,7 @@ const List<DiagnosticCode> diagnosticCodeValues = [
10191020
WarningCode.invalidAwaitNotRequiredAnnotation,
10201021
WarningCode.invalidDeprecatedExtendAnnotation,
10211022
WarningCode.invalidDeprecatedImplementAnnotation,
1023+
WarningCode.invalidDeprecatedInstantiateAnnotation,
10221024
WarningCode.invalidDeprecatedSubclassAnnotation,
10231025
WarningCode.invalidExportOfInternalElement,
10241026
WarningCode.invalidExportOfInternalElementIndirectly,

pkg/analyzer/lib/src/error/annotation_verifier.dart

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@ class AnnotationVerifier {
141141
_checkDeprecatedSubclass(node, node.parent);
142142
return;
143143
}
144+
145+
var isInstantiate =
146+
value.getField('_isInstantiate')?.toBoolValue() ?? false;
147+
if (isInstantiate) {
148+
_checkDeprecatedInstantiate(node, node.parent);
149+
return;
150+
}
144151
}
145152

146153
void _checkDeprecatedExtend(Annotation node, AstNode parent) {
@@ -154,10 +161,8 @@ class AnnotationVerifier {
154161
}
155162

156163
if (declaredElement is ClassElement) {
157-
var hasGenerativeConstructor = declaredElement.constructors.any(
158-
(c) => c.isPublic && c.isGenerative,
159-
);
160-
if (declaredElement.isExtendableOutside && hasGenerativeConstructor) {
164+
if (declaredElement.isExtendableOutside &&
165+
declaredElement.hasGenerativeConstructor) {
161166
return;
162167
}
163168
}
@@ -194,6 +199,29 @@ class AnnotationVerifier {
194199
);
195200
}
196201

202+
void _checkDeprecatedInstantiate(Annotation node, AstNode parent) {
203+
Element? declaredElement;
204+
if (parent
205+
case ClassDeclaration(:var declaredFragment) ||
206+
ClassTypeAlias(:var declaredFragment)) {
207+
declaredElement = declaredFragment!.element;
208+
} else if (parent is GenericTypeAlias) {
209+
declaredElement = parent.type.type?.element;
210+
}
211+
212+
if (declaredElement is ClassElement) {
213+
if (!declaredElement.isAbstract &&
214+
declaredElement.hasGenerativeConstructor) {
215+
return;
216+
}
217+
}
218+
219+
_diagnosticReporter.atNode(
220+
node.name,
221+
WarningCode.invalidDeprecatedInstantiateAnnotation,
222+
);
223+
}
224+
197225
void _checkDeprecatedSubclass(Annotation node, AstNode parent) {
198226
Element? declaredElement;
199227
if (parent
@@ -735,3 +763,8 @@ class AnnotationVerifier {
735763
};
736764
}
737765
}
766+
767+
extension on ClassElement {
768+
bool get hasGenerativeConstructor =>
769+
constructors.any((c) => c.isPublic && c.isGenerative);
770+
}

pkg/analyzer/lib/src/error/best_practices_verifier.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
300300
@override
301301
void visitConstructorName(ConstructorName node) {
302302
_deprecatedMemberUseVerifier.constructorName(node);
303+
_deprecatedFunctionalityVerifier.constructorName(node);
303304
super.visitConstructorName(node);
304305
}
305306

pkg/analyzer/lib/src/error/codes.g.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6489,6 +6489,14 @@ class WarningCode extends DiagnosticCode {
64896489
uniqueName: 'DEPRECATED_IMPLEMENTS_FUNCTION',
64906490
);
64916491

6492+
/// Parameters:
6493+
/// Object p0: the name of the member
6494+
static const WarningCode deprecatedInstantiate = WarningCode(
6495+
'DEPRECATED_INSTANTIATE',
6496+
"Instantiating '{0}' is deprecated.",
6497+
correctionMessage: "Try instantiating a non-abstract class.",
6498+
);
6499+
64926500
/// No parameters.
64936501
static const WarningCode deprecatedMixinFunction = WarningCode(
64946502
'DEPRECATED_SUBTYPE_OF_FUNCTION',
@@ -6825,6 +6833,13 @@ class WarningCode extends DiagnosticCode {
68256833
correctionMessage: "Try removing the '@Deprecated.implement' annotation.",
68266834
);
68276835

6836+
/// No parameters.
6837+
static const WarningCode invalidDeprecatedInstantiateAnnotation = WarningCode(
6838+
'INVALID_DEPRECATED_INSTANTIATE_ANNOTATION',
6839+
"The annotation '@Deprecated.instantiate' can only be applied to classes.",
6840+
correctionMessage: "Try removing the '@Deprecated.instantiate' annotation.",
6841+
);
6842+
68286843
/// No parameters.
68296844
static const WarningCode invalidDeprecatedSubclassAnnotation = WarningCode(
68306845
'INVALID_DEPRECATED_SUBCLASS_ANNOTATION',

pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ class DeprecatedFunctionalityVerifier {
2828
_checkForDeprecatedImplement(node.implementsClause?.interfaces);
2929
}
3030

31+
void constructorName(ConstructorName node) {
32+
var classElement = node.type.element;
33+
if (classElement == null) return;
34+
if (classElement.hasDeprecatedWithField('_isInstantiate')) {
35+
_diagnosticReporter.atNode(
36+
node,
37+
WarningCode.deprecatedInstantiate,
38+
arguments: [classElement.name!],
39+
);
40+
}
41+
}
42+
3143
void enumDeclaration(EnumDeclaration node) {
3244
_checkForDeprecatedImplement(node.implementsClause?.interfaces);
3345
}

pkg/analyzer/lib/src/test_utilities/mock_sdk.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,26 +318,37 @@ class Deprecated extends Object {
318318
final bool _isImplement;
319319
final bool _isExtend;
320320
final bool _isSubclass;
321+
final bool _isInstantiate;
321322
const Deprecated(this.message)
322323
: _isUse = true,
323324
_isImplement = false,
324325
_isExtend = false,
325-
_isSubclass = false;
326+
_isSubclass = false,
327+
_isInstantiate = false;
326328
const Deprecated.implement([this.message = "next release"])
327329
: _isUse = false,
328330
_isImplement = true,
329331
_isExtend = false,
330-
_isSubclass = false;
332+
_isSubclass = false,
333+
_isInstantiate = false;
331334
const Deprecated.extend([this.message = "next release"])
332335
: _isUse = false,
333336
_isImplement = false,
334337
_isExtend = true,
335-
_isSubclass = false;
338+
_isSubclass = false,
339+
_isInstantiate = false;
336340
const Deprecated.subclass([this.message = "next release"])
337341
: _isUse = false,
338342
_isImplement = false,
339343
_isExtend = false,
340-
_isSubclass = true;
344+
_isSubclass = true,
345+
_isInstantiate = false;
346+
const Deprecated.instantiate([this.message = "next release"])
347+
: _isUse = false,
348+
_isImplement = false,
349+
_isExtend = false,
350+
_isSubclass = false,
351+
_isInstantiate = true;
341352
}
342353
343354
class pragma {

pkg/analyzer/messages.yaml

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23909,7 +23909,7 @@ WarningCode:
2390923909
documentation: |-
2391023910
#### Description
2391123911

23912-
The analyzer produces this diagnostic when a class which is annotated with
23912+
The analyzer produces this diagnostic when a class annotated with
2391323913
`@Deprecated.extend` is used in the `extends` clause of a class
2391423914
declaration.
2391523915

@@ -23984,12 +23984,12 @@ WarningCode:
2398423984
documentation: |-
2398523985
#### Description
2398623986

23987-
The analyzer produces this diagnostic when a class which is annotated with
23987+
The analyzer produces this diagnostic when a class annotated with
2398823988
`@Deprecated.implement` is used in the `implements` clause of a class or
2398923989
enum declaration. This annotation indicates that the ability for classes
2399023990
to implement the annotated class is deprecated, and will soon be removed,
23991-
perhaps
23992-
by marking the annotated class with `interface`, `final`, or `sealed`.
23991+
perhaps by marking the annotated class with `interface`, `final`, or
23992+
`sealed`.
2399323993

2399423994
#### Example
2399523995

@@ -24024,6 +24024,43 @@ WarningCode:
2402424024
problemMessage: "Implementing 'Function' has no effect."
2402524025
correctionMessage: "Try removing 'Function' from the 'implements' clause."
2402624026
hasPublishedDocs: true
24027+
DEPRECATED_INSTANTIATE:
24028+
parameters:
24029+
Object p0: the name of the member
24030+
problemMessage: "Instantiating '#p0' is deprecated."
24031+
correctionMessage: Try instantiating a non-abstract class.
24032+
hasPublishedDocs: false
24033+
documentation: |-
24034+
#### Description
24035+
24036+
The analyzer produces this diagnostic when a class annotated with
24037+
`@Deprecated.instantiate` is instantiated. This annotation indicates that
24038+
the ability to instantiate the class is deprecated, and will soon be removed,
24039+
perhaps by marking the annotated class with `abstract`, or `sealed`.
24040+
24041+
#### Example
24042+
24043+
If the library `p` defines a class annotated with
24044+
`@Deprecated.instantiate`:
24045+
24046+
```dart
24047+
%uri="package:p/p.dart"
24048+
@Deprecated.instantiate()
24049+
class C {}
24050+
```
24051+
24052+
Then, the following code, when in a library other than `p`, produces this
24053+
diagnostic:
24054+
24055+
```dart
24056+
import 'package:p/p.dart';
24057+
24058+
var c = [!C!]();
24059+
```
24060+
24061+
#### Common fixes
24062+
24063+
Follow any directions found in the `Deprecation.instantiate` annotation.
2402724064
DEPRECATED_MIXIN_FUNCTION:
2402824065
parameters: none
2402924066
sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
@@ -24093,7 +24130,7 @@ WarningCode:
2409324130
documentation: |-
2409424131
#### Description
2409524132

24096-
The analyzer produces this diagnostic when a class which is annotated with
24133+
The analyzer produces this diagnostic when a class annotated with
2409724134
`@Deprecated.subclass` is used in the `extends` clause of a class
2409824135
declaration, or the `implements` clause of a class or enum declaration.
2409924136

@@ -24804,6 +24841,36 @@ WarningCode:
2480424841

2480524842
Remove the annotation:
2480624843

24844+
```dart
24845+
sealed class C {}
24846+
```
24847+
INVALID_DEPRECATED_INSTANTIATE_ANNOTATION:
24848+
parameters: none
24849+
problemMessage: "The annotation '@Deprecated.instantiate' can only be applied to classes."
24850+
correctionMessage: Try removing the '@Deprecated.instantiate' annotation.
24851+
hasPublishedDocs: false
24852+
documentation: |-
24853+
#### Description
24854+
24855+
The analyzer produces this diagnostic when anything other than an
24856+
instantiable class is annotated with Deprecated.instantiate. An
24857+
instantiable class is one not declared with the `abstract` or `sealed`
24858+
keywords, and with at least one public, generative constructor.
24859+
24860+
#### Example
24861+
24862+
The following code produces this diagnostic because the annotation is on a
24863+
sealed class:
24864+
24865+
```dart
24866+
@[!Deprecated.instantiate!]()
24867+
sealed class C {}
24868+
```
24869+
24870+
#### Common fixes
24871+
24872+
Remove the annotation:
24873+
2480724874
```dart
2480824875
sealed class C {}
2480924876
```

pkg/analyzer/test/src/diagnostics/deprecated_implement_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class Bar implements Foo2 {}
5959
test_annotatedClassTypeAlias() async {
6060
newFile('$testPackageLibPath/foo.dart', r'''
6161
@Deprecated.implement()
62-
class Foo = Object with M;
62+
class Foo = Object with M;
6363
mixin M {}
6464
''');
6565

0 commit comments

Comments
 (0)