Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: pkg/analysis_server/lib/src/analysis_server.dart

Issue 987663002: Fix for subscribing for notifications for files in packages. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes for review comments. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/context_manager.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/context_manager.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698