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

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

Issue 300023004: Partial implementation of the 'setAnalysisRoots' API. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 6 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
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 8
9 import 'package:analysis_server/src/analysis_logger.dart'; 9 import 'package:analysis_server/src/analysis_logger.dart';
10 import 'package:analysis_server/src/channel.dart'; 10 import 'package:analysis_server/src/channel.dart';
11 import 'package:analysis_server/src/protocol.dart'; 11 import 'package:analysis_server/src/protocol.dart';
12 import 'package:analysis_server/src/resource.dart';
13 import 'package:analyzer/src/generated/ast.dart';
12 import 'package:analyzer/src/generated/engine.dart'; 14 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/error.dart'; 15 import 'package:analyzer/src/generated/error.dart';
14 import 'package:analyzer/src/generated/java_core.dart'; 16 import 'package:analyzer/src/generated/java_core.dart';
17 import 'package:analyzer/src/generated/sdk.dart';
18 import 'package:analyzer/src/generated/sdk_io.dart';
19 import 'package:analyzer/src/generated/source_io.dart';
15 20
16 /** 21 /**
17 * Instances of the class [AnalysisServer] implement a server that listens on a 22 * Instances of the class [AnalysisServer] implement a server that listens on a
18 * [CommunicationChannel] for analysis requests and process them. 23 * [CommunicationChannel] for analysis requests and process them.
19 */ 24 */
20 class AnalysisServer { 25 class AnalysisServer {
21 /** 26 /**
22 * The name of the notification of new errors associated with a source. 27 * The name of the notification of new errors associated with a source.
23 */ 28 */
24 static const String ERROR_NOTIFICATION_NAME = 'context.errors'; 29 static const String ERROR_NOTIFICATION_NAME = 'context.errors';
(...skipping 18 matching lines...) Expand all
43 */ 48 */
44 static const String CONNECTED_NOTIFICATION = 'server.connected'; 49 static const String CONNECTED_NOTIFICATION = 'server.connected';
45 50
46 /** 51 /**
47 * The channel from which requests are received and to which responses should 52 * The channel from which requests are received and to which responses should
48 * be sent. 53 * be sent.
49 */ 54 */
50 final ServerCommunicationChannel channel; 55 final ServerCommunicationChannel channel;
51 56
52 /** 57 /**
58 * The [ResourceProvider] using which paths are converted into [Resource]s.
59 */
60 final ResourceProvider resourceProvider;
61
62 /**
53 * A flag indicating whether the server is running. When false, contexts 63 * A flag indicating whether the server is running. When false, contexts
54 * will no longer be added to [contextWorkQueue], and [performTask] will 64 * will no longer be added to [contextWorkQueue], and [performTask] will
55 * discard any tasks it finds on [contextWorkQueue]. 65 * discard any tasks it finds on [contextWorkQueue].
56 */ 66 */
57 bool running; 67 bool running;
58 68
59 /** 69 /**
60 * A list of the request handlers used to handle the requests sent to this 70 * A list of the request handlers used to handle the requests sent to this
61 * server. 71 * server.
62 */ 72 */
63 List<RequestHandler> handlers; 73 List<RequestHandler> handlers;
64 74
65 /** 75 // TODO(scheglov) remove once setAnalysisRoots() is completely implemented
66 * A table mapping context id's to the analysis contexts associated with them. 76 // /**
67 */ 77 // * A table mapping context id's to the analysis contexts associated with the m.
68 final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContex t>(); 78 // */
79 // final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisCont ext>();
80 //
81 // /**
82 // * A table mapping analysis contexts to the context id's associated with the m.
83 // */
84 // final Map<AnalysisContext, String> contextIdMap = new Map<AnalysisContext, S tring>();
69 85
70 /** 86 /**
71 * A table mapping analysis contexts to the context id's associated with them. 87 * A table mapping [Folder]s to the [PubFolder]s associated with them.
72 */ 88 */
73 final Map<AnalysisContext, String> contextIdMap = new Map<AnalysisContext, Str ing>(); 89 final Map<Folder, PubFolder> folderMap = <Folder, PubFolder>{};
74 90
75 /** 91 /**
76 * A list of the analysis contexts for which analysis work needs to be 92 * A list of the analysis contexts for which analysis work needs to be
77 * performed. 93 * performed.
78 * 94 *
79 * Invariant: when this list is non-empty, there is exactly one pending call 95 * Invariant: when this list is non-empty, there is exactly one pending call
80 * to [performTask] on the event queue. When this list is empty, there are 96 * to [performTask] on the event queue. When this list is empty, there are
81 * no calls to [performTask] on the event queue. 97 * no calls to [performTask] on the event queue.
82 */ 98 */
83 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>(); 99 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>();
84 100
85 /** 101 /**
86 * A set of the [ServerService]s to send notifications for. 102 * A set of the [ServerService]s to send notifications for.
87 */ 103 */
88 Set<ServerService> serverServices = new Set<ServerService>(); 104 Set<ServerService> serverServices = new Set<ServerService>();
89 105
90 /** 106 /**
91 * Initialize a newly created server to receive requests from and send 107 * Initialize a newly created server to receive requests from and send
92 * responses to the given [channel]. 108 * responses to the given [channel].
93 */ 109 */
94 AnalysisServer(this.channel) { 110 AnalysisServer(this.channel, this.resourceProvider) {
95 AnalysisEngine.instance.logger = new AnalysisLogger(); 111 AnalysisEngine.instance.logger = new AnalysisLogger();
96 running = true; 112 running = true;
97 Notification notification = new Notification(CONNECTED_NOTIFICATION); 113 Notification notification = new Notification(CONNECTED_NOTIFICATION);
98 channel.sendNotification(notification); 114 channel.sendNotification(notification);
99 channel.listen(handleRequest, onDone: done, onError: error); 115 channel.listen(handleRequest, onDone: done, onError: error);
100 } 116 }
101 117
102 /** 118 /**
103 * If [running] is true, add the given [context] to the list of analysis 119 * If [running] is true, add the given [context] to the list of analysis
104 * contexts for which analysis work needs to be performed, and ensure that 120 * contexts for which analysis work needs to be performed, and ensure that
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 contextWorkQueue.clear(); 181 contextWorkQueue.clear();
166 } 182 }
167 if (contextWorkQueue.isEmpty) { 183 if (contextWorkQueue.isEmpty) {
168 // Nothing to do. 184 // Nothing to do.
169 return; 185 return;
170 } 186 }
171 // 187 //
172 // Look for a context that has work to be done and then perform one task. 188 // Look for a context that has work to be done and then perform one task.
173 // 189 //
174 List<ChangeNotice> notices = null; 190 List<ChangeNotice> notices = null;
175 String contextId; 191 // String contextId;
176 try { 192 try {
177 AnalysisContext context = contextWorkQueue[0]; 193 AnalysisContext context = contextWorkQueue[0];
178 contextId = contextIdMap[context]; 194 // contextId = contextIdMap[context];
179 AnalysisResult result = context.performAnalysisTask(); 195 AnalysisResult result = context.performAnalysisTask();
180 notices = result.changeNotices; 196 notices = result.changeNotices;
181 } finally { 197 } finally {
182 if (notices == null) { 198 if (notices == null) {
183 // Either we have no more work to do for this context, or there was an 199 // Either we have no more work to do for this context, or there was an
184 // unhandled exception trying to perform the analysis. In either case, 200 // unhandled exception trying to perform the analysis. In either case,
185 // remove the context form the work queue so we won't try to do more 201 // remove the context form the work queue so we won't try to do more
186 // analysis on it. 202 // analysis on it.
187 contextWorkQueue.removeAt(0); 203 contextWorkQueue.removeAt(0);
188 } 204 }
189 // 205 //
190 // Schedule this method to be run again if there is any more work to be 206 // Schedule this method to be run again if there is any more work to be
191 // done. 207 // done.
192 // 208 //
193 if (!contextWorkQueue.isEmpty) { 209 if (!contextWorkQueue.isEmpty) {
194 _scheduleTask(); 210 _scheduleTask();
195 } 211 }
196 } 212 }
197 if (notices != null) { 213 // TODO(scheglov) implement for [PubFolder]
198 sendNotices(contextId, notices); 214 // if (notices != null) {
215 // sendNotices(contextId, notices);
216 // }
217 }
218
219 // TODO(scheglov) rewrite for the new API.
220 // /**
221 // * Send the information in the given list of notices back to the client.
222 // */
223 // void sendNotices(String contextId, List<ChangeNotice> notices) {
224 // for (int i = 0; i < notices.length; i++) {
225 // ChangeNotice notice = notices[i];
226 // Notification notification = new Notification(ERROR_NOTIFICATION_NAME);
227 // notification.setParameter(CONTEXT_ID_PARAM, contextId);
228 // notification.setParameter(SOURCE_PARAM, notice.source.encoding);
229 // notification.setParameter(ERRORS_PARAM, notice.errors.map(
230 // errorToJson).toList());
231 // sendNotification(notification);
232 // }
233 // }
234
235 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
236 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?
237 Set<Folder> newFolders = includedFolders.difference(currentFolders);
238 Set<Folder> oldFolders = currentFolders.difference(includedFolders);
239 // remove old contexts
240 for (Folder folder in oldFolders) {
241 // TODO(scheglov) implement
242 }
243 // add new contexts
244 for (Folder folder in newFolders) {
245 PubFolder pubFolder = new PubFolder(folder);
Brian Wilkerson 2014/05/27 14:09:57 What about analysis roots that do not contain a pu
246 folderMap[folder] = pubFolder;
247 addContextToWorkQueue(pubFolder.context);
199 } 248 }
200 } 249 }
201 250
202 /** 251 /**
203 * Send the information in the given list of notices back to the client. 252 * Return the [AnalysisContext] that is used to analyze the given [path].
253 * Return `null` if there is no such context.
204 */ 254 */
205 void sendNotices(String contextId, List<ChangeNotice> notices) { 255 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
206 for (int i = 0; i < notices.length; i++) { 256 for (Folder folder in folderMap.keys) {
207 ChangeNotice notice = notices[i]; 257 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
208 Notification notification = new Notification(ERROR_NOTIFICATION_NAME); 258 return folderMap[folder].context;
209 notification.setParameter(CONTEXT_ID_PARAM, contextId); 259 }
210 notification.setParameter(SOURCE_PARAM, notice.source.encoding);
211 notification.setParameter(ERRORS_PARAM, notice.errors.map(
212 errorToJson).toList());
213 sendNotification(notification);
214 } 260 }
261 return null;
262 }
263
264 /**
265 * 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
266 * Return `null` if the file is not a part of any context.
267 */
268 CompilationUnit test_getResolvedCompilationUnit(String path) {
269 // prepare AnalysisContext
270 AnalysisContext context = test_getAnalysisContext(path);
271 if (context == null) {
272 return null;
273 }
274 // prepare sources
275 File file = resourceProvider.getResource(path);
276 Source unitSource = file.createSource(UriKind.FILE_URI);
277 List<Source> librarySources = context.getLibrariesContaining(unitSource);
278 if (librarySources.isEmpty) {
279 return null;
280 }
281 // get a resolved unit
282 return context.getResolvedCompilationUnit2(unitSource, librarySources[0]);
215 } 283 }
216 284
217 static Map<String, Object> errorToJson(AnalysisError analysisError) { 285 static Map<String, Object> errorToJson(AnalysisError analysisError) {
218 // TODO(paulberry): move this function into the AnalysisError class. 286 // TODO(paulberry): move this function into the AnalysisError class.
219 287
220 // TODO(paulberry): we really shouldn't be exposing errorCode.ordinal 288 // TODO(paulberry): we really shouldn't be exposing errorCode.ordinal
221 // outside the analyzer, since the ordinal numbers change whenever we 289 // outside the analyzer, since the ordinal numbers change whenever we
222 // regenerate the analysis engine. 290 // regenerate the analysis engine.
223 Map<String, Object> result = { 291 Map<String, Object> result = {
224 'source': analysisError.source.encoding, 292 'source': analysisError.source.encoding,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 static const AnalysisService OUTLINE = const AnalysisService('OUTLINE', 3); 326 static const AnalysisService OUTLINE = const AnalysisService('OUTLINE', 3);
259 327
260 static const List<AnalysisService> VALUES = 328 static const List<AnalysisService> VALUES =
261 const [ERRORS, HIGHLIGHTS, NAVIGATION, OUTLINE]; 329 const [ERRORS, HIGHLIGHTS, NAVIGATION, OUTLINE];
262 330
263 const AnalysisService(String name, int ordinal) : super(name, ordinal); 331 const AnalysisService(String name, int ordinal) : super(name, ordinal);
264 } 332 }
265 333
266 334
267 /** 335 /**
336 * Instances of [PubFolder] represents a [Folder] with a Pub `pubspec.yaml`.
337 *
338 * TODO(scheglov) implement complete projects/contexts semantics.
339 *
340 * This class is intentionally simplified to serve as a base to start working
341 * on services while work on complete semantics is being done in parallel.
342 */
343 class PubFolder {
344 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.
345
346 /**
347 * The root [Folder] of this [PubFolder].
348 */
349 final Folder _folder;
350
351 /**
352 * The `pubspec.yaml` file in [_folder].
353 */
354 File _pubspecFile;
355
356 /**
357 * The [AnalysisContext] of this [_folder].
358 */
359 AnalysisContext _context;
360
361 PubFolder(this._folder) {
362 // prepare pubspec.yaml
363 _pubspecFile = _folder.getChild('pubspec.yaml');
364 if (!_pubspecFile.exists) {
365 throw new ArgumentError('$_pubspecFile does not exist');
366 }
367 // TODO(scheglov) use configurable default SDK
368 DartSdk sdk = DEFAULT_SDK;
369 // create AnalysisContext
370 _context = AnalysisEngine.instance.createAnalysisContext();
371 // TODO(scheglov) replace FileUriResolver with an Resource based resolver
372 // TODO(scheglov) create packages resolver
373 _context.sourceFactory = new SourceFactory([
374 new DartUriResolver(sdk),
375 new FileUriResolver(),
376 // new PackageUriResolver(),
377 ]);
378 // add folder files
379 {
380 ChangeSet changeSet = new ChangeSet();
381 _addSourceFiles(changeSet, _folder);
382 _context.applyChanges(changeSet);
383 }
384 }
385
386 /**
387 * Return the [AnalysisContext] of this folder.
388 */
389 AnalysisContext get context => _context;
390
391 /**
392 * Resursively adds all Dart and HTML files to the [changeSet].
393 */
394 static void _addSourceFiles(ChangeSet changeSet, Folder folder) {
395 List<Resource> children = folder.getChildren();
396 for (Resource child in children) {
397 if (child is File) {
398 String fileName = child.shortName;
399 if (AnalysisEngine.isDartFileName(fileName)
400 || AnalysisEngine.isHtmlFileName(fileName)) {
401 Source source = child.createSource(UriKind.FILE_URI);
402 changeSet.addedSource(source);
403 }
404 } else if (child is Folder) {
405 _addSourceFiles(changeSet, child);
406 }
407 }
408 }
409 }
410
411
412 /**
268 * An enumeration of the services provided by the server domain. 413 * An enumeration of the services provided by the server domain.
269 */ 414 */
270 class ServerService extends Enum2<ServerService> { 415 class ServerService extends Enum2<ServerService> {
271 static const ServerService STATUS = const ServerService('STATUS', 0); 416 static const ServerService STATUS = const ServerService('STATUS', 0);
272 417
273 static const List<ServerService> VALUES = const [STATUS]; 418 static const List<ServerService> VALUES = const [STATUS];
274 419
275 const ServerService(String name, int ordinal) : super(name, ordinal); 420 const ServerService(String name, int ordinal) : super(name, ordinal);
276 } 421 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/domain_analysis.dart » ('j') | pkg/analysis_server/lib/src/domain_analysis.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698