| 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..4b5529dbe73963050da59200c9751bb13915d436 100644
|
| --- a/pkg/analysis_server/lib/src/analysis_server.dart
|
| +++ b/pkg/analysis_server/lib/src/analysis_server.dart
|
| @@ -367,26 +367,7 @@ class AnalysisServer {
|
| * path.
|
| */
|
| AnalysisContext getAnalysisContext(String path) {
|
| - // try to find a containing context
|
| - 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) {
|
| - containingFolder = folder;
|
| - }
|
| - }
|
| - }
|
| - 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 getContextSourcePair(path).context;
|
| }
|
|
|
| /**
|
| @@ -412,6 +393,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;
|
| + 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 +502,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 +532,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 +576,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 +849,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 +873,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 +900,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 +913,9 @@ class AnalysisServer {
|
| contextFound = true;
|
| }
|
| }
|
| + if (firstSource == null) {
|
| + firstSource = source;
|
| + }
|
| if (!contextFound) {
|
| unanalyzed.add(file);
|
| }
|
| @@ -933,7 +937,6 @@ class AnalysisServer {
|
| schedulePerformAnalysisOperation(context);
|
| });
|
| operationQueue.reschedule();
|
| - Source firstSource = files.length > 0 ? getSource(files[0]) : null;
|
| _onPriorityChangeController.add(new PriorityChangeEvent(firstSource));
|
| }
|
|
|
| @@ -962,8 +965,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 +993,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 +1078,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);
|
| }
|
|
|
| /**
|
| @@ -1156,6 +1164,27 @@ class ContextsChangedEvent {
|
| }
|
|
|
| /**
|
| + * Information about a file - an [AnalysisContext] that analyses the file,
|
| + * and the [Source] representing the file in this context.
|
| + */
|
| +class ContextSourcePair {
|
| + /**
|
| + * A context that analysis the file.
|
| + * May be `null` if the file is not analyzed by any context.
|
| + */
|
| + final AnalysisContext context;
|
| +
|
| + /**
|
| + * The source that corresponds to the file.
|
| + * May be `null` if the file is not a regular file.
|
| + * If the file cannot be found in the [context], then it has a `file` uri.
|
| + */
|
| + final Source source;
|
| +
|
| + ContextSourcePair(this.context, this.source);
|
| +}
|
| +
|
| +/**
|
| * A [PriorityChangeEvent] indicates the set the priority files has changed.
|
| */
|
| class PriorityChangeEvent {
|
|
|