| Index: dart/site/try/poi/scope_information_visitor.dart
|
| diff --git a/dart/site/try/poi/scope_information_visitor.dart b/dart/site/try/poi/scope_information_visitor.dart
|
| index 3f9a2fe4d326cb626c588d22003ad1e57a57b8fd..0ba7bc3c2d7e8663dc2fc55d898e0f9839873b89 100644
|
| --- a/dart/site/try/poi/scope_information_visitor.dart
|
| +++ b/dart/site/try/poi/scope_information_visitor.dart
|
| @@ -29,492 +29,6 @@ import 'package:compiler/src/elements/elements.dart' show
|
| import 'package:compiler/src/dart_types.dart' show
|
| DartType;
|
|
|
| -/****************** IGNORE THIS ONLY FOR SMALL DIFF ****************************
|
| -
|
| -/// Enabled by the option --enable-dart-mind. Controls if this program should
|
| -/// be querying Dart Mind.
|
| -bool isDartMindEnabled = false;
|
| -
|
| -/// Iterator over lines from standard input (or the argument array).
|
| -Iterator<String> stdin;
|
| -
|
| -/// Enabled by the option --simulate-mutation. When true, this program will
|
| -/// only prompt for one file name, and subsequent runs will read
|
| -/// FILENAME.N.dart, where N starts at 1, and is increased on each iteration.
|
| -/// For example, if the program is invoked as:
|
| -///
|
| -/// dart poi.dart --simulate-mutation test.dart 11 22 33 44
|
| -///
|
| -/// The program will first read the file 'test.dart' and compute scope
|
| -/// information about position 11, then position 22 in test.dart.1.dart, then
|
| -/// position 33 in test.dart.2.dart, and finally position 44 in
|
| -/// test.dart.3.dart.
|
| -bool isSimulateMutationEnabled = false;
|
| -
|
| -/// Counts the number of times [runPoi] has been invoked.
|
| -int poiCount;
|
| -
|
| -int globalCounter = 0;
|
| -
|
| -/// Enabled by the option --verbose (or -v). Prints more information than you
|
| -/// really need.
|
| -bool isVerbose = false;
|
| -
|
| -/// Enabled by the option --compile. Also compiles the program after analyzing
|
| -/// the POI.
|
| -bool isCompiler = false;
|
| -
|
| -/// Enabled by the option --minify. Passes the same option to the compiler to
|
| -/// generate minified output.
|
| -bool enableMinification = false;
|
| -
|
| -/// When true (the default value) print serialized scope information at the
|
| -/// provided position.
|
| -const bool PRINT_SCOPE_INFO =
|
| - const bool.fromEnvironment('PRINT_SCOPE_INFO', defaultValue: true);
|
| -
|
| -Stopwatch wallClock = new Stopwatch();
|
| -
|
| -PoiTask poiTask;
|
| -
|
| -Compiler cachedCompiler;
|
| -
|
| -/// Iterator for reading lines from [io.stdin].
|
| -class StdinIterator implements Iterator<String> {
|
| - String current;
|
| -
|
| - bool moveNext() {
|
| - current = io.stdin.readLineSync();
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -printFormattedTime(message, int us) {
|
| - String m = '$message${" " * 65}'.substring(0, 60);
|
| - String i = '${" " * 10}${(us/1000).toStringAsFixed(3)}';
|
| - i = i.substring(i.length - 10);
|
| - print('$m ${i}ms');
|
| -}
|
| -
|
| -printWallClock(message) {
|
| - if (!isVerbose) return;
|
| - if (wallClock.isRunning) {
|
| - print('$message');
|
| - printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
|
| - wallClock.reset();
|
| - } else {
|
| - print(message);
|
| - }
|
| -}
|
| -
|
| -printVerbose(message) {
|
| - if (!isVerbose) return;
|
| - print(message);
|
| -}
|
| -
|
| -main(List<String> arguments) {
|
| - poiCount = 0;
|
| - wallClock.start();
|
| - List<String> nonOptionArguments = [];
|
| - for (String argument in arguments) {
|
| - if (argument.startsWith('-')) {
|
| - switch (argument) {
|
| - case '--simulate-mutation':
|
| - isSimulateMutationEnabled = true;
|
| - break;
|
| - case '--enable-dart-mind':
|
| - isDartMindEnabled = true;
|
| - break;
|
| - case '-v':
|
| - case '--verbose':
|
| - isVerbose = true;
|
| - break;
|
| - case '--compile':
|
| - isCompiler = true;
|
| - break;
|
| - case '--minify':
|
| - enableMinification = true;
|
| - break;
|
| - default:
|
| - throw 'Unknown option: $argument.';
|
| - }
|
| - } else {
|
| - nonOptionArguments.add(argument);
|
| - }
|
| - }
|
| - if (nonOptionArguments.isEmpty) {
|
| - stdin = new StdinIterator();
|
| - } else {
|
| - stdin = nonOptionArguments.iterator;
|
| - }
|
| -
|
| - FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler();
|
| - handler
|
| - ..verbose = false
|
| - ..enableColors = true;
|
| - api.CompilerInputProvider inputProvider = handler.provider;
|
| -
|
| - return prompt('Dart file: ').then((String fileName) {
|
| - if (isSimulateMutationEnabled) {
|
| - inputProvider = simulateMutation(fileName, inputProvider);
|
| - }
|
| - return prompt('Position: ').then((String position) {
|
| - return parseUserInput(fileName, position, inputProvider, handler);
|
| - });
|
| - });
|
| -}
|
| -
|
| -/// Create an input provider that implements the behavior documented at
|
| -/// [simulateMutation].
|
| -api.CompilerInputProvider simulateMutation(
|
| - String fileName,
|
| - api.CompilerInputProvider inputProvider) {
|
| - Uri script = Uri.base.resolveUri(new Uri.file(fileName));
|
| - int count = poiCount;
|
| - Future cache;
|
| - String cachedFileName = script.toFilePath();
|
| - int counter = ++globalCounter;
|
| - return (Uri uri) {
|
| - if (counter != globalCounter) throw 'Using old provider';
|
| - printVerbose('fake inputProvider#$counter($uri): $poiCount $count');
|
| - if (uri == script) {
|
| - if (poiCount == count) {
|
| - cachedFileName = uri.toFilePath();
|
| - if (count != 0) {
|
| - cachedFileName = '$cachedFileName.$count.dart';
|
| - }
|
| - printVerbose('Not using cached version of $cachedFileName');
|
| - cache = new io.File(cachedFileName).readAsBytes().then((data) {
|
| - printVerbose(
|
| - 'Read file $cachedFileName: '
|
| - '${UTF8.decode(data.take(100).toList(), allowMalformed: true)}...');
|
| - return data;
|
| - });
|
| - count++;
|
| - } else {
|
| - printVerbose('Using cached version of $cachedFileName');
|
| - }
|
| - return cache;
|
| - } else {
|
| - printVerbose('Using original provider for $uri');
|
| - return inputProvider(uri);
|
| - }
|
| - };
|
| -}
|
| -
|
| -Future<String> prompt(message) {
|
| - if (stdin is StdinIterator) {
|
| - io.stdout.write(message);
|
| - }
|
| - return io.stdout.flush().then((_) {
|
| - stdin.moveNext();
|
| - return stdin.current;
|
| - });
|
| -}
|
| -
|
| -Future queryDartMind(String prefix, String info) {
|
| - // TODO(lukechurch): Use [info] for something.
|
| - String encodedArg0 = Uri.encodeComponent('"$prefix"');
|
| - String mindQuery =
|
| - 'http://dart-mind.appspot.com/rpc'
|
| - '?action=GetExportingPubCompletions'
|
| - '&arg0=$encodedArg0';
|
| - Uri uri = Uri.parse(mindQuery);
|
| -
|
| - io.HttpClient client = new io.HttpClient();
|
| - return client.getUrl(uri).then((io.HttpClientRequest request) {
|
| - return request.close();
|
| - }).then((io.HttpClientResponse response) {
|
| - Completer<String> completer = new Completer<String>();
|
| - response.transform(UTF8.decoder).listen((contents) {
|
| - completer.complete(contents);
|
| - });
|
| - return completer.future;
|
| - });
|
| -}
|
| -
|
| -Future parseUserInput(
|
| - String fileName,
|
| - String positionString,
|
| - api.CompilerInputProvider inputProvider,
|
| - api.DiagnosticHandler handler) {
|
| - Future repeat() {
|
| - printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
|
| - wallClock.reset();
|
| -
|
| - return prompt('Position: ').then((String positionString) {
|
| - wallClock.reset();
|
| - return parseUserInput(fileName, positionString, inputProvider, handler);
|
| - });
|
| - }
|
| -
|
| - printWallClock("\n\n\nparseUserInput('$fileName', '$positionString')");
|
| -
|
| - Uri script = Uri.base.resolveUri(new Uri.file(fileName));
|
| - if (positionString == null) return null;
|
| - int position = int.parse(
|
| - positionString, onError: (_) { print('Please enter an integer.'); });
|
| - if (position == null) return repeat();
|
| -
|
| - inputProvider(script);
|
| - if (isVerbose) {
|
| - handler(
|
| - script, position, position + 1,
|
| - 'Point of interest. '
|
| - 'Cursor is immediately before highlighted character.',
|
| - api.Diagnostic.HINT);
|
| - }
|
| -
|
| - Stopwatch sw = new Stopwatch()..start();
|
| -
|
| - Future future = runPoi(script, position, inputProvider, handler);
|
| - return future.then((Element element) {
|
| - if (isVerbose) {
|
| - printFormattedTime('Resolving took', sw.elapsedMicroseconds);
|
| - }
|
| - sw.reset();
|
| - String info = scopeInformation(element, position);
|
| - sw.stop();
|
| - if (PRINT_SCOPE_INFO) {
|
| - print(info);
|
| - }
|
| - printVerbose('Scope information took ${sw.elapsedMicroseconds}us.');
|
| - sw..reset()..start();
|
| - Token token = findToken(element, position);
|
| - String prefix;
|
| - if (token != null) {
|
| - if (token.charOffset + token.charCount <= position) {
|
| - // After the token; in whitespace, or in the beginning of another token.
|
| - prefix = "";
|
| - } else if (token.kind == IDENTIFIER_TOKEN ||
|
| - token.kind == KEYWORD_TOKEN) {
|
| - prefix = token.value.substring(0, position - token.charOffset);
|
| - }
|
| - }
|
| - sw.stop();
|
| - printVerbose('Find token took ${sw.elapsedMicroseconds}us.');
|
| - if (isDartMindEnabled && prefix != null) {
|
| - sw..reset()..start();
|
| - return queryDartMind(prefix, info).then((String dartMindSuggestion) {
|
| - sw.stop();
|
| - print('Dart Mind ($prefix): $dartMindSuggestion.');
|
| - printVerbose('Dart Mind took ${sw.elapsedMicroseconds}us.');
|
| - return repeat();
|
| - });
|
| - } else {
|
| - if (isDartMindEnabled) {
|
| - print("Didn't talk to Dart Mind, no identifier at POI ($token).");
|
| - }
|
| - return repeat();
|
| - }
|
| - });
|
| -}
|
| -
|
| -/// Find the token corresponding to [position] in [element]. The method only
|
| -/// works for instances of [PartialElement] or [LibraryElement]. Support for
|
| -/// [LibraryElement] is currently limited, and works only for named libraries.
|
| -Token findToken(modelx.ElementX element, int position) {
|
| - Token beginToken;
|
| - DeclarationSite site = element.declarationSite;
|
| - if (site is PartialElement) {
|
| - beginToken = site.beginToken;
|
| - } else if (element.isLibrary) {
|
| - // TODO(ahe): Generalize support for library elements (and update above
|
| - // documentation).
|
| - modelx.LibraryElementX lib = element;
|
| - var tag = lib.libraryTag;
|
| - if (tag != null) {
|
| - beginToken = tag.libraryKeyword;
|
| - }
|
| - } else {
|
| - beginToken = element.position;
|
| - }
|
| - if (beginToken == null) return null;
|
| - for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) {
|
| - if (token.charOffset < position && position <= token.next.charOffset) {
|
| - return token;
|
| - }
|
| - }
|
| - return null;
|
| -}
|
| -
|
| -Future<Element> runPoi(
|
| - Uri script,
|
| - int position,
|
| - api.CompilerInputProvider inputProvider,
|
| - api.DiagnosticHandler handler) {
|
| - Stopwatch sw = new Stopwatch()..start();
|
| - Uri libraryRoot = Uri.base.resolve('sdk/');
|
| - Uri packageRoot = Uri.base.resolveUri(
|
| - new Uri.file('${io.Platform.packageRoot}/'));
|
| -
|
| - var options = [
|
| - '--analyze-main',
|
| - '--no-source-maps',
|
| - '--verbose',
|
| - '--categories=Client,Server',
|
| - '--incremental-support',
|
| - '--disable-type-inference',
|
| - ];
|
| -
|
| - if (!isCompiler) {
|
| - options.add('--analyze-only');
|
| - }
|
| -
|
| - if (enableMinification) {
|
| - options.add('--minify');
|
| - }
|
| -
|
| - LibraryUpdater updater;
|
| -
|
| - Future<bool> reuseLibrary(LibraryElement library) {
|
| - return poiTask.measure(() => updater.reuseLibrary(library));
|
| - }
|
| -
|
| - Future<Compiler> invokeReuseCompiler() {
|
| - updater = new LibraryUpdater(
|
| - cachedCompiler, inputProvider, script, printWallClock, printVerbose);
|
| - return reuseCompiler(
|
| - diagnosticHandler: handler,
|
| - inputProvider: inputProvider,
|
| - options: options,
|
| - cachedCompiler: cachedCompiler,
|
| - libraryRoot: libraryRoot,
|
| - packageRoot: packageRoot,
|
| - packagesAreImmutable: true,
|
| - reuseLibrary: reuseLibrary);
|
| - }
|
| -
|
| - return invokeReuseCompiler().then((Compiler newCompiler) {
|
| - // TODO(ahe): Move this "then" block to [reuseCompiler].
|
| - if (updater.failed) {
|
| - cachedCompiler = null;
|
| - return invokeReuseCompiler();
|
| - } else {
|
| - return newCompiler;
|
| - }
|
| - }).then((Compiler newCompiler) {
|
| - if (!isCompiler) {
|
| - newCompiler.enqueuerFilter = new ScriptOnlyFilter(script);
|
| - }
|
| - return runPoiInternal(newCompiler, sw, updater, position);
|
| - });
|
| -}
|
| -
|
| -Future<Element> runPoiInternal(
|
| - Compiler newCompiler,
|
| - Stopwatch sw,
|
| - LibraryUpdater updater,
|
| - int position) {
|
| - bool isFullCompile = cachedCompiler != newCompiler;
|
| - cachedCompiler = newCompiler;
|
| - if (poiTask == null || poiTask.compiler != cachedCompiler) {
|
| - poiTask = new PoiTask(cachedCompiler);
|
| - cachedCompiler.tasks.add(poiTask);
|
| - }
|
| -
|
| - if (!isFullCompile) {
|
| - printFormattedTime(
|
| - 'Analyzing changes and updating elements took', sw.elapsedMicroseconds);
|
| - }
|
| - sw.reset();
|
| -
|
| - Future<bool> compilation;
|
| -
|
| - if (updater.hasPendingUpdates) {
|
| - compilation = new Future(() {
|
| - var node = js.statement(
|
| - r'var $dart_patch = #', js.escapedString(updater.computeUpdateJs()));
|
| - print(updater.prettyPrintJs(node));
|
| -
|
| - return !cachedCompiler.compilationFailed;
|
| - });
|
| - } else {
|
| - compilation = cachedCompiler.run(updater.uri);
|
| - }
|
| -
|
| - return compilation.then((success) {
|
| - printVerbose('Compiler queue processed in ${sw.elapsedMicroseconds}us');
|
| - if (isVerbose) {
|
| - for (final task in cachedCompiler.tasks) {
|
| - int time = task.timingMicroseconds;
|
| - if (time != 0) {
|
| - printFormattedTime('${task.name} took', time);
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (poiCount != null) poiCount++;
|
| - if (success != true) {
|
| - throw 'Compilation failed';
|
| - }
|
| - return findPosition(position, cachedCompiler.mainApp);
|
| - });
|
| -}
|
| -
|
| -Element findPosition(int position, Element element) {
|
| - FindPositionVisitor visitor = new FindPositionVisitor(position, element);
|
| - element.accept(visitor);
|
| - return visitor.element;
|
| -}
|
| -
|
| -String scopeInformation(Element element, int position) {
|
| - ScopeInformationVisitor visitor =
|
| - new ScopeInformationVisitor(element, position);
|
| - element.accept(visitor);
|
| - return '${visitor.buffer}';
|
| -}
|
| -
|
| -class FindPositionVisitor extends ElementVisitor {
|
| - final int position;
|
| - Element element;
|
| -
|
| - FindPositionVisitor(this.position, this.element);
|
| -
|
| - visitElement(modelx.ElementX e) {
|
| - DeclarationSite site = e.declarationSite;
|
| - if (site is PartialElement) {
|
| - if (site.beginToken.charOffset <= position &&
|
| - position < site.endToken.next.charOffset) {
|
| - element = e;
|
| - }
|
| - }
|
| - }
|
| -
|
| - visitClassElement(ClassElement e) {
|
| - if (e is PartialClassElement) {
|
| - if (e.beginToken.charOffset <= position &&
|
| - position < e.endToken.next.charOffset) {
|
| - element = e;
|
| - visitScopeContainerElement(e);
|
| - }
|
| - }
|
| - }
|
| -
|
| - visitScopeContainerElement(ScopeContainerElement e) {
|
| - e.forEachLocalMember((Element element) => element.accept(this));
|
| - }
|
| -}
|
| -
|
| -class ScriptOnlyFilter implements QueueFilter {
|
| - final Uri script;
|
| -
|
| - ScriptOnlyFilter(this.script);
|
| -
|
| - bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true;
|
| -
|
| - void processWorkItem(void f(WorkItem work), WorkItem work) {
|
| - if (work.element.library.canonicalUri == script) {
|
| - f(work);
|
| - printWallClock('Processed ${work.element}.');
|
| - } else {
|
| - printWallClock('Skipped ${work.element}.');
|
| - }
|
| - }
|
| -}
|
| -
|
| -*******************************************************************************/
|
| -
|
| /**
|
| * Serializes scope information about an element. This is accomplished by
|
| * calling the [serialize] method on each element. Some elements need special
|
|
|