OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 analysis.server; | 5 library analysis.server; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 import 'dart:core' hide Resource; | 9 import 'dart:core' hide Resource; |
10 import 'dart:math' show max; | 10 import 'dart:math' show max; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 * The object used to manage the SDK's known to this server. | 149 * The object used to manage the SDK's known to this server. |
150 */ | 150 */ |
151 DartSdkManager sdkManager; | 151 DartSdkManager sdkManager; |
152 | 152 |
153 /** | 153 /** |
154 * The instrumentation service that is to be used by this analysis server. | 154 * The instrumentation service that is to be used by this analysis server. |
155 */ | 155 */ |
156 final InstrumentationService instrumentationService; | 156 final InstrumentationService instrumentationService; |
157 | 157 |
158 /** | 158 /** |
159 * A table mapping [Folder]s to the [AnalysisContext]s associated with them. | |
160 */ | |
161 final Map<Folder, AnalysisContext> folderMap = | |
162 new HashMap<Folder, AnalysisContext>(); | |
163 | |
164 /** | |
165 * A queue of the operations to perform in this server. | 159 * A queue of the operations to perform in this server. |
166 */ | 160 */ |
167 ServerOperationQueue operationQueue; | 161 ServerOperationQueue operationQueue; |
168 | 162 |
169 /** | 163 /** |
170 * True if there is a pending future which will execute [performOperation]. | 164 * True if there is a pending future which will execute [performOperation]. |
171 */ | 165 */ |
172 bool performOperationPending = false; | 166 bool performOperationPending = false; |
173 | 167 |
174 /** | 168 /** |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
348 }); | 342 }); |
349 Notification notification = | 343 Notification notification = |
350 new ServerConnectedParams(VERSION).toNotification(); | 344 new ServerConnectedParams(VERSION).toNotification(); |
351 channel.sendNotification(notification); | 345 channel.sendNotification(notification); |
352 channel.listen(handleRequest, onDone: done, onError: error); | 346 channel.listen(handleRequest, onDone: done, onError: error); |
353 handlers = serverPlugin.createDomains(this); | 347 handlers = serverPlugin.createDomains(this); |
354 sdkManager = new DartSdkManager(defaultSdkCreator); | 348 sdkManager = new DartSdkManager(defaultSdkCreator); |
355 } | 349 } |
356 | 350 |
357 /** | 351 /** |
352 * Return the [AnalysisContext]s that are being used to analyze the analysis | |
353 * roots. | |
354 */ | |
355 Iterable<AnalysisContext> get analysisContexts => | |
356 contextManager.analysisContexts; | |
357 | |
358 /** | |
359 * Return a table mapping [Folder]s to the [AnalysisContext]s associated with | |
360 * them. | |
361 */ | |
362 Map<Folder, AnalysisContext> get folderMap => contextManager.folderMap; | |
363 | |
364 /** | |
358 * The [Future] that completes when analysis is complete. | 365 * The [Future] that completes when analysis is complete. |
359 */ | 366 */ |
360 Future get onAnalysisComplete { | 367 Future get onAnalysisComplete { |
361 if (isAnalysisComplete()) { | 368 if (isAnalysisComplete()) { |
362 return new Future.value(); | 369 return new Future.value(); |
363 } | 370 } |
364 if (_onAnalysisCompleteCompleter == null) { | 371 if (_onAnalysisCompleteCompleter == null) { |
365 _onAnalysisCompleteCompleter = new Completer(); | 372 _onAnalysisCompleteCompleter = new Completer(); |
366 } | 373 } |
367 return _onAnalysisCompleteCompleter.future; | 374 return _onAnalysisCompleteCompleter.future; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 */ | 465 */ |
459 AnalysisContext getAnalysisContext(String path) { | 466 AnalysisContext getAnalysisContext(String path) { |
460 return getContextSourcePair(path).context; | 467 return getContextSourcePair(path).context; |
461 } | 468 } |
462 | 469 |
463 /** | 470 /** |
464 * Return any [AnalysisContext] that is analyzing the given [source], either | 471 * Return any [AnalysisContext] that is analyzing the given [source], either |
465 * explicitly or implicitly. Return `null` if there is no such context. | 472 * explicitly or implicitly. Return `null` if there is no such context. |
466 */ | 473 */ |
467 AnalysisContext getAnalysisContextForSource(Source source) { | 474 AnalysisContext getAnalysisContextForSource(Source source) { |
468 for (AnalysisContext context in folderMap.values) { | 475 for (AnalysisContext context in analysisContexts) { |
469 SourceKind kind = context.getKindOf(source); | 476 SourceKind kind = context.getKindOf(source); |
470 if (kind != SourceKind.UNKNOWN) { | 477 if (kind != SourceKind.UNKNOWN) { |
471 return context; | 478 return context; |
472 } | 479 } |
473 } | 480 } |
474 return null; | 481 return null; |
475 } | 482 } |
476 | 483 |
477 /** | |
478 * Return the [AnalysisContext]s that are being used to analyze the analysis | |
479 * roots. | |
480 */ | |
481 Iterable<AnalysisContext> getAnalysisContexts() { | |
482 return folderMap.values; | |
483 } | |
484 | |
485 CompilationUnitElement getCompilationUnitElement(String file) { | 484 CompilationUnitElement getCompilationUnitElement(String file) { |
486 ContextSourcePair pair = getContextSourcePair(file); | 485 ContextSourcePair pair = getContextSourcePair(file); |
487 if (pair == null) { | 486 if (pair == null) { |
488 return null; | 487 return null; |
489 } | 488 } |
490 // prepare AnalysisContext and Source | 489 // prepare AnalysisContext and Source |
491 AnalysisContext context = pair.context; | 490 AnalysisContext context = pair.context; |
492 Source unitSource = pair.source; | 491 Source unitSource = pair.source; |
493 if (context == null || unitSource == null) { | 492 if (context == null || unitSource == null) { |
494 return null; | 493 return null; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
550 File file = resource; | 549 File file = resource; |
551 { | 550 { |
552 AnalysisContext containingContext = getContainingContext(path); | 551 AnalysisContext containingContext = getContainingContext(path); |
553 if (containingContext != null) { | 552 if (containingContext != null) { |
554 Source source = | 553 Source source = |
555 ContextManagerImpl.createSourceInContext(containingContext, file); | 554 ContextManagerImpl.createSourceInContext(containingContext, file); |
556 return new ContextSourcePair(containingContext, source); | 555 return new ContextSourcePair(containingContext, source); |
557 } | 556 } |
558 } | 557 } |
559 // try to find a context that analysed the file | 558 // try to find a context that analysed the file |
560 for (AnalysisContext context in folderMap.values) { | 559 for (AnalysisContext context in analysisContexts) { |
561 Source source = ContextManagerImpl.createSourceInContext(context, file); | 560 Source source = ContextManagerImpl.createSourceInContext(context, file); |
562 SourceKind kind = context.getKindOf(source); | 561 SourceKind kind = context.getKindOf(source); |
563 if (kind != SourceKind.UNKNOWN) { | 562 if (kind != SourceKind.UNKNOWN) { |
564 return new ContextSourcePair(context, source); | 563 return new ContextSourcePair(context, source); |
565 } | 564 } |
566 } | 565 } |
567 // try to find a context for which the file is a priority source | 566 // try to find a context for which the file is a priority source |
568 for (InternalAnalysisContext context in folderMap.values) { | 567 for (InternalAnalysisContext context in analysisContexts) { |
569 List<Source> sources = context.getSourcesWithFullName(path); | 568 List<Source> sources = context.getSourcesWithFullName(path); |
570 if (sources.isNotEmpty) { | 569 if (sources.isNotEmpty) { |
571 Source source = sources.first; | 570 Source source = sources.first; |
572 return new ContextSourcePair(context, source); | 571 return new ContextSourcePair(context, source); |
573 } | 572 } |
574 } | 573 } |
575 // file-based source | 574 // file-based source |
576 Source fileSource = file.createSource(); | 575 Source fileSource = file.createSource(); |
577 return new ContextSourcePair(null, fileSource); | 576 return new ContextSourcePair(null, fileSource); |
578 } | 577 } |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1110 // Prepare the context/source pair. | 1109 // Prepare the context/source pair. |
1111 ContextSourcePair contextSource = getContextSourcePair(file); | 1110 ContextSourcePair contextSource = getContextSourcePair(file); |
1112 AnalysisContext preferredContext = contextSource.context; | 1111 AnalysisContext preferredContext = contextSource.context; |
1113 Source source = contextSource.source; | 1112 Source source = contextSource.source; |
1114 // Try to make the file analyzable. | 1113 // Try to make the file analyzable. |
1115 // If it is not in any context yet, add it to the first one which | 1114 // If it is not in any context yet, add it to the first one which |
1116 // could use it, e.g. imports its package, even if not the library. | 1115 // could use it, e.g. imports its package, even if not the library. |
1117 if (preferredContext == null) { | 1116 if (preferredContext == null) { |
1118 Resource resource = resourceProvider.getResource(file); | 1117 Resource resource = resourceProvider.getResource(file); |
1119 if (resource is File && resource.exists) { | 1118 if (resource is File && resource.exists) { |
1120 for (AnalysisContext context in folderMap.values) { | 1119 for (AnalysisContext context in analysisContexts) { |
1121 Uri uri = context.sourceFactory.restoreUri(source); | 1120 Uri uri = context.sourceFactory.restoreUri(source); |
1122 if (uri.scheme != 'file') { | 1121 if (uri.scheme != 'file') { |
1123 preferredContext = context; | 1122 preferredContext = context; |
1124 source = | 1123 source = |
1125 ContextManagerImpl.createSourceInContext(context, resource); | 1124 ContextManagerImpl.createSourceInContext(context, resource); |
1126 break; | 1125 break; |
1127 } | 1126 } |
1128 } | 1127 } |
1129 } | 1128 } |
1130 } | 1129 } |
1131 // Fill the source map. | 1130 // Fill the source map. |
1132 bool contextFound = false; | 1131 bool contextFound = false; |
1133 if (preferredContext != null) { | 1132 if (preferredContext != null) { |
1134 sourceMap.putIfAbsent(preferredContext, () => <Source>[]).add(source); | 1133 sourceMap.putIfAbsent(preferredContext, () => <Source>[]).add(source); |
1135 contextFound = true; | 1134 contextFound = true; |
1136 } | 1135 } |
1137 for (AnalysisContext context in folderMap.values) { | 1136 for (AnalysisContext context in analysisContexts) { |
1138 if (context != preferredContext && | 1137 if (context != preferredContext && |
1139 context.getKindOf(source) != SourceKind.UNKNOWN) { | 1138 context.getKindOf(source) != SourceKind.UNKNOWN) { |
1140 sourceMap.putIfAbsent(context, () => <Source>[]).add(source); | 1139 sourceMap.putIfAbsent(context, () => <Source>[]).add(source); |
1141 contextFound = true; | 1140 contextFound = true; |
1142 } | 1141 } |
1143 } | 1142 } |
1144 if (firstSource == null) { | 1143 if (firstSource == null) { |
1145 firstSource = source; | 1144 firstSource = source; |
1146 } | 1145 } |
1147 if (!contextFound) { | 1146 if (!contextFound) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1241 } else if (change is RemoveContentOverlay) { | 1240 } else if (change is RemoveContentOverlay) { |
1242 newContents = null; | 1241 newContents = null; |
1243 } else { | 1242 } else { |
1244 // Protocol parsing should have ensured that we never get here. | 1243 // Protocol parsing should have ensured that we never get here. |
1245 throw new AnalysisException('Illegal change type'); | 1244 throw new AnalysisException('Illegal change type'); |
1246 } | 1245 } |
1247 overlayState.setContents(source, newContents); | 1246 overlayState.setContents(source, newContents); |
1248 // If the source does not exist, then it was an overlay-only one. | 1247 // If the source does not exist, then it was an overlay-only one. |
1249 // Remove it from contexts. | 1248 // Remove it from contexts. |
1250 if (newContents == null && !source.exists()) { | 1249 if (newContents == null && !source.exists()) { |
1251 for (InternalAnalysisContext context in folderMap.values) { | 1250 for (InternalAnalysisContext context in analysisContexts) { |
1252 List<Source> sources = context.getSourcesWithFullName(file); | 1251 List<Source> sources = context.getSourcesWithFullName(file); |
1253 ChangeSet changeSet = new ChangeSet(); | 1252 ChangeSet changeSet = new ChangeSet(); |
1254 sources.forEach(changeSet.removedSource); | 1253 sources.forEach(changeSet.removedSource); |
1255 context.applyChanges(changeSet); | 1254 context.applyChanges(changeSet); |
1256 schedulePerformAnalysisOperation(context); | 1255 schedulePerformAnalysisOperation(context); |
1257 } | 1256 } |
1258 return; | 1257 return; |
1259 } | 1258 } |
1260 // Update all contexts. | 1259 // Update all contexts. |
1261 bool anyContextUpdated = false; | 1260 bool anyContextUpdated = false; |
1262 for (InternalAnalysisContext context in folderMap.values) { | 1261 for (InternalAnalysisContext context in analysisContexts) { |
1263 List<Source> sources = context.getSourcesWithFullName(file); | 1262 List<Source> sources = context.getSourcesWithFullName(file); |
1264 sources.forEach((Source source) { | 1263 sources.forEach((Source source) { |
1265 anyContextUpdated = true; | 1264 anyContextUpdated = true; |
1266 if (context.handleContentsChanged( | 1265 if (context.handleContentsChanged( |
1267 source, oldContents, newContents, true)) { | 1266 source, oldContents, newContents, true)) { |
1268 schedulePerformAnalysisOperation(context); | 1267 schedulePerformAnalysisOperation(context); |
1269 } else { | 1268 } else { |
1270 // When the client sends any change for a source, we should resend | 1269 // When the client sends any change for a source, we should resend |
1271 // subscribed notifications, even if there were no changes in the | 1270 // subscribed notifications, even if there were no changes in the |
1272 // source contents. | 1271 // source contents. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1309 } | 1308 } |
1310 | 1309 |
1311 /** | 1310 /** |
1312 * Use the given updaters to update the values of the options in every | 1311 * Use the given updaters to update the values of the options in every |
1313 * existing analysis context. | 1312 * existing analysis context. |
1314 */ | 1313 */ |
1315 void updateOptions(List<OptionUpdater> optionUpdaters) { | 1314 void updateOptions(List<OptionUpdater> optionUpdaters) { |
1316 // | 1315 // |
1317 // Update existing contexts. | 1316 // Update existing contexts. |
1318 // | 1317 // |
1319 folderMap.forEach((Folder folder, AnalysisContext context) { | 1318 for (AnalysisContext context in analysisContexts) { |
1320 AnalysisOptionsImpl options = | 1319 AnalysisOptionsImpl options = |
1321 new AnalysisOptionsImpl.from(context.analysisOptions); | 1320 new AnalysisOptionsImpl.from(context.analysisOptions); |
1322 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1321 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
1323 optionUpdater(options); | 1322 optionUpdater(options); |
1324 }); | 1323 }); |
1325 context.analysisOptions = options; | 1324 context.analysisOptions = options; |
1326 // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis | 1325 // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis |
1327 // to be scheduled for this context. | 1326 // to be scheduled for this context. |
1328 }); | 1327 } |
1328 ; | |
Paul Berry
2016/02/29 21:46:31
Stray `;`
Brian Wilkerson
2016/02/29 22:04:13
Done
| |
1329 // | 1329 // |
1330 // Update the defaults used to create new contexts. | 1330 // Update the defaults used to create new contexts. |
1331 // | 1331 // |
1332 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1332 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
1333 optionUpdater(defaultContextOptions); | 1333 optionUpdater(defaultContextOptions); |
1334 }); | 1334 }); |
1335 } | 1335 } |
1336 | 1336 |
1337 void _computingPackageMap(bool computing) { | 1337 void _computingPackageMap(bool computing) { |
1338 if (serverServices.contains(ServerService.STATUS)) { | 1338 if (serverServices.contains(ServerService.STATUS)) { |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1716 /** | 1716 /** |
1717 * The [PerformanceTag] for time spent in server request handlers. | 1717 * The [PerformanceTag] for time spent in server request handlers. |
1718 */ | 1718 */ |
1719 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); | 1719 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); |
1720 | 1720 |
1721 /** | 1721 /** |
1722 * The [PerformanceTag] for time spent in split store microtasks. | 1722 * The [PerformanceTag] for time spent in split store microtasks. |
1723 */ | 1723 */ |
1724 static PerformanceTag splitStore = new PerformanceTag('splitStore'); | 1724 static PerformanceTag splitStore = new PerformanceTag('splitStore'); |
1725 } | 1725 } |
OLD | NEW |