Chromium Code Reviews| Index: pkg/analysis_server/lib/src/analysis_server.dart |
| diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart |
| index 6c7aae92c48bdb42885e76999a4b328fa638ca6f..1b72d179e3024a7dbb2ae10c2778ee48899191cd 100644 |
| --- a/pkg/analysis_server/lib/src/analysis_server.dart |
| +++ b/pkg/analysis_server/lib/src/analysis_server.dart |
| @@ -367,26 +367,26 @@ class AnalysisServer { |
| * path. |
| */ |
| AnalysisContext getAnalysisContext(String path) { |
| - // try to find a containing context |
| + return getContextSourcePair(path).context; |
| + } |
| + |
| + /** |
| + * Return the [AnalysisContext] that contains the given [path]. |
| + * Return `null` if no context contains the [path]. |
| + */ |
| + AnalysisContext getContainingContext(String path) { |
| Folder containingFolder = null; |
| - for (Folder folder in folderMap.keys) { |
| - if (folder.path == path || folder.contains(path)) { |
| - if (containingFolder == null) { |
| - containingFolder = folder; |
| - } else if (containingFolder.path.length < folder.path.length) { |
| + AnalysisContext containingContext = null; |
| + folderMap.forEach((Folder folder, AnalysisContext context) { |
| + if (folder.isOrContains(path)) { |
| + if (containingFolder == null || |
| + containingFolder.path.length < folder.path.length) { |
| containingFolder = folder; |
| + containingContext = context; |
| } |
| } |
| - } |
| - if (containingFolder != null) { |
| - return folderMap[containingFolder]; |
| - } |
| - Resource resource = resourceProvider.getResource(path); |
| - if (resource is Folder) { |
| - return null; |
| - } |
| - // check if there is a context that analyzed this source |
| - return getAnalysisContextForSource(_getSourceWithoutContext(path)); |
| + }); |
| + return containingContext; |
| } |
| /** |
| @@ -412,6 +412,67 @@ class AnalysisServer { |
| } |
| /** |
| + * Return the primary [ContextSourcePair] representing the given [path]. |
| + * |
| + * The [AnalysisContext] of this pair will be the context that explicitly |
| + * contains the path, if any such context exists, otherwise it will be the |
| + * first context that implicitly analyzes it. |
| + * |
| + * If the [path] is not analyzed by any context, a [ContextSourcePair] with |
| + * `null` context and `file` [Source] is returned. |
| + * |
| + * If the [path] dosn't represent a file, `null` is returned as a [Source]. |
| + * |
| + * Does not return `null`. |
| + */ |
| + ContextSourcePair getContextSourcePair(String path) { |
| + // try SDK |
| + { |
| + Uri uri = resourceProvider.pathContext.toUri(path); |
| + Source sdkSource = defaultSdk.fromFileUri(uri); |
| + if (sdkSource != null) { |
| + AnalysisContext anyContext = folderMap.values.first; |
| + return new ContextSourcePair(anyContext, sdkSource); |
| + } |
| + } |
| + // try to find the deep-most containing context |
| + Resource resource = resourceProvider.getResource(path); |
| + File file = resource is File ? resource : null; |
| + { |
| + Folder containingFolder = null; |
|
Brian Wilkerson
2015/03/06 15:04:27
This is very similar to getContainingContext; it w
scheglov
2015/03/06 21:47:03
Done.
|
| + AnalysisContext containingContext = null; |
| + folderMap.forEach((Folder folder, AnalysisContext context) { |
| + if (folder.isOrContains(path)) { |
| + if (containingFolder == null || |
| + containingFolder.path.length < folder.path.length) { |
| + containingFolder = folder; |
| + containingContext = context; |
| + } |
| + } |
| + }); |
| + if (containingContext != null) { |
| + Source source = file != null |
| + ? ContextManager.createSourceInContext(containingContext, file) |
| + : null; |
| + return new ContextSourcePair(containingContext, source); |
| + } |
| + } |
| + // try to find a context that analysed the file |
| + for (AnalysisContext context in folderMap.values) { |
| + Source source = file != null |
| + ? ContextManager.createSourceInContext(context, file) |
| + : null; |
| + SourceKind kind = context.getKindOf(source); |
| + if (kind != SourceKind.UNKNOWN) { |
| + return new ContextSourcePair(context, source); |
| + } |
| + } |
| + // file-based source |
| + Source fileSource = file != null ? file.createSource() : null; |
| + return new ContextSourcePair(null, fileSource); |
| + } |
| + |
| + /** |
| * Returns [Element]s at the given [offset] of the given [file]. |
| * |
| * May be empty if cannot be resolved, but not `null`. |
| @@ -460,37 +521,18 @@ class AnalysisServer { |
| * the current state. |
| */ |
| AnalysisErrorInfo getErrors(String file) { |
| - // prepare AnalysisContext |
| - AnalysisContext context = getAnalysisContext(file); |
| + ContextSourcePair contextSource = getContextSourcePair(file); |
| + AnalysisContext context = contextSource.context; |
| + Source source = contextSource.source; |
| if (context == null) { |
| return null; |
| } |
| - // prepare Source |
| - Source source = getSource(file); |
| - if (context.getKindOf(source) == SourceKind.UNKNOWN) { |
| + if (!source.exists()) { |
| return null; |
| } |
| - // get errors for the file |
| return context.getErrors(source); |
| } |
| - /** |
| - * Returns resolved [AstNode]s at the given [offset] of the given [file]. |
| - * |
| - * May be empty, but not `null`. |
| - */ |
| - List<AstNode> getNodesAtOffset(String file, int offset) { |
| - List<CompilationUnit> units = getResolvedCompilationUnits(file); |
| - List<AstNode> nodes = <AstNode>[]; |
| - for (CompilationUnit unit in units) { |
| - AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| - if (node != null) { |
| - nodes.add(node); |
| - } |
| - } |
| - return nodes; |
| - } |
| - |
| // TODO(brianwilkerson) Add the following method after 'prioritySources' has |
| // been added to InternalAnalysisContext. |
| // /** |
| @@ -509,19 +551,37 @@ class AnalysisServer { |
| // } |
| /** |
| + * Returns resolved [AstNode]s at the given [offset] of the given [file]. |
| + * |
| + * May be empty, but not `null`. |
| + */ |
| + List<AstNode> getNodesAtOffset(String file, int offset) { |
| + List<CompilationUnit> units = getResolvedCompilationUnits(file); |
| + List<AstNode> nodes = <AstNode>[]; |
| + for (CompilationUnit unit in units) { |
| + AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| + if (node != null) { |
| + nodes.add(node); |
| + } |
| + } |
| + return nodes; |
| + } |
| + |
| + /** |
| * Returns resolved [CompilationUnit]s of the Dart file with the given [path]. |
| * |
| * May be empty, but not `null`. |
| */ |
| List<CompilationUnit> getResolvedCompilationUnits(String path) { |
| List<CompilationUnit> units = <CompilationUnit>[]; |
| + ContextSourcePair contextSource = getContextSourcePair(path); |
| // prepare AnalysisContext |
| - AnalysisContext context = getAnalysisContext(path); |
| + AnalysisContext context = contextSource.context; |
| if (context == null) { |
| return units; |
| } |
| // add a unit for each unit/library combination |
| - Source unitSource = getSource(path); |
| + Source unitSource = contextSource.source; |
| List<Source> librarySources = context.getLibrariesContaining(unitSource); |
| for (Source librarySource in librarySources) { |
| CompilationUnit unit = |
| @@ -535,50 +595,6 @@ class AnalysisServer { |
| } |
| /** |
| - * Returns the [CompilationUnit] of the Dart file with the given [path] that |
| - * should be used to resend notifications for already resolved unit. |
| - * Returns `null` if the file is not a part of any context, library has not |
| - * been yet resolved, or any problem happened. |
| - */ |
| - CompilationUnit getResolvedCompilationUnitToResendNotification(String path) { |
| - // prepare AnalysisContext |
| - AnalysisContext context = getAnalysisContext(path); |
| - if (context == null) { |
| - return null; |
| - } |
| - // prepare sources |
| - Source unitSource = getSource(path); |
| - List<Source> librarySources = context.getLibrariesContaining(unitSource); |
| - if (librarySources.isEmpty) { |
| - return null; |
| - } |
| - // if library has not been resolved yet, the unit will be resolved later |
| - Source librarySource = librarySources[0]; |
| - if (context.getLibraryElement(librarySource) == null) { |
| - return null; |
| - } |
| - // if library has been already resolved, resolve unit |
| - return context.resolveCompilationUnit2(unitSource, librarySource); |
| - } |
| - |
| - /** |
| - * Return the [Source] of the Dart file with the given [path]. |
| - */ |
| - Source getSource(String path) { |
| - // try SDK |
| - { |
| - Uri uri = resourceProvider.pathContext.toUri(path); |
| - Source sdkSource = defaultSdk.fromFileUri(uri); |
| - if (sdkSource != null) { |
| - return sdkSource; |
| - } |
| - } |
| - // file-based source |
| - File file = resourceProvider.getResource(path); |
| - return ContextManager.createSourceInContext(getAnalysisContext(path), file); |
| - } |
| - |
| - /** |
| * Handle a [request] that was read from the communication channel. |
| */ |
| void handleRequest(Request request) { |
| @@ -852,16 +868,17 @@ class AnalysisServer { |
| Set<String> todoFiles = |
| oldFiles != null ? newFiles.difference(oldFiles) : newFiles; |
| for (String file in todoFiles) { |
| - Source source = getSource(file); |
| + ContextSourcePair contextSource = getContextSourcePair(file); |
| // prepare context |
| - AnalysisContext context = getAnalysisContext(file); |
| + AnalysisContext context = contextSource.context; |
| if (context == null) { |
| continue; |
| } |
| // Dart unit notifications. |
| if (AnalysisEngine.isDartFileName(file)) { |
| + Source source = contextSource.source; |
| CompilationUnit dartUnit = |
| - getResolvedCompilationUnitToResendNotification(file); |
| + _getResolvedCompilationUnitToResendNotification(context, source); |
| if (dartUnit != null) { |
| switch (service) { |
| case AnalysisService.HIGHLIGHTS: |
| @@ -875,6 +892,7 @@ class AnalysisServer { |
| sendAnalysisNotificationOccurrences(this, file, dartUnit); |
| break; |
| case AnalysisService.OUTLINE: |
| + AnalysisContext context = dartUnit.element.context; |
| LineInfo lineInfo = context.getLineInfo(source); |
| sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit); |
| break; |
| @@ -901,9 +919,11 @@ class AnalysisServer { |
| Map<AnalysisContext, List<Source>> sourceMap = |
| new HashMap<AnalysisContext, List<Source>>(); |
| List<String> unanalyzed = new List<String>(); |
| + Source firstSource = null; |
| files.forEach((file) { |
| - AnalysisContext preferredContext = getAnalysisContext(file); |
| - Source source = getSource(file); |
| + ContextSourcePair contextSource = getContextSourcePair(file); |
| + AnalysisContext preferredContext = contextSource.context; |
| + Source source = contextSource.source; |
| bool contextFound = false; |
| for (AnalysisContext context in folderMap.values) { |
| if (context == preferredContext || |
| @@ -912,6 +932,9 @@ class AnalysisServer { |
| contextFound = true; |
| } |
| } |
| + if (firstSource == null) { |
| + firstSource = source; |
| + } |
| if (!contextFound) { |
| unanalyzed.add(file); |
| } |
| @@ -933,7 +956,6 @@ class AnalysisServer { |
| schedulePerformAnalysisOperation(context); |
| }); |
| operationQueue.reschedule(); |
| - Source firstSource = files.length > 0 ? getSource(files[0]) : null; |
| _onPriorityChangeController.add(new PriorityChangeEvent(firstSource)); |
| } |
| @@ -962,8 +984,9 @@ class AnalysisServer { |
| void test_flushResolvedUnit(String file) { |
| if (AnalysisEngine.isDartFileName(file)) { |
| - AnalysisContextImpl context = getAnalysisContext(file); |
| - Source source = getSource(file); |
| + ContextSourcePair contextSource = getContextSourcePair(file); |
| + AnalysisContextImpl context = contextSource.context; |
| + Source source = contextSource.source; |
| DartEntry dartEntry = context.getReadableSourceEntryOrNull(source); |
| dartEntry.flushAstStructures(); |
| } |
| @@ -989,7 +1012,8 @@ class AnalysisServer { |
| */ |
| void updateContent(String id, Map<String, dynamic> changes) { |
| changes.forEach((file, change) { |
| - Source source = getSource(file); |
| + ContextSourcePair contextSource = getContextSourcePair(file); |
| + Source source = contextSource.source; |
| operationQueue.sourceAboutToChange(source); |
| // Prepare the new contents. |
| String oldContents = overlayState.getContents(source); |
| @@ -1073,21 +1097,24 @@ class AnalysisServer { |
| } |
| /** |
| - * Return the [Source] of the Dart file with the given [path], assuming that |
| - * we do not know the context in which the path should be interpreted. |
| + * Returns the [CompilationUnit] of the Dart file with the given [source] that |
| + * should be used to resend notifications for already resolved unit. |
| + * Returns `null` if the file is not a part of any context, library has not |
| + * been yet resolved, or any problem happened. |
| */ |
| - Source _getSourceWithoutContext(String path) { |
| - // try SDK |
| - { |
| - Uri uri = resourceProvider.pathContext.toUri(path); |
| - Source sdkSource = defaultSdk.fromFileUri(uri); |
| - if (sdkSource != null) { |
| - return sdkSource; |
| - } |
| + CompilationUnit _getResolvedCompilationUnitToResendNotification( |
| + AnalysisContext context, Source source) { |
| + List<Source> librarySources = context.getLibrariesContaining(source); |
| + if (librarySources.isEmpty) { |
| + return null; |
| } |
| - // file-based source |
| - File file = resourceProvider.getResource(path); |
| - return file.createSource(); |
| + // if library has not been resolved yet, the unit will be resolved later |
| + Source librarySource = librarySources[0]; |
| + if (context.getLibraryElement(librarySource) == null) { |
| + return null; |
| + } |
| + // if library has been already resolved, resolve unit |
| + return context.resolveCompilationUnit2(source, librarySource); |
| } |
| /** |
| @@ -1155,6 +1182,12 @@ class ContextsChangedEvent { |
| this.removed: AnalysisContext.EMPTY_LIST}); |
| } |
| +class ContextSourcePair { |
|
Brian Wilkerson
2015/03/06 15:04:27
Comments?
scheglov
2015/03/06 21:47:03
Done.
|
| + final AnalysisContext context; |
| + final Source source; |
| + ContextSourcePair(this.context, this.source); |
| +} |
| + |
| /** |
| * A [PriorityChangeEvent] indicates the set the priority files has changed. |
| */ |