Skip to content

Commit

Permalink
linter: fix omit_local_variable_types for coerced int
Browse files Browse the repository at this point in the history
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 <pquitslund@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
  • Loading branch information
srawlins authored and Commit Queue committed Aug 19, 2024
1 parent 4e812af commit dd8ec91
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 31 deletions.
68 changes: 37 additions & 31 deletions pkg/linter/lib/src/rules/omit_local_variable_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
Expand Down Expand Up @@ -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);
}
Expand All @@ -93,7 +93,9 @@ class OmitLocalVariableTypes extends LintRule {
class _Visitor extends SimpleAstVisitor<void> {
final LintRule rule;

_Visitor(this.rule);
final TypeProvider typeProvider;

_Visitor(this.rule, this.typeProvider);

@override
void visitForStatement(ForStatement node) {
Expand All @@ -103,18 +105,16 @@ class _Visitor extends SimpleAstVisitor<void> {
} 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);
}
}
}
Expand All @@ -124,20 +124,6 @@ class _Visitor extends SimpleAstVisitor<void> {
_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 ||
Expand All @@ -147,13 +133,33 @@ class _Visitor extends SimpleAstVisitor<void> {
}
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;
}
}
8 changes: 8 additions & 0 deletions pkg/linter/test/rules/omit_local_variable_types_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit dd8ec91

Please sign in to comment.