Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

pattern assignment support for parameter_assignments #4212

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 54 additions & 6 deletions lib/src/rules/parameter_assignments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';

import '../analyzer.dart';

Expand Down Expand Up @@ -125,16 +126,48 @@ class _DeclarationVisitor extends RecursiveAstVisitor {
{required this.paramIsNotNullByDefault,
required this.paramDefaultsToNull});

Element? get parameterElement => parameter.declaredElement;

void checkPatternElements(DartPattern node) {
NodeList<PatternField>? fields;
if (node is RecordPattern) fields = node.fields;
if (node is ObjectPattern) fields = node.fields;
if (fields != null) {
for (var field in fields) {
if (field.pattern.element == parameterElement) {
reportLint(node);
}
}
} else {
List<AstNode>? elements;
if (node is ListPattern) elements = node.elements;
if (node is MapPattern) elements = node.elements;
if (elements == null) return;
for (var element in elements) {
if (element is MapPatternEntry) {
element = element.value;
}
if (element.element == parameterElement) {
reportLint(node);
}
}
}
}

void reportLint(AstNode node) {
rule.reportLint(node, arguments: [parameter.name!.lexeme]);
}

@override
visitAssignmentExpression(AssignmentExpression node) {
if (paramIsNotNullByDefault) {
if (_isFormalParameterReassigned(parameter, node)) {
rule.reportLint(node, arguments: [parameter.name!.lexeme]);
reportLint(node);
}
} else if (paramDefaultsToNull) {
if (_isFormalParameterReassigned(parameter, node)) {
if (hasBeenAssigned) {
rule.reportLint(node, arguments: [parameter.name!.lexeme]);
reportLint(node);
}
hasBeenAssigned = true;
}
Expand All @@ -143,13 +176,20 @@ class _DeclarationVisitor extends RecursiveAstVisitor {
super.visitAssignmentExpression(node);
}

@override
visitPatternAssignment(PatternAssignment node) {
checkPatternElements(node.pattern);

super.visitPatternAssignment(node);
}

@override
visitPostfixExpression(PostfixExpression node) {
if (paramIsNotNullByDefault) {
var operand = node.operand;
if (operand is SimpleIdentifier &&
operand.staticElement == parameter.declaredElement) {
rule.reportLint(node, arguments: [parameter.name!.lexeme]);
operand.staticElement == parameterElement) {
reportLint(node);
}
}

Expand All @@ -161,8 +201,8 @@ class _DeclarationVisitor extends RecursiveAstVisitor {
if (paramIsNotNullByDefault) {
var operand = node.operand;
if (operand is SimpleIdentifier &&
operand.staticElement == parameter.declaredElement) {
rule.reportLint(node, arguments: [parameter.name!.lexeme]);
operand.staticElement == parameterElement) {
reportLint(node);
}
}

Expand Down Expand Up @@ -206,3 +246,11 @@ class _Visitor extends SimpleAstVisitor<void> {
}
}
}

extension on AstNode {
Element? get element {
var self = this;
if (self is AssignedVariablePattern) return self.element;
return null;
}
}
61 changes: 61 additions & 0 deletions test/rules/parameter_assignments_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../rule_test_support.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ParameterAssignmentsTest);
defineReflectiveTests(ParameterAssignmentsTestLanguage300);
});
}

Expand Down Expand Up @@ -177,3 +178,63 @@ class A {
]);
}
}

@reflectiveTest
class ParameterAssignmentsTestLanguage300 extends LintRuleTest
with LanguageVersion300Mixin {
@override
String get lintRule => 'parameter_assignments';

// If and switch cases don't need verification since params aren't valid
// constant pattern expressions.

test_listAssignment() async {
await assertDiagnostics(r'''
f(var b) {
[b] = [1];
print('$b');
}
''', [
lint(13, 3),
]);
}

test_mapAssignment() async {
await assertDiagnostics(r'''
f(var a) {
{'a': a} = {'a': 1};
print('$a');
}
''', [
lint(13, 8),
]);
}

test_objectAssignment() async {
await assertDiagnostics(r'''
class A {
int a;
A(this.a);
}

f(var b) {
A(a: b) = A(1);
print('$b');
}
''', [
lint(48, 7),
]);
}

test_recordAssignment() async {
await assertDiagnostics(r'''
void f(var a) {
var b = 0;
(a, b) = (1, 2);
print(b);
}
''', [
lint(31, 6),
]);
}
}