`non_constant_identifier_names` support for augmentations
See: https://github.com/dart-lang/linter/issues/4883
Change-Id: Ia83e8a6e8e726bc3ef83ccbc5c0106f9698e4d4c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352978
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/linter/lib/src/extensions.dart b/pkg/linter/lib/src/extensions.dart
index 6143aac..b60b4b3 100644
--- a/pkg/linter/lib/src/extensions.dart
+++ b/pkg/linter/lib/src/extensions.dart
@@ -2,12 +2,12 @@
// 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/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'; // ignore: implementation_imports
import 'package:analyzer/src/dart/element/member.dart'; // ignore: implementation_imports
import 'package:collection/collection.dart';
@@ -25,6 +25,19 @@
extension AstNodeExtension on AstNode {
Iterable<AstNode> get childNodes => childEntities.whereType<AstNode>();
+ bool get isAugmentation {
+ var self = this;
+ return switch (self) {
+ ConstructorDeclaration() => self.augmentKeyword != null,
+ FunctionDeclarationImpl() => self.augmentKeyword != null,
+ FunctionExpression() => self.parent?.isAugmentation ?? false,
+ MethodDeclaration() => self.augmentKeyword != null,
+ // TODO(pq): unimplemented
+ // VariableDeclaration() => self.augmentKeyword != null,
+ _ => false
+ };
+ }
+
bool get isEffectivelyPrivate {
var node = this;
if (node.isInternal) return true;
diff --git a/pkg/linter/lib/src/rules/non_constant_identifier_names.dart b/pkg/linter/lib/src/rules/non_constant_identifier_names.dart
index d49173d..6ea45e4 100644
--- a/pkg/linter/lib/src/rules/non_constant_identifier_names.dart
+++ b/pkg/linter/lib/src/rules/non_constant_identifier_names.dart
@@ -95,6 +95,7 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
+ if (node.isAugmentation) return;
// For rationale on accepting underscores, see:
// https://github.com/dart-lang/linter/issues/1854
checkIdentifier(node.name, underscoresOk: true);
@@ -118,7 +119,9 @@
@override
void visitFormalParameterList(FormalParameterList node) {
+ var inAugmentation = node.parent?.isAugmentation ?? false;
for (var p in node.parameters) {
+ if (inAugmentation && p.isNamed) continue;
if (p is! FieldFormalParameter) {
checkIdentifier(p.name, underscoresOk: true);
}
@@ -127,12 +130,14 @@
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
+ if (node.isAugmentation) return;
+
checkIdentifier(node.name);
}
@override
void visitMethodDeclaration(MethodDeclaration node) {
- if (!node.isOperator) {
+ if (!node.isOperator && !node.isAugmentation) {
checkIdentifier(node.name);
}
}
diff --git a/pkg/linter/test/rules/non_constant_identifier_names_test.dart b/pkg/linter/test/rules/non_constant_identifier_names_test.dart
index 4f84d99..6600521 100644
--- a/pkg/linter/test/rules/non_constant_identifier_names_test.dart
+++ b/pkg/linter/test/rules/non_constant_identifier_names_test.dart
@@ -222,6 +222,180 @@
@override
String get lintRule => 'non_constant_identifier_names';
+ test_augmentedConstructor() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ A.Aa();
+}
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment A.Aa();
+}
+''');
+ }
+
+ @FailingTest(reason: 'Null check operator used on a null value')
+ test_augmentedField() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int Xx = 1;
+}
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment int Xx = 2;
+}
+''');
+ }
+
+ test_augmentedFunction() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+void Ff() { }
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment void Ff() { }
+''');
+ }
+
+ test_augmentedFunction_namedParam() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+void f({String? Ss}) { }
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment void f({String? Ss}) { }
+''');
+ }
+
+ test_augmentedFunction_positionalParam() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+void f(String? Ss, [int? Xx]) { }
+''');
+
+ await assertDiagnostics(r'''
+library augment 'a.dart';
+
+augment void f(String? Ss, [int? Xx]) { }
+''', [
+ lint(50, 2),
+ lint(60, 2),
+ ]);
+ }
+
+ test_augmentedGetter() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int get Gg => 1;
+}
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment int get Gg => 2;
+}
+''');
+ }
+
+ test_augmentedMethod() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ void Mm() { }
+}
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment void Mm() { }
+}
+''');
+ }
+
+ test_augmentedMethod_namedParam() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ void m({String? Ss}) { }
+}
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment void m({String? Ss}) { }
+}
+''');
+ }
+
+ test_augmentedMethod_positionalParam() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ void m(String? Ss, [int? Xx]) { }
+}
+''');
+
+ await assertDiagnostics(r'''
+library augment 'a.dart';
+
+augment class A {
+ augment void m(String? Ss, [int? Xx]) { }
+}
+''', [
+ lint(70, 2),
+ lint(80, 2),
+ ]);
+ }
+
+ @FailingTest(
+ reason:
+ "CompileTimeErrorCode.DUPLICATE_DEFINITION [39, 2, The name 'Xx' is already defined.]")
+ test_augmentedTopLevelVariable() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+int Xx = 1;
+''');
+
+ await assertNoDiagnostics(r'''
+library augment 'a.dart';
+
+augment int Xx = 2;
+''');
+ }
+
///https://github.com/dart-lang/linter/issues/193
test_ignoreSyntheticNodes() async {
await assertDiagnostics(r'''