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

Side by Side Diff: dart/pkg/dart2js_incremental/lib/library_updater.dart

Issue 724843002: Rewrite, document, and test qualifiedNamesIn. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address Johnni's comments. Created 6 years, 1 month 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 | « no previous file | dart/tests/try/poi/qualified_names_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 dart2js_incremental.library_updater; 5 library dart2js_incremental.library_updater;
6 6
7 import 'dart:async' show 7 import 'dart:async' show
8 Future; 8 Future;
9 9
10 import 'dart:convert' show 10 import 'dart:convert' show
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 if (element is PartialFunctionElement) { 225 if (element is PartialFunctionElement) {
226 return canReuseRemovedFunction(element); 226 return canReuseRemovedFunction(element);
227 } 227 }
228 return cannotReuse( 228 return cannotReuse(
229 element, "Removed element that isn't a method."); 229 element, "Removed element that isn't a method.");
230 } 230 }
231 231
232 bool canReuseRemovedFunction(PartialFunctionElement element) { 232 bool canReuseRemovedFunction(PartialFunctionElement element) {
233 logVerbose("Removed method $element."); 233 logVerbose("Removed method $element.");
234 234
235 PartialClassElement cls = element.enclosingClass; 235 ScopeContainerElement container = element.enclosingElement;
236 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) { 236 for (ScopeContainerElement scope in scopesAffectedBy(element, container)) {
237 scanSites(scope, (Element member, DeclarationSite site) { 237 scanSites(scope, (Element member, DeclarationSite site) {
238 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. 238 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
239 Map<String, List<String>> names = qualifiedNamesIn(site); 239 Map<String, List<String>> names = qualifiedNamesIn(site);
240 if (canNamesResolveTo(names, element, cls)) { 240 if (canNamesResolveStaticallyTo(names, element, container)) {
241 _elementsToInvalidate.add(member); 241 _elementsToInvalidate.add(member);
242 } 242 }
243 }); 243 });
244 } 244 }
245 245
246 _removedElements.add(element); 246 _removedElements.add(element);
247 247
248 updates.add(new RemovedFunctionUpdate(compiler, element)); 248 updates.add(new RemovedFunctionUpdate(compiler, element));
249 249
250 return true; 250 return true;
251 } 251 }
252 252
253 /// Invoke [f] on each [DeclarationSite] in [element]. If [element] is a
254 /// [ScopeContainerElement], invoke f on all local members as well.
253 void scanSites( 255 void scanSites(
254 Element element, 256 Element element,
255 void f(ElementX element, DeclarationSite site)) { 257 void f(ElementX element, DeclarationSite site)) {
256 DeclarationSite site = declarationSite(element); 258 DeclarationSite site = declarationSite(element);
257 if (site != null) { 259 if (site != null) {
258 f(element, site); 260 f(element, site);
259 } 261 }
260 if (element is ScopeContainerElement) { 262 if (element is ScopeContainerElement) {
261 element.forEachLocalMember((member) { scanSites(member, f); }); 263 element.forEachLocalMember((member) { scanSites(member, f); });
262 } 264 }
263 } 265 }
264 266
267 /// Assume [element] is either removed from or added to [container], and
268 /// return all [ScopeContainerElement] that can see this change.
265 List<ScopeContainerElement> scopesAffectedBy( 269 List<ScopeContainerElement> scopesAffectedBy(
266 Element element, 270 Element element,
267 ClassElement cls) { 271 ScopeContainerElement container) {
268 // TODO(ahe): Use library export graph to compute this. 272 // TODO(ahe): Use library export graph to compute this.
269 // TODO(ahe): Should return all user-defined libraries and packages. 273 // TODO(ahe): Should return all user-defined libraries and packages.
270 LibraryElement library = element.library; 274 LibraryElement library = container.library;
271 List<ScopeContainerElement> result = <ScopeContainerElement>[library]; 275 List<ScopeContainerElement> result = <ScopeContainerElement>[library];
272 276
273 if (cls == null) return result; 277 if (!container.isClass) return result;
278
279 ClassElement cls = container;
274 280
275 var externalSubtypes = 281 var externalSubtypes =
276 compiler.world.subtypesOf(cls).where((e) => e.library != library); 282 compiler.world.subtypesOf(cls).where((e) => e.library != library);
277 283
278 return result..addAll(externalSubtypes); 284 return result..addAll(externalSubtypes);
279 } 285 }
280 286
281 /// Returns true if function [before] can be reused to reflect the changes in 287 /// Returns true if function [before] can be reused to reflect the changes in
282 /// [after]. 288 /// [after].
283 /// 289 ///
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 if (superName != null) { 659 if (superName != null) {
654 updates.add( 660 updates.add(
655 js.statement('delete #.prototype.#', [elementAccess, superName])); 661 js.statement('delete #.prototype.#', [elementAccess, superName]));
656 } 662 }
657 } else { 663 } else {
658 updates.add(js.statement('delete #', [elementAccess])); 664 updates.add(js.statement('delete #', [elementAccess]));
659 } 665 }
660 } 666 }
661 } 667 }
662 668
663 Map<String, List<String>> qualifiedNamesIn(PartialElement element) { 669 /// Returns all qualified names in [element] with less than four identifiers. A
670 /// qualified name is an identifier followed by a sequence of dots and
671 /// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the
672 /// fourth identifier).
673 ///
674 /// The longest possible name that can be resolved is three identifiers, for
675 /// example, "prefix.MyClass.staticMethod". Since four or more identifiers
676 /// cannot resolve to anything statically, they're not included in the returned
677 /// value of this method.
678 Set<String> qualifiedNamesIn(PartialElement element) {
664 Token beginToken = element.beginToken; 679 Token beginToken = element.beginToken;
665 Token endToken = element.endToken; 680 Token endToken = element.endToken;
666 Token token = beginToken; 681 Token token = beginToken;
667 if (element is PartialClassElement) { 682 if (element is PartialClassElement) {
668 ClassNode node = element.cachedNode; 683 ClassNode node = element.cachedNode;
669 if (node != null) { 684 if (node != null) {
670 NodeList body = node.body; 685 NodeList body = node.body;
671 if (body != null) { 686 if (body != null) {
672 endToken = body.beginToken; 687 endToken = body.beginToken;
673 } 688 }
674 } 689 }
675 } 690 }
676 Map<String, List<String>> names = new Map<String, List<String>>(); 691 Set<String> names = new Set<String>();
677 List<List<Token>> qualifieds = <List<Token>>[];
678 do { 692 do {
679 if (token.isIdentifier()) { 693 if (token.isIdentifier()) {
680 List<String> name = names.putIfAbsent(token.value, () => <String>[]); 694 String name = token.value;
681 while (identical('.', token.next.stringValue) && 695 // [name] is a single "identifier".
682 token.next.next.isIdentifier()) { 696 names.add(name);
697 if (identical('.', token.next.stringValue) &&
698 token.next.next.isIdentifier()) {
683 token = token.next.next; 699 token = token.next.next;
684 name.add(token.value); 700 name += '.${token.value}';
701 // [name] is "idenfifier.idenfifier".
702 names.add(name);
703
704 if (identical('.', token.next.stringValue) &&
705 token.next.next.isIdentifier()) {
706 token = token.next.next;
707 name += '.${token.value}';
708 // [name] is "idenfifier.idenfifier.idenfifier".
709 names.add(name);
710
711 while (identical('.', token.next.stringValue) &&
712 token.next.next.isIdentifier()) {
713 // Skip remaining identifiers, they cannot statically resolve to
714 // anything, and must be dynamic sends.
715 token = token.next.next;
716 }
717 }
685 } 718 }
686 } 719 }
687 token = token.next; 720 token = token.next;
688 } while (token.kind != EOF_TOKEN && token != endToken); 721 } while (token.kind != EOF_TOKEN && token != endToken);
689 return names; 722 return names;
690 } 723 }
691 724
692 bool canNamesResolveTo( 725 /// Returns true if one of the qualified names in names (as computed by
693 Map<String, List<String>> names, 726 /// [qualifiedNamesIn]) could be a static reference to [element].
727 bool canNamesResolveStaticallyTo(
728 Set<String> names,
694 Element element, 729 Element element,
695 ClassElement cls) { 730 ScopeContainerElement container) {
696 if (names.containsKey(element.name)) { 731 if (names.contains(element.name)) return true;
697 return true; 732 if (container != null && container.isClass) {
733 // [names] contains C.m, where C is the name of [container], and m is the
734 // name of [element].
735 if (names.contains("${container.name}.${element.name}")) return true;
698 } 736 }
699 if (cls != null) { 737 // TODO(ahe): Check for prefixes as well.
700 List<String> rest = names[cls.name];
701 if (rest != null && rest.contains(element.name)) {
702 // [names] contains C.m, where C is the name of [cls], and m is the name
703 // of [element].
704 return true;
705 }
706 }
707 return false; 738 return false;
708 } 739 }
709 740
710 DeclarationSite declarationSite(Element element) { 741 DeclarationSite declarationSite(Element element) {
711 return element is ElementX ? element.declarationSite : null; 742 return element is ElementX ? element.declarationSite : null;
712 } 743 }
713 744
714 abstract class JsFeatures { 745 abstract class JsFeatures {
715 Compiler get compiler; 746 Compiler get compiler;
716 747
717 JavaScriptBackend get backend => compiler.backend; 748 JavaScriptBackend get backend => compiler.backend;
718 749
719 Namer get namer => backend.namer; 750 Namer get namer => backend.namer;
720 751
721 CodeEmitterTask get emitter => backend.emitter; 752 CodeEmitterTask get emitter => backend.emitter;
722 } 753 }
OLDNEW
« no previous file with comments | « no previous file | dart/tests/try/poi/qualified_names_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698