| 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' |
| 11 show CompletionContributor, CompletionRequest; | 11 show CompletionContributor, CompletionRequest; |
| 12 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; | 12 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; |
| 13 import 'package:analysis_server/src/provisional/completion/dart/completion_plugi
n.dart'; | 13 import 'package:analysis_server/src/provisional/completion/dart/completion_plugi
n.dart'; |
| 14 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; | 14 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; |
| 15 import 'package:analysis_server/src/services/completion/completion_core.dart'; | 15 import 'package:analysis_server/src/services/completion/completion_core.dart'; |
| 16 import 'package:analysis_server/src/services/completion/completion_performance.d
art'; | 16 import 'package:analysis_server/src/services/completion/completion_performance.d
art'; |
| 17 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter
.dart'; | 17 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter
.dart'; |
| 18 import 'package:analysis_server/src/services/completion/dart/contribution_sorter
.dart'; | 18 import 'package:analysis_server/src/services/completion/dart/contribution_sorter
.dart'; |
| 19 import 'package:analysis_server/src/services/completion/dart/optype.dart'; | 19 import 'package:analysis_server/src/services/completion/dart/optype.dart'; |
| 20 import 'package:analysis_server/src/services/search/search_engine.dart'; | 20 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 21 import 'package:analyzer/dart/element/element.dart'; | 21 import 'package:analyzer/dart/element/element.dart'; |
| 22 import 'package:analyzer/dart/element/type.dart'; | 22 import 'package:analyzer/dart/element/type.dart'; |
| 23 import 'package:analyzer/file_system/file_system.dart'; | 23 import 'package:analyzer/file_system/file_system.dart'; |
| 24 import 'package:analyzer/src/context/context.dart' | 24 import 'package:analyzer/src/context/context.dart' |
| 25 show AnalysisFutureHelper, AnalysisContextImpl; | 25 show AnalysisFutureHelper, AnalysisContextImpl; |
| 26 import 'package:analyzer/src/generated/ast.dart'; | 26 import 'package:analyzer/src/generated/ast.dart'; |
| 27 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl; | 27 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl; |
| 28 import 'package:analyzer/src/generated/java_engine.dart'; |
| 28 import 'package:analyzer/src/generated/scanner.dart'; | 29 import 'package:analyzer/src/generated/scanner.dart'; |
| 29 import 'package:analyzer/src/generated/source.dart'; | 30 import 'package:analyzer/src/generated/source.dart'; |
| 30 import 'package:analyzer/src/task/dart.dart'; | 31 import 'package:analyzer/src/task/dart.dart'; |
| 31 import 'package:analyzer/task/dart.dart'; | 32 import 'package:analyzer/task/dart.dart'; |
| 33 import 'package:analyzer/task/model.dart'; |
| 32 | 34 |
| 33 /** | 35 /** |
| 34 * [DartCompletionManager] determines if a completion request is Dart specific | 36 * [DartCompletionManager] determines if a completion request is Dart specific |
| 35 * and forwards those requests to all [DartCompletionContributor]s. | 37 * and forwards those requests to all [DartCompletionContributor]s. |
| 36 */ | 38 */ |
| 37 class DartCompletionManager implements CompletionContributor { | 39 class DartCompletionManager implements CompletionContributor { |
| 38 /** | 40 /** |
| 39 * The [contributionSorter] is a long-lived object that isn't allowed | 41 * The [contributionSorter] is a long-lived object that isn't allowed |
| 40 * to maintain state between calls to [DartContributionSorter#sort(...)]. | 42 * to maintain state between calls to [DartContributionSorter#sort(...)]. |
| 41 */ | 43 */ |
| 42 static DartContributionSorter contributionSorter = new CommonUsageSorter(); | 44 static DartContributionSorter contributionSorter = new CommonUsageSorter(); |
| 43 | 45 |
| 44 @override | 46 @override |
| 45 Future<List<CompletionSuggestion>> computeSuggestions( | 47 Future<List<CompletionSuggestion>> computeSuggestions( |
| 46 CompletionRequest request) async { | 48 CompletionRequest request) async { |
| 49 request.checkAborted(); |
| 47 if (!AnalysisEngine.isDartFileName(request.source.shortName)) { | 50 if (!AnalysisEngine.isDartFileName(request.source.shortName)) { |
| 48 return EMPTY_LIST; | 51 return EMPTY_LIST; |
| 49 } | 52 } |
| 50 | 53 |
| 51 CompletionPerformance performance = | 54 CompletionPerformance performance = |
| 52 (request as CompletionRequestImpl).performance; | 55 (request as CompletionRequestImpl).performance; |
| 53 const BUILD_REQUEST_TAG = 'build DartCompletionRequestImpl'; | |
| 54 performance.logStartTime(BUILD_REQUEST_TAG); | |
| 55 DartCompletionRequestImpl dartRequest = | 56 DartCompletionRequestImpl dartRequest = |
| 56 await DartCompletionRequestImpl.from(request); | 57 await DartCompletionRequestImpl.from(request); |
| 57 performance.logElapseTime(BUILD_REQUEST_TAG); | |
| 58 | 58 |
| 59 // Don't suggest in comments. | 59 // Don't suggest in comments. |
| 60 if (dartRequest.target.isCommentText) { | 60 if (dartRequest.target.isCommentText) { |
| 61 return EMPTY_LIST; | 61 return EMPTY_LIST; |
| 62 } | 62 } |
| 63 | 63 |
| 64 ReplacementRange range = | 64 ReplacementRange range = |
| 65 new ReplacementRange.compute(dartRequest.offset, dartRequest.target); | 65 new ReplacementRange.compute(dartRequest.offset, dartRequest.target); |
| 66 (request as CompletionRequestImpl) | 66 (request as CompletionRequestImpl) |
| 67 ..replacementOffset = range.offset | 67 ..replacementOffset = range.offset |
| 68 ..replacementLength = range.length; | 68 ..replacementLength = range.length; |
| 69 | 69 |
| 70 // Request Dart specific completions from each contributor | 70 // Request Dart specific completions from each contributor |
| 71 Map<String, CompletionSuggestion> suggestionMap = | 71 Map<String, CompletionSuggestion> suggestionMap = |
| 72 <String, CompletionSuggestion>{}; | 72 <String, CompletionSuggestion>{}; |
| 73 for (DartCompletionContributor contributor | 73 for (DartCompletionContributor contributor |
| 74 in dartCompletionPlugin.contributors) { | 74 in dartCompletionPlugin.contributors) { |
| 75 String contributorTag = | 75 String contributorTag = |
| 76 'DartCompletionManager - ${contributor.runtimeType}'; | 76 'DartCompletionManager - ${contributor.runtimeType}'; |
| 77 performance.logStartTime(contributorTag); | 77 performance.logStartTime(contributorTag); |
| 78 List<CompletionSuggestion> contributorSuggestions = | 78 List<CompletionSuggestion> contributorSuggestions = |
| 79 await contributor.computeSuggestions(dartRequest); | 79 await contributor.computeSuggestions(dartRequest); |
| 80 performance.logElapseTime(contributorTag); | 80 performance.logElapseTime(contributorTag); |
| 81 request.checkAborted(); |
| 81 | 82 |
| 82 for (CompletionSuggestion newSuggestion in contributorSuggestions) { | 83 for (CompletionSuggestion newSuggestion in contributorSuggestions) { |
| 83 var oldSuggestion = suggestionMap.putIfAbsent( | 84 var oldSuggestion = suggestionMap.putIfAbsent( |
| 84 newSuggestion.completion, () => newSuggestion); | 85 newSuggestion.completion, () => newSuggestion); |
| 85 if (newSuggestion != oldSuggestion && | 86 if (newSuggestion != oldSuggestion && |
| 86 newSuggestion.relevance > oldSuggestion.relevance) { | 87 newSuggestion.relevance > oldSuggestion.relevance) { |
| 87 suggestionMap[newSuggestion.completion] = newSuggestion; | 88 suggestionMap[newSuggestion.completion] = newSuggestion; |
| 88 } | 89 } |
| 89 } | 90 } |
| 90 } | 91 } |
| 91 | 92 |
| 92 // Adjust suggestion relevance before returning | 93 // Adjust suggestion relevance before returning |
| 93 List<CompletionSuggestion> suggestions = suggestionMap.values.toList(); | 94 List<CompletionSuggestion> suggestions = suggestionMap.values.toList(); |
| 94 const SORT_TAG = 'DartCompletionManager - sort'; | 95 const SORT_TAG = 'DartCompletionManager - sort'; |
| 95 performance.logStartTime(SORT_TAG); | 96 performance.logStartTime(SORT_TAG); |
| 96 await contributionSorter.sort(dartRequest, suggestions); | 97 await contributionSorter.sort(dartRequest, suggestions); |
| 97 performance.logElapseTime(SORT_TAG); | 98 performance.logElapseTime(SORT_TAG); |
| 99 request.checkAborted(); |
| 98 return suggestions; | 100 return suggestions; |
| 99 } | 101 } |
| 100 } | 102 } |
| 101 | 103 |
| 102 /** | 104 /** |
| 103 * The information about a requested list of completions within a Dart file. | 105 * The information about a requested list of completions within a Dart file. |
| 104 */ | 106 */ |
| 105 class DartCompletionRequestImpl implements DartCompletionRequest { | 107 class DartCompletionRequestImpl implements DartCompletionRequest { |
| 106 @override | 108 @override |
| 107 final AnalysisContext context; | 109 final AnalysisContext context; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 132 */ | 134 */ |
| 133 LibraryElement _coreLib; | 135 LibraryElement _coreLib; |
| 134 | 136 |
| 135 /** | 137 /** |
| 136 * The [DartType] for Object in dart:core | 138 * The [DartType] for Object in dart:core |
| 137 */ | 139 */ |
| 138 InterfaceType _objectType; | 140 InterfaceType _objectType; |
| 139 | 141 |
| 140 OpType _opType; | 142 OpType _opType; |
| 141 | 143 |
| 144 final CompletionRequest _originalRequest; |
| 145 |
| 142 final CompletionPerformance performance; | 146 final CompletionPerformance performance; |
| 143 | 147 |
| 144 DartCompletionRequestImpl._( | 148 DartCompletionRequestImpl._( |
| 145 this.context, | 149 this.context, |
| 146 this.resourceProvider, | 150 this.resourceProvider, |
| 147 this.searchEngine, | 151 this.searchEngine, |
| 148 this.librarySource, | 152 this.librarySource, |
| 149 this.source, | 153 this.source, |
| 150 this.offset, | 154 this.offset, |
| 151 CompilationUnit unit, | 155 CompilationUnit unit, |
| 156 this._originalRequest, |
| 152 this.performance) { | 157 this.performance) { |
| 153 _updateTargets(unit); | 158 _updateTargets(unit); |
| 154 } | 159 } |
| 155 | 160 |
| 156 @override | 161 @override |
| 157 LibraryElement get coreLib { | 162 LibraryElement get coreLib { |
| 158 if (_coreLib == null) { | 163 if (_coreLib == null) { |
| 159 Source coreUri = context.sourceFactory.forUri('dart:core'); | 164 Source coreUri = context.sourceFactory.forUri('dart:core'); |
| 160 _coreLib = context.computeLibraryElement(coreUri); | 165 _coreLib = context.computeLibraryElement(coreUri); |
| 161 } | 166 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 return _objectType; | 198 return _objectType; |
| 194 } | 199 } |
| 195 | 200 |
| 196 OpType get opType { | 201 OpType get opType { |
| 197 if (_opType == null) { | 202 if (_opType == null) { |
| 198 _opType = new OpType.forCompletion(target, offset); | 203 _opType = new OpType.forCompletion(target, offset); |
| 199 } | 204 } |
| 200 return _opType; | 205 return _opType; |
| 201 } | 206 } |
| 202 | 207 |
| 208 /** |
| 209 * Throw [AbortCompletion] if the completion request has been aborted. |
| 210 */ |
| 211 void checkAborted() { |
| 212 _originalRequest.checkAborted(); |
| 213 } |
| 214 |
| 203 // For internal use only | 215 // For internal use only |
| 204 @override | 216 @override |
| 205 Future<List<Directive>> resolveDirectives() async { | 217 Future<List<Directive>> resolveDirectives() async { |
| 218 checkAborted(); |
| 219 |
| 206 CompilationUnit libUnit; | 220 CompilationUnit libUnit; |
| 207 if (librarySource != null) { | 221 if (librarySource != null) { |
| 208 // TODO(danrubel) only resolve the directives | 222 // TODO(danrubel) only resolve the directives |
| 209 const RESOLVE_DIRECTIVES_TAG = 'resolve directives'; | 223 libUnit = await _computeAsync( |
| 210 performance.logStartTime(RESOLVE_DIRECTIVES_TAG); | 224 this, |
| 211 libUnit = await new AnalysisFutureHelper<CompilationUnit>( | 225 new LibrarySpecificUnit(librarySource, librarySource), |
| 212 context, | 226 RESOLVED_UNIT3, |
| 213 new LibrarySpecificUnit(librarySource, librarySource), | 227 performance, |
| 214 RESOLVED_UNIT3) | 228 'resolve directives'); |
| 215 .computeAsync(); | |
| 216 performance.logElapseTime(RESOLVE_DIRECTIVES_TAG); | |
| 217 } | 229 } |
| 218 return libUnit?.directives; | 230 return libUnit?.directives; |
| 219 } | 231 } |
| 220 | 232 |
| 221 @override | 233 @override |
| 222 Future resolveExpression(Expression expression) async { | 234 Future resolveExpression(Expression expression) async { |
| 235 checkAborted(); |
| 236 |
| 223 // Return immediately if the expression has already been resolved | 237 // Return immediately if the expression has already been resolved |
| 224 if (expression.propagatedType != null) { | 238 if (expression.propagatedType != null) { |
| 225 return; | 239 return; |
| 226 } | 240 } |
| 227 | 241 |
| 228 // Gracefully degrade if librarySource cannot be determined | 242 // Gracefully degrade if librarySource cannot be determined |
| 229 if (librarySource == null) { | 243 if (librarySource == null) { |
| 230 return; | 244 return; |
| 231 } | 245 } |
| 232 | 246 |
| 233 // Resolve declarations in the target unit | 247 // Resolve declarations in the target unit |
| 234 // TODO(danrubel) resolve the expression or containing method | 248 // TODO(danrubel) resolve the expression or containing method |
| 235 // rather than the entire complilation unit | 249 // rather than the entire complilation unit |
| 236 const RESOLVE_EXPRESSION_TAG = 'resolve expression'; | 250 CompilationUnit resolvedUnit = await _computeAsync( |
| 237 performance.logStartTime(RESOLVE_EXPRESSION_TAG); | 251 this, |
| 238 CompilationUnit resolvedUnit = | 252 new LibrarySpecificUnit(librarySource, source), |
| 239 await new AnalysisFutureHelper<CompilationUnit>(context, | 253 RESOLVED_UNIT, |
| 240 new LibrarySpecificUnit(librarySource, source), RESOLVED_UNIT) | 254 performance, |
| 241 .computeAsync(); | 255 'resolve expression'); |
| 242 performance.logElapseTime(RESOLVE_EXPRESSION_TAG); | |
| 243 | 256 |
| 244 // TODO(danrubel) determine if the underlying source has been modified | 257 // TODO(danrubel) determine if the underlying source has been modified |
| 245 // in a way that invalidates the completion request | 258 // in a way that invalidates the completion request |
| 246 // and return null | 259 // and return null |
| 247 | 260 |
| 248 // Gracefully degrade if unit cannot be resolved | 261 // Gracefully degrade if unit cannot be resolved |
| 249 if (resolvedUnit == null) { | 262 if (resolvedUnit == null) { |
| 250 return; | 263 return; |
| 251 } | 264 } |
| 252 | 265 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 278 } | 291 } |
| 279 if (node is PrefixedIdentifier) { | 292 if (node is PrefixedIdentifier) { |
| 280 if (identical(node.identifier, target.entity)) { | 293 if (identical(node.identifier, target.entity)) { |
| 281 dotTarget = node.prefix; | 294 dotTarget = node.prefix; |
| 282 } | 295 } |
| 283 } | 296 } |
| 284 } | 297 } |
| 285 | 298 |
| 286 /** | 299 /** |
| 287 * Return a [Future] that completes with a newly created completion request | 300 * Return a [Future] that completes with a newly created completion request |
| 288 * based on the given [request]. | 301 * based on the given [request]. This method will throw [AbortCompletion] |
| 302 * if the completion request has been aborted. |
| 289 */ | 303 */ |
| 290 static Future<DartCompletionRequest> from(CompletionRequest request) async { | 304 static Future<DartCompletionRequest> from(CompletionRequest request) async { |
| 305 request.checkAborted(); |
| 291 CompletionPerformance performance = | 306 CompletionPerformance performance = |
| 292 (request as CompletionRequestImpl).performance; | 307 (request as CompletionRequestImpl).performance; |
| 293 const BUILD_REQUEST_TAG = 'build DartCompletionRequest'; | 308 const BUILD_REQUEST_TAG = 'build DartCompletionRequest'; |
| 294 performance.logStartTime(BUILD_REQUEST_TAG); | 309 performance.logStartTime(BUILD_REQUEST_TAG); |
| 295 | 310 |
| 296 Source source = request.source; | 311 Source source = request.source; |
| 297 AnalysisContext context = request.context; | 312 AnalysisContext context = request.context; |
| 298 | 313 |
| 299 const PARSE_TAG = 'parse unit'; | 314 const PARSE_TAG = 'parse unit'; |
| 300 performance.logStartTime(PARSE_TAG); | 315 performance.logStartTime(PARSE_TAG); |
| 301 CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT); | 316 CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT); |
| 302 performance.logElapseTime(PARSE_TAG); | 317 performance.logElapseTime(PARSE_TAG); |
| 303 | 318 |
| 304 Source libSource; | 319 Source libSource; |
| 305 if (unit.directives.any((d) => d is PartOfDirective)) { | 320 if (unit.directives.any((d) => d is PartOfDirective)) { |
| 306 List<Source> libraries = context.getLibrariesContaining(source); | 321 List<Source> libraries = context.getLibrariesContaining(source); |
| 307 if (libraries.isNotEmpty) { | 322 if (libraries.isNotEmpty) { |
| 308 libSource = libraries[0]; | 323 libSource = libraries[0]; |
| 309 } | 324 } |
| 310 } else { | 325 } else { |
| 311 libSource = source; | 326 libSource = source; |
| 312 } | 327 } |
| 313 | 328 |
| 314 // Most (all?) contributors need declarations in scope to be resolved | 329 // Most (all?) contributors need declarations in scope to be resolved |
| 315 if (libSource != null) { | 330 if (libSource != null) { |
| 316 const RESOLVE_DECLARATIONS_TAG = 'resolve declarations'; | 331 unit = await _computeAsync( |
| 317 performance.logStartTime(RESOLVE_DECLARATIONS_TAG); | 332 request, |
| 318 unit = await new AnalysisFutureHelper<CompilationUnit>(context, | 333 new LibrarySpecificUnit(libSource, source), |
| 319 new LibrarySpecificUnit(libSource, source), RESOLVED_UNIT3) | 334 RESOLVED_UNIT3, |
| 320 .computeAsync(); | 335 performance, |
| 321 performance.logElapseTime(RESOLVE_DECLARATIONS_TAG); | 336 'resolve declarations'); |
| 322 } | 337 } |
| 323 | 338 |
| 324 DartCompletionRequestImpl dartRequest = new DartCompletionRequestImpl._( | 339 DartCompletionRequestImpl dartRequest = new DartCompletionRequestImpl._( |
| 325 request.context, | 340 request.context, |
| 326 request.resourceProvider, | 341 request.resourceProvider, |
| 327 request.searchEngine, | 342 request.searchEngine, |
| 328 libSource, | 343 libSource, |
| 329 request.source, | 344 request.source, |
| 330 request.offset, | 345 request.offset, |
| 331 unit, | 346 unit, |
| 347 request, |
| 332 performance); | 348 performance); |
| 333 | 349 |
| 334 // Resolve the expression in which the completion occurs | 350 // Resolve the expression in which the completion occurs |
| 335 // to properly determine if identifiers should be suggested | 351 // to properly determine if identifiers should be suggested |
| 336 // rather than invocations. | 352 // rather than invocations. |
| 337 if (dartRequest.target.maybeFunctionalArgument()) { | 353 if (dartRequest.target.maybeFunctionalArgument()) { |
| 338 AstNode node = dartRequest.target.containingNode.parent; | 354 AstNode node = dartRequest.target.containingNode.parent; |
| 339 if (node is Expression) { | 355 if (node is Expression) { |
| 340 const FUNCTIONAL_ARG_TAG = 'resolve expression for isFunctionalArg'; | 356 const FUNCTIONAL_ARG_TAG = 'resolve expression for isFunctionalArg'; |
| 341 performance.logStartTime(FUNCTIONAL_ARG_TAG); | 357 performance.logStartTime(FUNCTIONAL_ARG_TAG); |
| 342 await dartRequest.resolveExpression(node); | 358 await dartRequest.resolveExpression(node); |
| 343 performance.logElapseTime(FUNCTIONAL_ARG_TAG); | 359 performance.logElapseTime(FUNCTIONAL_ARG_TAG); |
| 360 dartRequest.checkAborted(); |
| 344 } | 361 } |
| 345 } | 362 } |
| 346 | 363 |
| 347 performance.logElapseTime(BUILD_REQUEST_TAG); | 364 performance.logElapseTime(BUILD_REQUEST_TAG); |
| 348 return dartRequest; | 365 return dartRequest; |
| 349 } | 366 } |
| 367 |
| 368 static Future _computeAsync(CompletionRequest request, AnalysisTarget target, |
| 369 ResultDescriptor descriptor, CompletionPerformance performance, String per
fTag) async { |
| 370 request.checkAborted(); |
| 371 performance.logStartTime(perfTag); |
| 372 var result; |
| 373 try { |
| 374 result = |
| 375 await new AnalysisFutureHelper(request.context, target, descriptor) |
| 376 .computeAsync(); |
| 377 } catch (e, s) { |
| 378 if (e is AnalysisNotScheduledError) { |
| 379 request.checkAborted(); |
| 380 } |
| 381 throw new AnalysisException( |
| 382 'failed to $perfTag', new CaughtException(e, s)); |
| 383 } |
| 384 request.checkAborted(); |
| 385 return result; |
| 386 } |
| 350 } | 387 } |
| 351 | 388 |
| 352 /** | 389 /** |
| 353 * Utility class for computing the code completion replacement range | 390 * Utility class for computing the code completion replacement range |
| 354 */ | 391 */ |
| 355 class ReplacementRange { | 392 class ReplacementRange { |
| 356 int offset; | 393 int offset; |
| 357 int length; | 394 int length; |
| 358 | 395 |
| 359 ReplacementRange(this.offset, this.length); | 396 ReplacementRange(this.offset, this.length); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 // Replacement range for import URI | 435 // Replacement range for import URI |
| 399 return new ReplacementRange(start, end - start); | 436 return new ReplacementRange(start, end - start); |
| 400 } | 437 } |
| 401 } | 438 } |
| 402 } | 439 } |
| 403 } | 440 } |
| 404 } | 441 } |
| 405 return new ReplacementRange(requestOffset, 0); | 442 return new ReplacementRange(requestOffset, 0); |
| 406 } | 443 } |
| 407 } | 444 } |
| OLD | NEW |