OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library services.completion.dart.manager; | 5 library services.completion.dart.manager; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
10 import 'package:analysis_server/src/provisional/completion/completion_core.dart' | 10 import 'package:analysis_server/src/provisional/completion/completion_core.dart' |
(...skipping 13 matching lines...) Expand all Loading... |
24 import 'package:analyzer/src/task/dart.dart'; | 24 import 'package:analyzer/src/task/dart.dart'; |
25 import 'package:analyzer/task/dart.dart'; | 25 import 'package:analyzer/task/dart.dart'; |
26 | 26 |
27 /** | 27 /** |
28 * [DartCompletionManager] determines if a completion request is Dart specific | 28 * [DartCompletionManager] determines if a completion request is Dart specific |
29 * and forwards those requests to all [DartCompletionContributor]s. | 29 * and forwards those requests to all [DartCompletionContributor]s. |
30 */ | 30 */ |
31 class DartCompletionManager implements CompletionContributor { | 31 class DartCompletionManager implements CompletionContributor { |
32 @override | 32 @override |
33 Future<List<CompletionSuggestion>> computeSuggestions( | 33 Future<List<CompletionSuggestion>> computeSuggestions( |
34 CompletionRequest request) { | 34 CompletionRequest request) async { |
35 if (AnalysisEngine.isDartFileName(request.source.shortName)) { | 35 if (!AnalysisEngine.isDartFileName(request.source.shortName)) { |
36 return _computeDartSuggestions( | 36 return EMPTY_LIST; |
37 new DartCompletionRequestImpl.forRequest(request)); | |
38 } | 37 } |
39 return new Future.value(); | |
40 } | |
41 | 38 |
42 /** | |
43 * Return a [Future] that completes with a list of suggestions | |
44 * for the given completion [request]. | |
45 */ | |
46 Future<List<CompletionSuggestion>> _computeDartSuggestions( | |
47 DartCompletionRequest request) async { | |
48 // Request Dart specific completions from each contributor | 39 // Request Dart specific completions from each contributor |
| 40 DartCompletionRequestImpl dartRequest = |
| 41 await DartCompletionRequestImpl.from(request); |
49 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; | 42 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; |
50 for (DartCompletionContributor c in dartCompletionPlugin.contributors) { | 43 for (DartCompletionContributor c in dartCompletionPlugin.contributors) { |
51 suggestions.addAll(await c.computeSuggestions(request)); | 44 suggestions.addAll(await c.computeSuggestions(dartRequest)); |
52 } | 45 } |
53 return suggestions; | 46 return suggestions; |
54 } | 47 } |
55 } | 48 } |
56 | 49 |
57 /** | 50 /** |
58 * The information about a requested list of completions within a Dart file. | 51 * The information about a requested list of completions within a Dart file. |
59 */ | 52 */ |
60 class DartCompletionRequestImpl extends CompletionRequestImpl | 53 class DartCompletionRequestImpl extends CompletionRequestImpl |
61 implements DartCompletionRequest { | 54 implements DartCompletionRequest { |
62 /** | 55 /** |
63 * The source for the library containing the completion request. | 56 * Return a [Future] that completes with a newly created completion request |
64 * This may be different from the source in which the completion is requested | 57 * based on the given [request]. |
65 * if the completion is being requested in a part file. | |
66 * This may be `null` if the library for a part file cannot be determined. | |
67 */ | 58 */ |
68 Source _librarySource; | 59 static Future<DartCompletionRequest> from(CompletionRequest request) async { |
| 60 Source source = request.source; |
| 61 AnalysisContext context = request.context; |
| 62 CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT); |
| 63 |
| 64 Source libSource; |
| 65 if (unit.directives.any((d) => d is PartOfDirective)) { |
| 66 List<Source> libraries = context.getLibrariesContaining(source); |
| 67 if (libraries.isNotEmpty) { |
| 68 libSource = libraries[0]; |
| 69 } |
| 70 } else { |
| 71 libSource = source; |
| 72 } |
| 73 |
| 74 // Most (all?) contributors need declarations in scope to be resolved |
| 75 if (libSource != null) { |
| 76 unit = await new AnalysisFutureHelper<CompilationUnit>(context, |
| 77 new LibrarySpecificUnit(libSource, source), RESOLVED_UNIT3) |
| 78 .computeAsync(); |
| 79 } |
| 80 |
| 81 return new DartCompletionRequestImpl._( |
| 82 request.context, |
| 83 request.resourceProvider, |
| 84 request.searchEngine, |
| 85 libSource, |
| 86 request.source, |
| 87 request.offset, |
| 88 unit); |
| 89 } |
| 90 |
| 91 DartCompletionRequestImpl._( |
| 92 AnalysisContext context, |
| 93 ResourceProvider resourceProvider, |
| 94 SearchEngine searchEngine, |
| 95 this.librarySource, |
| 96 Source source, |
| 97 int offset, |
| 98 CompilationUnit unit) |
| 99 : super(context, resourceProvider, searchEngine, source, offset) { |
| 100 _updateTargets(unit); |
| 101 } |
69 | 102 |
70 /** | 103 /** |
71 * The [DartType] for Object in dart:core | 104 * The [DartType] for Object in dart:core |
72 */ | 105 */ |
73 InterfaceType _objectType; | 106 InterfaceType _objectType; |
74 | 107 |
75 /** | |
76 * `true` if [resolveDeclarationsInScope] has partially resolved the unit | |
77 * referenced by [target], else `false`. | |
78 */ | |
79 bool _haveResolveDeclarationsInScope = false; | |
80 | |
81 @override | 108 @override |
82 Expression dotTarget; | 109 Expression dotTarget; |
83 | 110 |
84 @override | 111 @override |
| 112 Source librarySource; |
| 113 |
| 114 @override |
85 CompletionTarget target; | 115 CompletionTarget target; |
86 | 116 |
87 /** | |
88 * Initialize a newly created completion request based on the given request. | |
89 */ | |
90 factory DartCompletionRequestImpl.forRequest(CompletionRequest request) { | |
91 return new DartCompletionRequestImpl._( | |
92 request.context, | |
93 request.resourceProvider, | |
94 request.searchEngine, | |
95 request.source, | |
96 request.offset); | |
97 } | |
98 | |
99 DartCompletionRequestImpl._( | |
100 AnalysisContext context, | |
101 ResourceProvider resourceProvider, | |
102 SearchEngine searchEngine, | |
103 Source source, | |
104 int offset) | |
105 : super(context, resourceProvider, searchEngine, source, offset) { | |
106 _updateTargets(context.computeResult(source, PARSED_UNIT)); | |
107 if (target.unit.directives.any((d) => d is PartOfDirective)) { | |
108 List<Source> libraries = context.getLibrariesContaining(source); | |
109 if (libraries.isNotEmpty) { | |
110 _librarySource = libraries[0]; | |
111 } | |
112 } else { | |
113 _librarySource = source; | |
114 } | |
115 } | |
116 | |
117 @override | 117 @override |
118 Future<LibraryElement> get libraryElement async { | 118 Future<LibraryElement> get libraryElement async { |
119 //TODO(danrubel) build the library element rather than all the declarations | 119 //TODO(danrubel) build the library element rather than all the declarations |
120 CompilationUnit unit = await resolveDeclarationsInScope(); | 120 CompilationUnit unit = target.unit; |
121 if (unit != null) { | 121 if (unit != null) { |
122 CompilationUnitElement elem = unit.element; | 122 CompilationUnitElement elem = unit.element; |
123 if (elem != null) { | 123 if (elem != null) { |
124 return elem.library; | 124 return elem.library; |
125 } | 125 } |
126 } | 126 } |
127 return null; | 127 return null; |
128 } | 128 } |
129 | 129 |
130 @override | 130 @override |
131 InterfaceType get objectType { | 131 InterfaceType get objectType { |
132 if (_objectType == null) { | 132 if (_objectType == null) { |
133 Source coreUri = context.sourceFactory.forUri('dart:core'); | 133 Source coreUri = context.sourceFactory.forUri('dart:core'); |
134 LibraryElement coreLib = context.getLibraryElement(coreUri); | 134 LibraryElement coreLib = context.getLibraryElement(coreUri); |
135 _objectType = coreLib.getType('Object').type; | 135 _objectType = coreLib.getType('Object').type; |
136 } | 136 } |
137 return _objectType; | 137 return _objectType; |
138 } | 138 } |
139 | 139 |
140 @override | 140 @override |
141 Future<CompilationUnit> resolveDeclarationsInScope() async { | |
142 CompilationUnit unit = target.unit; | |
143 if (_haveResolveDeclarationsInScope) { | |
144 return unit; | |
145 } | |
146 | |
147 // Gracefully degrade if librarySource cannot be determined | |
148 if (_librarySource == null) { | |
149 return null; | |
150 } | |
151 | |
152 // Resolve declarations in the target unit | |
153 CompilationUnit resolvedUnit = | |
154 await new AnalysisFutureHelper<CompilationUnit>(context, | |
155 new LibrarySpecificUnit(_librarySource, source), RESOLVED_UNIT3) | |
156 .computeAsync(); | |
157 | |
158 // TODO(danrubel) determine if the underlying source has been modified | |
159 // in a way that invalidates the completion request | |
160 // and return null | |
161 | |
162 // Gracefully degrade if unit cannot be resolved | |
163 if (resolvedUnit == null) { | |
164 return null; | |
165 } | |
166 | |
167 // Recompute the target for the newly resolved unit | |
168 _updateTargets(resolvedUnit); | |
169 _haveResolveDeclarationsInScope = true; | |
170 return resolvedUnit; | |
171 } | |
172 | |
173 @override | |
174 Future<List<Directive>> resolveDirectives() async { | 141 Future<List<Directive>> resolveDirectives() async { |
175 CompilationUnit libUnit; | 142 CompilationUnit libUnit; |
176 if (_librarySource == source) { | 143 if (librarySource == source) { |
177 libUnit = await resolveDeclarationsInScope(); | 144 libUnit = target.unit; |
178 } else if (_librarySource != null) { | 145 } else if (librarySource != null) { |
| 146 // TODO(danrubel) only resolve the directives |
179 libUnit = await new AnalysisFutureHelper<CompilationUnit>( | 147 libUnit = await new AnalysisFutureHelper<CompilationUnit>( |
180 context, | 148 context, |
181 new LibrarySpecificUnit(_librarySource, _librarySource), | 149 new LibrarySpecificUnit(librarySource, librarySource), |
182 RESOLVED_UNIT3) | 150 RESOLVED_UNIT3) |
183 .computeAsync(); | 151 .computeAsync(); |
184 } | 152 } |
185 return libUnit?.directives; | 153 return libUnit?.directives; |
186 } | 154 } |
187 | 155 |
188 @override | 156 @override |
189 Future resolveExpression(Expression expression) async { | 157 Future resolveExpression(Expression expression) async { |
190 //TODO(danrubel) resolve the expression or containing method | 158 // Return immediately if the expression has already been resolved |
191 // rather than the entire complilation unit | 159 if (expression.propagatedType != null) { |
| 160 return; |
| 161 } |
192 | 162 |
193 // Gracefully degrade if librarySource cannot be determined | 163 // Gracefully degrade if librarySource cannot be determined |
194 if (_librarySource == null) { | 164 if (librarySource == null) { |
195 return null; | 165 return; |
196 } | 166 } |
197 | 167 |
198 // Resolve declarations in the target unit | 168 // Resolve declarations in the target unit |
| 169 // TODO(danrubel) resolve the expression or containing method |
| 170 // rather than the entire complilation unit |
199 CompilationUnit resolvedUnit = | 171 CompilationUnit resolvedUnit = |
200 await new AnalysisFutureHelper<CompilationUnit>(context, | 172 await new AnalysisFutureHelper<CompilationUnit>(context, |
201 new LibrarySpecificUnit(_librarySource, source), RESOLVED_UNIT) | 173 new LibrarySpecificUnit(librarySource, source), RESOLVED_UNIT) |
202 .computeAsync(); | 174 .computeAsync(); |
203 | 175 |
204 // TODO(danrubel) determine if the underlying source has been modified | 176 // TODO(danrubel) determine if the underlying source has been modified |
205 // in a way that invalidates the completion request | 177 // in a way that invalidates the completion request |
206 // and return null | 178 // and return null |
207 | 179 |
208 // Gracefully degrade if unit cannot be resolved | 180 // Gracefully degrade if unit cannot be resolved |
209 if (resolvedUnit == null) { | 181 if (resolvedUnit == null) { |
210 return null; | 182 return; |
211 } | 183 } |
212 | 184 |
213 // Recompute the target for the newly resolved unit | 185 // Recompute the target for the newly resolved unit |
214 _updateTargets(resolvedUnit); | 186 _updateTargets(resolvedUnit); |
215 _haveResolveDeclarationsInScope = true; | |
216 } | 187 } |
217 | 188 |
218 /** | 189 /** |
219 * Update the completion [target] and [dotTarget] based on the given [unit]. | 190 * Update the completion [target] and [dotTarget] based on the given [unit]. |
220 */ | 191 */ |
221 void _updateTargets(CompilationUnit unit) { | 192 void _updateTargets(CompilationUnit unit) { |
222 dotTarget = null; | 193 dotTarget = null; |
223 target = new CompletionTarget.forOffset(unit, offset); | 194 target = new CompletionTarget.forOffset(unit, offset); |
224 AstNode node = target.containingNode; | 195 AstNode node = target.containingNode; |
225 if (node is MethodInvocation) { | 196 if (node is MethodInvocation) { |
(...skipping 10 matching lines...) Expand all Loading... |
236 dotTarget = node.realTarget; | 207 dotTarget = node.realTarget; |
237 } | 208 } |
238 } | 209 } |
239 if (node is PrefixedIdentifier) { | 210 if (node is PrefixedIdentifier) { |
240 if (identical(node.identifier, target.entity)) { | 211 if (identical(node.identifier, target.entity)) { |
241 dotTarget = node.prefix; | 212 dotTarget = node.prefix; |
242 } | 213 } |
243 } | 214 } |
244 } | 215 } |
245 } | 216 } |
OLD | NEW |