Chromium Code Reviews| Index: lib/compiler/implementation/dart_backend/usager.dart |
| diff --git a/lib/compiler/implementation/dart_backend/usager.dart b/lib/compiler/implementation/dart_backend/usager.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bb2132480e0a881b0aff5c9086bf0dee18cf5229 |
| --- /dev/null |
| +++ b/lib/compiler/implementation/dart_backend/usager.dart |
| @@ -0,0 +1,322 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +class SendVisitor extends ResolvedVisitor<String> { |
| + final Usager usager; |
| + |
| + SendVisitor(this.usager, TreeElements elements) : super(elements); |
| + |
| + R visitSuperSend(Send node) => node.visitChildren(usager); |
| + R visitOperatorSend(Send node) => node.visitChildren(usager); |
| + R visitClosureSend(Send node) => node.visitChildren(usager); |
| + R visitDynamicSend(Send node) => node.visitChildren(usager); |
| + R visitForeignSend(Send node) => node.visitChildren(usager); |
| + |
| + R visitGetterSend(Send node) { |
| + final element = elements[node]; |
| + if (element !== null && element.isTopLevel()) { |
|
Anton Muhin
2012/08/07 12:32:11
maybe use early return: if (element === null || el
Roman
2012/08/07 15:44:03
Done.
|
| + if (node.receiver !== null) { |
| + // Library reference prefix. Omit it. |
|
Anton Muhin
2012/08/07 12:32:11
please, add an assert, that receiver resolves to p
Roman
2012/08/07 15:44:03
Done.
|
| + usager.useNull(node.receiver); |
| + } |
| + usager.useElement(node.selector, element); |
| + usager.visit(node.argumentsNode); |
|
Anton Muhin
2012/08/07 12:32:11
I am not quite happy we duplicate visitChildren he
Roman
2012/08/07 15:44:03
Changed to visitChildren, it should not matter muc
|
| + } else { |
| + node.visitChildren(usager); |
| + } |
| + } |
| + |
| + R visitStaticSend(Send node) { |
|
Anton Muhin
2012/08/07 12:32:11
isn't that too complicated?
e.g. shouldn't we ren
Roman
2012/08/07 15:44:03
I will use magic from your CL to make it better.
|
| + final element = elements[node]; |
| + if (element.isTopLevel()) { |
| + if (node.receiver !== null) { |
| + // Library reference prefix. Omit it. |
| + usager.useNull(node.receiver); |
| + } |
| + usager.useMethod(node.selector, element); |
| + usager.visit(node.argumentsNode); |
| + } else if ( |
| + (element.isGenerativeConstructor() || element.isFactoryConstructor()) |
| + // Don't want to rename redirects to :this(args) or super calls. |
| + && !Initializers.isConstructorRedirect(node) |
| + && !Initializers.isSuperConstructorCall(node)) { |
| + final FunctionElement constructor = element.asFunctionElement(); |
| + final Send nameAsSend = constructor.cachedNode.name.asSend(); |
| + if (nameAsSend !== null) { |
| + // Named constructor or factory call. |
| + if (node.selector is TypeAnnotation) { |
| + // Simple A.fromFoo(); |
| + assert(node.selector.typeName is Send); |
| + assert(node.selector.typeName.receiver is Identifier); |
| + assert(node.selector.typeName.selector is Identifier); |
| + usager.useType(node.selector.typeName.receiver, |
| + usager.resolveType(node.selector)); |
| + usager.useConstructorName( |
| + node.selector.typeName.selector, constructor); |
| + } else { |
| + // lib.A.fromFoo() or A<T>.fromFoo() |
| + // or lib.A.fromFoo() or lib.A<T>.fromFoo(); |
| + assert(node.selector is Send); |
| + assert(node.selector.selector is Identifier); |
| + assert(node.selector.receiver is TypeAnnotation); |
| + usager.useType(node.selector.receiver.typeName, |
| + usager.resolveType(node.selector.receiver)); |
| + usager.useConstructorName(node.selector.selector, constructor); |
| + usager.visit(node.selector.receiver.typeArguments); |
| + } |
| + } else { |
| + // Ordinary constructor call. |
| + assert(node.selector is TypeAnnotation); |
| + usager.useType( |
| + node.selector.typeName, usager.resolveType(node.selector)); |
| + usager.visit(node.selector.typeArguments); |
| + } |
| + } else { |
| + // Fallback to default processing. |
| + node.visitChildren(usager); |
| + } |
| + } |
| +} |
| + |
| +class Usager implements Visitor { |
| + final Compiler compiler; |
| + final Map<Node, Usage> usages; |
| + Element currentElement; |
| + TreeElements treeElements; |
| + |
| + Usager(this.compiler) : usages = new Map<Node, Usage>(); |
| + |
| + /** |
| + * Checks if [:libraryElement:] is a core lib, that is a library |
| + * provided by the implementation like dart:core, dart:coreimpl, etc. |
| + */ |
| + bool isDartCoreLib(Compiler compiler, LibraryElement libraryElement) { |
| + final libraries = compiler.libraries; |
| + for (final uri in libraries.getKeys()) { |
| + if (libraryElement === libraries[uri]) { |
| + if (uri.startsWith('dart:')) return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + void process(Element element, TreeElements elements) { |
| + currentElement = element; |
| + treeElements = elements; |
| + Node elementNode = element.parseNode(compiler); |
| + elementNode.accept(this); |
| + } |
| + |
| + Type resolveType(TypeAnnotation typeAnnotation) { |
| + if (treeElements === null) return null; |
| + var result = treeElements.getType(typeAnnotation); |
| + if (result == null) { |
|
Anton Muhin
2012/08/07 12:32:11
nit: === null
Roman
2012/08/07 15:44:03
Done.
|
| + result = compiler.resolveTypeAnnotation(currentElement, typeAnnotation); |
| + } |
| + return result; |
| + } |
| + |
| + void useType(Node node, Type type) { |
| + assert(type !== null); |
| + usages[node] = new TypeUsage(type); |
| + } |
| + void useConstructorName(Identifier node, FunctionElement constructor) { |
| + assert(constructor !== null); |
| + usages[node] = new ConstructorNameUsage(constructor); |
| + } |
| + void useMethod(Node node, Element method) { |
| + assert(method !== null); |
| + assert(method is FunctionElement || method is VariableElement); |
| + usages[node] = new MethodUsage(method); |
| + } |
| + void useNull(Node node) { |
| + usages[node] = new NullUsage(); |
| + } |
| + void useElement(Node node, Element element) { |
| + assert(element !== null); |
| + usages[node] = new ElementUsage(element); |
| + } |
| + |
| + void internalError(String reason, [Node node]) { |
| + compiler.cancel(reason: reason, node: node); |
| + } |
| + |
| + R visit(Node node) => (node == null) ? null : node.accept(this); |
|
Anton Muhin
2012/08/07 12:32:11
nit: === null
Roman
2012/08/07 15:44:03
Done.
|
| + |
| + R visitBlock(Block node) { |
|
Anton Muhin
2012/08/07 12:32:11
arrow syntax, your variant returns null.
Anton Muhin
2012/08/07 12:32:11
cannot you reuse AbstractVisitor?
|
| + node.visitChildren(this); |
| + } |
| + R visitBreakStatement(BreakStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitCascade(Cascade node) { |
| + node.visitChildren(this); |
| + } |
| + R visitCascadeReceiver(CascadeReceiver node) { |
| + node.visitChildren(this); |
| + } |
| + R visitCaseMatch(CaseMatch node) { |
| + node.visitChildren(this); |
| + } |
| + R visitCatchBlock(CatchBlock node) { |
| + node.visitChildren(this); |
| + } |
| + R visitClassNode(ClassNode node) { |
| + internalError('Should never meet ClassNode', node); |
| + } |
| + R visitConditional(Conditional node) { |
| + node.visitChildren(this); |
| + } |
| + R visitContinueStatement(ContinueStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitDoWhile(DoWhile node) { |
| + node.visitChildren(this); |
| + } |
| + R visitEmptyStatement(EmptyStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitExpressionStatement(ExpressionStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitFor(For node) { |
| + node.visitChildren(this); |
| + } |
| + R visitForIn(ForIn node) { |
| + node.visitChildren(this); |
| + } |
| + R visitFunctionDeclaration(FunctionDeclaration node) { |
| + node.visitChildren(this); |
| + } |
| + R visitFunctionExpression(FunctionExpression node) { |
| + node.visitChildren(this); |
| + } |
| + R visitIdentifier(Identifier node) { |
| + if (currentElement.isGenerativeConstructor() |
| + || currentElement.isFactoryConstructor()) { |
| + // Two complicated cases for class/interface renaming: |
| + // 1) class which implements constructors of other interfaces, but not |
| + // implements interfaces themselves: |
| + // 0.dart: class C { I(); } |
| + // 1.dart and 2.dart: interface I default C { I(); } |
| + // now we have to duplicate our I() constructor in C class with |
| + // proper names. |
| + // 2) (even worse for us): |
| + // 0.dart: class C { C(); } |
| + // 1.dart: interface C default p0.C { C(); } |
| + // the second case is just a bug now. |
| + final ClassElement enclosingClass = currentElement.getEnclosingClass(); |
| + if (node.token.slowToString() == enclosingClass.name.slowToString()) { |
| + // TODO: distinguish the case of constructor vs. nested named closure |
| + // (see function_syntax_test). |
| + // TODO: fix the bugs above and turn if into the assert. |
| + useType(node, enclosingClass.type); |
| + } |
| + } else if (currentElement.isFunction() |
| + && currentElement.cachedNode.name == node) { |
| + useMethod(node, currentElement); |
| + } |
| + } |
| + R visitIf(If node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLabel(Label node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLabeledStatement(LabeledStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralBool(LiteralBool node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralDouble(LiteralDouble node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralInt(LiteralInt node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralList(LiteralList node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralMap(LiteralMap node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralMapEntry(LiteralMapEntry node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralNull(LiteralNull node) { |
| + node.visitChildren(this); |
| + } |
| + R visitLiteralString(LiteralString node) { |
| + node.visitChildren(this); |
| + } |
| + R visitModifiers(Modifiers node) { |
| + node.visitChildren(this); |
| + } |
| + R visitNamedArgument(NamedArgument node) { |
| + node.visitChildren(this); |
| + } |
| + R visitNewExpression(NewExpression node) { |
| + node.visitChildren(this); |
| + } |
| + R visitNodeList(NodeList node) { |
| + node.visitChildren(this); |
| + } |
| + R visitOperator(Operator node) { |
| + node.visitChildren(this); |
| + } |
| + R visitParenthesizedExpression(ParenthesizedExpression node) { |
| + node.visitChildren(this); |
| + } |
| + R visitReturn(Return node) { |
| + node.visitChildren(this); |
| + } |
| + R visitScriptTag(ScriptTag node) { |
| + node.visitChildren(this); |
| + } |
| + R visitSend(Send send) => new SendVisitor(this, treeElements).visitSend(send); |
| + R visitSendSet(SendSet node) { |
| + node.visitChildren(this); |
| + } |
| + R visitStringInterpolation(StringInterpolation node) { |
| + node.visitChildren(this); |
| + } |
| + R visitStringInterpolationPart(StringInterpolationPart node) { |
| + node.visitChildren(this); |
| + } |
| + R visitStringJuxtaposition(StringJuxtaposition node) { |
| + node.visitChildren(this); |
| + } |
| + R visitSwitchCase(SwitchCase node) { |
| + node.visitChildren(this); |
| + } |
| + R visitSwitchStatement(SwitchStatement node) { |
| + node.visitChildren(this); |
| + } |
| + R visitThrow(Throw node) { |
| + node.visitChildren(this); |
| + } |
| + R visitTryStatement(TryStatement node) { |
| + node.visitChildren(this); |
| + } |
| + |
| + R visitTypeAnnotation(TypeAnnotation node) { |
| + Type type = resolveType(node); |
| + useType(node.typeName, type); |
| + visit(node.typeArguments); |
| + } |
| + |
| + R visitTypedef(Typedef node) { |
| + node.visitChildren(this); |
| + } |
| + R visitTypeVariable(TypeVariable node) { |
| + node.visitChildren(this); |
| + } |
| + R visitVariableDefinitions(VariableDefinitions node) { |
| + node.visitChildren(this); |
| + } |
| + R visitWhile(While node) { |
| + node.visitChildren(this); |
| + } |
| +} |