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

Side by Side Diff: dart/site/try/poi/scope_information_visitor.dart

Issue 757043002: Various clean up. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years 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 | « dart/site/try/poi/poi.dart ('k') | dart/tests/try/poi/apply_updates_test.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 trydart.poi.scope_information_visitor; 5 library trydart.poi.scope_information_visitor;
6 6
7 import 'package:compiler/src/elements/modelx.dart' as modelx; 7 import 'package:compiler/src/elements/modelx.dart' as modelx;
8 8
9 import 'package:compiler/src/elements/modelx.dart' show 9 import 'package:compiler/src/elements/modelx.dart' show
10 CompilationUnitElementX, 10 CompilationUnitElementX,
(...skipping 11 matching lines...) Expand all
22 CompilationUnitElement, 22 CompilationUnitElement,
23 Element, 23 Element,
24 ElementCategory, 24 ElementCategory,
25 FunctionElement, 25 FunctionElement,
26 LibraryElement, 26 LibraryElement,
27 ScopeContainerElement; 27 ScopeContainerElement;
28 28
29 import 'package:compiler/src/dart_types.dart' show 29 import 'package:compiler/src/dart_types.dart' show
30 DartType; 30 DartType;
31 31
32 /****************** IGNORE THIS ONLY FOR SMALL DIFF ****************************
33
34 /// Enabled by the option --enable-dart-mind. Controls if this program should
35 /// be querying Dart Mind.
36 bool isDartMindEnabled = false;
37
38 /// Iterator over lines from standard input (or the argument array).
39 Iterator<String> stdin;
40
41 /// Enabled by the option --simulate-mutation. When true, this program will
42 /// only prompt for one file name, and subsequent runs will read
43 /// FILENAME.N.dart, where N starts at 1, and is increased on each iteration.
44 /// For example, if the program is invoked as:
45 ///
46 /// dart poi.dart --simulate-mutation test.dart 11 22 33 44
47 ///
48 /// The program will first read the file 'test.dart' and compute scope
49 /// information about position 11, then position 22 in test.dart.1.dart, then
50 /// position 33 in test.dart.2.dart, and finally position 44 in
51 /// test.dart.3.dart.
52 bool isSimulateMutationEnabled = false;
53
54 /// Counts the number of times [runPoi] has been invoked.
55 int poiCount;
56
57 int globalCounter = 0;
58
59 /// Enabled by the option --verbose (or -v). Prints more information than you
60 /// really need.
61 bool isVerbose = false;
62
63 /// Enabled by the option --compile. Also compiles the program after analyzing
64 /// the POI.
65 bool isCompiler = false;
66
67 /// Enabled by the option --minify. Passes the same option to the compiler to
68 /// generate minified output.
69 bool enableMinification = false;
70
71 /// When true (the default value) print serialized scope information at the
72 /// provided position.
73 const bool PRINT_SCOPE_INFO =
74 const bool.fromEnvironment('PRINT_SCOPE_INFO', defaultValue: true);
75
76 Stopwatch wallClock = new Stopwatch();
77
78 PoiTask poiTask;
79
80 Compiler cachedCompiler;
81
82 /// Iterator for reading lines from [io.stdin].
83 class StdinIterator implements Iterator<String> {
84 String current;
85
86 bool moveNext() {
87 current = io.stdin.readLineSync();
88 return true;
89 }
90 }
91
92 printFormattedTime(message, int us) {
93 String m = '$message${" " * 65}'.substring(0, 60);
94 String i = '${" " * 10}${(us/1000).toStringAsFixed(3)}';
95 i = i.substring(i.length - 10);
96 print('$m ${i}ms');
97 }
98
99 printWallClock(message) {
100 if (!isVerbose) return;
101 if (wallClock.isRunning) {
102 print('$message');
103 printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
104 wallClock.reset();
105 } else {
106 print(message);
107 }
108 }
109
110 printVerbose(message) {
111 if (!isVerbose) return;
112 print(message);
113 }
114
115 main(List<String> arguments) {
116 poiCount = 0;
117 wallClock.start();
118 List<String> nonOptionArguments = [];
119 for (String argument in arguments) {
120 if (argument.startsWith('-')) {
121 switch (argument) {
122 case '--simulate-mutation':
123 isSimulateMutationEnabled = true;
124 break;
125 case '--enable-dart-mind':
126 isDartMindEnabled = true;
127 break;
128 case '-v':
129 case '--verbose':
130 isVerbose = true;
131 break;
132 case '--compile':
133 isCompiler = true;
134 break;
135 case '--minify':
136 enableMinification = true;
137 break;
138 default:
139 throw 'Unknown option: $argument.';
140 }
141 } else {
142 nonOptionArguments.add(argument);
143 }
144 }
145 if (nonOptionArguments.isEmpty) {
146 stdin = new StdinIterator();
147 } else {
148 stdin = nonOptionArguments.iterator;
149 }
150
151 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler();
152 handler
153 ..verbose = false
154 ..enableColors = true;
155 api.CompilerInputProvider inputProvider = handler.provider;
156
157 return prompt('Dart file: ').then((String fileName) {
158 if (isSimulateMutationEnabled) {
159 inputProvider = simulateMutation(fileName, inputProvider);
160 }
161 return prompt('Position: ').then((String position) {
162 return parseUserInput(fileName, position, inputProvider, handler);
163 });
164 });
165 }
166
167 /// Create an input provider that implements the behavior documented at
168 /// [simulateMutation].
169 api.CompilerInputProvider simulateMutation(
170 String fileName,
171 api.CompilerInputProvider inputProvider) {
172 Uri script = Uri.base.resolveUri(new Uri.file(fileName));
173 int count = poiCount;
174 Future cache;
175 String cachedFileName = script.toFilePath();
176 int counter = ++globalCounter;
177 return (Uri uri) {
178 if (counter != globalCounter) throw 'Using old provider';
179 printVerbose('fake inputProvider#$counter($uri): $poiCount $count');
180 if (uri == script) {
181 if (poiCount == count) {
182 cachedFileName = uri.toFilePath();
183 if (count != 0) {
184 cachedFileName = '$cachedFileName.$count.dart';
185 }
186 printVerbose('Not using cached version of $cachedFileName');
187 cache = new io.File(cachedFileName).readAsBytes().then((data) {
188 printVerbose(
189 'Read file $cachedFileName: '
190 '${UTF8.decode(data.take(100).toList(), allowMalformed: true)}...' );
191 return data;
192 });
193 count++;
194 } else {
195 printVerbose('Using cached version of $cachedFileName');
196 }
197 return cache;
198 } else {
199 printVerbose('Using original provider for $uri');
200 return inputProvider(uri);
201 }
202 };
203 }
204
205 Future<String> prompt(message) {
206 if (stdin is StdinIterator) {
207 io.stdout.write(message);
208 }
209 return io.stdout.flush().then((_) {
210 stdin.moveNext();
211 return stdin.current;
212 });
213 }
214
215 Future queryDartMind(String prefix, String info) {
216 // TODO(lukechurch): Use [info] for something.
217 String encodedArg0 = Uri.encodeComponent('"$prefix"');
218 String mindQuery =
219 'http://dart-mind.appspot.com/rpc'
220 '?action=GetExportingPubCompletions'
221 '&arg0=$encodedArg0';
222 Uri uri = Uri.parse(mindQuery);
223
224 io.HttpClient client = new io.HttpClient();
225 return client.getUrl(uri).then((io.HttpClientRequest request) {
226 return request.close();
227 }).then((io.HttpClientResponse response) {
228 Completer<String> completer = new Completer<String>();
229 response.transform(UTF8.decoder).listen((contents) {
230 completer.complete(contents);
231 });
232 return completer.future;
233 });
234 }
235
236 Future parseUserInput(
237 String fileName,
238 String positionString,
239 api.CompilerInputProvider inputProvider,
240 api.DiagnosticHandler handler) {
241 Future repeat() {
242 printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
243 wallClock.reset();
244
245 return prompt('Position: ').then((String positionString) {
246 wallClock.reset();
247 return parseUserInput(fileName, positionString, inputProvider, handler);
248 });
249 }
250
251 printWallClock("\n\n\nparseUserInput('$fileName', '$positionString')");
252
253 Uri script = Uri.base.resolveUri(new Uri.file(fileName));
254 if (positionString == null) return null;
255 int position = int.parse(
256 positionString, onError: (_) { print('Please enter an integer.'); });
257 if (position == null) return repeat();
258
259 inputProvider(script);
260 if (isVerbose) {
261 handler(
262 script, position, position + 1,
263 'Point of interest. '
264 'Cursor is immediately before highlighted character.',
265 api.Diagnostic.HINT);
266 }
267
268 Stopwatch sw = new Stopwatch()..start();
269
270 Future future = runPoi(script, position, inputProvider, handler);
271 return future.then((Element element) {
272 if (isVerbose) {
273 printFormattedTime('Resolving took', sw.elapsedMicroseconds);
274 }
275 sw.reset();
276 String info = scopeInformation(element, position);
277 sw.stop();
278 if (PRINT_SCOPE_INFO) {
279 print(info);
280 }
281 printVerbose('Scope information took ${sw.elapsedMicroseconds}us.');
282 sw..reset()..start();
283 Token token = findToken(element, position);
284 String prefix;
285 if (token != null) {
286 if (token.charOffset + token.charCount <= position) {
287 // After the token; in whitespace, or in the beginning of another token.
288 prefix = "";
289 } else if (token.kind == IDENTIFIER_TOKEN ||
290 token.kind == KEYWORD_TOKEN) {
291 prefix = token.value.substring(0, position - token.charOffset);
292 }
293 }
294 sw.stop();
295 printVerbose('Find token took ${sw.elapsedMicroseconds}us.');
296 if (isDartMindEnabled && prefix != null) {
297 sw..reset()..start();
298 return queryDartMind(prefix, info).then((String dartMindSuggestion) {
299 sw.stop();
300 print('Dart Mind ($prefix): $dartMindSuggestion.');
301 printVerbose('Dart Mind took ${sw.elapsedMicroseconds}us.');
302 return repeat();
303 });
304 } else {
305 if (isDartMindEnabled) {
306 print("Didn't talk to Dart Mind, no identifier at POI ($token).");
307 }
308 return repeat();
309 }
310 });
311 }
312
313 /// Find the token corresponding to [position] in [element]. The method only
314 /// works for instances of [PartialElement] or [LibraryElement]. Support for
315 /// [LibraryElement] is currently limited, and works only for named libraries.
316 Token findToken(modelx.ElementX element, int position) {
317 Token beginToken;
318 DeclarationSite site = element.declarationSite;
319 if (site is PartialElement) {
320 beginToken = site.beginToken;
321 } else if (element.isLibrary) {
322 // TODO(ahe): Generalize support for library elements (and update above
323 // documentation).
324 modelx.LibraryElementX lib = element;
325 var tag = lib.libraryTag;
326 if (tag != null) {
327 beginToken = tag.libraryKeyword;
328 }
329 } else {
330 beginToken = element.position;
331 }
332 if (beginToken == null) return null;
333 for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) {
334 if (token.charOffset < position && position <= token.next.charOffset) {
335 return token;
336 }
337 }
338 return null;
339 }
340
341 Future<Element> runPoi(
342 Uri script,
343 int position,
344 api.CompilerInputProvider inputProvider,
345 api.DiagnosticHandler handler) {
346 Stopwatch sw = new Stopwatch()..start();
347 Uri libraryRoot = Uri.base.resolve('sdk/');
348 Uri packageRoot = Uri.base.resolveUri(
349 new Uri.file('${io.Platform.packageRoot}/'));
350
351 var options = [
352 '--analyze-main',
353 '--no-source-maps',
354 '--verbose',
355 '--categories=Client,Server',
356 '--incremental-support',
357 '--disable-type-inference',
358 ];
359
360 if (!isCompiler) {
361 options.add('--analyze-only');
362 }
363
364 if (enableMinification) {
365 options.add('--minify');
366 }
367
368 LibraryUpdater updater;
369
370 Future<bool> reuseLibrary(LibraryElement library) {
371 return poiTask.measure(() => updater.reuseLibrary(library));
372 }
373
374 Future<Compiler> invokeReuseCompiler() {
375 updater = new LibraryUpdater(
376 cachedCompiler, inputProvider, script, printWallClock, printVerbose);
377 return reuseCompiler(
378 diagnosticHandler: handler,
379 inputProvider: inputProvider,
380 options: options,
381 cachedCompiler: cachedCompiler,
382 libraryRoot: libraryRoot,
383 packageRoot: packageRoot,
384 packagesAreImmutable: true,
385 reuseLibrary: reuseLibrary);
386 }
387
388 return invokeReuseCompiler().then((Compiler newCompiler) {
389 // TODO(ahe): Move this "then" block to [reuseCompiler].
390 if (updater.failed) {
391 cachedCompiler = null;
392 return invokeReuseCompiler();
393 } else {
394 return newCompiler;
395 }
396 }).then((Compiler newCompiler) {
397 if (!isCompiler) {
398 newCompiler.enqueuerFilter = new ScriptOnlyFilter(script);
399 }
400 return runPoiInternal(newCompiler, sw, updater, position);
401 });
402 }
403
404 Future<Element> runPoiInternal(
405 Compiler newCompiler,
406 Stopwatch sw,
407 LibraryUpdater updater,
408 int position) {
409 bool isFullCompile = cachedCompiler != newCompiler;
410 cachedCompiler = newCompiler;
411 if (poiTask == null || poiTask.compiler != cachedCompiler) {
412 poiTask = new PoiTask(cachedCompiler);
413 cachedCompiler.tasks.add(poiTask);
414 }
415
416 if (!isFullCompile) {
417 printFormattedTime(
418 'Analyzing changes and updating elements took', sw.elapsedMicroseconds);
419 }
420 sw.reset();
421
422 Future<bool> compilation;
423
424 if (updater.hasPendingUpdates) {
425 compilation = new Future(() {
426 var node = js.statement(
427 r'var $dart_patch = #', js.escapedString(updater.computeUpdateJs()));
428 print(updater.prettyPrintJs(node));
429
430 return !cachedCompiler.compilationFailed;
431 });
432 } else {
433 compilation = cachedCompiler.run(updater.uri);
434 }
435
436 return compilation.then((success) {
437 printVerbose('Compiler queue processed in ${sw.elapsedMicroseconds}us');
438 if (isVerbose) {
439 for (final task in cachedCompiler.tasks) {
440 int time = task.timingMicroseconds;
441 if (time != 0) {
442 printFormattedTime('${task.name} took', time);
443 }
444 }
445 }
446
447 if (poiCount != null) poiCount++;
448 if (success != true) {
449 throw 'Compilation failed';
450 }
451 return findPosition(position, cachedCompiler.mainApp);
452 });
453 }
454
455 Element findPosition(int position, Element element) {
456 FindPositionVisitor visitor = new FindPositionVisitor(position, element);
457 element.accept(visitor);
458 return visitor.element;
459 }
460
461 String scopeInformation(Element element, int position) {
462 ScopeInformationVisitor visitor =
463 new ScopeInformationVisitor(element, position);
464 element.accept(visitor);
465 return '${visitor.buffer}';
466 }
467
468 class FindPositionVisitor extends ElementVisitor {
469 final int position;
470 Element element;
471
472 FindPositionVisitor(this.position, this.element);
473
474 visitElement(modelx.ElementX e) {
475 DeclarationSite site = e.declarationSite;
476 if (site is PartialElement) {
477 if (site.beginToken.charOffset <= position &&
478 position < site.endToken.next.charOffset) {
479 element = e;
480 }
481 }
482 }
483
484 visitClassElement(ClassElement e) {
485 if (e is PartialClassElement) {
486 if (e.beginToken.charOffset <= position &&
487 position < e.endToken.next.charOffset) {
488 element = e;
489 visitScopeContainerElement(e);
490 }
491 }
492 }
493
494 visitScopeContainerElement(ScopeContainerElement e) {
495 e.forEachLocalMember((Element element) => element.accept(this));
496 }
497 }
498
499 class ScriptOnlyFilter implements QueueFilter {
500 final Uri script;
501
502 ScriptOnlyFilter(this.script);
503
504 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true;
505
506 void processWorkItem(void f(WorkItem work), WorkItem work) {
507 if (work.element.library.canonicalUri == script) {
508 f(work);
509 printWallClock('Processed ${work.element}.');
510 } else {
511 printWallClock('Skipped ${work.element}.');
512 }
513 }
514 }
515
516 *******************************************************************************/
517
518 /** 32 /**
519 * Serializes scope information about an element. This is accomplished by 33 * Serializes scope information about an element. This is accomplished by
520 * calling the [serialize] method on each element. Some elements need special 34 * calling the [serialize] method on each element. Some elements need special
521 * treatment, as their enclosing scope must also be serialized. 35 * treatment, as their enclosing scope must also be serialized.
522 */ 36 */
523 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { 37 class ScopeInformationVisitor extends ElementVisitor/* <void> */ {
524 // TODO(ahe): Include function parameters and local variables. 38 // TODO(ahe): Include function parameters and local variables.
525 39
526 final Compiler compiler; 40 final Compiler compiler;
527 final Element currentElement; 41 final Element currentElement;
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 } 298 }
785 return result; 299 return result;
786 } 300 }
787 } 301 }
788 302
789 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope; 303 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope;
790 304
791 modelx.ImportScope importScope(modelx.LibraryElementX element) { 305 modelx.ImportScope importScope(modelx.LibraryElementX element) {
792 return element.importScope; 306 return element.importScope;
793 } 307 }
OLDNEW
« no previous file with comments | « dart/site/try/poi/poi.dart ('k') | dart/tests/try/poi/apply_updates_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698