OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, 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 library services.completion.dart.invocation; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:analysis_server/src/protocol_server.dart' | |
10 show CompletionSuggestion, CompletionSuggestionKind, SourceChange; | |
11 import 'package:analysis_server/src/protocol_server.dart' as protocol | |
12 hide CompletionSuggestion, CompletionSuggestionKind; | |
13 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
; | |
14 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; | |
15 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; | |
16 import 'package:analyzer/dart/element/element.dart'; | |
17 import 'package:analyzer/src/generated/ast.dart'; | |
18 import 'package:analyzer/src/generated/resolver.dart'; | |
19 import 'package:analyzer/src/generated/source.dart'; | |
20 | |
21 /** | |
22 * A completion contributor used to suggest replacing partial identifiers inside | |
23 * a class declaration with templates for inherited members. | |
24 */ | |
25 class InheritedContributor implements DartCompletionContributor { | |
26 @override | |
27 Future<List<CompletionSuggestion>> computeSuggestions( | |
28 DartCompletionRequest request) async { | |
29 SimpleIdentifier targetId = _getTargetId(request.target); | |
30 if (targetId == null) { | |
31 return EMPTY_LIST; | |
32 } | |
33 ClassDeclaration classDecl = | |
34 targetId.getAncestor((p) => p is ClassDeclaration); | |
35 if (classDecl == null) { | |
36 return EMPTY_LIST; | |
37 } | |
38 | |
39 // Generate a collection of inherited members | |
40 ClassElement classElem = classDecl.element; | |
41 InheritanceManager manager = new InheritanceManager(classElem.library); | |
42 MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem); | |
43 List<String> memberNames = _computeMemberNames(map, classElem); | |
44 | |
45 // Build suggestions | |
46 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; | |
47 for (String memberName in memberNames) { | |
48 ExecutableElement element = map.get(memberName); | |
49 // Gracefully degrade if the overridden element has not been resolved. | |
50 if (element.returnType != null) { | |
51 CompletionSuggestion suggestion = | |
52 _buildSuggestion(request, targetId, element); | |
53 if (suggestion != null) { | |
54 suggestions.add(suggestion); | |
55 } | |
56 } | |
57 } | |
58 return suggestions; | |
59 } | |
60 | |
61 /** | |
62 * Return a template for an override of the given [element] in the given | |
63 * [source]. If selected, the template will replace [targetId]. | |
64 */ | |
65 String _buildRepacementText(Source source, SimpleIdentifier targetId, | |
66 CompilationUnit unit, ExecutableElement element) { | |
67 // AnalysisContext context = element.context; | |
68 // Inject partially resolved unit for use by change builder | |
69 // DartChangeBuilder builder = new DartChangeBuilder(context, unit); | |
70 // builder.addFileEdit(source, context.getModificationStamp(source), | |
71 // (DartFileEditBuilder builder) { | |
72 // builder.addReplacement(targetId.offset, targetId.length, | |
73 // (DartEditBuilder builder) { | |
74 // builder.writeOverrideOfInheritedMember(element); | |
75 // }); | |
76 // }); | |
77 // return builder.sourceChange.edits[0].edits[0].replacement.trim(); | |
78 return ''; | |
79 } | |
80 | |
81 /** | |
82 * Build a suggestion to replace [targetId] in the given [unit] | |
83 * with an override of the given [element]. | |
84 */ | |
85 CompletionSuggestion _buildSuggestion(DartCompletionRequest request, | |
86 SimpleIdentifier targetId, ExecutableElement element) { | |
87 String completion = _buildRepacementText( | |
88 request.source, targetId, request.target.unit, element); | |
89 if (completion == null || completion.length == 0) { | |
90 return null; | |
91 } | |
92 CompletionSuggestion suggestion = new CompletionSuggestion( | |
93 CompletionSuggestionKind.IDENTIFIER, | |
94 DART_RELEVANCE_HIGH, | |
95 completion, | |
96 targetId.offset, | |
97 0, | |
98 element.isDeprecated, | |
99 false); | |
100 suggestion.element = protocol.convertElement(element); | |
101 return suggestion; | |
102 } | |
103 | |
104 /** | |
105 * Return a list containing the names of all of the inherited but not | |
106 * implemented members of the class represented by the given [element]. | |
107 * The [map] is used to find all of the members that are inherited. | |
108 */ | |
109 List<String> _computeMemberNames(MemberMap map, ClassElement element) { | |
110 List<String> memberNames = <String>[]; | |
111 int count = map.size; | |
112 for (int i = 0; i < count; i++) { | |
113 String memberName = map.getKey(i); | |
114 if (!_hasMember(element, memberName)) { | |
115 memberNames.add(memberName); | |
116 } | |
117 } | |
118 return memberNames; | |
119 } | |
120 | |
121 /** | |
122 * If the target looks like a partial identifier inside a class declaration | |
123 * then return that identifier, otherwise return `null`. | |
124 */ | |
125 SimpleIdentifier _getTargetId(CompletionTarget target) { | |
126 AstNode node = target.containingNode; | |
127 if (node is ClassDeclaration) { | |
128 Object entity = target.entity; | |
129 if (entity is FieldDeclaration) { | |
130 NodeList<VariableDeclaration> variables = entity.fields.variables; | |
131 if (variables.length == 1) { | |
132 SimpleIdentifier targetId = variables[0].name; | |
133 if (targetId.name.isEmpty) { | |
134 return targetId; | |
135 } | |
136 } | |
137 } | |
138 } | |
139 return null; | |
140 } | |
141 | |
142 /** | |
143 * Return `true` if the given [classElement] directly declares a member with | |
144 * the given [memberName]. | |
145 */ | |
146 bool _hasMember(ClassElement classElement, String memberName) { | |
147 return classElement.getField(memberName) != null || | |
148 classElement.getGetter(memberName) != null || | |
149 classElement.getMethod(memberName) != null || | |
150 classElement.getSetter(memberName) != null; | |
151 } | |
152 } | |
OLD | NEW |