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..f4afec8d9ef68e6d679d76294bc513f9e5b8c06e |
| --- /dev/null |
| +++ b/lib/compiler/implementation/dart_backend/usager.dart |
| @@ -0,0 +1,221 @@ |
| +// 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); |
|
Anton Muhin
2012/08/07 16:00:30
why do you need to visit children?
Anton Muhin
2012/08/07 16:00:30
R should be now String
Roman
2012/08/08 06:46:14
Fixed, visiting children now in PlaceholderCollect
Roman
2012/08/08 06:46:14
Actually it should not return anything.
|
| + 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]; |
| + // element === null means dynamic property access. |
| + if (element === null || !element.isTopLevel()) { |
| + node.visitChildren(usager); |
| + return; |
|
Anton Muhin
2012/08/07 16:00:30
you promise to return String, but explicitly retur
|
| + } |
| + // Unqualified <class> in static invocation, why it's not a type annotation? |
| + // Another option would be to process in visitStaticSend, NB: |
| + // those elements are not top-level. |
| + // OR: unqualified top level. |
| + usager.useElement(node.selector, element); |
| + if (node.receiver !== null) { |
| + // <lib prefix>.<top level>. |
| + usager.useNull(node.receiver); // Cut library prefix. |
| + } |
| + usager.visit(node.argumentsNode); |
| + } |
| + |
| + R visitStaticSend(Send node) { |
| + final element = elements[node]; |
| + if (!element.isTopLevel()) { |
| + node.visitChildren(usager); |
| + return; |
| + } |
| + // Another ugly case: <lib prefix>.<top level> is represented as |
| + // receiver: lib prefix, selector: top level. |
| + usager.useMethod(node.selector, element); |
| + if (node.receiver !== null) { |
| + assert(elements[node.receiver].isPrefix()); |
| + // Hack: putting null into map overrides receiver of original node. |
| + usager.useNull(node.receiver); |
| + } |
| + usager.visit(node.argumentsNode); |
| + } |
| +} |
| + |
| +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) { |
|
Anton Muhin
2012/08/07 16:00:30
I don't think it should belong to any class.
Roman
2012/08/08 06:46:14
Forgot to remove.
|
| + final libraries = compiler.libraries; |
| + for (final uri in libraries.getKeys()) { |
| + if (libraryElement === libraries[uri]) { |
| + if (uri.startsWith('dart:')) return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + void processConstructorName( |
| + FunctionElement element, FunctionExpression node) { |
| + // 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 enclosingClass = currentElement.getEnclosingClass(); |
| + Node nameNode = node.name; |
| + if (nameNode is Send) nameNode = nameNode.receiver; |
| + if (nameNode.token.slowToString() == enclosingClass.name.slowToString()) { |
|
Anton Muhin
2012/08/07 16:24:08
please, add a comment that this if is needed for c
Roman
2012/08/08 06:46:14
Done.
|
| + useType(nameNode, enclosingClass.type); |
| + } |
| + } |
| + |
| + void process(Element element, TreeElements elements) { |
| + currentElement = element; |
| + treeElements = elements; |
| + Node elementNode = element.parseNode(compiler); |
| + if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { |
| + processConstructorName(element, elementNode); |
| + } |
| + elementNode.accept(this); |
| + } |
| + |
| + Type resolveType(TypeAnnotation typeAnnotation) { |
| + if (treeElements === null) return null; |
| + var result = treeElements.getType(typeAnnotation); |
|
Anton Muhin
2012/08/07 16:00:30
please, TODO to have better type resolution.
Roman
2012/08/08 06:46:14
Done.
|
| + if (result === null) { |
| + result = compiler.resolveTypeAnnotation(currentElement, typeAnnotation); |
| + } |
| + return result; |
| + } |
| + |
| + void useType(Node node, Type type) { |
|
Anton Muhin
2012/08/07 16:00:30
as we discussed, use is probably wrong name
Roman
2012/08/08 06:46:14
renamed to placeholderForType
|
| + assert(type !== null); |
| + usages[node] = new TypeUsage(type); |
| + } |
| + 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); |
| + |
| + R visitBlock(Block node) => 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) => node.visitChildren(this); |
| + 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) { |
| + if (currentElement.isClass()) { |
| + throw 'e'; |
| + } |
| + final type = compiler.resolveTypeAnnotation(currentElement, node); |
| + if (type is !InterfaceType) return null; |
| + var target = node.typeName; |
| + if (node.typeName is Send) { |
| + final element = treeElements[node]; |
| + if (element !== null) { |
| + final send = node.typeName.asSend(); |
| + final isPrefixed = element.lookupConstructor( |
| + send.receiver.source, send.selector.source) === null; |
| + if (!isPrefixed) target = send.receiver; |
| + } |
| + } |
| + useType(target, 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); |
| +} |