Skip to content

Commit

Permalink
Implement the lint 'specify_nonobvious_local_variable_types'
Browse files Browse the repository at this point in the history
This lint is the complement of 'omit_obvious_local_variable_types'
in that it flags every declaration that does _not_ specify the type
of a local variable, when it has an initializing expression whose type
is not obvious (defined as in 'omit_obvious_local_variable_types').

Change-Id: If80a961e47fed0412d0ea0bac5ac010e26fea7bc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/379160
Reviewed-by: Brian Wilkerson <[email protected]>
Commit-Queue: Erik Ernst <[email protected]>
Reviewed-by: Phil Quitslund <[email protected]>
  • Loading branch information
eernstg authored and Commit Queue committed Aug 13, 2024
1 parent 196f6c9 commit 5b7c600
Show file tree
Hide file tree
Showing 15 changed files with 958 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,8 @@ LintCode.sort_pub_dependencies:
status: needsFix
LintCode.sort_unnamed_constructors_first:
status: hasFix
LintCode.specify_nonobvious_local_variable_types:
status: hasFix
LintCode.test_types_in_equals:
status: noFix
LintCode.throw_in_finally:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ final _builtInLintProducers = <LintCode, List<ProducerGenerator>>{
LinterLintCode.sort_unnamed_constructors_first: [
SortUnnamedConstructorFirst.new,
],
LinterLintCode.specify_nonobvious_local_variable_types: [
AddTypeAnnotation.bulkFixable,
],
LinterLintCode.type_annotate_public_apis: [
AddTypeAnnotation.bulkFixable,
],
Expand Down
2 changes: 2 additions & 0 deletions pkg/analysis_server/lib/src/services/linter/lint_names.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ abstract final class LintNames {
static const String sort_constructors_first = 'sort_constructors_first';
static const String sort_unnamed_constructors_first =
'sort_unnamed_constructors_first';
static const String specify_nonobvious_local_variable_types =
'specify_nonobvious_local_variable_types';
static const String type_annotate_public_apis = 'type_annotate_public_apis';
static const String type_init_formals = 'type_init_formals';
static const String type_literal_in_constant_pattern =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ void main() {
defineReflectiveTests(PreferTypingUninitializedVariablesBulkTest);
defineReflectiveTests(PreferTypingUninitializedVariablesInFileTest);
defineReflectiveTests(PreferTypingUninitializedVariablesLintTest);
defineReflectiveTests(SpecifyNonObviousLocalVariableTypesBulkTest);
defineReflectiveTests(SpecifyNonObviousLocalVariableTypesInFileTest);
defineReflectiveTests(SpecifyNonObviousLocalVariableTypesLintTest);
defineReflectiveTests(TypeAnnotatePublicAPIsBulkTest);
defineReflectiveTests(TypeAnnotatePublicAPIsInFileTest);
defineReflectiveTests(TypeAnnotatePublicAPIsLintTest);
Expand Down Expand Up @@ -404,6 +407,171 @@ void f() {
}
}

@reflectiveTest
class SpecifyNonObviousLocalVariableTypesBulkTest extends BulkFixProcessorTest {
@override
String get lintCode => LintNames.specify_nonobvious_local_variable_types;

Future<void> test_bulk() async {
await resolveTestCode('''
void main() {
final a = x;
var b = x;
}
int x = 1;
''');
await assertHasFix('''
void main() {
final int a = x;
int b = x;
}
int x = 1;
''');
}
}

@reflectiveTest
class SpecifyNonObviousLocalVariableTypesInFileTest
extends FixInFileProcessorTest {
Future<void> test_File() async {
createAnalysisOptionsFile(
lints: [LintNames.specify_nonobvious_local_variable_types]);
await resolveTestCode(r'''
f() {
var x = g(0), y = g('');
return (x, y);
}
T g<T>(T d) => d;
''');
var fixes = await getFixesForFirstError();
expect(fixes, hasLength(0));
}
}

@reflectiveTest
class SpecifyNonObviousLocalVariableTypesLintTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.ADD_TYPE_ANNOTATION;

@override
String get lintCode => LintNames.specify_nonobvious_local_variable_types;

Future<void> test_listPattern_destructured() async {
await resolveTestCode('''
f() {
var [a] = [1, 1.5];
print(a);
}
''');
await assertHasFix('''
f() {
var [num a] = [1, 1.5];
print(a);
}
''');
}

Future<void> test_local_variable() async {
await resolveTestCode('''
int f() {
final f = x;
return f;
}
int x = 1;
''');
await assertHasFix('''
int f() {
final int f = x;
return f;
}
int x = 1;
''');
}

Future<void> test_mapPattern_destructured() async {
await resolveTestCode('''
f() {
var {'a': a} = {'a': x};
print(a);
}
int x = 1;
''');
await assertHasFix('''
f() {
var {'a': int a} = {'a': x};
print(a);
}
int x = 1;
''');
}

Future<void> test_objectPattern_switch_final() async {
await resolveTestCode('''
class A {
int a;
A(this.a);
}
var a = A(1);
f() {
switch (a) {
case A(a: >0 && final b): print(b);
}
}
''');
await assertHasFix('''
class A {
int a;
A(this.a);
}
var a = A(1);
f() {
switch (a) {
case A(a: >0 && final int b): print(b);
}
}
''');
}

Future<void> test_recordPattern_switch() async {
await resolveTestCode('''
f() {
switch ((1, x)) {
case (final a, int b): print(a); print(b);
}
}
int x = 2;
''');
await assertHasFix('''
f() {
switch ((1, x)) {
case (final int a, int b): print(a); print(b);
}
}
int x = 2;
''');
}

Future<void> test_recordPattern_switch_var() async {
await resolveTestCode('''
f() {
switch ((1, x)) {
case (int a, var b): print(a); print(b);
}
}
int x = 2;
''');
await assertHasFix('''
f() {
switch ((1, x)) {
case (int a, int b): print(a); print(b);
}
}
int x = 2;
''');
}
}

@reflectiveTest
class TypeAnnotatePublicAPIsBulkTest extends BulkFixProcessorTest {
@override
Expand Down
1 change: 1 addition & 0 deletions pkg/linter/example/all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ linter:
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- specify_nonobvious_local_variable_types
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
Expand Down
9 changes: 8 additions & 1 deletion pkg/linter/lib/src/linter_lint_codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ class LinterLintCode extends LintCode {

static const LintCode omit_obvious_local_variable_types = LinterLintCode(
'omit_obvious_local_variable_types',
"Unnecessary and obvious type annotation on a local variable.",
"Omit the type annotation on a local variable when the type is obvious.",
correctionMessage: "Try removing the type annotation.",
);

Expand Down Expand Up @@ -1462,6 +1462,13 @@ class LinterLintCode extends LintCode {
"Try moving the unnamed constructor before all other constructors.",
);

static const LintCode specify_nonobvious_local_variable_types =
LinterLintCode(
'specify_nonobvious_local_variable_types',
"Specify the type of a local variable when the type is non-obvious.",
correctionMessage: "Try adding a type annotation.",
);

static const LintCode test_types_in_equals = LinterLintCode(
'test_types_in_equals',
"Missing type test for '{0}' in '=='.",
Expand Down
2 changes: 2 additions & 0 deletions pkg/linter/lib/src/rules.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ import 'rules/slash_for_doc_comments.dart';
import 'rules/sort_child_properties_last.dart';
import 'rules/sort_constructors_first.dart';
import 'rules/sort_unnamed_constructors_first.dart';
import 'rules/specify_nonobvious_local_variable_types.dart';
import 'rules/super_goes_last.dart';
import 'rules/test_types_in_equals.dart';
import 'rules/throw_in_finally.dart';
Expand Down Expand Up @@ -422,6 +423,7 @@ void registerLintRules() {
..register(SortPubDependencies())
..register(SortUnnamedConstructorsFirst())
..register(SuperGoesLast())
..register(SpecifyNonObviousLocalVariableTypes())
..register(TestTypesInEquals())
..register(ThrowInFinally())
..register(TightenTypeOfInitializingFormals())
Expand Down
5 changes: 4 additions & 1 deletion pkg/linter/lib/src/rules/omit_local_variable_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ class OmitLocalVariableTypes extends LintRule {
categories: {LintRuleCategory.style});

@override
List<String> get incompatibleRules => const ['always_specify_types'];
List<String> get incompatibleRules => const [
'always_specify_types',
'specify_nonobvious_local_variable_types',
];

@override
LintCode get lintCode => LinterLintCode.omit_local_variable_types;
Expand Down
Loading

0 comments on commit 5b7c600

Please sign in to comment.