Chromium Code Reviews| 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 visitDynamicSend(Send node) => null; | |
| 14 String visitForeignSend(Send node) => null; | |
| 15 | |
| 16 String visitGetterSend(Send node) { | |
| 17 final element = elements[node]; | |
| 18 if (element === null || !element.isTopLevel()) return null; | |
| 19 return renamer.renameElement(element); | |
| 20 } | |
| 21 | |
| 22 String visitStaticSend(Send node) { | |
| 23 final element = elements[node]; | |
| 24 | |
| 25 if (element.isTopLevel()) return renamer.renameElement(element); | |
| 26 | |
| 27 if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { | |
| 28 // Don't want to rename redirects to :this(args) or super calls. | |
| 29 if (Initializers.isConstructorRedirect(node)) return null; | |
| 30 if (Initializers.isSuperConstructorCall(node)) return null; | |
| 31 | |
| 32 TypeAnnotation typeAnnotation; | |
| 33 if (node.selector is TypeAnnotation) { | |
| 34 // <simple class name> case. | |
| 35 typeAnnotation = node.selector; | |
| 36 } else if (node.selector.receiver is TypeAnnotation) { | |
| 37 // <complex generic type> case. | |
| 38 typeAnnotation = node.selector.receiver; | |
| 39 } else { | |
| 40 internalError("Don't know how to deduce type", node: node); | |
| 41 } | |
| 42 final type = new Unparser(renamer).unparse(typeAnnotation); | |
| 43 | |
| 44 final constructor = element.asFunctionElement().cachedNode; | |
| 45 final nameAsSend = constructor.name.asSend(); | |
| 46 if (nameAsSend !== null) { | |
| 47 final name = nameAsSend.selector.asIdentifier().source.slowToString(); | |
| 48 return '$type.$name'; | |
| 49 } | |
| 50 return '$type'; | |
| 51 } | |
| 52 | |
| 53 return null; | |
| 54 } | |
| 55 | |
| 56 void internalError(String reason, [Node node]) { | |
| 57 renamer.compiler.cancel(reason: reason, node: node); | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 /** | 5 /** |
| 62 * 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. |
| 63 * TODO(smok): Make sure that top-level fields are correctly renamed. | 7 * TODO(smok): Make sure that top-level fields are correctly renamed. |
| 64 */ | 8 */ |
| 65 class ConflictingRenamer extends Renamer { | 9 class ConflictingRenamer extends Renamer { |
| 66 final Compiler compiler; | 10 final Compiler compiler; |
| 67 final Map<Element, String> renamed; | 11 final Map<Element, String> renamed; |
| 68 final Set<String> usedTopLevelIdentifiers; | 12 final Set<String> usedTopLevelIdentifiers; |
| 69 final Map<LibraryElement, String> imports; | 13 final Map<LibraryElement, String> imports; |
| 70 TreeElements contextElements; | 14 final Map<Node, Usage> usages; |
| 71 Element context; | |
| 72 | 15 |
| 73 Map<Element, TreeElements> get resolvedElements() => | 16 ConflictingRenamer(this.compiler, this.usages) : |
| 74 compiler.enqueuer.resolution.resolvedElements; | |
| 75 | |
| 76 ConflictingRenamer(this.compiler) : | |
| 77 renamed = new Map<Element, String>(), | 17 renamed = new Map<Element, String>(), |
| 78 usedTopLevelIdentifiers = new Set<String>(), | 18 usedTopLevelIdentifiers = new Set<String>(), |
| 79 imports = new Map<LibraryElement, String>(); | 19 imports = new Map<LibraryElement, String>() { |
| 80 | 20 // Rename main() right now so that nobody takes its place. |
| 81 void setContext(Element element) { | 21 renameElement(compiler.mainApp.find(Compiler.MAIN)); |
|
Anton Muhin
2012/08/07 12:32:11
will it always work? there is this --allow-mock-c
Roman
2012/08/07 15:44:03
Compiler does the same thing. Main is required any
| |
| 82 this.context = element; | |
| 83 contextElements = resolvedElements[element]; | |
| 84 } | 22 } |
| 85 | 23 |
| 86 String renameSendMethod(Send send) => | 24 // Renamer impl. |
| 87 new SendRenamer(this, contextElements).visitSend(send); | 25 String rename(Node node) { |
| 88 | 26 Usage usage = usages[node]; |
| 89 String renameTypeName(TypeAnnotation typeAnnotation) { | 27 if (usage !== null) return usage.rename(this); |
| 90 Type type; | |
| 91 if (context.isClass()) { | |
| 92 // This only happens if we're unparsing class declaration. | |
| 93 type = new TypeResolver(compiler) | |
| 94 .resolveTypeAnnotation(typeAnnotation, null, context); | |
| 95 } else { | |
| 96 type = compiler.resolveTypeAnnotation(context, typeAnnotation); | |
| 97 } | |
| 98 return renameType(type); | |
| 99 } | |
| 100 | |
| 101 String renameType(Type type) => renameElement(type.element); | |
| 102 | |
| 103 String renameIdentifier(Identifier node) { | |
| 104 if (context.isGenerativeConstructor() || context.isFactoryConstructor()) { | |
| 105 // Two complicated cases for class/interface renaming: | |
| 106 // 1) class which implements constructors of other interfaces, but not | |
| 107 // implements interfaces themselves: | |
| 108 // 0.dart: class C { I(); } | |
| 109 // 1.dart and 2.dart: interface I default C { I(); } | |
| 110 // now we have to duplicate our I() constructor in C class with | |
| 111 // proper names. | |
| 112 // 2) (even worse for us): | |
| 113 // 0.dart: class C { C(); } | |
| 114 // 1.dart: interface C default p0.C { C(); } | |
| 115 // the second case is just a bug now. | |
| 116 final enclosingClass = context.getEnclosingClass(); | |
| 117 if (node.token.slowToString() == enclosingClass.name.slowToString()) { | |
| 118 // TODO: distinguish the case of constructor vs. nested named closure | |
| 119 // (see function_syntax_test). | |
| 120 // TODO: fix the bugs above and turn if into the assert. | |
| 121 return renameElement(enclosingClass); | |
| 122 } | |
| 123 } | |
| 124 if (context.isFunction() && context.cachedNode.name == node) { | |
| 125 return renameElement(context); | |
| 126 } | |
| 127 return null; | 28 return null; |
| 128 } | 29 } |
| 129 | 30 |
| 31 String renameConstructorName(FunctionElement element) { | |
| 32 String fullName = element.name.slowToString(); | |
| 33 String classPrefix = | |
| 34 "${element.getEnclosingClass().type.name.slowToString()}\$"; | |
|
Anton Muhin
2012/08/07 12:32:11
nit: single quotes, please
| |
| 35 if (element.isGenerativeConstructor()) { | |
|
Anton Muhin
2012/08/07 12:32:11
why you have this difference? Why you process A.
Roman
2012/08/07 15:44:03
I think this code is broken. We don't plan to rena
| |
| 36 assert(fullName.startsWith(classPrefix)); | |
| 37 return fullName.substring(classPrefix.length); | |
| 38 } else { | |
| 39 assert(element.isFactoryConstructor()); | |
| 40 // TODO(smok): Remove this fragile check, $ can appear in ID. | |
|
Anton Muhin
2012/08/07 12:32:11
cannot you use cachedNode to understand the name o
| |
| 41 return fullName.substring(fullName.indexOf("\$") + 1); | |
| 42 } | |
| 43 } | |
| 44 | |
| 130 String renameElement(Element element) { | 45 String renameElement(Element element) { |
| 131 // TODO(smok): Make sure that the new name does not conflict with existing | 46 // TODO(smok): Make sure that the new name does not conflict with existing |
| 132 // local identifiers. | 47 // local identifiers. |
| 133 if (renamed[element] !== null) return renamed[element]; | 48 if (renamed[element] !== null) return renamed[element]; |
| 134 | 49 |
| 135 generateUniqueName(name) { | 50 generateUniqueName(name) { |
| 136 while (usedTopLevelIdentifiers.contains(name)) { | 51 while (usedTopLevelIdentifiers.contains(name)) { |
| 137 name = "p_$name"; | 52 name = "p_$name"; |
| 138 } | 53 } |
| 139 usedTopLevelIdentifiers.add(name); | 54 usedTopLevelIdentifiers.add(name); |
| 140 return name; | 55 return name; |
| 141 } | 56 } |
| 142 | 57 |
| 143 String originalName = element.name.slowToString(); | 58 String originalName = element.name.slowToString(); |
| 144 // TODO(antonm): we should rename lib private names as well. | 59 // TODO(antonm): we should rename lib private names as well. |
| 145 if (!element.isTopLevel()) return originalName; | 60 if (!element.isTopLevel()) return originalName; |
| 146 final library = element.getLibrary(); | 61 final library = element.getLibrary(); |
| 147 if (library === compiler.coreLibrary) return originalName; | 62 if (library === compiler.coreLibrary) return originalName; |
| 148 if (isDartCoreLib(compiler, library)) { | 63 if (isDartCoreLib(compiler, library)) { |
| 149 final prefix = | 64 final prefix = |
| 150 imports.putIfAbsent(library, () => generateUniqueName('p')); | 65 imports.putIfAbsent(library, () => generateUniqueName('p')); |
| 151 return '$prefix.$originalName'; | 66 return '$prefix.$originalName'; |
| 152 } | 67 } |
| 153 return renamed[element] = generateUniqueName(originalName); | 68 return renamed[element] = generateUniqueName(originalName); |
| 154 } | 69 } |
| 155 } | 70 } |
| OLD | NEW |