Skip to content

Commit e8413cd

Browse files
bwilkersoncommit-bot@chromium.org
authored andcommitted
Add a fix to allow unqualified references to static members to be qualified.
Change-Id: Iecc08f6ed05509ff170c3276c89bfbaf1406a437 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117165 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent d0052c1 commit e8413cd

File tree

4 files changed

+295
-1
lines changed

4 files changed

+295
-1
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ class DartFixKind {
266266
"Move type arguments to after class name");
267267
static const MAKE_VARIABLE_NOT_FINAL = const FixKind(
268268
'MAKE_VARIABLE_NOT_FINAL', 50, "Make variable '{0}' not final");
269+
static const QUALIFY_REFERENCE =
270+
const FixKind('QUALIFY_REFERENCE', 50, "Use '{0}'");
269271
static const REMOVE_ANNOTATION =
270272
const FixKind('REMOVE_ANNOTATION', 50, "Remove the '{0}' annotation");
271273
static const REMOVE_AWAIT = const FixKind('REMOVE_AWAIT', 50, "Remove await");

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

+48
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,22 @@ class FixProcessor extends BaseProcessor {
566566
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER) {
567567
await _addFix_replaceWithExtensionName();
568568
}
569+
if (errorCode ==
570+
CompileTimeErrorCode
571+
.UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE) {
572+
await _addFix_qualifyReference();
573+
// TODO(brianwilkerson) Consider adding fixes to create a field, getter,
574+
// method or setter. The existing _addFix methods would need to be
575+
// updated so that only the appropriate subset is generated.
576+
}
577+
if (errorCode ==
578+
StaticTypeWarningCode
579+
.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER) {
580+
await _addFix_qualifyReference();
581+
// TODO(brianwilkerson) Consider adding fixes to create a field, getter,
582+
// method or setter. The existing _addFix methods would need to be
583+
// updated so that only the appropriate subset is generated.
584+
}
569585
// lints
570586
if (errorCode is LintCode) {
571587
String name = errorCode.name;
@@ -3035,6 +3051,38 @@ class FixProcessor extends BaseProcessor {
30353051
_addFixFromBuilder(changeBuilder, DartFixKind.ADD_NE_NULL);
30363052
}
30373053

3054+
Future<void> _addFix_qualifyReference() async {
3055+
if (node is! SimpleIdentifier) {
3056+
return;
3057+
}
3058+
SimpleIdentifier memberName = node;
3059+
AstNode parent = node.parent;
3060+
AstNode target = null;
3061+
if (parent is MethodInvocation && node == parent.methodName) {
3062+
target = parent.target;
3063+
} else if (parent is PropertyAccess && node == parent.propertyName) {
3064+
target = parent.target;
3065+
}
3066+
if (target != null) {
3067+
return;
3068+
}
3069+
Element enclosingElement = memberName.staticElement.enclosingElement;
3070+
if (enclosingElement.library != unitLibraryElement) {
3071+
// TODO(brianwilkerson) Support qualifying references to members defined
3072+
// in other libraries. `DartEditBuilder` currently defines the method
3073+
// `writeType`, which is close, but we also need to handle extensions,
3074+
// which don't have a type.
3075+
return;
3076+
}
3077+
String containerName = enclosingElement.name;
3078+
var changeBuilder = _newDartChangeBuilder();
3079+
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
3080+
builder.addSimpleInsertion(node.offset, '$containerName.');
3081+
});
3082+
_addFixFromBuilder(changeBuilder, DartFixKind.QUALIFY_REFERENCE,
3083+
args: ['$containerName.${memberName.name}']);
3084+
}
3085+
30383086
Future<void> _addFix_removeAnnotation() async {
30393087
void addFix(Annotation node) async {
30403088
if (node == null) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
// Copyright (c) 2019, 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/fix.dart';
6+
import 'package:analyzer/src/dart/analysis/experiments.dart';
7+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import 'fix_processor.dart';
11+
12+
main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(QualifyReferenceTest);
15+
defineReflectiveTests(QualifyReferenceWithExtensionMethodsTest);
16+
});
17+
}
18+
19+
@reflectiveTest
20+
class QualifyReferenceTest extends FixProcessorTest {
21+
@override
22+
FixKind get kind => DartFixKind.QUALIFY_REFERENCE;
23+
24+
test_class_direct() async {
25+
await resolveTestUnit('''
26+
class C {
27+
static void m() {}
28+
}
29+
class D extends C {
30+
void f() {
31+
m();
32+
}
33+
}
34+
''');
35+
await assertHasFix('''
36+
class C {
37+
static void m() {}
38+
}
39+
class D extends C {
40+
void f() {
41+
C.m();
42+
}
43+
}
44+
''');
45+
}
46+
47+
test_class_imported() async {
48+
newFile('/home/test/lib/a.dart', content: '''
49+
class A {
50+
static void m() {}
51+
}
52+
''');
53+
await resolveTestUnit('''
54+
import 'a.dart';
55+
class B extends A {
56+
void f() {
57+
m();
58+
}
59+
}
60+
''');
61+
await assertNoFix();
62+
}
63+
64+
test_class_importedWithPrefix() async {
65+
newFile('/home/test/lib/a.dart', content: '''
66+
class A {
67+
static void m() {}
68+
}
69+
''');
70+
await resolveTestUnit('''
71+
import 'a.dart' as a;
72+
class B extends a.A {
73+
void f() {
74+
m();
75+
}
76+
}
77+
''');
78+
await assertNoFix();
79+
}
80+
81+
test_class_indirect() async {
82+
await resolveTestUnit('''
83+
class A {
84+
static void m() {}
85+
}
86+
class B extends A {}
87+
class C extends B {}
88+
class D extends C {
89+
void f() {
90+
m();
91+
}
92+
}
93+
''');
94+
await assertHasFix('''
95+
class A {
96+
static void m() {}
97+
}
98+
class B extends A {}
99+
class C extends B {}
100+
class D extends C {
101+
void f() {
102+
A.m();
103+
}
104+
}
105+
''');
106+
}
107+
108+
test_class_notImported() async {
109+
newFile('/home/test/lib/a.dart', content: '''
110+
class A {
111+
static void m() {}
112+
}
113+
''');
114+
newFile('/home/test/lib/b.dart', content: '''
115+
import 'a.dart';
116+
class B extends A {}
117+
''');
118+
await resolveTestUnit('''
119+
import 'b.dart';
120+
class C extends B {
121+
void f() {
122+
m();
123+
}
124+
}
125+
''');
126+
await assertNoFix();
127+
}
128+
}
129+
130+
@reflectiveTest
131+
class QualifyReferenceWithExtensionMethodsTest extends QualifyReferenceTest {
132+
@override
133+
void setupResourceProvider() {
134+
super.setupResourceProvider();
135+
createAnalysisOptionsFile(experiments: [EnableString.extension_methods]);
136+
}
137+
138+
test_extension_direct() async {
139+
await resolveTestUnit('''
140+
class C {
141+
static void m() {}
142+
}
143+
extension E on C {
144+
void f() {
145+
m();
146+
}
147+
}
148+
''');
149+
await assertHasFix('''
150+
class C {
151+
static void m() {}
152+
}
153+
extension E on C {
154+
void f() {
155+
C.m();
156+
}
157+
}
158+
''');
159+
}
160+
161+
test_extension_imported() async {
162+
newFile('/home/test/lib/a.dart', content: '''
163+
class A {
164+
static void m() {}
165+
}
166+
''');
167+
await resolveTestUnit('''
168+
import 'a.dart';
169+
extension E on A {
170+
void f() {
171+
m();
172+
}
173+
}
174+
''');
175+
await assertNoFix();
176+
}
177+
178+
test_extension_importedWithPrefix() async {
179+
newFile('/home/test/lib/a.dart', content: '''
180+
class A {
181+
static void m() {}
182+
}
183+
''');
184+
await resolveTestUnit('''
185+
import 'a.dart' as a;
186+
extension E on a.A {
187+
void f() {
188+
m();
189+
}
190+
}
191+
''');
192+
await assertNoFix();
193+
}
194+
195+
test_extension_indirect() async {
196+
await resolveTestUnit('''
197+
class A {
198+
static void m() {}
199+
}
200+
class B extends A {}
201+
class C extends B {}
202+
extension E on C {
203+
void f() {
204+
m();
205+
}
206+
}
207+
''');
208+
await assertHasFix('''
209+
class A {
210+
static void m() {}
211+
}
212+
class B extends A {}
213+
class C extends B {}
214+
extension E on C {
215+
void f() {
216+
A.m();
217+
}
218+
}
219+
''');
220+
}
221+
222+
test_extension_notImported() async {
223+
newFile('/home/test/lib/a.dart', content: '''
224+
class A {
225+
static void m() {}
226+
}
227+
''');
228+
newFile('/home/test/lib/b.dart', content: '''
229+
import 'a.dart';
230+
class B extends A {}
231+
''');
232+
await resolveTestUnit('''
233+
import 'b.dart';
234+
extension E on B {
235+
void f() {
236+
m();
237+
}
238+
}
239+
''');
240+
await assertNoFix();
241+
}
242+
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ import 'make_field_not_final_test.dart' as make_field_not_final;
7676
import 'make_final_test.dart' as make_final;
7777
import 'make_variable_not_final_test.dart' as make_variable_not_final;
7878
import 'move_type_arguments_to_class_test.dart' as move_type_arguments_to_class;
79+
import 'qualify_reference_test.dart' as qualify_reference;
7980
import 'remove_annotation_test.dart' as remove_annotation;
8081
import 'remove_await_test.dart' as remove_await;
8182
import 'remove_dead_code_test.dart' as remove_dead_code;
8283
import 'remove_duplicate_case_test.dart' as remove_duplicate_case;
8384
import 'remove_empty_catch_test.dart' as remove_empty_catch;
8485
import 'remove_empty_constructor_body_test.dart'
8586
as remove_empty_constructor_body;
86-
import 'remove_unused_label_test.dart' as remove_unused_label;
8787
import 'remove_empty_else_test.dart' as remove_empty_else;
8888
import 'remove_empty_statement_test.dart' as remove_empty_statement;
8989
import 'remove_initializer_test.dart' as remove_initializer;
@@ -103,6 +103,7 @@ import 'remove_unnecessary_new_test.dart' as remove_unnecessary_new;
103103
import 'remove_unused_catch_clause_test.dart' as remove_unused_catch_clause;
104104
import 'remove_unused_catch_stack_test.dart' as remove_unused_catch_stack;
105105
import 'remove_unused_import_test.dart' as remove_unused_import;
106+
import 'remove_unused_label_test.dart' as remove_unused_label;
106107
import 'rename_to_camel_case_test.dart' as rename_to_camel_case;
107108
import 'replace_boolean_with_bool_test.dart' as replace_boolean_with_bool;
108109
import 'replace_colon_with_equals_test.dart' as replace_colon_with_equals;
@@ -195,6 +196,7 @@ main() {
195196
make_final.main();
196197
make_variable_not_final.main();
197198
move_type_arguments_to_class.main();
199+
qualify_reference.main();
198200
remove_annotation.main();
199201
remove_await.main();
200202
remove_dead_code.main();

0 commit comments

Comments
 (0)