From 509a8edd8d48cf81bac097969cffbd7cc995b414 Mon Sep 17 00:00:00 2001 From: Brian Wilkerson Date: Fri, 13 Mar 2026 06:56:21 -0700 Subject: [PATCH] Update the annotateOverrides lint for primary constructors Change-Id: Ia1581e9223e5edee2ca96b124282d89ede4e2b28 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/487700 Commit-Queue: Brian Wilkerson Reviewed-by: Samuel Rawlins --- .../lib/src/rules/annotate_overrides.dart | 30 ++++++++++- .../test/rules/annotate_overrides_test.dart | 50 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/pkg/linter/lib/src/rules/annotate_overrides.dart b/pkg/linter/lib/src/rules/annotate_overrides.dart index 7a7072691c6..2d453a35329 100644 --- a/pkg/linter/lib/src/rules/annotate_overrides.dart +++ b/pkg/linter/lib/src/rules/annotate_overrides.dart @@ -10,6 +10,8 @@ import 'package:analyzer/dart/ast/token.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/error/error.dart'; +// ignore: implementation_imports +import 'package:analyzer/src/dart/ast/extensions.dart'; import '../analyzer.dart'; import '../diagnostic.dart' as diag; @@ -32,6 +34,7 @@ class AnnotateOverrides extends AnalysisRule { var visitor = _Visitor(this, context); registry.addFieldDeclaration(this, visitor); registry.addMethodDeclaration(this, visitor); + registry.addPrimaryConstructorDeclaration(this, visitor); } } @@ -45,7 +48,11 @@ class _Visitor extends SimpleAstVisitor { if (element == null) return; if (element.metadata.hasOverride) return; - var member = element.overriddenMember; + var memberElement = element; + if (memberElement case FieldFormalParameterElement(:var field?)) { + memberElement = field; + } + var member = memberElement.overriddenMember; if (member != null) { rule.reportAtToken(target, arguments: [member.name!]); } @@ -70,4 +77,25 @@ class _Visitor extends SimpleAstVisitor { check(node.declaredFragment?.element, node.name); } + + @override + void visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { + if (node.isAugmentation) return; + + var parent = node.parent; + if (parent is ClassDeclaration || parent is EnumDeclaration) { + for (var parameter in node.formalParameters.parameters) { + if (parameter.notDefault case SimpleFormalParameter( + :var name, + keyword: var keywordToken, + )) { + if (keywordToken case Token(keyword: var keyword?)) { + if (keyword == Keyword.FINAL || keyword == Keyword.VAR) { + check(parameter.declaredFragment?.element, name ?? keywordToken); + } + } + } + } + } + } } diff --git a/pkg/linter/test/rules/annotate_overrides_test.dart b/pkg/linter/test/rules/annotate_overrides_test.dart index 89fd296d955..7a52d2e8550 100644 --- a/pkg/linter/test/rules/annotate_overrides_test.dart +++ b/pkg/linter/test/rules/annotate_overrides_test.dart @@ -92,6 +92,29 @@ augment class B { '''); } + test_class_declaringParameter_withAnnotation() async { + await assertNoDiagnostics(r''' +class A { + int get x => 4; +} + +class B(@override var int x) extends A {} +'''); + } + + test_class_declaringParameter_withoutAnnotation() async { + await assertDiagnostics( + r''' +class A { + int get x => 4; +} + +class B(var int x) extends A {} +''', + [lint(47, 1)], + ); + } + test_class_fieldWithAnnotation() async { await assertNoDiagnostics(r''' class A { @@ -196,6 +219,33 @@ class B extends A { ); } + test_enum_declaringParameter_withAnnotation() async { + await assertNoDiagnostics(r''' +enum E(@override final int x) implements I { + e(0) +} + +class I { + int get x => 4; +} +'''); + } + + test_enum_declaringParameter_withoutAnnotation() async { + await assertDiagnostics( + r''' +enum E(final int x) implements I { + e(0) +} + +class I { + int get x => 4; +} +''', + [lint(17, 1)], + ); + } + test_enum_fieldWithAnnotation() async { await assertNoDiagnostics(r''' class O {