From dd8ec91e969ba9efc5e2a867c8e565fde1ab60b9 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 19 Aug 2024 19:43:59 +0000 Subject: [PATCH] linter: fix omit_local_variable_types for coerced int Fixes https://github.com/dart-lang/linter/issues/5010 Cq-Include-Trybots: luci.dart.try:flutter-analyze-try,analyzer-win-release-try,pkg-win-release-try Change-Id: Id302aceb24bb9a80f0f13b3ec91b7a57c09a7d52 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381101 Reviewed-by: Phil Quitslund Commit-Queue: Samuel Rawlins --- .../src/rules/omit_local_variable_types.dart | 68 ++++++++++--------- .../rules/omit_local_variable_types_test.dart | 8 +++ 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/pkg/linter/lib/src/rules/omit_local_variable_types.dart b/pkg/linter/lib/src/rules/omit_local_variable_types.dart index 927b65acc4b6..0aaefdc1c5ed 100644 --- a/pkg/linter/lib/src/rules/omit_local_variable_types.dart +++ b/pkg/linter/lib/src/rules/omit_local_variable_types.dart @@ -6,9 +6,9 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; +import 'package:analyzer/dart/element/type_provider.dart'; import '../analyzer.dart'; -import '../extensions.dart'; import '../linter_lint_codes.dart'; const _desc = r'Omit type annotations for local variables.'; @@ -84,7 +84,7 @@ class OmitLocalVariableTypes extends LintRule { @override void registerNodeProcessors( NodeLintRegistry registry, LinterContext context) { - var visitor = _Visitor(this); + var visitor = _Visitor(this, context.typeProvider); registry.addForStatement(this, visitor); registry.addVariableDeclarationStatement(this, visitor); } @@ -93,7 +93,9 @@ class OmitLocalVariableTypes extends LintRule { class _Visitor extends SimpleAstVisitor { final LintRule rule; - _Visitor(this.rule); + final TypeProvider typeProvider; + + _Visitor(this.rule, this.typeProvider); @override void visitForStatement(ForStatement node) { @@ -103,18 +105,16 @@ class _Visitor extends SimpleAstVisitor { } else if (loopParts is ForEachPartsWithDeclaration) { var loopVariableType = loopParts.loopVariable.type; var staticType = loopVariableType?.type; - if (staticType == null || staticType is DynamicType) { - return; - } - var iterableType = loopParts.iterable.staticType; - if (iterableType is InterfaceType) { - // TODO(srawlins): Is `DartType.asInstanceOf` the more correct API here? - var iterableInterfaces = iterableType.implementedInterfaces - .where((type) => type.isDartCoreIterable); - if (iterableInterfaces.length == 1 && - iterableInterfaces.first.typeArguments.first == staticType) { - rule.reportLint(loopVariableType); - } + if (staticType == null || staticType is DynamicType) return; + + var loopType = loopParts.iterable.staticType; + if (loopType is! InterfaceType) return; + + var iterableType = loopType.asInstanceOf(typeProvider.iterableElement); + if (iterableType == null) return; + if (iterableType.typeArguments.isNotEmpty && + iterableType.typeArguments.first == staticType) { + rule.reportLint(loopVariableType); } } } @@ -124,20 +124,6 @@ class _Visitor extends SimpleAstVisitor { _visitVariableDeclarationList(node.variables); } - bool _dependsOnDeclaredTypeForInference(Expression? initializer) { - if (initializer is MethodInvocation) { - if (initializer.typeArguments == null) { - var element = initializer.methodName.staticElement; - if (element is FunctionElement) { - if (element.returnType is TypeParameterType) { - return true; - } - } - } - } - return false; - } - void _visitVariableDeclarationList(VariableDeclarationList node) { var staticType = node.type?.type; if (staticType == null || @@ -147,13 +133,33 @@ class _Visitor extends SimpleAstVisitor { } for (var child in node.variables) { var initializer = child.initializer; - if (initializer?.staticType != staticType) { + if (initializer == null || initializer.staticType != staticType) { return; } - if (_dependsOnDeclaredTypeForInference(initializer)) { + + if (initializer is IntegerLiteral && !staticType.isDartCoreInt) { + // Coerced int. + return; + } + + if (initializer.dependsOnDeclaredTypeForInference) { return; } } rule.reportLint(node.type); } } + +extension on Expression { + bool get dependsOnDeclaredTypeForInference { + if (this case MethodInvocation(:var methodName, typeArguments: null)) { + var element = methodName.staticElement; + if (element is FunctionElement) { + if (element.returnType is TypeParameterType) { + return true; + } + } + } + return false; + } +} diff --git a/pkg/linter/test/rules/omit_local_variable_types_test.dart b/pkg/linter/test/rules/omit_local_variable_types_test.dart index 19229cb27881..d7a0171bac5a 100644 --- a/pkg/linter/test/rules/omit_local_variable_types_test.dart +++ b/pkg/linter/test/rules/omit_local_variable_types_test.dart @@ -201,6 +201,14 @@ f() { '''); } + test_rightSideIsInt_typedWithDouble() async { + await assertNoDiagnostics(r''' +void f() { + double x = 0; +} +'''); + } + test_rightSideIsInt_typedWithDynamic() async { await assertNoDiagnostics(r''' void f() {