Skip to content

Commit

Permalink
augmentation support for avoid_equals_and_hash_code_on_mutable_classes
Browse files Browse the repository at this point in the history
Fixes: dart-lang/linter#4932

Change-Id: Ic9b20d81ae36536251568dbf25616b9ddc9f6693
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/363142
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
pq authored and Commit Queue committed Apr 16, 2024
1 parent ae6d2ed commit 9330195
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:analyzer/dart/element/element.dart';

import '../analyzer.dart';
import '../ast.dart';
import '../extensions.dart';

const _desc =
r'Avoid overloading operator == and hashCode on classes not marked `@immutable`.';
Expand Down Expand Up @@ -95,24 +96,31 @@ class _Visitor extends SimpleAstVisitor<void> {

@override
void visitMethodDeclaration(MethodDeclaration node) {
if (node.isAugmentation) return;

if (node.name.type == TokenType.EQ_EQ || isHashCode(node)) {
var classElement = _getClassForMethod(node);
if (classElement != null && !_hasImmutableAnnotation(classElement)) {
var classElement = node.classElement;
if (classElement != null && !classElement.hasImmutableAnnotation) {
rule.reportLintForToken(node.firstTokenAfterCommentAndMetadata,
arguments: [node.name.lexeme]);
}
}
}
}

ClassElement? _getClassForMethod(MethodDeclaration node) =>
// TODO(pq): should this be ClassOrMixinDeclaration ?
node.thisOrAncestorOfType<ClassDeclaration>()?.declaredElement;

bool _hasImmutableAnnotation(ClassElement clazz) {
extension on ClassElement {
bool get hasImmutableAnnotation {
// TODO(pq): consider augmentations? https://github.com/dart-lang/linter/issues/4939
var inheritedAndSelfElements = <InterfaceElement>[
...clazz.allSupertypes.map((t) => t.element),
clazz,
...allSupertypes.map((t) => t.element),
this,
];
return inheritedAndSelfElements.any((e) => e.hasImmutable);
}
}

extension on MethodDeclaration {
ClassElement? get classElement =>
// TODO(pq): should this be ClassOrMixinDeclaration ?
thisOrAncestorOfType<ClassDeclaration>()?.declaredElement;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,44 @@ class A {
]);
}

test_mutableClass_augmentationMethod() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {
@override
int get hashCode => 0;
}
''');

await assertNoDiagnostics(r'''
augment library 'a.dart';
augment class A {
augment int get hashCode => 0;
}
''');
}

test_mutableClass_augmented() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertDiagnostics(r'''
augment library 'a.dart';
augment class A {
@override
int get hashCode => 0;
}
''', [
lint(59, 3),
]);
}

test_subtypeOfImmutableClass() async {
await assertNoDiagnostics(r'''
import 'package:meta/meta.dart';
Expand Down

0 comments on commit 9330195

Please sign in to comment.