| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 class SendVisitor extends ResolvedVisitor { |
| 6 final PlaceholderCollector collector; |
| 7 |
| 8 SendVisitor(this.collector, TreeElements elements) : super(elements); |
| 9 |
| 10 visitSuperSend(Send node) {} |
| 11 visitOperatorSend(Send node) {} |
| 12 visitClosureSend(Send node) {} |
| 13 visitForeignSend(Send node) {} |
| 14 |
| 15 visitDynamicSend(Send node) { |
| 16 tryRenamePrivateId(node); |
| 17 } |
| 18 |
| 19 tryRenamePrivateId(Send node) { |
| 20 Node selector = node.selector; |
| 21 assert(selector !== null); |
| 22 if (selector.source.isPrivate()) { |
| 23 collector.makePrivateIdentifier(selector); |
| 24 } |
| 25 } |
| 26 |
| 27 visitGetterSend(Send node) { |
| 28 final element = elements[node]; |
| 29 // element === null means dynamic property access. |
| 30 // We don't want to rename non top-level element access. |
| 31 if (element === null || !element.isTopLevel()) { |
| 32 tryRenamePrivateId(node); |
| 33 return; |
| 34 } |
| 35 // Unqualified <class> in static invocation, why it's not a type annotation? |
| 36 // Another option would be to process in visitStaticSend, NB: |
| 37 // those elements are not top-level. |
| 38 // OR: unqualified top level. |
| 39 collector.makeElementPlaceholder(node.selector, element); |
| 40 if (node.receiver !== null) { |
| 41 // <lib prefix>.<top level>. |
| 42 collector.makeNullPlaceholder(node.receiver); // Cut library prefix. |
| 43 } |
| 44 } |
| 45 |
| 46 visitStaticSend(Send node) { |
| 47 final element = elements[node]; |
| 48 if (!element.isTopLevel()) return; |
| 49 // Another ugly case: <lib prefix>.<top level> is represented as |
| 50 // receiver: lib prefix, selector: top level. |
| 51 collector.makeElementPlaceholder(node.selector, element); |
| 52 if (node.receiver !== null) { |
| 53 assert(elements[node.receiver].isPrefix()); |
| 54 // Hack: putting null into map overrides receiver of original node. |
| 55 collector.makeNullPlaceholder(node.receiver); |
| 56 } |
| 57 } |
| 58 } |
| 59 |
| 60 class PlaceholderCollector extends AbstractVisitor { |
| 61 final Compiler compiler; |
| 62 final Map<Node, Placeholder> placeholders; |
| 63 Element currentElement; |
| 64 TreeElements treeElements; |
| 65 |
| 66 PlaceholderCollector(this.compiler) : |
| 67 placeholders = new Map<Node, Placeholder>(); |
| 68 |
| 69 void collectFunctionDeclarationPlaceholder( |
| 70 FunctionElement element, Node node) { |
| 71 if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { |
| 72 // Two complicated cases for class/interface renaming: |
| 73 // 1) class which implements constructors of other interfaces, but not |
| 74 // implements interfaces themselves: |
| 75 // 0.dart: class C { I(); } |
| 76 // 1.dart and 2.dart: interface I default C { I(); } |
| 77 // now we have to duplicate our I() constructor in C class with |
| 78 // proper names. |
| 79 // 2) (even worse for us): |
| 80 // 0.dart: class C { C(); } |
| 81 // 1.dart: interface C default p0.C { C(); } |
| 82 // the second case is just a bug now. |
| 83 final enclosingClass = element.getEnclosingClass(); |
| 84 Node nameNode = node.name; |
| 85 if (nameNode is Send) nameNode = nameNode.receiver; |
| 86 // For cases like class C implements I { I(); } |
| 87 if (nameNode.token.slowToString() == enclosingClass.name.slowToString()) { |
| 88 makeTypePlaceholder(nameNode, enclosingClass.type); |
| 89 } |
| 90 } else if (element.isTopLevel()) { |
| 91 makeElementPlaceholder(node.name, element); |
| 92 } |
| 93 } |
| 94 |
| 95 void collect(Element element, TreeElements elements) { |
| 96 // Skip AbstractFieldElement, it has no node. |
| 97 // Instead getters and setters should be processed explicitly. |
| 98 if (element is AbstractFieldElement) return; |
| 99 if (element.isField()) { |
| 100 currentElement = element; |
| 101 // TODO(smok): In the future make sure we don't process same |
| 102 // variable list element twice, better merge this with emitter logic. |
| 103 element = element.variables; |
| 104 } |
| 105 currentElement = element; |
| 106 treeElements = elements; |
| 107 Node elementNode = element.parseNode(compiler); |
| 108 if (element is FunctionElement) { |
| 109 collectFunctionDeclarationPlaceholder(element, elementNode); |
| 110 } |
| 111 elementNode.accept(this); |
| 112 } |
| 113 |
| 114 Type resolveType(TypeAnnotation typeAnnotation) { |
| 115 if (treeElements === null) return null; |
| 116 var result = treeElements.getType(typeAnnotation); |
| 117 // TODO: Have better type resolution. |
| 118 if (result === null) { |
| 119 result = compiler.resolveTypeAnnotation(currentElement, typeAnnotation); |
| 120 } |
| 121 return result; |
| 122 } |
| 123 |
| 124 void makeTypePlaceholder(Node node, Type type) { |
| 125 makeElementPlaceholder(node, type.element); |
| 126 } |
| 127 |
| 128 void makeNullPlaceholder(Node node) { |
| 129 placeholders[node] = new NullPlaceholder(); |
| 130 } |
| 131 |
| 132 void makeElementPlaceholder(Node node, Element element) { |
| 133 assert(element !== null); |
| 134 placeholders[node] = new ElementPlaceholder(element); |
| 135 } |
| 136 |
| 137 void makePrivateIdentifier(Identifier node) { |
| 138 assert(node !== null); |
| 139 placeholders[node] = |
| 140 new PrivatePlaceholder(currentElement.getLibrary(), node); |
| 141 } |
| 142 |
| 143 void internalError(String reason, [Node node]) { |
| 144 compiler.cancel(reason: reason, node: node); |
| 145 } |
| 146 |
| 147 visit(Node node) => (node === null) ? null : node.accept(this); |
| 148 |
| 149 visitNode(Node node) { node.visitChildren(this); } // We must go deeper. |
| 150 |
| 151 visitClassNode(ClassNode node) { |
| 152 internalError('Should never meet ClassNode', node); |
| 153 } |
| 154 |
| 155 void visitIdentifier(Identifier node) { |
| 156 if (node.source.isPrivate()) { |
| 157 makePrivateIdentifier(node); |
| 158 } |
| 159 } |
| 160 |
| 161 visitSend(Send send) { |
| 162 new SendVisitor(this, treeElements).visitSend(send); |
| 163 super.visitSend(send); |
| 164 } |
| 165 |
| 166 visitTypeAnnotation(TypeAnnotation node) { |
| 167 final type = compiler.resolveTypeAnnotation(currentElement, node); |
| 168 if (type is !InterfaceType) return null; |
| 169 var target = node.typeName; |
| 170 if (node.typeName is Send) { |
| 171 final element = treeElements[node]; |
| 172 if (element !== null) { |
| 173 final send = node.typeName.asSend(); |
| 174 final hasPrefix = element.lookupConstructor( |
| 175 send.receiver.source, send.selector.source) === null; |
| 176 if (!hasPrefix) target = send.receiver; |
| 177 } |
| 178 } |
| 179 makeTypePlaceholder(target, type); |
| 180 visit(node.typeArguments); |
| 181 } |
| 182 } |
| OLD | NEW |