Skip to content

Commit cc34c05

Browse files
srawlinsCommit Queue
authored andcommitted
DAS: Add a fix for strict_top_level_inference
Change-Id: I990542bd6455113a70ead1d680f50b1163e6e263 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401800 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 79b5240 commit cc34c05

File tree

4 files changed

+114
-67
lines changed

4 files changed

+114
-67
lines changed

pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,29 @@ class AddReturnType extends ResolvedCorrectionProducer {
3333

3434
@override
3535
Future<void> compute(ChangeBuilder builder) async {
36-
Token? insertBeforeEntity;
37-
FunctionBody? body;
38-
var executable = node;
39-
if (executable is MethodDeclaration && executable.name == token) {
40-
if (executable.returnType != null) {
36+
if (node
37+
case MethodDeclaration(:var name, :var returnType, :var isSetter) ||
38+
FunctionDeclaration(:var name, :var returnType, :var isSetter)) {
39+
if (name != token) {
4140
return;
4241
}
43-
if (executable.isSetter) {
42+
if (returnType != null) {
4443
return;
4544
}
46-
insertBeforeEntity =
47-
executable.operatorKeyword ??
48-
executable.propertyKeyword ??
49-
executable.name;
50-
body = executable.body;
51-
} else if (executable is FunctionDeclaration && executable.name == token) {
52-
if (executable.returnType != null) {
53-
return;
54-
}
55-
if (executable.isSetter) {
45+
if (isSetter) {
5646
return;
5747
}
58-
insertBeforeEntity = executable.propertyKeyword ?? executable.name;
59-
body = executable.functionExpression.body;
48+
}
49+
50+
Token insertBeforeEntity;
51+
FunctionBody body;
52+
if (node case MethodDeclaration method) {
53+
insertBeforeEntity =
54+
method.operatorKeyword ?? method.propertyKeyword ?? method.name;
55+
body = method.body;
56+
} else if (node case FunctionDeclaration method) {
57+
insertBeforeEntity = method.propertyKeyword ?? method.name;
58+
body = method.functionExpression.body;
6059
} else {
6160
return;
6261
}
@@ -66,10 +65,9 @@ class AddReturnType extends ResolvedCorrectionProducer {
6665
return;
6766
}
6867

69-
var insertBeforeEntity_final = insertBeforeEntity;
7068
await builder.addDartFileEdit(file, (builder) {
7169
if (returnType is DynamicType || builder.canWriteType(returnType)) {
72-
builder.addInsertion(insertBeforeEntity_final.offset, (builder) {
70+
builder.addInsertion(insertBeforeEntity.offset, (builder) {
7371
if (returnType is DynamicType) {
7472
builder.write('dynamic');
7573
} else {
@@ -81,7 +79,7 @@ class AddReturnType extends ResolvedCorrectionProducer {
8179
});
8280
}
8381

84-
/// Return the type of value returned by the function [body], or `null` if a
82+
/// Returns the type of value returned by the function [body], or `null` if a
8583
/// type can't be inferred.
8684
DartType? _inferReturnType(FunctionBody body) {
8785
DartType? baseType;
@@ -100,10 +98,8 @@ class AddReturnType extends ResolvedCorrectionProducer {
10098
return null;
10199
}
102100

103-
var isAsynchronous = body.isAsynchronous;
104-
var isGenerator = body.isGenerator;
105-
if (isAsynchronous) {
106-
if (isGenerator) {
101+
if (body.isAsynchronous) {
102+
if (body.isGenerator) {
107103
return typeProvider.streamElement2.instantiate(
108104
typeArguments: [baseType],
109105
nullabilitySuffix: baseType.nullabilitySuffix,
@@ -114,7 +110,7 @@ class AddReturnType extends ResolvedCorrectionProducer {
114110
nullabilitySuffix: baseType.nullabilitySuffix,
115111
);
116112
}
117-
} else if (isGenerator) {
113+
} else if (body.isGenerator) {
118114
return typeProvider.iterableElement2.instantiate(
119115
typeArguments: [baseType],
120116
nullabilitySuffix: baseType.nullabilitySuffix,
@@ -144,13 +140,8 @@ class _ReturnTypeComputer extends RecursiveAstVisitor<void> {
144140
void visitReturnStatement(ReturnStatement node) {
145141
hasReturn = true;
146142
// prepare expression
147-
var expression = node.expression;
148-
if (expression == null) {
149-
return;
150-
}
151-
// prepare type
152-
var type = expression.typeOrThrow;
153-
if (type.isBottom) {
143+
var type = node.expression?.typeOrThrow;
144+
if (type == null || type.isBottom) {
154145
return;
155146
}
156147
// combine types

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
# issue created for it.
4545
#
4646
# Stats:
47-
# - 54 "needsEvaluation"
47+
# - 58 "needsEvaluation"
4848
# - 308 "needsFix"
49-
# - 465 "hasFix"
49+
# - 470 "hasFix"
5050
# - 514 "noFix"
5151

5252
AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR:
@@ -2368,17 +2368,19 @@ LintCode.specify_nonobvious_local_variable_types:
23682368
LintCode.specify_nonobvious_property_types:
23692369
status: hasFix
23702370
LintCode.strict_top_level_inference_add_type:
2371-
status: noFix
2372-
notes: |-
2373-
There is no obvious way to pick a good candidate type.
2371+
status: hasFix
23742372
LintCode.strict_top_level_inference_replace_keyword:
23752373
status: noFix
23762374
notes: |-
2377-
There is no obvious way to pick a good candidate type.
2375+
Conceivably for variable declarations we can search some space (like the
2376+
library or the compilation unit) for what values are assigned, and suggest
2377+
the LUB of those value(s)' type(s).
23782378
LintCode.strict_top_level_inference_split_to_types:
23792379
status: noFix
23802380
notes: |-
2381-
There is no obvious way to pick a good candidate type.
2381+
Conceivably for variable declarations we can search some space (like the
2382+
library or the compilation unit) for what values are assigned, and suggest
2383+
the LUB of those value(s)' type(s).
23822384
LintCode.test_types_in_equals:
23832385
status: noFix
23842386
LintCode.throw_in_finally:

pkg/analysis_server/lib/src/services/correction/fix_internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ final _builtInLintProducers = <LintCode, List<ProducerGenerator>>{
467467
LinterLintCode.specify_nonobvious_property_types: [
468468
AddTypeAnnotation.bulkFixable,
469469
],
470+
LinterLintCode.strict_top_level_inference_add_type: [AddReturnType.new],
470471
LinterLintCode.type_annotate_public_apis: [AddTypeAnnotation.bulkFixable],
471472
LinterLintCode.type_init_formals: [RemoveTypeAnnotation.other],
472473
LinterLintCode.type_literal_in_constant_pattern: [

pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,14 @@ import 'fix_processor.dart';
1111

1212
void main() {
1313
defineReflectiveSuite(() {
14+
defineReflectiveTests(AddReturnType_AlwaysDeclareReturnTypesTest);
15+
defineReflectiveTests(AddReturnType_StrictTopLevelInferenceTest);
1416
defineReflectiveTests(AddReturnTypeBulkTest);
15-
defineReflectiveTests(AddReturnTypeLintTest);
1617
});
1718
}
1819

1920
@reflectiveTest
20-
class AddReturnTypeBulkTest extends BulkFixProcessorTest {
21-
@override
22-
String get lintCode => LintNames.always_declare_return_types;
23-
24-
Future<void> test_singleFile() async {
25-
await resolveTestCode('''
26-
class A {
27-
get foo => 0;
28-
m(p) {
29-
return p;
30-
}
31-
}
32-
''');
33-
await assertHasFix('''
34-
class A {
35-
int get foo => 0;
36-
dynamic m(p) {
37-
return p;
38-
}
39-
}
40-
''');
41-
}
42-
}
43-
44-
@reflectiveTest
45-
class AddReturnTypeLintTest extends FixProcessorLintTest {
21+
class AddReturnType_AlwaysDeclareReturnTypesTest extends FixProcessorLintTest {
4622
@override
4723
FixKind get kind => DartFixKind.ADD_RETURN_TYPE;
4824

@@ -238,3 +214,80 @@ int get foo => 0;
238214
''');
239215
}
240216
}
217+
218+
@reflectiveTest
219+
class AddReturnType_StrictTopLevelInferenceTest extends FixProcessorLintTest {
220+
@override
221+
FixKind get kind => DartFixKind.ADD_RETURN_TYPE;
222+
223+
@override
224+
String get lintCode => LintNames.strict_top_level_inference;
225+
226+
Future<void> test_instanceMethod_typeVariable() async {
227+
await resolveTestCode('''
228+
class C<T> {
229+
f(T p) {
230+
return p;
231+
}
232+
}
233+
''');
234+
await assertHasFix('''
235+
class C<T> {
236+
T f(T p) {
237+
return p;
238+
}
239+
}
240+
''');
241+
}
242+
243+
Future<void> test_topLevelFunction() async {
244+
await resolveTestCode('''
245+
f() {
246+
return '';
247+
}
248+
''');
249+
await assertHasFix('''
250+
String f() {
251+
return '';
252+
}
253+
''');
254+
}
255+
256+
Future<void> test_topLevelFunction_typeVariable() async {
257+
await resolveTestCode('''
258+
f<T>(T p) {
259+
return [p];
260+
}
261+
''');
262+
await assertHasFix('''
263+
List<T> f<T>(T p) {
264+
return [p];
265+
}
266+
''');
267+
}
268+
}
269+
270+
@reflectiveTest
271+
class AddReturnTypeBulkTest extends BulkFixProcessorTest {
272+
@override
273+
String get lintCode => LintNames.always_declare_return_types;
274+
275+
Future<void> test_singleFile() async {
276+
await resolveTestCode('''
277+
class A {
278+
get foo => 0;
279+
m(p) {
280+
return p;
281+
}
282+
}
283+
''');
284+
await assertHasFix('''
285+
class A {
286+
int get foo => 0;
287+
dynamic m(p) {
288+
return p;
289+
}
290+
}
291+
''');
292+
}
293+
}

0 commit comments

Comments
 (0)