| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class SendRenamer extends ResolvedVisitor<String> { | |
| 6 final ConflictingRenamer renamer; | |
| 7 | |
| 8 SendRenamer(this.renamer, elements) : super(elements); | |
| 9 | |
| 10 String visitSuperSend(Send node) => null; | |
| 11 String visitOperatorSend(Send node) => null; | |
| 12 String visitClosureSend(Send node) => null; | |
| 13 String visitForeignSend(Send node) => null; | |
| 14 | |
| 15 String tryRenamePrivateId(Send node) { | |
| 16 Identifier selector = node.selector.asIdentifier(); | |
| 17 assert(selector !== null); | |
| 18 String originalName = selector.source.slowToString(); | |
| 19 if (originalName.startsWith('_')) { | |
| 20 String newName = renamer.renamePrivateId( | |
| 21 renamer.context.getLibrary(), originalName); | |
| 22 if (node.receiver !== null) { | |
| 23 // TODO: ugly, should be fixed with new renamer infrastructure. | |
| 24 String receiver = new Unparser(renamer).unparse(node.receiver); | |
| 25 newName = '$receiver.$newName'; | |
| 26 } | |
| 27 return newName; | |
| 28 } | |
| 29 | |
| 30 return null; | |
| 31 } | |
| 32 | |
| 33 String visitDynamicSend(Send node) => tryRenamePrivateId(node); | |
| 34 | |
| 35 String visitGetterSend(Send node) { | |
| 36 final element = elements[node]; | |
| 37 if (element === null || !element.isTopLevel()) { | |
| 38 return tryRenamePrivateId(node); | |
| 39 } | |
| 40 return renamer.renameElement(element); | |
| 41 } | |
| 42 | |
| 43 String visitStaticSend(Send node) { | |
| 44 final element = elements[node]; | |
| 45 | |
| 46 if (element.isTopLevel()) return renamer.renameElement(element); | |
| 47 | |
| 48 if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { | |
| 49 // Don't want to rename redirects to :this(args) or super calls. | |
| 50 if (Initializers.isConstructorRedirect(node)) return null; | |
| 51 if (Initializers.isSuperConstructorCall(node)) return null; | |
| 52 | |
| 53 TypeAnnotation typeAnnotation; | |
| 54 if (node.selector is TypeAnnotation) { | |
| 55 // <simple class name> case. | |
| 56 typeAnnotation = node.selector; | |
| 57 } else if (node.selector.receiver is TypeAnnotation) { | |
| 58 // <complex generic type> case. | |
| 59 typeAnnotation = node.selector.receiver; | |
| 60 } else { | |
| 61 internalError("Don't know how to deduce type", node: node); | |
| 62 } | |
| 63 final type = new Unparser(renamer).unparse(typeAnnotation); | |
| 64 | |
| 65 final constructor = element.asFunctionElement().cachedNode; | |
| 66 final nameAsSend = constructor.name.asSend(); | |
| 67 if (nameAsSend !== null) { | |
| 68 final name = nameAsSend.selector.asIdentifier().source.slowToString(); | |
| 69 return '$type.$name'; | |
| 70 } | |
| 71 return '$type'; | |
| 72 } | |
| 73 | |
| 74 return null; | |
| 75 } | |
| 76 | |
| 77 void internalError(String reason, [Node node]) { | |
| 78 renamer.compiler.cancel(reason: reason, node: node); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 /** | 5 /** |
| 83 * Renames only top-level elements that would let to ambiguity if not renamed. | 6 * Renames only top-level elements that would let to ambiguity if not renamed. |
| 84 * TODO(smok): Make sure that top-level fields are correctly renamed. | 7 * TODO(smok): Make sure that top-level fields are correctly renamed. |
| 85 */ | 8 */ |
| 86 class ConflictingRenamer extends Renamer { | 9 class ConflictingRenamer { |
| 87 final Compiler compiler; | 10 final Compiler compiler; |
| 88 final Map<LibraryElement, Map<String, String>> renamed; | 11 final Map<LibraryElement, Map<String, String>> renamed; |
| 89 final Set<String> usedTopLevelIdentifiers; | 12 final Set<String> usedTopLevelIdentifiers; |
| 90 final Map<LibraryElement, String> imports; | 13 final Map<LibraryElement, String> imports; |
| 14 final Map<Node, Placeholder> placeholders; |
| 91 int privateNameCounter = 0; | 15 int privateNameCounter = 0; |
| 92 TreeElements contextElements; | |
| 93 Element context; | |
| 94 | 16 |
| 95 Map<Element, TreeElements> get resolvedElements() => | 17 ConflictingRenamer(this.compiler, this.placeholders) : |
| 96 compiler.enqueuer.resolution.resolvedElements; | |
| 97 | |
| 98 ConflictingRenamer(this.compiler) : | |
| 99 renamed = new Map<LibraryElement, Map<String, String>>(), | 18 renamed = new Map<LibraryElement, Map<String, String>>(), |
| 100 usedTopLevelIdentifiers = new Set<String>(), | 19 usedTopLevelIdentifiers = new Set<String>(), |
| 101 imports = new Map<LibraryElement, String>(); | 20 imports = new Map<LibraryElement, String>() { |
| 102 | 21 // Rename main() right now so that nobody takes its place. |
| 103 void setContext(Element element) { | 22 renameElement(compiler.mainApp.find(Compiler.MAIN)); |
| 104 this.context = element; | |
| 105 contextElements = resolvedElements[element]; | |
| 106 } | 23 } |
| 107 | 24 |
| 108 String renameSendMethod(Send send) => | 25 // Renamer implementation. |
| 109 new SendRenamer(this, contextElements).visitSend(send); | 26 String rename(Node node) { |
| 110 | 27 Placeholder placeholder = placeholders[node]; |
| 111 String renameTypeName(TypeAnnotation typeAnnotation) { | 28 return (placeholder !== null) ? placeholder.rename(this) : null; |
| 112 Type type; | |
| 113 if (context.isClass()) { | |
| 114 // This only happens if we're unparsing class declaration. | |
| 115 type = new TypeResolver(compiler) | |
| 116 .resolveTypeAnnotation(typeAnnotation, null, context); | |
| 117 } else { | |
| 118 type = compiler.resolveTypeAnnotation(context, typeAnnotation); | |
| 119 } | |
| 120 return renameType(type); | |
| 121 } | |
| 122 | |
| 123 String renameType(Type type) => renameElement(type.element); | |
| 124 | |
| 125 String renameIdentifier(Identifier node) { | |
| 126 if (context.isGenerativeConstructor() || context.isFactoryConstructor()) { | |
| 127 // Two complicated cases for class/interface renaming: | |
| 128 // 1) class which implements constructors of other interfaces, but not | |
| 129 // implements interfaces themselves: | |
| 130 // 0.dart: class C { I(); } | |
| 131 // 1.dart and 2.dart: interface I default C { I(); } | |
| 132 // now we have to duplicate our I() constructor in C class with | |
| 133 // proper names. | |
| 134 // 2) (even worse for us): | |
| 135 // 0.dart: class C { C(); } | |
| 136 // 1.dart: interface C default p0.C { C(); } | |
| 137 // the second case is just a bug now. | |
| 138 final enclosingClass = context.getEnclosingClass(); | |
| 139 if (node.token.slowToString() == enclosingClass.name.slowToString()) { | |
| 140 // TODO: distinguish the case of constructor vs. nested named closure | |
| 141 // (see function_syntax_test). | |
| 142 // TODO: fix the bugs above and turn if into the assert. | |
| 143 return renameElement(enclosingClass); | |
| 144 } | |
| 145 } | |
| 146 if (context.isFunction() && context.isTopLevel() && | |
| 147 context.cachedNode.name == node) { | |
| 148 return renameElement(context); | |
| 149 } | |
| 150 // TODO: as the rest of renameIdentifier should go closer to | |
| 151 // Emitter.outputElement. | |
| 152 // Note: this code should only rename private identifiers for class' | |
| 153 // fields/getters/setters/methods. Top-level identifiers are renamed | |
| 154 // just to escape conflicts and that should be enough as we shouldn't | |
| 155 // be able to resolve private identifiers for other libraries. | |
| 156 final originalName = node.source.slowToString(); | |
| 157 if (originalName.startsWith('_')) { | |
| 158 return '${renamePrivateId(context.getLibrary(), originalName)}'; | |
| 159 } | |
| 160 return null; | |
| 161 } | 29 } |
| 162 | 30 |
| 163 String getName(LibraryElement library, String originalName, renamer) => | 31 String getName(LibraryElement library, String originalName, renamer) => |
| 164 renamed.putIfAbsent(library, () => <String>{}) | 32 renamed.putIfAbsent(library, () => <String>{}) |
| 165 .putIfAbsent(originalName, renamer); | 33 .putIfAbsent(originalName, renamer); |
| 166 | 34 |
| 167 String renamePrivateId(LibraryElement library, String originalName) => | 35 String renamePrivateIdentifier(LibraryElement library, String id) => |
| 168 getName(library, originalName, | 36 getName(library, id, () => '_${privateNameCounter++}${id}'); |
| 169 () => '_${privateNameCounter++}${originalName}'); | |
| 170 | 37 |
| 171 String renameElement(Element element) { | 38 String renameElement(Element element) { |
| 172 // TODO: investigate what went wrong here. | 39 assert(element.isTopLevel()); |
| 173 if (!element.isTopLevel()) return null; | |
| 174 | |
| 175 // This comes from currently buggy TypeAnnotation renamer. | |
| 176 // It should be solved in there and it will be solved with | |
| 177 // new fancy renamer. TODO: remove this cruft. | |
| 178 if (element === compiler.types.voidType.element) return null; | |
| 179 | |
| 180 // TODO(smok): Make sure that the new name does not conflict with existing | 40 // TODO(smok): Make sure that the new name does not conflict with existing |
| 181 // local identifiers. | 41 // local identifiers. |
| 182 generateUniqueName(name) { | 42 generateUniqueName(name) { |
| 183 while (usedTopLevelIdentifiers.contains(name)) name = 'p_$name'; | 43 while (usedTopLevelIdentifiers.contains(name)) name = 'p_$name'; |
| 184 usedTopLevelIdentifiers.add(name); | 44 usedTopLevelIdentifiers.add(name); |
| 185 return name; | 45 return name; |
| 186 } | 46 } |
| 187 | 47 |
| 188 String originalName = element.name.slowToString(); | 48 String originalName = element.name.slowToString(); |
| 189 LibraryElement library = element.getLibrary(); | 49 LibraryElement library = element.getLibrary(); |
| 190 if (library === compiler.coreLibrary) return originalName; | 50 if (library === compiler.coreLibrary) return originalName; |
| 191 if (isDartCoreLib(compiler, library)) { | 51 if (isDartCoreLib(compiler, library)) { |
| 192 final prefix = | 52 final prefix = |
| 193 imports.putIfAbsent(library, () => generateUniqueName('p')); | 53 imports.putIfAbsent(library, () => generateUniqueName('p')); |
| 194 return '$prefix.$originalName'; | 54 return '$prefix.$originalName'; |
| 195 } | 55 } |
| 196 | 56 |
| 197 return getName(library, originalName, | 57 return getName(library, originalName, |
| 198 () => generateUniqueName(originalName)); | 58 () => generateUniqueName(originalName)); |
| 199 } | 59 } |
| 200 } | 60 } |
| OLD | NEW |