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 7ebd6c680fc2cfde806d6178e3a0591fd9f4b63d..4ca12d1e00034770578f5e68f5908d900446e5b1 100644 |
| --- a/pkg/analysis_server/lib/src/analysis_server.dart |
| +++ b/pkg/analysis_server/lib/src/analysis_server.dart |
| @@ -9,9 +9,14 @@ import 'dart:async'; |
| import 'package:analysis_server/src/analysis_logger.dart'; |
| import 'package:analysis_server/src/channel.dart'; |
| import 'package:analysis_server/src/protocol.dart'; |
| +import 'package:analysis_server/src/resource.dart'; |
| +import 'package:analyzer/src/generated/ast.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/error.dart'; |
| import 'package:analyzer/src/generated/java_core.dart'; |
| +import 'package:analyzer/src/generated/sdk.dart'; |
| +import 'package:analyzer/src/generated/sdk_io.dart'; |
| +import 'package:analyzer/src/generated/source_io.dart'; |
| /** |
| * Instances of the class [AnalysisServer] implement a server that listens on a |
| @@ -50,6 +55,11 @@ class AnalysisServer { |
| final ServerCommunicationChannel channel; |
| /** |
| + * The [ResourceProvider] using which paths are converted into [Resource]s. |
| + */ |
| + final ResourceProvider resourceProvider; |
| + |
| + /** |
| * A flag indicating whether the server is running. When false, contexts |
| * will no longer be added to [contextWorkQueue], and [performTask] will |
| * discard any tasks it finds on [contextWorkQueue]. |
| @@ -62,15 +72,21 @@ class AnalysisServer { |
| */ |
| List<RequestHandler> handlers; |
| - /** |
| - * A table mapping context id's to the analysis contexts associated with them. |
| - */ |
| - final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContext>(); |
| + // TODO(scheglov) remove once setAnalysisRoots() is completely implemented |
| +// /** |
| +// * A table mapping context id's to the analysis contexts associated with them. |
| +// */ |
| +// final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContext>(); |
| +// |
| +// /** |
| +// * A table mapping analysis contexts to the context id's associated with them. |
| +// */ |
| +// final Map<AnalysisContext, String> contextIdMap = new Map<AnalysisContext, String>(); |
| /** |
| - * A table mapping analysis contexts to the context id's associated with them. |
| + * A table mapping [Folder]s to the [PubFolder]s associated with them. |
| */ |
| - final Map<AnalysisContext, String> contextIdMap = new Map<AnalysisContext, String>(); |
| + final Map<Folder, PubFolder> folderMap = <Folder, PubFolder>{}; |
| /** |
| * A list of the analysis contexts for which analysis work needs to be |
| @@ -91,7 +107,7 @@ class AnalysisServer { |
| * Initialize a newly created server to receive requests from and send |
| * responses to the given [channel]. |
| */ |
| - AnalysisServer(this.channel) { |
| + AnalysisServer(this.channel, this.resourceProvider) { |
| AnalysisEngine.instance.logger = new AnalysisLogger(); |
| running = true; |
| Notification notification = new Notification(CONNECTED_NOTIFICATION); |
| @@ -172,10 +188,10 @@ class AnalysisServer { |
| // Look for a context that has work to be done and then perform one task. |
| // |
| List<ChangeNotice> notices = null; |
| - String contextId; |
| +// String contextId; |
| try { |
| AnalysisContext context = contextWorkQueue[0]; |
| - contextId = contextIdMap[context]; |
| +// contextId = contextIdMap[context]; |
| AnalysisResult result = context.performAnalysisTask(); |
| notices = result.changeNotices; |
| } finally { |
| @@ -194,24 +210,76 @@ class AnalysisServer { |
| _scheduleTask(); |
| } |
| } |
| - if (notices != null) { |
| - sendNotices(contextId, notices); |
| + // TODO(scheglov) implement for [PubFolder] |
| +// if (notices != null) { |
| +// sendNotices(contextId, notices); |
| +// } |
| + } |
| + |
| + // TODO(scheglov) rewrite for the new API. |
| +// /** |
| +// * Send the information in the given list of notices back to the client. |
| +// */ |
| +// void sendNotices(String contextId, List<ChangeNotice> notices) { |
| +// for (int i = 0; i < notices.length; i++) { |
| +// ChangeNotice notice = notices[i]; |
| +// Notification notification = new Notification(ERROR_NOTIFICATION_NAME); |
| +// notification.setParameter(CONTEXT_ID_PARAM, contextId); |
| +// notification.setParameter(SOURCE_PARAM, notice.source.encoding); |
| +// notification.setParameter(ERRORS_PARAM, notice.errors.map( |
| +// errorToJson).toList()); |
| +// sendNotification(notification); |
| +// } |
| +// } |
| + |
| + void setAnalysisRoots(Set<Folder> includedFolders, Set<Folder> excludedFolders) { |
|
Brian Wilkerson
2014/05/27 14:09:57
This doesn't look for nested pub folders.
scheglov
2014/05/27 18:24:24
Yes, and it is intentional.
I've added comment to
|
| + Set<Folder> currentFolders = new Set<Folder>.from(folderMap.keys); |
|
Paul Berry
2014/05/27 16:30:29
What about analysis roots that aren't folders?
|
| + Set<Folder> newFolders = includedFolders.difference(currentFolders); |
| + Set<Folder> oldFolders = currentFolders.difference(includedFolders); |
| + // remove old contexts |
| + for (Folder folder in oldFolders) { |
| + // TODO(scheglov) implement |
| + } |
| + // add new contexts |
| + for (Folder folder in newFolders) { |
| + PubFolder pubFolder = new PubFolder(folder); |
|
Brian Wilkerson
2014/05/27 14:09:57
What about analysis roots that do not contain a pu
|
| + folderMap[folder] = pubFolder; |
| + addContextToWorkQueue(pubFolder.context); |
| + } |
| + } |
| + |
| + /** |
| + * Return the [AnalysisContext] that is used to analyze the given [path]. |
| + * Return `null` if there is no such context. |
| + */ |
| + AnalysisContext test_getAnalysisContext(String path) { |
|
Paul Berry
2014/05/27 16:30:29
What does it mean that this function (and test_get
scheglov
2014/05/27 18:24:24
These methods are supposed to be used only by test
|
| + for (Folder folder in folderMap.keys) { |
| + if (path.startsWith(folder.fullName)) { |
|
Brian Wilkerson
2014/05/27 14:09:57
Would it be better to use the names of folders as
scheglov
2014/05/27 18:24:24
I don't know.
In theory Resource can provide some
|
| + return folderMap[folder].context; |
| + } |
| } |
| + return null; |
| } |
| /** |
| - * Send the information in the given list of notices back to the client. |
| + * Return the [CompilationUnit] of the Dart file with the given [path]. |
|
Paul Berry
2014/05/27 16:30:29
What happens if the dart file in question isn't un
scheglov
2014/05/27 18:24:24
I guess we will have to check if the file is under
|
| + * Return `null` if the file is not a part of any context. |
| */ |
| - void sendNotices(String contextId, List<ChangeNotice> notices) { |
| - for (int i = 0; i < notices.length; i++) { |
| - ChangeNotice notice = notices[i]; |
| - Notification notification = new Notification(ERROR_NOTIFICATION_NAME); |
| - notification.setParameter(CONTEXT_ID_PARAM, contextId); |
| - notification.setParameter(SOURCE_PARAM, notice.source.encoding); |
| - notification.setParameter(ERRORS_PARAM, notice.errors.map( |
| - errorToJson).toList()); |
| - sendNotification(notification); |
| + CompilationUnit test_getResolvedCompilationUnit(String path) { |
| + // prepare AnalysisContext |
| + AnalysisContext context = test_getAnalysisContext(path); |
| + if (context == null) { |
| + return null; |
| } |
| + // prepare sources |
| + File file = resourceProvider.getResource(path); |
| + Source unitSource = file.createSource(UriKind.FILE_URI); |
| + List<Source> librarySources = context.getLibrariesContaining(unitSource); |
| + if (librarySources.isEmpty) { |
| + return null; |
| + } |
| + // get a resolved unit |
| + return context.getResolvedCompilationUnit2(unitSource, librarySources[0]); |
| } |
| static Map<String, Object> errorToJson(AnalysisError analysisError) { |
| @@ -265,6 +333,83 @@ class AnalysisService extends Enum2<AnalysisService> { |
| /** |
| + * Instances of [PubFolder] represents a [Folder] with a Pub `pubspec.yaml`. |
| + * |
| + * TODO(scheglov) implement complete projects/contexts semantics. |
| + * |
| + * This class is intentionally simplified to serve as a base to start working |
| + * on services while work on complete semantics is being done in parallel. |
| + */ |
| +class PubFolder { |
| + static final DartSdk DEFAULT_SDK = DirectoryBasedDartSdk.defaultSdk; |
|
Brian Wilkerson
2014/05/27 14:09:57
I don't think this is the best place to store the
scheglov
2014/05/27 18:24:24
Done.
|
| + |
| + /** |
| + * The root [Folder] of this [PubFolder]. |
| + */ |
| + final Folder _folder; |
| + |
| + /** |
| + * The `pubspec.yaml` file in [_folder]. |
| + */ |
| + File _pubspecFile; |
| + |
| + /** |
| + * The [AnalysisContext] of this [_folder]. |
| + */ |
| + AnalysisContext _context; |
| + |
| + PubFolder(this._folder) { |
| + // prepare pubspec.yaml |
| + _pubspecFile = _folder.getChild('pubspec.yaml'); |
| + if (!_pubspecFile.exists) { |
| + throw new ArgumentError('$_pubspecFile does not exist'); |
| + } |
| + // TODO(scheglov) use configurable default SDK |
| + DartSdk sdk = DEFAULT_SDK; |
| + // create AnalysisContext |
| + _context = AnalysisEngine.instance.createAnalysisContext(); |
| + // TODO(scheglov) replace FileUriResolver with an Resource based resolver |
| + // TODO(scheglov) create packages resolver |
| + _context.sourceFactory = new SourceFactory([ |
| + new DartUriResolver(sdk), |
| + new FileUriResolver(), |
| + // new PackageUriResolver(), |
| + ]); |
| + // add folder files |
| + { |
| + ChangeSet changeSet = new ChangeSet(); |
| + _addSourceFiles(changeSet, _folder); |
| + _context.applyChanges(changeSet); |
| + } |
| + } |
| + |
| + /** |
| + * Return the [AnalysisContext] of this folder. |
| + */ |
| + AnalysisContext get context => _context; |
| + |
| + /** |
| + * Resursively adds all Dart and HTML files to the [changeSet]. |
| + */ |
| + static void _addSourceFiles(ChangeSet changeSet, Folder folder) { |
| + List<Resource> children = folder.getChildren(); |
| + for (Resource child in children) { |
| + if (child is File) { |
| + String fileName = child.shortName; |
| + if (AnalysisEngine.isDartFileName(fileName) |
| + || AnalysisEngine.isHtmlFileName(fileName)) { |
| + Source source = child.createSource(UriKind.FILE_URI); |
| + changeSet.addedSource(source); |
| + } |
| + } else if (child is Folder) { |
| + _addSourceFiles(changeSet, child); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| +/** |
| * An enumeration of the services provided by the server domain. |
| */ |
| class ServerService extends Enum2<ServerService> { |