| 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:math' show max; | 9 import 'dart:math' show max; |
| 10 | 10 |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 } | 360 } |
| 361 | 361 |
| 362 /** | 362 /** |
| 363 * Return the preferred [AnalysisContext] for analyzing the given [path]. | 363 * Return the preferred [AnalysisContext] for analyzing the given [path]. |
| 364 * This will be the context that explicitly contains the path, if any such | 364 * This will be the context that explicitly contains the path, if any such |
| 365 * context exists, otherwise it will be the first analysis context that | 365 * context exists, otherwise it will be the first analysis context that |
| 366 * implicitly analyzes it. Return `null` if no context is analyzing the | 366 * implicitly analyzes it. Return `null` if no context is analyzing the |
| 367 * path. | 367 * path. |
| 368 */ | 368 */ |
| 369 AnalysisContext getAnalysisContext(String path) { | 369 AnalysisContext getAnalysisContext(String path) { |
| 370 // try to find a containing context | 370 return getContextSourcePair(path).context; |
| 371 Folder containingFolder = null; | |
| 372 for (Folder folder in folderMap.keys) { | |
| 373 if (folder.path == path || folder.contains(path)) { | |
| 374 if (containingFolder == null) { | |
| 375 containingFolder = folder; | |
| 376 } else if (containingFolder.path.length < folder.path.length) { | |
| 377 containingFolder = folder; | |
| 378 } | |
| 379 } | |
| 380 } | |
| 381 if (containingFolder != null) { | |
| 382 return folderMap[containingFolder]; | |
| 383 } | |
| 384 Resource resource = resourceProvider.getResource(path); | |
| 385 if (resource is Folder) { | |
| 386 return null; | |
| 387 } | |
| 388 // check if there is a context that analyzed this source | |
| 389 return getAnalysisContextForSource(_getSourceWithoutContext(path)); | |
| 390 } | 371 } |
| 391 | 372 |
| 392 /** | 373 /** |
| 393 * Return any [AnalysisContext] that is analyzing the given [source], either | 374 * Return any [AnalysisContext] that is analyzing the given [source], either |
| 394 * explicitly or implicitly. Return `null` if there is no such context. | 375 * explicitly or implicitly. Return `null` if there is no such context. |
| 395 */ | 376 */ |
| 396 AnalysisContext getAnalysisContextForSource(Source source) { | 377 AnalysisContext getAnalysisContextForSource(Source source) { |
| 397 for (AnalysisContext context in folderMap.values) { | 378 for (AnalysisContext context in folderMap.values) { |
| 398 SourceKind kind = context.getKindOf(source); | 379 SourceKind kind = context.getKindOf(source); |
| 399 if (kind != SourceKind.UNKNOWN) { | 380 if (kind != SourceKind.UNKNOWN) { |
| 400 return context; | 381 return context; |
| 401 } | 382 } |
| 402 } | 383 } |
| 403 return null; | 384 return null; |
| 404 } | 385 } |
| 405 | 386 |
| 406 /** | 387 /** |
| 407 * Return the [AnalysisContext]s that are being used to analyze the analysis | 388 * Return the [AnalysisContext]s that are being used to analyze the analysis |
| 408 * roots. | 389 * roots. |
| 409 */ | 390 */ |
| 410 Iterable<AnalysisContext> getAnalysisContexts() { | 391 Iterable<AnalysisContext> getAnalysisContexts() { |
| 411 return folderMap.values; | 392 return folderMap.values; |
| 412 } | 393 } |
| 413 | 394 |
| 414 /** | 395 /** |
| 396 * Return the primary [ContextSourcePair] representing the given [path]. |
| 397 * |
| 398 * The [AnalysisContext] of this pair will be the context that explicitly |
| 399 * contains the path, if any such context exists, otherwise it will be the |
| 400 * first context that implicitly analyzes it. |
| 401 * |
| 402 * If the [path] is not analyzed by any context, a [ContextSourcePair] with |
| 403 * `null` context and `file` [Source] is returned. |
| 404 * |
| 405 * If the [path] dosn't represent a file, `null` is returned as a [Source]. |
| 406 * |
| 407 * Does not return `null`. |
| 408 */ |
| 409 ContextSourcePair getContextSourcePair(String path) { |
| 410 // try SDK |
| 411 { |
| 412 Uri uri = resourceProvider.pathContext.toUri(path); |
| 413 Source sdkSource = defaultSdk.fromFileUri(uri); |
| 414 if (sdkSource != null) { |
| 415 AnalysisContext anyContext = folderMap.values.first; |
| 416 return new ContextSourcePair(anyContext, sdkSource); |
| 417 } |
| 418 } |
| 419 // try to find the deep-most containing context |
| 420 Resource resource = resourceProvider.getResource(path); |
| 421 File file = resource is File ? resource : null; |
| 422 { |
| 423 Folder containingFolder = null; |
| 424 AnalysisContext containingContext = null; |
| 425 folderMap.forEach((Folder folder, AnalysisContext context) { |
| 426 if (folder.isOrContains(path)) { |
| 427 if (containingFolder == null || |
| 428 containingFolder.path.length < folder.path.length) { |
| 429 containingFolder = folder; |
| 430 containingContext = context; |
| 431 } |
| 432 } |
| 433 }); |
| 434 if (containingContext != null) { |
| 435 Source source = file != null |
| 436 ? ContextManager.createSourceInContext(containingContext, file) |
| 437 : null; |
| 438 return new ContextSourcePair(containingContext, source); |
| 439 } |
| 440 } |
| 441 // try to find a context that analysed the file |
| 442 for (AnalysisContext context in folderMap.values) { |
| 443 Source source = file != null |
| 444 ? ContextManager.createSourceInContext(context, file) |
| 445 : null; |
| 446 SourceKind kind = context.getKindOf(source); |
| 447 if (kind != SourceKind.UNKNOWN) { |
| 448 return new ContextSourcePair(context, source); |
| 449 } |
| 450 } |
| 451 // file-based source |
| 452 Source fileSource = file != null ? file.createSource() : null; |
| 453 return new ContextSourcePair(null, fileSource); |
| 454 } |
| 455 |
| 456 /** |
| 415 * Returns [Element]s at the given [offset] of the given [file]. | 457 * Returns [Element]s at the given [offset] of the given [file]. |
| 416 * | 458 * |
| 417 * May be empty if cannot be resolved, but not `null`. | 459 * May be empty if cannot be resolved, but not `null`. |
| 418 */ | 460 */ |
| 419 List<Element> getElementsAtOffset(String file, int offset) { | 461 List<Element> getElementsAtOffset(String file, int offset) { |
| 420 List<AstNode> nodes = getNodesAtOffset(file, offset); | 462 List<AstNode> nodes = getNodesAtOffset(file, offset); |
| 421 return getElementsOfNodes(nodes, offset); | 463 return getElementsOfNodes(nodes, offset); |
| 422 } | 464 } |
| 423 | 465 |
| 424 /** | 466 /** |
| (...skipping 28 matching lines...) Expand all Loading... |
| 453 * Returns `null` if [file] does not belong to any [AnalysisContext], or the | 495 * Returns `null` if [file] does not belong to any [AnalysisContext], or the |
| 454 * file does not exist. | 496 * file does not exist. |
| 455 * | 497 * |
| 456 * The array of errors will be empty if there are no errors in [file]. The | 498 * The array of errors will be empty if there are no errors in [file]. The |
| 457 * errors contained in the array can be incomplete. | 499 * errors contained in the array can be incomplete. |
| 458 * | 500 * |
| 459 * This method does not wait for all errors to be computed, and returns just | 501 * This method does not wait for all errors to be computed, and returns just |
| 460 * the current state. | 502 * the current state. |
| 461 */ | 503 */ |
| 462 AnalysisErrorInfo getErrors(String file) { | 504 AnalysisErrorInfo getErrors(String file) { |
| 463 // prepare AnalysisContext | 505 ContextSourcePair contextSource = getContextSourcePair(file); |
| 464 AnalysisContext context = getAnalysisContext(file); | 506 AnalysisContext context = contextSource.context; |
| 507 Source source = contextSource.source; |
| 465 if (context == null) { | 508 if (context == null) { |
| 466 return null; | 509 return null; |
| 467 } | 510 } |
| 468 // prepare Source | 511 if (!source.exists()) { |
| 469 Source source = getSource(file); | |
| 470 if (context.getKindOf(source) == SourceKind.UNKNOWN) { | |
| 471 return null; | 512 return null; |
| 472 } | 513 } |
| 473 // get errors for the file | |
| 474 return context.getErrors(source); | 514 return context.getErrors(source); |
| 475 } | 515 } |
| 476 | 516 |
| 477 /** | |
| 478 * Returns resolved [AstNode]s at the given [offset] of the given [file]. | |
| 479 * | |
| 480 * May be empty, but not `null`. | |
| 481 */ | |
| 482 List<AstNode> getNodesAtOffset(String file, int offset) { | |
| 483 List<CompilationUnit> units = getResolvedCompilationUnits(file); | |
| 484 List<AstNode> nodes = <AstNode>[]; | |
| 485 for (CompilationUnit unit in units) { | |
| 486 AstNode node = new NodeLocator.con1(offset).searchWithin(unit); | |
| 487 if (node != null) { | |
| 488 nodes.add(node); | |
| 489 } | |
| 490 } | |
| 491 return nodes; | |
| 492 } | |
| 493 | |
| 494 // TODO(brianwilkerson) Add the following method after 'prioritySources' has | 517 // TODO(brianwilkerson) Add the following method after 'prioritySources' has |
| 495 // been added to InternalAnalysisContext. | 518 // been added to InternalAnalysisContext. |
| 496 // /** | 519 // /** |
| 497 // * Return a list containing the full names of all of the sources that are | 520 // * Return a list containing the full names of all of the sources that are |
| 498 // * priority sources. | 521 // * priority sources. |
| 499 // */ | 522 // */ |
| 500 // List<String> getPriorityFiles() { | 523 // List<String> getPriorityFiles() { |
| 501 // List<String> priorityFiles = new List<String>(); | 524 // List<String> priorityFiles = new List<String>(); |
| 502 // folderMap.values.forEach((ContextDirectory directory) { | 525 // folderMap.values.forEach((ContextDirectory directory) { |
| 503 // InternalAnalysisContext context = directory.context; | 526 // InternalAnalysisContext context = directory.context; |
| 504 // context.prioritySources.forEach((Source source) { | 527 // context.prioritySources.forEach((Source source) { |
| 505 // priorityFiles.add(source.fullName); | 528 // priorityFiles.add(source.fullName); |
| 506 // }); | 529 // }); |
| 507 // }); | 530 // }); |
| 508 // return priorityFiles; | 531 // return priorityFiles; |
| 509 // } | 532 // } |
| 510 | 533 |
| 511 /** | 534 /** |
| 535 * Returns resolved [AstNode]s at the given [offset] of the given [file]. |
| 536 * |
| 537 * May be empty, but not `null`. |
| 538 */ |
| 539 List<AstNode> getNodesAtOffset(String file, int offset) { |
| 540 List<CompilationUnit> units = getResolvedCompilationUnits(file); |
| 541 List<AstNode> nodes = <AstNode>[]; |
| 542 for (CompilationUnit unit in units) { |
| 543 AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| 544 if (node != null) { |
| 545 nodes.add(node); |
| 546 } |
| 547 } |
| 548 return nodes; |
| 549 } |
| 550 |
| 551 /** |
| 512 * Returns resolved [CompilationUnit]s of the Dart file with the given [path]. | 552 * Returns resolved [CompilationUnit]s of the Dart file with the given [path]. |
| 513 * | 553 * |
| 514 * May be empty, but not `null`. | 554 * May be empty, but not `null`. |
| 515 */ | 555 */ |
| 516 List<CompilationUnit> getResolvedCompilationUnits(String path) { | 556 List<CompilationUnit> getResolvedCompilationUnits(String path) { |
| 517 List<CompilationUnit> units = <CompilationUnit>[]; | 557 List<CompilationUnit> units = <CompilationUnit>[]; |
| 558 ContextSourcePair contextSource = getContextSourcePair(path); |
| 518 // prepare AnalysisContext | 559 // prepare AnalysisContext |
| 519 AnalysisContext context = getAnalysisContext(path); | 560 AnalysisContext context = contextSource.context; |
| 520 if (context == null) { | 561 if (context == null) { |
| 521 return units; | 562 return units; |
| 522 } | 563 } |
| 523 // add a unit for each unit/library combination | 564 // add a unit for each unit/library combination |
| 524 Source unitSource = getSource(path); | 565 Source unitSource = contextSource.source; |
| 525 List<Source> librarySources = context.getLibrariesContaining(unitSource); | 566 List<Source> librarySources = context.getLibrariesContaining(unitSource); |
| 526 for (Source librarySource in librarySources) { | 567 for (Source librarySource in librarySources) { |
| 527 CompilationUnit unit = | 568 CompilationUnit unit = |
| 528 context.resolveCompilationUnit2(unitSource, librarySource); | 569 context.resolveCompilationUnit2(unitSource, librarySource); |
| 529 if (unit != null) { | 570 if (unit != null) { |
| 530 units.add(unit); | 571 units.add(unit); |
| 531 } | 572 } |
| 532 } | 573 } |
| 533 // done | 574 // done |
| 534 return units; | 575 return units; |
| 535 } | 576 } |
| 536 | 577 |
| 537 /** | 578 /** |
| 538 * Returns the [CompilationUnit] of the Dart file with the given [path] that | |
| 539 * should be used to resend notifications for already resolved unit. | |
| 540 * Returns `null` if the file is not a part of any context, library has not | |
| 541 * been yet resolved, or any problem happened. | |
| 542 */ | |
| 543 CompilationUnit getResolvedCompilationUnitToResendNotification(String path) { | |
| 544 // prepare AnalysisContext | |
| 545 AnalysisContext context = getAnalysisContext(path); | |
| 546 if (context == null) { | |
| 547 return null; | |
| 548 } | |
| 549 // prepare sources | |
| 550 Source unitSource = getSource(path); | |
| 551 List<Source> librarySources = context.getLibrariesContaining(unitSource); | |
| 552 if (librarySources.isEmpty) { | |
| 553 return null; | |
| 554 } | |
| 555 // if library has not been resolved yet, the unit will be resolved later | |
| 556 Source librarySource = librarySources[0]; | |
| 557 if (context.getLibraryElement(librarySource) == null) { | |
| 558 return null; | |
| 559 } | |
| 560 // if library has been already resolved, resolve unit | |
| 561 return context.resolveCompilationUnit2(unitSource, librarySource); | |
| 562 } | |
| 563 | |
| 564 /** | |
| 565 * Return the [Source] of the Dart file with the given [path]. | |
| 566 */ | |
| 567 Source getSource(String path) { | |
| 568 // try SDK | |
| 569 { | |
| 570 Uri uri = resourceProvider.pathContext.toUri(path); | |
| 571 Source sdkSource = defaultSdk.fromFileUri(uri); | |
| 572 if (sdkSource != null) { | |
| 573 return sdkSource; | |
| 574 } | |
| 575 } | |
| 576 // file-based source | |
| 577 File file = resourceProvider.getResource(path); | |
| 578 return ContextManager.createSourceInContext(getAnalysisContext(path), file); | |
| 579 } | |
| 580 | |
| 581 /** | |
| 582 * Handle a [request] that was read from the communication channel. | 579 * Handle a [request] that was read from the communication channel. |
| 583 */ | 580 */ |
| 584 void handleRequest(Request request) { | 581 void handleRequest(Request request) { |
| 585 _performance.logRequest(request); | 582 _performance.logRequest(request); |
| 586 runZoned(() { | 583 runZoned(() { |
| 587 ServerPerformanceStatistics.serverRequests.makeCurrentWhile(() { | 584 ServerPerformanceStatistics.serverRequests.makeCurrentWhile(() { |
| 588 int count = handlers.length; | 585 int count = handlers.length; |
| 589 for (int i = 0; i < count; i++) { | 586 for (int i = 0; i < count; i++) { |
| 590 try { | 587 try { |
| 591 Response response = handlers[i].handleRequest(request); | 588 Response response = handlers[i].handleRequest(request); |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 * Implementation for `analysis.setSubscriptions`. | 842 * Implementation for `analysis.setSubscriptions`. |
| 846 */ | 843 */ |
| 847 void setAnalysisSubscriptions( | 844 void setAnalysisSubscriptions( |
| 848 Map<AnalysisService, Set<String>> subscriptions) { | 845 Map<AnalysisService, Set<String>> subscriptions) { |
| 849 // send notifications for already analyzed sources | 846 // send notifications for already analyzed sources |
| 850 subscriptions.forEach((service, Set<String> newFiles) { | 847 subscriptions.forEach((service, Set<String> newFiles) { |
| 851 Set<String> oldFiles = analysisServices[service]; | 848 Set<String> oldFiles = analysisServices[service]; |
| 852 Set<String> todoFiles = | 849 Set<String> todoFiles = |
| 853 oldFiles != null ? newFiles.difference(oldFiles) : newFiles; | 850 oldFiles != null ? newFiles.difference(oldFiles) : newFiles; |
| 854 for (String file in todoFiles) { | 851 for (String file in todoFiles) { |
| 855 Source source = getSource(file); | 852 ContextSourcePair contextSource = getContextSourcePair(file); |
| 856 // prepare context | 853 // prepare context |
| 857 AnalysisContext context = getAnalysisContext(file); | 854 AnalysisContext context = contextSource.context; |
| 858 if (context == null) { | 855 if (context == null) { |
| 859 continue; | 856 continue; |
| 860 } | 857 } |
| 861 // Dart unit notifications. | 858 // Dart unit notifications. |
| 862 if (AnalysisEngine.isDartFileName(file)) { | 859 if (AnalysisEngine.isDartFileName(file)) { |
| 860 Source source = contextSource.source; |
| 863 CompilationUnit dartUnit = | 861 CompilationUnit dartUnit = |
| 864 getResolvedCompilationUnitToResendNotification(file); | 862 _getResolvedCompilationUnitToResendNotification(context, source); |
| 865 if (dartUnit != null) { | 863 if (dartUnit != null) { |
| 866 switch (service) { | 864 switch (service) { |
| 867 case AnalysisService.HIGHLIGHTS: | 865 case AnalysisService.HIGHLIGHTS: |
| 868 sendAnalysisNotificationHighlights(this, file, dartUnit); | 866 sendAnalysisNotificationHighlights(this, file, dartUnit); |
| 869 break; | 867 break; |
| 870 case AnalysisService.NAVIGATION: | 868 case AnalysisService.NAVIGATION: |
| 871 // TODO(scheglov) consider support for one unit in 2+ libraries | 869 // TODO(scheglov) consider support for one unit in 2+ libraries |
| 872 sendAnalysisNotificationNavigation(this, file, dartUnit); | 870 sendAnalysisNotificationNavigation(this, file, dartUnit); |
| 873 break; | 871 break; |
| 874 case AnalysisService.OCCURRENCES: | 872 case AnalysisService.OCCURRENCES: |
| 875 sendAnalysisNotificationOccurrences(this, file, dartUnit); | 873 sendAnalysisNotificationOccurrences(this, file, dartUnit); |
| 876 break; | 874 break; |
| 877 case AnalysisService.OUTLINE: | 875 case AnalysisService.OUTLINE: |
| 876 AnalysisContext context = dartUnit.element.context; |
| 878 LineInfo lineInfo = context.getLineInfo(source); | 877 LineInfo lineInfo = context.getLineInfo(source); |
| 879 sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit); | 878 sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit); |
| 880 break; | 879 break; |
| 881 case AnalysisService.OVERRIDES: | 880 case AnalysisService.OVERRIDES: |
| 882 sendAnalysisNotificationOverrides(this, file, dartUnit); | 881 sendAnalysisNotificationOverrides(this, file, dartUnit); |
| 883 break; | 882 break; |
| 884 } | 883 } |
| 885 } | 884 } |
| 886 } | 885 } |
| 887 } | 886 } |
| 888 }); | 887 }); |
| 889 // remember new subscriptions | 888 // remember new subscriptions |
| 890 this.analysisServices = subscriptions; | 889 this.analysisServices = subscriptions; |
| 891 } | 890 } |
| 892 | 891 |
| 893 /** | 892 /** |
| 894 * Set the priority files to the given [files]. | 893 * Set the priority files to the given [files]. |
| 895 */ | 894 */ |
| 896 void setPriorityFiles(String requestId, List<String> files) { | 895 void setPriorityFiles(String requestId, List<String> files) { |
| 897 // Note: when a file is a priority file, that information needs to be | 896 // Note: when a file is a priority file, that information needs to be |
| 898 // propagated to all contexts that analyze the file, so that all contexts | 897 // propagated to all contexts that analyze the file, so that all contexts |
| 899 // will be able to do incremental resolution of the file. See | 898 // will be able to do incremental resolution of the file. See |
| 900 // dartbug.com/22209. | 899 // dartbug.com/22209. |
| 901 Map<AnalysisContext, List<Source>> sourceMap = | 900 Map<AnalysisContext, List<Source>> sourceMap = |
| 902 new HashMap<AnalysisContext, List<Source>>(); | 901 new HashMap<AnalysisContext, List<Source>>(); |
| 903 List<String> unanalyzed = new List<String>(); | 902 List<String> unanalyzed = new List<String>(); |
| 903 Source firstSource = null; |
| 904 files.forEach((file) { | 904 files.forEach((file) { |
| 905 AnalysisContext preferredContext = getAnalysisContext(file); | 905 ContextSourcePair contextSource = getContextSourcePair(file); |
| 906 Source source = getSource(file); | 906 AnalysisContext preferredContext = contextSource.context; |
| 907 Source source = contextSource.source; |
| 907 bool contextFound = false; | 908 bool contextFound = false; |
| 908 for (AnalysisContext context in folderMap.values) { | 909 for (AnalysisContext context in folderMap.values) { |
| 909 if (context == preferredContext || | 910 if (context == preferredContext || |
| 910 context.getKindOf(source) != SourceKind.UNKNOWN) { | 911 context.getKindOf(source) != SourceKind.UNKNOWN) { |
| 911 sourceMap.putIfAbsent(context, () => <Source>[]).add(source); | 912 sourceMap.putIfAbsent(context, () => <Source>[]).add(source); |
| 912 contextFound = true; | 913 contextFound = true; |
| 913 } | 914 } |
| 914 } | 915 } |
| 916 if (firstSource == null) { |
| 917 firstSource = source; |
| 918 } |
| 915 if (!contextFound) { | 919 if (!contextFound) { |
| 916 unanalyzed.add(file); | 920 unanalyzed.add(file); |
| 917 } | 921 } |
| 918 }); | 922 }); |
| 919 if (unanalyzed.isNotEmpty) { | 923 if (unanalyzed.isNotEmpty) { |
| 920 StringBuffer buffer = new StringBuffer(); | 924 StringBuffer buffer = new StringBuffer(); |
| 921 buffer.writeAll(unanalyzed, ', '); | 925 buffer.writeAll(unanalyzed, ', '); |
| 922 throw new RequestFailure( | 926 throw new RequestFailure( |
| 923 new Response.unanalyzedPriorityFiles(requestId, buffer.toString())); | 927 new Response.unanalyzedPriorityFiles(requestId, buffer.toString())); |
| 924 } | 928 } |
| 925 folderMap.forEach((Folder folder, AnalysisContext context) { | 929 folderMap.forEach((Folder folder, AnalysisContext context) { |
| 926 List<Source> sourceList = sourceMap[context]; | 930 List<Source> sourceList = sourceMap[context]; |
| 927 if (sourceList == null) { | 931 if (sourceList == null) { |
| 928 sourceList = Source.EMPTY_ARRAY; | 932 sourceList = Source.EMPTY_ARRAY; |
| 929 } | 933 } |
| 930 context.analysisPriorityOrder = sourceList; | 934 context.analysisPriorityOrder = sourceList; |
| 931 // Schedule the context for analysis so that it has the opportunity to | 935 // Schedule the context for analysis so that it has the opportunity to |
| 932 // cache the AST's for the priority sources as soon as possible. | 936 // cache the AST's for the priority sources as soon as possible. |
| 933 schedulePerformAnalysisOperation(context); | 937 schedulePerformAnalysisOperation(context); |
| 934 }); | 938 }); |
| 935 operationQueue.reschedule(); | 939 operationQueue.reschedule(); |
| 936 Source firstSource = files.length > 0 ? getSource(files[0]) : null; | |
| 937 _onPriorityChangeController.add(new PriorityChangeEvent(firstSource)); | 940 _onPriorityChangeController.add(new PriorityChangeEvent(firstSource)); |
| 938 } | 941 } |
| 939 | 942 |
| 940 /** | 943 /** |
| 941 * Returns `true` if errors should be reported for [file] with the given | 944 * Returns `true` if errors should be reported for [file] with the given |
| 942 * absolute path. | 945 * absolute path. |
| 943 */ | 946 */ |
| 944 bool shouldSendErrorsNotificationFor(String file) { | 947 bool shouldSendErrorsNotificationFor(String file) { |
| 945 return !_noErrorNotification && | 948 return !_noErrorNotification && |
| 946 contextDirectoryManager.isInAnalysisRoot(file); | 949 contextDirectoryManager.isInAnalysisRoot(file); |
| 947 } | 950 } |
| 948 | 951 |
| 949 void shutdown() { | 952 void shutdown() { |
| 950 running = false; | 953 running = false; |
| 951 if (index != null) { | 954 if (index != null) { |
| 952 index.clear(); | 955 index.clear(); |
| 953 index.stop(); | 956 index.stop(); |
| 954 } | 957 } |
| 955 // Defer closing the channel and shutting down the instrumentation server so | 958 // Defer closing the channel and shutting down the instrumentation server so |
| 956 // that the shutdown response can be sent and logged. | 959 // that the shutdown response can be sent and logged. |
| 957 new Future(() { | 960 new Future(() { |
| 958 instrumentationService.shutdown(); | 961 instrumentationService.shutdown(); |
| 959 channel.close(); | 962 channel.close(); |
| 960 }); | 963 }); |
| 961 } | 964 } |
| 962 | 965 |
| 963 void test_flushResolvedUnit(String file) { | 966 void test_flushResolvedUnit(String file) { |
| 964 if (AnalysisEngine.isDartFileName(file)) { | 967 if (AnalysisEngine.isDartFileName(file)) { |
| 965 AnalysisContextImpl context = getAnalysisContext(file); | 968 ContextSourcePair contextSource = getContextSourcePair(file); |
| 966 Source source = getSource(file); | 969 AnalysisContextImpl context = contextSource.context; |
| 970 Source source = contextSource.source; |
| 967 DartEntry dartEntry = context.getReadableSourceEntryOrNull(source); | 971 DartEntry dartEntry = context.getReadableSourceEntryOrNull(source); |
| 968 dartEntry.flushAstStructures(); | 972 dartEntry.flushAstStructures(); |
| 969 } | 973 } |
| 970 } | 974 } |
| 971 | 975 |
| 972 /** | 976 /** |
| 973 * Performs all scheduled analysis operations. | 977 * Performs all scheduled analysis operations. |
| 974 */ | 978 */ |
| 975 void test_performAllAnalysisOperations() { | 979 void test_performAllAnalysisOperations() { |
| 976 while (true) { | 980 while (true) { |
| 977 ServerOperation operation = operationQueue.takeIf((operation) { | 981 ServerOperation operation = operationQueue.takeIf((operation) { |
| 978 return operation is PerformAnalysisOperation; | 982 return operation is PerformAnalysisOperation; |
| 979 }); | 983 }); |
| 980 if (operation == null) { | 984 if (operation == null) { |
| 981 break; | 985 break; |
| 982 } | 986 } |
| 983 operation.perform(this); | 987 operation.perform(this); |
| 984 } | 988 } |
| 985 } | 989 } |
| 986 | 990 |
| 987 /** | 991 /** |
| 988 * Implementation for `analysis.updateContent`. | 992 * Implementation for `analysis.updateContent`. |
| 989 */ | 993 */ |
| 990 void updateContent(String id, Map<String, dynamic> changes) { | 994 void updateContent(String id, Map<String, dynamic> changes) { |
| 991 changes.forEach((file, change) { | 995 changes.forEach((file, change) { |
| 992 Source source = getSource(file); | 996 ContextSourcePair contextSource = getContextSourcePair(file); |
| 997 Source source = contextSource.source; |
| 993 operationQueue.sourceAboutToChange(source); | 998 operationQueue.sourceAboutToChange(source); |
| 994 // Prepare the new contents. | 999 // Prepare the new contents. |
| 995 String oldContents = overlayState.getContents(source); | 1000 String oldContents = overlayState.getContents(source); |
| 996 String newContents; | 1001 String newContents; |
| 997 if (change is AddContentOverlay) { | 1002 if (change is AddContentOverlay) { |
| 998 newContents = change.content; | 1003 newContents = change.content; |
| 999 } else if (change is ChangeContentOverlay) { | 1004 } else if (change is ChangeContentOverlay) { |
| 1000 if (oldContents == null) { | 1005 if (oldContents == null) { |
| 1001 // The client may only send a ChangeContentOverlay if there is | 1006 // The client may only send a ChangeContentOverlay if there is |
| 1002 // already an existing overlay for the source. | 1007 // already an existing overlay for the source. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 // | 1071 // |
| 1067 // Update the defaults used to create new contexts. | 1072 // Update the defaults used to create new contexts. |
| 1068 // | 1073 // |
| 1069 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; | 1074 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; |
| 1070 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1075 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
| 1071 optionUpdater(options); | 1076 optionUpdater(options); |
| 1072 }); | 1077 }); |
| 1073 } | 1078 } |
| 1074 | 1079 |
| 1075 /** | 1080 /** |
| 1076 * Return the [Source] of the Dart file with the given [path], assuming that | 1081 * Returns the [CompilationUnit] of the Dart file with the given [source] that |
| 1077 * we do not know the context in which the path should be interpreted. | 1082 * should be used to resend notifications for already resolved unit. |
| 1083 * Returns `null` if the file is not a part of any context, library has not |
| 1084 * been yet resolved, or any problem happened. |
| 1078 */ | 1085 */ |
| 1079 Source _getSourceWithoutContext(String path) { | 1086 CompilationUnit _getResolvedCompilationUnitToResendNotification( |
| 1080 // try SDK | 1087 AnalysisContext context, Source source) { |
| 1081 { | 1088 List<Source> librarySources = context.getLibrariesContaining(source); |
| 1082 Uri uri = resourceProvider.pathContext.toUri(path); | 1089 if (librarySources.isEmpty) { |
| 1083 Source sdkSource = defaultSdk.fromFileUri(uri); | 1090 return null; |
| 1084 if (sdkSource != null) { | |
| 1085 return sdkSource; | |
| 1086 } | |
| 1087 } | 1091 } |
| 1088 // file-based source | 1092 // if library has not been resolved yet, the unit will be resolved later |
| 1089 File file = resourceProvider.getResource(path); | 1093 Source librarySource = librarySources[0]; |
| 1090 return file.createSource(); | 1094 if (context.getLibraryElement(librarySource) == null) { |
| 1095 return null; |
| 1096 } |
| 1097 // if library has been already resolved, resolve unit |
| 1098 return context.resolveCompilationUnit2(source, librarySource); |
| 1091 } | 1099 } |
| 1092 | 1100 |
| 1093 /** | 1101 /** |
| 1094 * Schedules [performOperation] exection. | 1102 * Schedules [performOperation] exection. |
| 1095 */ | 1103 */ |
| 1096 void _schedulePerformOperation() { | 1104 void _schedulePerformOperation() { |
| 1097 if (performOperationPending) { | 1105 if (performOperationPending) { |
| 1098 return; | 1106 return; |
| 1099 } | 1107 } |
| 1100 /* | 1108 /* |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1149 * The contexts that were removed from the server. | 1157 * The contexts that were removed from the server. |
| 1150 */ | 1158 */ |
| 1151 final List<AnalysisContext> removed; | 1159 final List<AnalysisContext> removed; |
| 1152 | 1160 |
| 1153 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, | 1161 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, |
| 1154 this.changed: AnalysisContext.EMPTY_LIST, | 1162 this.changed: AnalysisContext.EMPTY_LIST, |
| 1155 this.removed: AnalysisContext.EMPTY_LIST}); | 1163 this.removed: AnalysisContext.EMPTY_LIST}); |
| 1156 } | 1164 } |
| 1157 | 1165 |
| 1158 /** | 1166 /** |
| 1167 * Information about a file - an [AnalysisContext] that analyses the file, |
| 1168 * and the [Source] representing the file in this context. |
| 1169 */ |
| 1170 class ContextSourcePair { |
| 1171 /** |
| 1172 * A context that analysis the file. |
| 1173 * May be `null` if the file is not analyzed by any context. |
| 1174 */ |
| 1175 final AnalysisContext context; |
| 1176 |
| 1177 /** |
| 1178 * The source that corresponds to the file. |
| 1179 * May be `null` if the file is not a regular file. |
| 1180 * If the file cannot be found in the [context], then it has a `file` uri. |
| 1181 */ |
| 1182 final Source source; |
| 1183 |
| 1184 ContextSourcePair(this.context, this.source); |
| 1185 } |
| 1186 |
| 1187 /** |
| 1159 * A [PriorityChangeEvent] indicates the set the priority files has changed. | 1188 * A [PriorityChangeEvent] indicates the set the priority files has changed. |
| 1160 */ | 1189 */ |
| 1161 class PriorityChangeEvent { | 1190 class PriorityChangeEvent { |
| 1162 final Source firstSource; | 1191 final Source firstSource; |
| 1163 | 1192 |
| 1164 PriorityChangeEvent(this.firstSource); | 1193 PriorityChangeEvent(this.firstSource); |
| 1165 } | 1194 } |
| 1166 | 1195 |
| 1167 class ServerContextManager extends ContextManager { | 1196 class ServerContextManager extends ContextManager { |
| 1168 final AnalysisServer analysisServer; | 1197 final AnalysisServer analysisServer; |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 /** | 1393 /** |
| 1365 * The [PerformanceTag] for time spent in server request handlers. | 1394 * The [PerformanceTag] for time spent in server request handlers. |
| 1366 */ | 1395 */ |
| 1367 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); | 1396 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); |
| 1368 | 1397 |
| 1369 /** | 1398 /** |
| 1370 * The [PerformanceTag] for time spent in split store microtasks. | 1399 * The [PerformanceTag] for time spent in split store microtasks. |
| 1371 */ | 1400 */ |
| 1372 static PerformanceTag splitStore = new PerformanceTag('splitStore'); | 1401 static PerformanceTag splitStore = new PerformanceTag('splitStore'); |
| 1373 } | 1402 } |
| OLD | NEW |