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

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: 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 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 if (element is PartialFunctionElement) { 228 if (element is PartialFunctionElement) {
229 return canReuseRemovedFunction(element); 229 return canReuseRemovedFunction(element);
230 } 230 }
231 return cannotReuse( 231 return cannotReuse(
232 element, "Removed element that isn't a method."); 232 element, "Removed element that isn't a method.");
233 } 233 }
234 234
235 bool canReuseRemovedFunction(PartialFunctionElement element) { 235 bool canReuseRemovedFunction(PartialFunctionElement element) {
236 logVerbose("Removed method $element."); 236 logVerbose("Removed method $element.");
237 237
238 PartialClassElement cls = element.enclosingClass; 238 ScopeContainerElement container = element.enclosingElement;
239 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) { 239 for (ScopeContainerElement scope in scopesAffectedBy(element, container)) {
240 scanSites(scope, (Element member, DeclarationSite site) { 240 scanSites(scope, (Element member, DeclarationSite site) {
241 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. 241 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
242 Map<String, List<String>> names = qualifiedNamesIn(site); 242 Map<String, List<String>> names = qualifiedNamesIn(site);
243 if (canNamesResolveTo(names, element, cls)) { 243 if (canNamesResolveTo(names, element, container)) {
244 _elementsToInvalidate.add(member); 244 _elementsToInvalidate.add(member);
245 } 245 }
246 }); 246 });
247 } 247 }
248 248
249 _removedElements.add(element); 249 _removedElements.add(element);
250 250
251 updates.add(new RemovedFunctionUpdate(compiler, element)); 251 updates.add(new RemovedFunctionUpdate(compiler, element));
252 252
253 return true; 253 return true;
254 } 254 }
255 255
256 /// Invoke [f] on each [DeclarationSite] in [element]. If [element] is a
257 /// [ScopeContainerElement], invoke f on all local members as well.
256 void scanSites( 258 void scanSites(
257 Element element, 259 Element element,
258 void f(ElementX element, DeclarationSite site)) { 260 void f(ElementX element, DeclarationSite site)) {
259 DeclarationSite site = declarationSite(element); 261 DeclarationSite site = declarationSite(element);
260 if (site != null) { 262 if (site != null) {
261 f(element, site); 263 f(element, site);
262 } 264 }
263 if (element is ScopeContainerElement) { 265 if (element is ScopeContainerElement) {
264 element.forEachLocalMember((member) { scanSites(member, f); }); 266 element.forEachLocalMember((member) { scanSites(member, f); });
265 } 267 }
266 } 268 }
267 269
270 /// Assume [element] is either removed from or added to [container], and
271 /// return all [ScopeContainerElement] that can see this change.
268 List<ScopeContainerElement> scopesAffectedBy( 272 List<ScopeContainerElement> scopesAffectedBy(
269 Element element, 273 Element element,
270 ClassElement cls) { 274 ScopeContainerElement container) {
271 // TODO(ahe): Use library export graph to compute this. 275 // TODO(ahe): Use library export graph to compute this.
272 // TODO(ahe): Should return all user-defined libraries and packages. 276 // TODO(ahe): Should return all user-defined libraries and packages.
273 LibraryElement library = element.library; 277 LibraryElement library = container.library;
274 List<ScopeContainerElement> result = <ScopeContainerElement>[library]; 278 List<ScopeContainerElement> result = <ScopeContainerElement>[library];
275 279
276 if (cls == null) return result; 280 if (!container.isClass) return result;
281
282 ClassElement cls = container;
277 283
278 var externalSubtypes = 284 var externalSubtypes =
279 compiler.world.subtypesOf(cls).where((e) => e.library != library); 285 compiler.world.subtypesOf(cls).where((e) => e.library != library);
280 286
281 return result..addAll(externalSubtypes); 287 return result..addAll(externalSubtypes);
282 } 288 }
283 289
284 /// Returns true if function [before] can be reused to reflect the changes in 290 /// Returns true if function [before] can be reused to reflect the changes in
285 /// [after]. 291 /// [after].
286 /// 292 ///
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 if (superName != null) { 673 if (superName != null) {
668 updates.add( 674 updates.add(
669 js.statement('delete #.prototype.#', [elementAccess, superName])); 675 js.statement('delete #.prototype.#', [elementAccess, superName]));
670 } 676 }
671 } else { 677 } else {
672 updates.add(js.statement('delete #', [elementAccess])); 678 updates.add(js.statement('delete #', [elementAccess]));
673 } 679 }
674 } 680 }
675 } 681 }
676 682
677 Map<String, List<String>> qualifiedNamesIn(PartialElement element) { 683 /// Returns all qualified names in [element] with less than four identifiers. A
684 /// qualified name is an identifier followed by a sequence of dots and
685 /// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the
686 /// fourth identifier).
Johnni Winther 2014/11/14 10:33:35 I guess the reason for the limit is prefix.Class.s
ahe 2014/11/17 10:39:47 Done.
687 Set<String> qualifiedNamesIn(PartialElement element) {
678 Token beginToken = element.beginToken; 688 Token beginToken = element.beginToken;
679 Token endToken = element.endToken; 689 Token endToken = element.endToken;
680 Token token = beginToken; 690 Token token = beginToken;
681 if (element is PartialClassElement) { 691 if (element is PartialClassElement) {
682 ClassNode node = element.cachedNode; 692 ClassNode node = element.cachedNode;
683 if (node != null) { 693 if (node != null) {
684 NodeList body = node.body; 694 NodeList body = node.body;
685 if (body != null) { 695 if (body != null) {
686 endToken = body.beginToken; 696 endToken = body.beginToken;
687 } 697 }
688 } 698 }
689 } 699 }
690 Map<String, List<String>> names = new Map<String, List<String>>(); 700 Set<String> names = new Set<String>();
691 List<List<Token>> qualifieds = <List<Token>>[];
692 do { 701 do {
693 if (token.isIdentifier()) { 702 if (token.isIdentifier()) {
694 List<String> name = names.putIfAbsent(token.value, () => <String>[]); 703 String name = token.value;
695 while (identical('.', token.next.stringValue) && 704 // [name] is a single "identifier".
696 token.next.next.isIdentifier()) { 705 names.add(name);
706 if (identical('.', token.next.stringValue) &&
707 token.next.next.isIdentifier()) {
697 token = token.next.next; 708 token = token.next.next;
698 name.add(token.value); 709 name += '.${token.value}';
710 // [name] is "idenfifier.idenfifier".
711 names.add(name);
712
713 if (identical('.', token.next.stringValue) &&
714 token.next.next.isIdentifier()) {
715 token = token.next.next;
716 name += '.${token.value}';
717 // [name] is "idenfifier.idenfifier.idenfifier".
718 names.add(name);
719
720 while (identical('.', token.next.stringValue) &&
721 token.next.next.isIdentifier()) {
722 // Skip remaining identifiers, they cannot statically resolve to
723 // anything, and must be dynamic sends.
724 token = token.next.next;
725 }
726 }
699 } 727 }
700 } 728 }
701 token = token.next; 729 token = token.next;
702 } while (token.kind != EOF_TOKEN && token != endToken); 730 } while (token.kind != EOF_TOKEN && token != endToken);
703 return names; 731 return names;
704 } 732 }
705 733
734 /// Returns true if one of the qualified names in names (as computed by
735 /// [qualifiedNamesIn]) could be a static reference to [element].
706 bool canNamesResolveTo( 736 bool canNamesResolveTo(
Johnni Winther 2014/11/14 10:33:35 Maybe rename to 'canNamesResolveStaticallyTo'
ahe 2014/11/17 10:39:47 Done.
707 Map<String, List<String>> names, 737 Set<String> names,
708 Element element, 738 Element element,
709 ClassElement cls) { 739 ScopeContainerElement container) {
710 if (names.containsKey(element.name)) { 740 if (names.contains(element.name)) return true;
711 return true; 741 if (container != null && container.isClass) {
742 // [names] contains C.m, where C is the name of [container], and m is the
743 // name of [element].
744 if (names.contains("${container.name}.${element.name}")) return true;
712 } 745 }
713 if (cls != null) { 746 // TODO(ahe): Check for prefixes as well.
714 List<String> rest = names[cls.name];
715 if (rest != null && rest.contains(element.name)) {
716 // [names] contains C.m, where C is the name of [cls], and m is the name
717 // of [element].
718 return true;
719 }
720 }
721 return false; 747 return false;
722 } 748 }
723 749
724 DeclarationSite declarationSite(Element element) { 750 DeclarationSite declarationSite(Element element) {
725 return element is ElementX ? element.declarationSite : null; 751 return element is ElementX ? element.declarationSite : null;
726 } 752 }
727 753
728 abstract class JsFeatures { 754 abstract class JsFeatures {
729 Compiler get compiler; 755 Compiler get compiler;
730 756
(...skipping 11 matching lines...) Expand all
742 768
743 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; 769 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter;
744 770
745 List<String> computeFields(ClassElement cls) { 771 List<String> computeFields(ClassElement cls) {
746 // TODO(ahe): Rewrite for new emitter. 772 // TODO(ahe): Rewrite for new emitter.
747 ClassBuilder builder = new ClassBuilder(cls, namer); 773 ClassBuilder builder = new ClassBuilder(cls, namer);
748 classEmitter.emitFields(cls, builder, ""); 774 classEmitter.emitFields(cls, builder, "");
749 return builder.fields; 775 return builder.fields;
750 } 776 }
751 } 777 }
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