Linter Demo Errors: 8Warnings: 45File: /home/fstrocco/Dart/dart/benchmark/compiler/lib/src/dart_backend/placeholder_collector.dart // 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. part of dart_backend; class LocalPlaceholder { final String identifier; final Set nodes; LocalPlaceholder(this.identifier) : nodes = new Set(); int get hashCode => identifier.hashCode; String toString() => 'local_placeholder[id($identifier), nodes($nodes)]'; } class FunctionScope { final Set parameterIdentifiers; final Set localPlaceholders; FunctionScope() : parameterIdentifiers = new Set(), localPlaceholders = new Set(); void registerParameter(Identifier node) { parameterIdentifiers.add(node.source); } } class ConstructorPlaceholder { final Identifier node; final ConstructorElement element; ConstructorPlaceholder(this.node, this.element); } class DeclarationTypePlaceholder { final TypeAnnotation typeNode; final bool requiresVar; DeclarationTypePlaceholder(this.typeNode, this.requiresVar); } class SendVisitor extends OldResolvedVisitor { final PlaceholderCollector collector; SendVisitor(this.collector, TreeElements elements) : super(elements); visitOperatorSend(Send node) { } visitForeignSend(Send node) {} visitSuperSend(Send node) { Element element = elements[node]; if (element != null && element.isConstructor) { collector.tryMakeConstructorPlaceholder(node, element); } else { collector.tryMakeMemberPlaceholder(node.selector); } } visitDynamicSend(Send node) { final element = elements[node]; if (element == null || !element.isErroneous) { collector.tryMakeMemberPlaceholder(node.selector); } } visitClosureSend(Send node) { final element = elements[node]; if (element != null) { collector.tryMakeLocalPlaceholder(element, node.selector); } } visitGetterSend(Send node) { final element = elements[node]; // element == null means dynamic property access. if (element == null) { collector.tryMakeMemberPlaceholder(node.selector); } else if (element.isErroneous) { collector.makeUnresolvedPlaceholder(node); return; } else if (element.isPrefix) { // Node is prefix part in case of source 'lib.somesetter = 5;' collector.makeErasePrefixPlaceholder(node); } else if (Elements.isStaticOrTopLevel(element)) { // Unqualified or prefixed top level or static. collector.makeElementPlaceholder(node.selector, element); } else if (!element.isTopLevel) { if (element.isInstanceMember) { collector.tryMakeMemberPlaceholder(node.selector); } else { // May get FunctionExpression here in selector // in case of A(int this.f()); if (node.selector is Identifier) { collector.tryMakeLocalPlaceholder(element, node.selector); } else { assert(node.selector is FunctionExpression); } } } } visitAssertSend(node) { visitStaticSend(node); } visitStaticSend(Send node) { Element element = elements[node]; collector.mirrorRenamer.registerStaticSend( collector.currentElement, element, node); if (Elements.isUnresolved(element) || elements.isAssert(node) || element.isDeferredLoaderGetter) { return; } if (element.isConstructor || element.isFactoryConstructor) { // Rename named constructor in redirection position: // class C { C.named(); C.redirecting() : this.named(); } if (node.receiver is Identifier && node.receiver.asIdentifier().isThis()) { assert(node.selector is Identifier); collector.tryMakeConstructorPlaceholder(node, element); } return; } collector.makeElementPlaceholder(node.selector, element); // Another ugly case: . is represented as // receiver: lib prefix, selector: top level. if (element.isTopLevel && node.receiver != null) { assert(elements[node.receiver].isPrefix); // Hack: putting null into map overrides receiver of original node. collector.makeErasePrefixPlaceholder(node.receiver); } } internalError(Spannable node, String reason) { collector.internalError(reason, node: node); } visitTypePrefixSend(Send node) { collector.makeElementPlaceholder(node, elements[node]); } visitTypeLiteralSend(Send node) { DartType type = elements.getTypeLiteralType(node); if (!type.isDynamic) { if (type is TypeVariableType) { collector.makeTypeVariablePlaceholder(node.selector, type); } else { collector.makeTypePlaceholder(node.selector, type); } } } } class PlaceholderCollector extends Visitor { final DiagnosticListener listener; final MirrorRenamer mirrorRenamer; final FunctionElement mainFunction; final Set fixedMemberNames; // member names which cannot be renamed. final Map elementAsts; final Set prefixNodesToErase = new Set(); final Set unresolvedNodes = new Set(); final Map> elementNodes = new Map>(); final Map functionScopes = new Map(); final Map> privateNodes = new Map>(); final List declarationTypePlaceholders = new List(); final Map> memberPlaceholders = new Map>(); final List constructorPlaceholders = new List(); Map currentLocalPlaceholders; Element currentElement; FunctionElement topmostEnclosingFunction; TreeElements treeElements; get currentFunctionScope => functionScopes.putIfAbsent( topmostEnclosingFunction, () => new FunctionScope()); PlaceholderCollector(this.listener, this.mirrorRenamer, this.fixedMemberNames, this.elementAsts, this.mainFunction); void collectFunctionDeclarationPlaceholders( FunctionElement element, FunctionExpression node) { if (element.isConstructor) { ConstructorElement constructor = element; tryMakeConstructorPlaceholder(node.name, element); RedirectingFactoryBody bodyAsRedirectingFactoryBody = node.body.asRedirectingFactoryBody(); if (bodyAsRedirectingFactoryBody != null) { // Factory redirection. FunctionElement redirectTarget = constructor.immediateRedirectionTarget; assert(redirectTarget != null && redirectTarget != element); tryMakeConstructorPlaceholder( bodyAsRedirectingFactoryBody.constructorReference, redirectTarget); } } else if (Elements.isStaticOrTopLevel(element)) { // Note: this code should only rename private identifiers for class' // fields/getters/setters/methods. Top-level identifiers are renamed // just to escape conflicts and that should be enough as we shouldn't // be able to resolve private identifiers for other libraries. makeElementPlaceholder(node.name, element); } else if (element.isClassMember) { if (node.name is Identifier) { tryMakeMemberPlaceholder(node.name); } else { assert(node.name.asSend().isOperator); } } } void collectFieldDeclarationPlaceholders(Element element, Node node) { Identifier name = node is Identifier ? node : node.asSend().selector; if (Elements.isStaticOrTopLevel(element)) { makeElementPlaceholder(name, element); } else if (Elements.isInstanceField(element)) { tryMakeMemberPlaceholder(name); } } void collect(Element element) { this.currentElement = element; this.topmostEnclosingFunction = null; final ElementAst elementAst = elementAsts[element]; this.treeElements = elementAst.treeElements; Node elementNode = elementAst.ast; if (element is FunctionElement) { collectFunctionDeclarationPlaceholders(element, elementNode); } else if (element is VariableElement) { VariableDefinitions definitions = elementNode; Node definition = definitions.definitions.nodes.head; collectFieldDeclarationPlaceholders(element, definition); makeVarDeclarationTypePlaceholder(definitions); } else { assert(element is ClassElement || element is TypedefElement); } currentLocalPlaceholders = new Map(); if (!(element is ConstructorElement && element.isRedirectingFactory)) { // Do not visit the body of redirecting factories. listener.withCurrentElement(element, () { elementNode.accept(this); }); } } // TODO(karlklose): should we create placeholders for these? bool isTypedefParameter(Element element) { return element != null && element.enclosingElement != null && element.enclosingElement.isTypedef; } void tryMakeLocalPlaceholder(Element element, Identifier node) { bool isNamedOptionalParameter() { FunctionTypedElement function = element.enclosingElement; FunctionSignature signature = function.functionSignature; if (!signature.optionalParametersAreNamed) return false; for (Element parameter in signature.optionalParameters) { if (identical(parameter, element)) return true; } return false; } if (element.isParameter && !isTypedefParameter(element) && isNamedOptionalParameter()) { currentFunctionScope.registerParameter(node); } else if (Elements.isLocal(element) && !isTypedefParameter(element)) { makeLocalPlaceholder(node); } } void tryMakeMemberPlaceholder(Identifier node) { assert(node != null); if (node is Operator) return; String identifier = node.source; if (fixedMemberNames.contains(identifier)) return; memberPlaceholders.putIfAbsent( identifier, () => new Set()).add(node); } void makeTypePlaceholder(Node node, DartType type) { Send send = node.asSend(); if (send != null) { // Prefix. assert(send.receiver is Identifier); assert(send.selector is Identifier); makeErasePrefixPlaceholder(send.receiver); node = send.selector; } makeElementPlaceholder(node, type.element); } void makeTypeVariablePlaceholder(Node node, TypeVariableType type) { Send send = node.asSend(); if (send != null) { // Prefix. assert(send.receiver is Identifier); assert(send.selector is Identifier); makeErasePrefixPlaceholder(send.receiver); node = send.selector; } tryMakeMemberPlaceholder(node); } void makeOmitDeclarationTypePlaceholder(TypeAnnotation type) { if (type == null) return; declarationTypePlaceholders.add( new DeclarationTypePlaceholder(type, false)); } void makeVarDeclarationTypePlaceholder(VariableDefinitions node) { // TODO(smok): Maybe instead of calling this method and // makeDeclaratioTypePlaceholder have type declaration placeholder // collector logic in visitVariableDefinitions when resolver becomes better // and/or catch syntax changes. if (node.type == null) return; Element definitionElement = treeElements[node.definitions.nodes.head]; bool requiresVar = !node.modifiers.isFinalOrConst; declarationTypePlaceholders.add( new DeclarationTypePlaceholder(node.type, requiresVar)); } /// Marks [node] to be erased in the output. /// This is done for library prefixes because they are not used in the output /// because all imports are flattened and conflicts are renamed away. void makeErasePrefixPlaceholder(Node node) { assert(node is Identifier || node is Send); prefixNodesToErase.add(node); } void makeElementPlaceholder(Node node, Element element) { assert(node != null); assert(element != null); LibraryElement library = element.library; if (identical(element, mainFunction)) return; if (library.isDartCore) return; if (library.isPlatformLibrary && !element.isTopLevel) { return; } ClassElement cls = element.enclosingClass; if (cls != null && cls.isEnumClass) { // Enums and enum values cannot be changed, since the semantics of // `toString` is defined by the names of the declarations. return; } if (element.isGetter || element.isSetter) { element = (element as FunctionElement).abstractField; } elementNodes.putIfAbsent(element, () => new Set()).add(node); } /// Marks [node] to be renamed per-library if it names an instance member /// and has a private name. void tryMakePrivateIdentifier(Node node, Element element) { if (node is Identifier && !Elements.isStaticOrTopLevel(element) && !Elements.isLocal(element) && isPrivateName(node.source)) { privateNodes.putIfAbsent( currentElement.library, () => new Set()).add(node); } } void makeUnresolvedPlaceholder(Node node) { unresolvedNodes.add(node); } void makeLocalPlaceholder(Identifier identifier) { LocalPlaceholder getLocalPlaceholder() { String name = identifier.source; return currentLocalPlaceholders.putIfAbsent(name, () { LocalPlaceholder localPlaceholder = new LocalPlaceholder(name); currentFunctionScope.localPlaceholders.add(localPlaceholder); return localPlaceholder; }); } getLocalPlaceholder().nodes.add(identifier); } /// Finds the first constructor on the chain of definingConstructor from /// [element] that is not in a synthetic class. Element findDefiningConstructor(ConstructorElement element) { while (element.definingConstructor != null) { element = element.definingConstructor; } return element; } void tryMakeConstructorPlaceholder(Node node, ConstructorElement element) { if (Elements.isUnresolved(element)) { makeUnresolvedPlaceholder(node); return; } // A library prefix. Node prefix; // The name of the class with the constructor. Node className; // Will be null for unnamed constructors. Identifier constructorName; // First deconstruct the constructor, there are 4 possibilities: // ClassName() // prefix.ClassName() // ClassName.constructorName() // prefix.ClassName.constructorName() if (node is Send) { if (node.receiver is Send) { Send receiver = node.receiver; // prefix.ClassName.constructorName() assert(treeElements[receiver.receiver] != null && treeElements[receiver.receiver].isPrefix); prefix = receiver.receiver; className = receiver.selector; constructorName = node.selector; } else { Element receiverElement = treeElements[node.receiver]; if (receiverElement != null && receiverElement.isPrefix) { // prefix.ClassName() prefix = node.receiver; className = node.selector; } else { // ClassName.constructorName() className = node.receiver; constructorName = node.selector; } } } else { // ClassName() className = node; } if (prefix != null) { makeErasePrefixPlaceholder(prefix); } if (className is TypeAnnotation) { visitTypeAnnotation(className); } else if (Elements.isUnresolved(element)) { // We handle unresolved nodes elsewhere. } else if (className.isThis() || className.isSuper()) { // Do not rename super and this. } else if (className is Identifier) { makeElementPlaceholder(className, element.contextClass); } else { throw "Bad type of constructor name $className"; } if (constructorName != null) { Element definingConstructor = findDefiningConstructor(element); constructorPlaceholders.add(new ConstructorPlaceholder(constructorName, definingConstructor)); tryMakePrivateIdentifier(constructorName, element); } } void internalError(String reason, {Node node}) { listener.internalError(node, reason); } visit(Node node) => (node == null) ? null : node.accept(this); visitNode(Node node) { node.visitChildren(this); } // We must go deeper. visitNewExpression(NewExpression node) { Send send = node.send; DartType type = treeElements.getType(node); assert(type != null); Element constructor = treeElements[send]; assert(constructor != null); assert(send.receiver == null); if (!Elements.isErroneous(constructor)) { tryMakeConstructorPlaceholder(node.send.selector, constructor); // TODO(smok): Should this be in visitNamedArgument? // Field names can be exposed as names of optional arguments, e.g. // class C { // final field; // C([this.field]); // } // Do not forget to rename them as well. FunctionElement constructorFunction = constructor; Link optionalParameters = constructorFunction.functionSignature.optionalParameters; for (final argument in send.argumentsNode) { NamedArgument named = argument.asNamedArgument(); if (named == null) continue; Identifier name = named.name; String nameAsString = name.source; for (final parameter in optionalParameters) { if (parameter.isInitializingFormal) { if (parameter.name == nameAsString) { tryMakeMemberPlaceholder(name); break; } } } } } else { makeUnresolvedPlaceholder(node.send.selector); } visit(node.send.argumentsNode); } visitSend(Send send) { Element element = treeElements[send]; tryMakePrivateIdentifier(send.selector, element); new SendVisitor(this, treeElements).visitSend(send); send.visitChildren(this); } visitSendSet(SendSet send) { Element element = treeElements[send]; if (Elements.isErroneous(element)) { // Complicated case: constructs like receiver.selector++ can resolve // to ErroneousElement. Fortunately, receiver.selector still // can be resoved via treeElements[send.selector], that's all // that is needed to rename the construct properly. element = treeElements[send.selector]; } tryMakePrivateIdentifier(send.selector, element); if (element == null) { if (send.receiver != null) tryMakeMemberPlaceholder(send.selector); } else if (!element.isErroneous) { if (Elements.isStaticOrTopLevel(element)) { // TODO(smok): Worth investigating why sometimes we get getter/setter // here and sometimes abstract field. assert(element.isClass || element is VariableElement || element.isAccessor || element.isAbstractField || element.isFunction || element.isTypedef || element is TypeVariableElement); makeElementPlaceholder(send.selector, element); } else { Identifier identifier = send.selector.asIdentifier(); if (identifier == null) { // Handle optional function expression parameters with default values. identifier = send.selector.asFunctionExpression().name; } if (Elements.isInstanceField(element)) { tryMakeMemberPlaceholder(identifier); } else { tryMakeLocalPlaceholder(element, identifier); } } } send.visitChildren(this); } visitTypeAnnotation(TypeAnnotation node) { final type = treeElements.getType(node); assert(invariant(node, type != null, message: "Missing type for type annotation: $treeElements")); if (!type.isVoid) { if (!type.treatAsDynamic) { if (type is TypeVariableType) { makeTypeVariablePlaceholder(node.typeName, type); } else { makeTypePlaceholder(node.typeName, type); } } else if (!type.isDynamic) { makeUnresolvedPlaceholder(node.typeName); } } // Visit only type arguments, otherwise in case of lib.Class type // annotation typeName is Send and we go to visitGetterSend, as a result // "Class" is added to member placeholders. visit(node.typeArguments); } visitVariableDefinitions(VariableDefinitions node) { // Collect only local placeholders. for (Node definition in node.definitions.nodes) { Element definitionElement = treeElements[definition]; // definitionElement may be null if we're inside variable definitions // of a function that is a parameter of another function. // TODO(smok): Fix this when resolver correctly deals with // such cases. if (definitionElement == null) continue; Send send = definition.asSend(); Identifier identifier = definition is Identifier ? definition : definition is Send ? (send.selector is Identifier ? send.selector : null) : null; tryMakePrivateIdentifier(identifier, definitionElement); if (send != null) { // May get FunctionExpression here in definition.selector // in case of A(int this.f()); if (send.selector is Identifier) { if (definitionElement.isInitializingFormal) { tryMakeMemberPlaceholder(send.selector); } else { tryMakeLocalPlaceholder(definitionElement, send.selector); } } else { assert(send.selector is FunctionExpression); if (definitionElement.isInitializingFormal) { tryMakeMemberPlaceholder( send.selector.asFunctionExpression().name); } } } else if (definition is Identifier) { tryMakeLocalPlaceholder(definitionElement, definition); } else if (definition is FunctionExpression) { // Skip, it will be processed in visitFunctionExpression. } else { internalError('Unexpected definition structure $definition'); } } node.visitChildren(this); } visitFunctionExpression(FunctionExpression node) { bool isKeyword(Identifier id) => id != null && Keyword.keywords[id.source] != null; Element element = treeElements[node]; // May get null; if (element != null) { tryMakePrivateIdentifier(node.name, element); // Rename only local functions. if (topmostEnclosingFunction == null && element is! LocalParameterElement && element is! InitializingFormalElement) { topmostEnclosingFunction = element; } if (!identical(element, currentElement)) { if (node.name != null) { assert(node.name is Identifier); tryMakeLocalPlaceholder(element, node.name); } } } node.visitChildren(this); // Make sure we don't omit return type of methods which names are // identifiers, because the following works fine: // int interface() => 1; // But omitting 'int' makes VM unhappy. // TODO(smok): Remove it when http://dartbug.com/5278 is fixed. if (node.name == null || !isKeyword(node.name.asIdentifier())) { makeOmitDeclarationTypePlaceholder(node.returnType); } collectFunctionParameters(node.parameters); } void collectFunctionParameters(NodeList parameters) { if (parameters == null) return; for (Node parameter in parameters.nodes) { if (parameter is NodeList) { // Optional parameter list. collectFunctionParameters(parameter); } else { assert(parameter is VariableDefinitions); makeOmitDeclarationTypePlaceholder( parameter.asVariableDefinitions().type); } } } visitClassNode(ClassNode node) { ClassElement classElement = currentElement; makeElementPlaceholder(node.name, classElement); node.visitChildren(this); } visitNamedMixinApplication(NamedMixinApplication node) { ClassElement classElement = currentElement; makeElementPlaceholder(node.name, classElement); node.visitChildren(this); } visitTypeVariable(TypeVariable node) { DartType type = treeElements.getType(node); assert(invariant(node, type != null, message: "Missing type for type variable: $treeElements")); makeTypeVariablePlaceholder(node.name, type); node.visitChildren(this); } visitTypedef(Typedef node) { assert(currentElement is TypedefElement); makeElementPlaceholder(node.name, currentElement); node.visitChildren(this); makeOmitDeclarationTypePlaceholder(node.returnType); collectFunctionParameters(node.formals); } visitBlock(Block node) { for (Node statement in node.statements.nodes) { if (statement is VariableDefinitions) { makeVarDeclarationTypePlaceholder(statement); } } node.visitChildren(this); } }