| 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 |