Skip to content

Commit e0d6fd0

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Completion. Issue 35449. Don't suggest @Protected instance members when not available.
Bug: #35449 Change-Id: Ie8d0b3ba354addbf42d2a4efe9c4dbf318e6c659 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358120 Reviewed-by: Keerti Parthasarathy <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 87473f8 commit e0d6fd0

File tree

2 files changed

+363
-2
lines changed

2 files changed

+363
-2
lines changed

pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,10 +662,9 @@ class DeclarationHelper {
662662
? request.inheritanceManager.getInheritedConcreteMap2(type.element)
663663
: request.inheritanceManager.getInterface(type.element).map;
664664

665-
var library = request.libraryElement;
666665
var membersByName = <String, List<ExecutableElement>>{};
667666
for (var rawMember in map.values) {
668-
if (!rawMember.isStatic && rawMember.isAccessibleIn(library)) {
667+
if (_canAccessInstanceMember(rawMember)) {
669668
var name = rawMember.displayName;
670669
membersByName
671670
.putIfAbsent(name, () => <ExecutableElement>[])
@@ -1020,6 +1019,38 @@ class DeclarationHelper {
10201019
}
10211020
}
10221021

1022+
bool _canAccessInstanceMember(ExecutableElement element) {
1023+
if (element.isStatic) {
1024+
return false;
1025+
}
1026+
1027+
var requestLibrary = request.libraryElement;
1028+
if (!element.isAccessibleIn(requestLibrary)) {
1029+
return false;
1030+
}
1031+
1032+
if (element.isProtected) {
1033+
var elementInterface = element.enclosingElement;
1034+
if (elementInterface is! InterfaceElement) {
1035+
return false;
1036+
}
1037+
1038+
if (elementInterface.library != requestLibrary) {
1039+
var contextInterface = request.target.enclosingInterfaceElement;
1040+
if (contextInterface == null) {
1041+
return false;
1042+
}
1043+
1044+
var contextType = contextInterface.thisType;
1045+
if (contextType.asInstanceOf(elementInterface) == null) {
1046+
return false;
1047+
}
1048+
}
1049+
}
1050+
1051+
return true;
1052+
}
1053+
10231054
/// Returns `true` if the [identifier] is composed of one or more underscore
10241055
/// characters and nothing else.
10251056
bool _isUnused(String identifier) => UnusedIdentifier.hasMatch(identifier);
@@ -1695,3 +1726,25 @@ extension on PropertyAccessorElement {
16951726
return false;
16961727
}
16971728
}
1729+
1730+
extension on ExecutableElement {
1731+
bool get isProtected {
1732+
final self = this;
1733+
if (self is PropertyAccessorElement &&
1734+
self.enclosingElement is InterfaceElement) {
1735+
if (self.hasProtected) {
1736+
return true;
1737+
}
1738+
var variable = self.variable2;
1739+
if (variable != null && variable.hasProtected) {
1740+
return true;
1741+
}
1742+
}
1743+
if (self is MethodElement &&
1744+
self.enclosingElement is InterfaceElement &&
1745+
self.hasProtected) {
1746+
return true;
1747+
}
1748+
return false;
1749+
}
1750+
}

pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,314 @@ class A { foo() {int x; x.^}}
171171
''');
172172
assertResponse(r'''
173173
suggestions
174+
''');
175+
}
176+
177+
Future<void> test_isProtected_field_otherLibrary_function() async {
178+
writeTestPackageConfig(
179+
meta: true,
180+
);
181+
182+
newFile('$testPackageLibPath/a.dart', r'''
183+
import 'package:meta/meta.dart';
184+
185+
class A {
186+
int f01 = 0;
187+
188+
@protected
189+
int f02 = 0;
190+
}
191+
''');
192+
193+
await computeSuggestions('''
194+
import 'a.dart';
195+
196+
void f(A a) {
197+
a.^
198+
}
199+
''');
200+
201+
assertResponse(r'''
202+
suggestions
203+
f01
204+
kind: field
205+
''');
206+
}
207+
208+
Future<void> test_isProtected_field_sameLibrary_function() async {
209+
writeTestPackageConfig(
210+
meta: true,
211+
);
212+
213+
await computeSuggestions('''
214+
import 'package:meta/meta.dart';
215+
216+
class A {
217+
int f01 = 0;
218+
219+
@protected
220+
int f02 = 0;
221+
}
222+
223+
void f(A a) {
224+
a.^
225+
}
226+
''');
227+
228+
assertResponse(r'''
229+
suggestions
230+
f01
231+
kind: field
232+
f02
233+
kind: field
234+
''');
235+
}
236+
237+
Future<void> test_isProtected_getter_otherLibrary_function() async {
238+
writeTestPackageConfig(
239+
meta: true,
240+
);
241+
242+
newFile('$testPackageLibPath/a.dart', r'''
243+
import 'package:meta/meta.dart';
244+
245+
class A {
246+
int get f01 => 0;
247+
248+
@protected
249+
int get f02 => 0;
250+
}
251+
''');
252+
253+
await computeSuggestions('''
254+
import 'a.dart';
255+
256+
void f(A a) {
257+
a.^
258+
}
259+
''');
260+
261+
assertResponse(r'''
262+
suggestions
263+
f01
264+
kind: getter
265+
''');
266+
}
267+
268+
Future<void> test_isProtected_getter_sameLibrary_function() async {
269+
writeTestPackageConfig(
270+
meta: true,
271+
);
272+
273+
await computeSuggestions('''
274+
import 'package:meta/meta.dart';
275+
276+
class A {
277+
int get f01 => 0;
278+
279+
@protected
280+
int get f02 => 0;
281+
}
282+
283+
void f(A a) {
284+
a.^
285+
}
286+
''');
287+
288+
assertResponse(r'''
289+
suggestions
290+
f01
291+
kind: getter
292+
f02
293+
kind: getter
294+
''');
295+
}
296+
297+
Future<void> test_isProtected_method_otherLibrary_class_notSubtype() async {
298+
writeTestPackageConfig(
299+
meta: true,
300+
);
301+
302+
newFile('$testPackageLibPath/a.dart', r'''
303+
import 'package:meta/meta.dart';
304+
305+
class A {
306+
void f01() {}
307+
308+
@protected
309+
void f02() {}
310+
}
311+
''');
312+
313+
await computeSuggestions('''
314+
import 'a.dart';
315+
316+
class B {
317+
void foo(A a) {
318+
a.^
319+
}
320+
}
321+
''');
322+
323+
assertResponse(r'''
324+
suggestions
325+
f01
326+
kind: methodInvocation
327+
''');
328+
}
329+
330+
Future<void> test_isProtected_method_otherLibrary_class_subtype() async {
331+
writeTestPackageConfig(
332+
meta: true,
333+
);
334+
335+
newFile('$testPackageLibPath/a.dart', r'''
336+
import 'package:meta/meta.dart';
337+
338+
class A {
339+
void f01() {}
340+
341+
@protected
342+
void f02() {}
343+
}
344+
''');
345+
346+
await computeSuggestions('''
347+
import 'a.dart';
348+
349+
class B extends A {
350+
void foo() {
351+
this.^
352+
}
353+
}
354+
''');
355+
356+
assertResponse(r'''
357+
suggestions
358+
f01
359+
kind: methodInvocation
360+
f02
361+
kind: methodInvocation
362+
''');
363+
}
364+
365+
Future<void> test_isProtected_method_otherLibrary_function() async {
366+
writeTestPackageConfig(
367+
meta: true,
368+
);
369+
370+
newFile('$testPackageLibPath/a.dart', r'''
371+
import 'package:meta/meta.dart';
372+
373+
class A {
374+
void f01() {}
375+
376+
@protected
377+
void f02() {}
378+
}
379+
''');
380+
381+
await computeSuggestions('''
382+
import 'a.dart';
383+
384+
void f(A a) {
385+
a.^
386+
}
387+
''');
388+
389+
assertResponse(r'''
390+
suggestions
391+
f01
392+
kind: methodInvocation
393+
''');
394+
}
395+
396+
Future<void> test_isProtected_method_sameLibrary_function() async {
397+
writeTestPackageConfig(
398+
meta: true,
399+
);
400+
401+
await computeSuggestions('''
402+
import 'package:meta/meta.dart';
403+
404+
class A {
405+
void f01() {}
406+
407+
@protected
408+
void f02() {}
409+
}
410+
411+
void f(A a) {
412+
a.^
413+
}
414+
''');
415+
416+
assertResponse(r'''
417+
suggestions
418+
f01
419+
kind: methodInvocation
420+
f02
421+
kind: methodInvocation
422+
''');
423+
}
424+
425+
Future<void> test_isProtected_setter_otherLibrary_function() async {
426+
writeTestPackageConfig(
427+
meta: true,
428+
);
429+
430+
newFile('$testPackageLibPath/a.dart', r'''
431+
import 'package:meta/meta.dart';
432+
433+
class A {
434+
set f01(int _) {}
435+
436+
@protected
437+
set f02(int _) {}
438+
}
439+
''');
440+
441+
await computeSuggestions('''
442+
import 'a.dart';
443+
444+
void f(A a) {
445+
a.^
446+
}
447+
''');
448+
449+
assertResponse(r'''
450+
suggestions
451+
f01
452+
kind: setter
453+
''');
454+
}
455+
456+
Future<void> test_isProtected_setter_sameLibrary_function() async {
457+
writeTestPackageConfig(
458+
meta: true,
459+
);
460+
461+
await computeSuggestions('''
462+
import 'package:meta/meta.dart';
463+
464+
class A {
465+
set f01(int _) {}
466+
467+
@protected
468+
set f02(int _) {}
469+
}
470+
471+
void f(A a) {
472+
a.^
473+
}
474+
''');
475+
476+
assertResponse(r'''
477+
suggestions
478+
f01
479+
kind: setter
480+
f02
481+
kind: setter
174482
''');
175483
}
176484
}

0 commit comments

Comments
 (0)