Skip to content

Commit f0ad03c

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Adds fixes for implicit_this_reference_in_initializer
Fixes: #60729 Change-Id: Ie2ee6ff84062b749a9a8385a3140f9bc35760df2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429081 Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 4fbb4dc commit f0ad03c

File tree

15 files changed

+528
-181
lines changed

15 files changed

+528
-181
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ abstract final class DartAssistKind {
1616
DartAssistKindPriority.DEFAULT,
1717
'Add digit separators',
1818
);
19+
static const ADD_LATE = AssistKind(
20+
'dart.assist.add.late',
21+
DartAssistKindPriority.DEFAULT,
22+
"Add 'late' modifier",
23+
);
1924
static const ADD_RETURN_TYPE = AssistKind(
2025
'dart.assist.add.returnType',
2126
DartAssistKindPriority.DEFAULT,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
66
import 'package:analysis_server/src/services/correction/dart/add_digit_separators.dart';
7+
import 'package:analysis_server/src/services/correction/dart/add_late.dart';
78
import 'package:analysis_server/src/services/correction/dart/add_return_type.dart';
89
import 'package:analysis_server/src/services/correction/dart/add_type_annotation.dart';
910
import 'package:analysis_server/src/services/correction/dart/assign_to_local_variable.dart';
@@ -82,6 +83,7 @@ const Set<ProducerGenerator> _builtInGenerators = {
8283
AddDiagnosticPropertyReference.new,
8384
AddDigitSeparatorEveryThreeDigits.new,
8485
AddDigitSeparatorEveryTwoDigits.new,
86+
AddLate.new,
8587
AddReturnType.new,
8688
AddTypeAnnotation.bulkFixable,
8789
AssignToLocalVariable.new,

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,42 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analysis_server/src/services/correction/assist.dart';
56
import 'package:analysis_server/src/services/correction/fix.dart';
67
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
78
import 'package:analyzer/dart/ast/ast.dart';
89
import 'package:analyzer/dart/ast/token.dart';
910
import 'package:analyzer/dart/element/element.dart';
1011
import 'package:analyzer/source/source.dart';
1112
import 'package:analyzer/src/dart/ast/extensions.dart';
13+
import 'package:analyzer_plugin/utilities/assist/assist.dart';
1214
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1315
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1416

1517
class AddLate extends ResolvedCorrectionProducer {
16-
AddLate({required super.context});
18+
final _Type _type;
19+
20+
AddLate({required super.context}) : _type = _Type.base;
21+
22+
AddLate.implicitThis({required super.context}) : _type = _Type.implicitThis;
1723

1824
@override
1925
CorrectionApplicability get applicability =>
20-
// TODO(applicability): comment on why.
26+
// TODO(applicability): not necessarily the right thing to do.
2127
CorrectionApplicability.singleLocation;
2228

29+
@override
30+
AssistKind? get assistKind => DartAssistKind.ADD_LATE;
31+
2332
@override
2433
FixKind get fixKind => DartFixKind.ADD_LATE;
2534

2635
@override
2736
Future<void> compute(ChangeBuilder builder) async {
28-
var node = this.node;
37+
AstNode? node = this.node;
38+
if (_type == _Type.implicitThis) {
39+
node = node.thisOrAncestorOfType<VariableDeclaration>();
40+
}
2941
if (node is VariableDeclaration) {
3042
var variableList = node.parent;
3143
if (variableList is VariableDeclarationList) {
@@ -34,15 +46,8 @@ class AddLate extends ResolvedCorrectionProducer {
3446
var keyword = variableList.keyword;
3547
if (keyword == null) {
3648
await _insertAt(builder, variableList.variables[0].offset);
37-
// TODO(brianwilkerson): Consider converting this into an assist and
38-
// expand it to support converting `var` to `late` as well as
39-
// working anywhere a non-late local variableElement or field is selected.
40-
// } else if (keyword.type == Keyword.VAR) {
41-
// builder.addFileEdit(file, (builder) {
42-
// builder.addSimpleReplacement(range.token(keyword), 'late');
43-
// });
4449
} else if (keyword.type != Keyword.CONST) {
45-
await _insertAt(builder, variableList.variables[0].offset);
50+
await _insertAt(builder, variableList.offset);
4651
}
4752
} else {
4853
var keyword = variableList.keyword;
@@ -105,3 +110,5 @@ class AddLate extends ResolvedCorrectionProducer {
105110
});
106111
}
107112
}
113+
114+
enum _Type { base, implicitThis }

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

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:analysis_server/src/services/correction/assist.dart';
66
import 'package:analysis_server/src/services/correction/fix.dart';
77
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
88
import 'package:analyzer/dart/ast/ast.dart';
9+
import 'package:analyzer/dart/element/type.dart';
910
import 'package:analyzer/src/utilities/extensions/ast.dart';
1011
import 'package:analyzer_plugin/utilities/assist/assist.dart';
1112
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -14,12 +15,15 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
1415

1516
class ConvertIntoGetter extends ResolvedCorrectionProducer {
1617
String _memberName = '';
18+
final _Type _type;
1719

18-
ConvertIntoGetter({required super.context});
20+
ConvertIntoGetter({required super.context}) : _type = _Type.base;
21+
ConvertIntoGetter.implicitThis({required super.context})
22+
: _type = _Type.implicitThis;
1923

2024
@override
2125
CorrectionApplicability get applicability =>
22-
// TODO(applicability): comment on why.
26+
// TODO(applicability): not necessarily the right thing to do.
2327
CorrectionApplicability.singleLocation;
2428

2529
@override
@@ -38,19 +42,23 @@ class ConvertIntoGetter extends ResolvedCorrectionProducer {
3842
Future<void> compute(ChangeBuilder builder) async {
3943
// Find the enclosing field declaration.
4044
FieldDeclaration? fieldDeclaration;
41-
for (var n in node.withParents) {
42-
if (n is FieldDeclaration) {
43-
fieldDeclaration = n;
45+
if (_type == _Type.implicitThis) {
46+
fieldDeclaration = node.thisOrAncestorOfType();
47+
} else {
48+
for (var n in node.withParents) {
49+
if (n is FieldDeclaration) {
50+
fieldDeclaration = n;
51+
break;
52+
}
53+
if (n is SimpleIdentifier ||
54+
n is VariableDeclaration ||
55+
n is VariableDeclarationList ||
56+
n is TypeAnnotation ||
57+
n is TypeArgumentList) {
58+
continue;
59+
}
4460
break;
4561
}
46-
if (n is SimpleIdentifier ||
47-
n is VariableDeclaration ||
48-
n is VariableDeclarationList ||
49-
n is TypeAnnotation ||
50-
n is TypeArgumentList) {
51-
continue;
52-
}
53-
break;
5462
}
5563
if (fieldDeclaration == null) {
5664
return;
@@ -68,12 +76,7 @@ class ConvertIntoGetter extends ResolvedCorrectionProducer {
6876
// Prepare the initializer.
6977
var initializer = field.initializer;
7078
// Add proposal.
71-
var code = '';
72-
var typeAnnotation = fieldList.type;
73-
if (typeAnnotation != null) {
74-
code += '${utils.getNodeText(typeAnnotation)} ';
75-
}
76-
code += 'get';
79+
var code = 'get';
7780
code += ' ${field.name.lexeme}';
7881
code += ' => ';
7982

@@ -83,9 +86,26 @@ class ConvertIntoGetter extends ResolvedCorrectionProducer {
8386
fieldList.type ??
8487
field.name;
8588

89+
var writeType = getCodeStyleOptions(unitResult.file).specifyReturnTypes;
8690
var replacementRange = range.startEnd(startingKeyword, fieldDeclaration);
8791
await builder.addDartFileEdit(file, (builder) {
8892
builder.addReplacement(replacementRange, (builder) {
93+
if (fieldList.type?.type case var type) {
94+
if (type == null || type is DynamicType) {
95+
type = initializer?.staticType;
96+
}
97+
if (type is InvalidType) {
98+
type = typeProvider.dynamicType;
99+
}
100+
if ((type != null && type is! DynamicType) || writeType) {
101+
builder.writeType(
102+
type,
103+
shouldWriteDynamic: writeType,
104+
required: writeType,
105+
);
106+
builder.write(' ');
107+
}
108+
}
89109
builder.write(code);
90110
if (initializer == null) {
91111
builder.addSimpleLinkedEdit('initializer', 'null');
@@ -97,3 +117,5 @@ class ConvertIntoGetter extends ResolvedCorrectionProducer {
97117
});
98118
}
99119
}
120+
121+
enum _Type { base, implicitThis }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS:
834834
CompileTimeErrorCode.IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER:
835835
status: hasFix
836836
CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER:
837-
status: noFix
837+
status: hasFix
838838
CompileTimeErrorCode.IMPLICIT_SUPER_INITIALIZER_MISSING_ARGUMENTS:
839839
status: hasFix
840840
CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,10 @@ final _builtInNonLintGenerators = <DiagnosticCode, List<ProducerGenerator>>{
726726
CompileTimeErrorCode.IMPLICIT_SUPER_INITIALIZER_MISSING_ARGUMENTS: [
727727
AddSuperParameter.new,
728728
],
729+
CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER: [
730+
ConvertIntoGetter.implicitThis,
731+
AddLate.implicitThis,
732+
],
729733
CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY: [RemoveUnusedImport.new],
730734
CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY: [RemoveUnusedImport.new],
731735
CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD: [
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analysis_server/src/services/correction/assist.dart';
6+
import 'package:analyzer_plugin/utilities/assist/assist.dart';
7+
import 'package:test_reflective_loader/test_reflective_loader.dart';
8+
9+
import 'assist_processor.dart';
10+
11+
void main() {
12+
defineReflectiveSuite(() {
13+
defineReflectiveTests(AddLateTest);
14+
});
15+
}
16+
17+
@reflectiveTest
18+
class AddLateTest extends AssistProcessorTest {
19+
@override
20+
AssistKind get kind => DartAssistKind.ADD_LATE;
21+
22+
Future<void> test_field_const() async {
23+
verifyNoTestUnitErrors = false;
24+
await resolveTestCode('''
25+
class C {
26+
const ^s = '';
27+
}
28+
''');
29+
await assertNoAssist();
30+
}
31+
32+
Future<void> test_field_final() async {
33+
await resolveTestCode('''
34+
class C {
35+
final s^ = '';
36+
}
37+
''');
38+
await assertHasAssist('''
39+
class C {
40+
late final s = '';
41+
}
42+
''');
43+
}
44+
45+
Future<void> test_field_finalType() async {
46+
await resolveTestCode('''
47+
class C {
48+
final String s^ = '';
49+
}
50+
''');
51+
await assertHasAssist('''
52+
class C {
53+
late final String s = '';
54+
}
55+
''');
56+
}
57+
58+
Future<void> test_field_type() async {
59+
await resolveTestCode('''
60+
class C {
61+
String s^ = '';
62+
}
63+
''');
64+
await assertHasAssist('''
65+
class C {
66+
late String s = '';
67+
}
68+
''');
69+
}
70+
71+
Future<void> test_field_var() async {
72+
await resolveTestCode('''
73+
class C {
74+
var s^;
75+
}
76+
''');
77+
await assertHasAssist('''
78+
class C {
79+
late var s;
80+
}
81+
''');
82+
}
83+
84+
Future<void> test_local() async {
85+
await resolveTestCode('''
86+
void foo() {
87+
String ^s;
88+
}
89+
''');
90+
await assertHasAssist('''
91+
void foo() {
92+
late String s;
93+
}
94+
''');
95+
}
96+
}

0 commit comments

Comments
 (0)