From 76cb9faa2782f6c64f81bcacb3797e44fd047c8e Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Fri, 26 Jun 2015 16:55:46 -0700 Subject: [PATCH] Update some files from CRLF to LF R=sra@google.com Review URL: https://codereview.chromium.org//1214853002. --- pkg/analyzer2dart/lib/src/cps_generator.dart | 1178 ++++++++--------- .../lib/src/semantic_visitor.dart | 542 ++++---- pkg/analyzer2dart/lib/src/util.dart | 84 +- pkg/compiler/lib/src/elements/common.dart | 944 ++++++------- .../lib/src/io/line_column_provider.dart | 154 +-- 5 files changed, 1451 insertions(+), 1451 deletions(-) diff --git a/pkg/analyzer2dart/lib/src/cps_generator.dart b/pkg/analyzer2dart/lib/src/cps_generator.dart index 8bd4c0ad668..1e5bb6dbf34 100644 --- a/pkg/analyzer2dart/lib/src/cps_generator.dart +++ b/pkg/analyzer2dart/lib/src/cps_generator.dart @@ -1,589 +1,589 @@ -// Copyright (c) 2014, 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. - -library analyzer2dart.cps_generator; - -import 'package:analyzer/analyzer.dart'; - -import 'package:compiler/src/dart_types.dart' as dart2js; -import 'package:compiler/src/elements/elements.dart' as dart2js; -import 'package:analyzer/src/generated/source.dart'; -import 'package:analyzer/src/generated/element.dart' as analyzer; - -import 'package:compiler/src/constant_system_dart.dart' - show DART_CONSTANT_SYSTEM; -import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; -import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; -import 'package:compiler/src/universe/universe.dart'; - -import 'semantic_visitor.dart'; -import 'element_converter.dart'; -import 'util.dart'; -import 'identifier_semantics.dart'; - -/// Visitor that converts the AST node of an analyzer element into a CPS ir -/// node. -class CpsElementVisitor extends analyzer.SimpleElementVisitor { - final ElementConverter converter; - final AstNode node; - - CpsElementVisitor(this.converter, this.node); - - @override - ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { - CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); - FunctionDeclaration functionDeclaration = node; - return visitor.handleFunctionDeclaration( - element, functionDeclaration.functionExpression.body); - } - - @override - ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { - CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); - MethodDeclaration methodDeclaration = node; - return visitor.handleFunctionDeclaration(element, methodDeclaration.body); - } - - @override - ir.FieldDefinition visitTopLevelVariableElement( - analyzer.TopLevelVariableElement element) { - CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); - VariableDeclaration variableDeclaration = node; - return visitor.handleFieldDeclaration(element, variableDeclaration); - } - - @override - ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { - CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); - if (!element.isFactory) { - ConstructorDeclaration constructorDeclaration = node; - FunctionBody body; - if (constructorDeclaration != null) { - body = constructorDeclaration.body; - } else { - assert(element.isSynthetic); - } - return visitor.handleConstructorDeclaration(element, body); - } - // TODO(johnniwinther): Support factory constructors. - return null; - } -} - -/// Visitor that converts analyzer AST nodes into CPS ir nodes. -class CpsGeneratingVisitor extends SemanticVisitor - with IrBuilderMixin { - /// Promote the type of [irBuilder] to [DartIrBuilder]. - /// The JS backend requires closure conversion which we do not support yet. - DartIrBuilder get irBuilder => super.irBuilder; - final analyzer.Element element; - final ElementConverter converter; - - CpsGeneratingVisitor(this.converter, this.element); - - Source get currentSource => element.source; - - analyzer.LibraryElement get currentLibrary => element.library; - - ir.Node visit(AstNode node) => node.accept(this); - - ir.ConstructorDefinition handleConstructorDeclaration( - analyzer.ConstructorElement constructor, FunctionBody body) { - dart2js.ConstructorElement element = converter.convertElement(constructor); - return withBuilder( - new DartIrBuilder(DART_CONSTANT_SYSTEM, - element, - // TODO(johnniwinther): Support closure variables. - new Set()), - () { - irBuilder.buildFunctionHeader( - constructor.parameters.map(converter.convertElement)); - // Visit the body directly to avoid processing the signature as - // expressions. - // Call to allow for `body == null` in case of synthesized constructors. - build(body); - return irBuilder.makeConstructorDefinition(const [], const []); - }); - } - - ir.FieldDefinition handleFieldDeclaration( - analyzer.PropertyInducingElement field, VariableDeclaration node) { - dart2js.FieldElement element = converter.convertElement(field); - return withBuilder( - new DartIrBuilder(DART_CONSTANT_SYSTEM, - element, - // TODO(johnniwinther): Support closure variables. - new Set()), - () { - irBuilder.buildFieldInitializerHeader(); - ir.Primitive initializer = build(node.initializer); - return irBuilder.makeFieldDefinition(initializer); - }); - } - - ir.FunctionDefinition handleFunctionDeclaration( - analyzer.ExecutableElement function, FunctionBody body) { - dart2js.FunctionElement element = converter.convertElement(function); - return withBuilder( - new DartIrBuilder(DART_CONSTANT_SYSTEM, - element, - // TODO(johnniwinther): Support closure variables. - new Set()), - () { - irBuilder.buildFunctionHeader( - function.parameters.map(converter.convertElement)); - // Visit the body directly to avoid processing the signature as - // expressions. - visit(body); - return irBuilder.makeFunctionDefinition(const []); - }); - } - - @override - ir.Primitive visitFunctionExpression(FunctionExpression node) { - return irBuilder.buildFunctionExpression( - handleFunctionDeclaration(node.element, node.body)); - } - - @override - ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { - return handleFunctionDeclaration( - node.element, node.functionExpression.body); - } - - @override - visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { - FunctionDeclaration functionDeclaration = node.functionDeclaration; - analyzer.FunctionElement function = functionDeclaration.element; - dart2js.FunctionElement element = converter.convertElement(function); - ir.FunctionDefinition definition = handleFunctionDeclaration( - function, functionDeclaration.functionExpression.body); - irBuilder.declareLocalFunction(element, definition); - } - - List visitArguments(ArgumentList argumentList) { - List arguments = []; - for (Expression argument in argumentList.arguments) { - ir.Primitive value = build(argument); - if (value == null) { - giveUp(argument, - 'Unsupported argument: $argument (${argument.runtimeType}).'); - } - arguments.add(value); - } - return arguments; - } - - @override - ir.Node visitMethodInvocation(MethodInvocation node) { - // Overridden to avoid eager visits of the receiver and arguments. - return handleMethodInvocation(node); - } - - @override - ir.Primitive visitDynamicInvocation(MethodInvocation node, - AccessSemantics semantics) { - // TODO(johnniwinther): Handle implicit `this`. - ir.Primitive receiver = build(semantics.target); - List arguments = visitArguments(node.argumentList); - return irBuilder.buildDynamicInvocation( - receiver, - createSelectorFromMethodInvocation( - node.argumentList, node.methodName.name), - arguments); - } - - @override - ir.Primitive visitStaticMethodInvocation(MethodInvocation node, - AccessSemantics semantics) { - analyzer.Element staticElement = semantics.element; - dart2js.Element element = converter.convertElement(staticElement); - List arguments = visitArguments(node.argumentList); - return irBuilder.buildStaticFunctionInvocation( - element, - createCallStructureFromMethodInvocation(node.argumentList), - arguments); - } - - @override - ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { - return handleLocalAccess(node, semantics); - } - - ir.Primitive handleLocalInvocation(MethodInvocation node, - AccessSemantics semantics) { - analyzer.Element staticElement = semantics.element; - dart2js.Element element = converter.convertElement(staticElement); - List arguments = visitArguments(node.argumentList); - CallStructure callStructure = createCallStructureFromMethodInvocation( - node.argumentList); - if (semantics.kind == AccessKind.LOCAL_FUNCTION) { - return irBuilder.buildLocalFunctionInvocation( - element, callStructure, arguments); - } else { - return irBuilder.buildLocalVariableInvocation( - element, callStructure, arguments); - } - } - - @override - ir.Node visitLocalVariableInvocation(MethodInvocation node, - AccessSemantics semantics) { - return handleLocalInvocation(node, semantics); - } - - @override - ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, - AccessSemantics semantics) { - return handleLocalInvocation(node, semantics); - } - - @override - ir.Primitive visitFunctionExpressionInvocation( - FunctionExpressionInvocation node) { - ir.Primitive target = build(node.function); - List arguments = visitArguments(node.argumentList); - return irBuilder.buildCallInvocation( - target, - createCallStructureFromMethodInvocation(node.argumentList), - arguments); - } - - @override - ir.Primitive visitInstanceCreationExpression( - InstanceCreationExpression node) { - analyzer.Element staticElement = node.staticElement; - if (staticElement != null) { - dart2js.Element element = converter.convertElement(staticElement); - dart2js.DartType type = converter.convertType(node.staticType); - List arguments = visitArguments(node.argumentList); - return irBuilder.buildConstructorInvocation( - element, - createCallStructureFromMethodInvocation(node.argumentList), - type, - arguments); - } - return giveUp(node, "Unresolved constructor invocation."); - } - - @override - ir.Constant visitNullLiteral(NullLiteral node) { - return irBuilder.buildNullConstant(); - } - - @override - ir.Constant visitBooleanLiteral(BooleanLiteral node) { - return irBuilder.buildBooleanConstant(node.value); - } - - @override - ir.Constant visitDoubleLiteral(DoubleLiteral node) { - return irBuilder.buildDoubleConstant(node.value); - } - - @override - ir.Constant visitIntegerLiteral(IntegerLiteral node) { - return irBuilder.buildIntegerConstant(node.value); - } - - @override - visitAdjacentStrings(AdjacentStrings node) { - String value = node.stringValue; - if (value != null) { - return irBuilder.buildStringConstant(value); - } - giveUp(node, "Non constant adjacent strings."); - } - - @override - ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { - return irBuilder.buildStringConstant(node.value); - } - - @override - visitStringInterpolation(StringInterpolation node) { - giveUp(node, "String interpolation."); - } - - @override - visitReturnStatement(ReturnStatement node) { - irBuilder.buildReturn(build(node.expression)); - } - - @override - ir.Node visitPropertyAccess(PropertyAccess node) { - // Overridden to avoid eager visits of the receiver. - return handlePropertyAccess(node); - } - - @override - ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { - return handleLocalAccess(node, semantics); - } - - @override - ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { - return handleLocalAccess(node, semantics); - } - - @override - visitVariableDeclaration(VariableDeclaration node) { - // TODO(johnniwinther): Handle constant local variables. - ir.Node initialValue = build(node.initializer); - irBuilder.declareLocalVariable( - converter.convertElement(node.element), - initialValue: initialValue); - } - - dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { - analyzer.Element element = semantics.element; - dart2js.Element target = converter.convertElement(element); - assert(invariant(node, target.isLocal, '$target expected to be local.')); - return target; - } - - ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { - dart2js.Element local = getLocal(node, semantics); - if (semantics.kind == AccessKind.LOCAL_FUNCTION) { - return irBuilder.buildLocalFunctionGet(local); - } else { - return irBuilder.buildLocalVariableGet(local); - } - } - - ir.Primitive handleLocalAssignment(AssignmentExpression node, - AccessSemantics semantics) { - if (node.operator.lexeme != '=') { - return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); - } - return irBuilder.buildLocalVariableSet( - getLocal(node, semantics), - build(node.rightHandSide)); - } - - @override - ir.Node visitAssignmentExpression(AssignmentExpression node) { - // Avoid eager visiting of left and right hand side. - return handleAssignmentExpression(node); - } - - @override - ir.Node visitLocalVariableAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return handleLocalAssignment(node, semantics); - } - - @override - ir.Node visitParameterAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return handleLocalAssignment(node, semantics); - } - - @override - ir.Node visitStaticFieldAssignment(AssignmentExpression node, - AccessSemantics semantics) { - if (node.operator.lexeme != '=') { - return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); - } - analyzer.Element element = semantics.element; - dart2js.Element target = converter.convertElement(element); - // TODO(johnniwinther): Selector information should be computed in the - // [TreeShaker] and shared with the [CpsGeneratingVisitor]. - assert(invariant(node, target.isTopLevel || target.isStatic, - '$target expected to be top-level or static.')); - return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); - } - - @override - ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { - // TODO(johnniwinther): Handle implicit `this`. - ir.Primitive receiver = build(semantics.target); - return irBuilder.buildDynamicGet(receiver, - new Selector.getter(semantics.identifier.name, - converter.convertElement(element.library))); - } - - @override - ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { - analyzer.Element element = semantics.element; - dart2js.Element target = converter.convertElement(element); - // TODO(johnniwinther): Selector information should be computed in the - // [TreeShaker] and shared with the [CpsGeneratingVisitor]. - assert(invariant(node, target.isTopLevel || target.isStatic, - '$target expected to be top-level or static.')); - return irBuilder.buildStaticFieldLazyGet(target, null); - } - - ir.Primitive handleBinaryExpression(BinaryExpression node, - String op) { - ir.Primitive left = build(node.leftOperand); - ir.Primitive right = build(node.rightOperand); - Selector selector = new Selector.binaryOperator(op); - return irBuilder.buildDynamicInvocation( - left, selector, [right]); - } - - ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { - return irBuilder.buildLogicalOperator( - build(node.leftOperand), - subbuild(node.rightOperand), - isLazyOr: isLazyOr); - } - - @override - ir.Node visitBinaryExpression(BinaryExpression node) { - // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be - // available through an enum. - String op = node.operator.lexeme; - switch (op) { - case '||': - case '&&': - return handleLazyOperator(node, isLazyOr: op == '||'); - case '!=': - return irBuilder.buildNegation(handleBinaryExpression(node, '==')); - default: - return handleBinaryExpression(node, op); - } - } - - @override - ir.Node visitConditionalExpression(ConditionalExpression node) { - return irBuilder.buildConditional( - build(node.condition), - subbuild(node.thenExpression), - subbuild(node.elseExpression)); - } - - @override - visitIfStatement(IfStatement node) { - irBuilder.buildIf( - build(node.condition), - subbuild(node.thenStatement), - subbuild(node.elseStatement)); - } - - @override - visitBlock(Block node) { - irBuilder.buildBlock(node.statements, build); - } - - @override - ir.Node visitListLiteral(ListLiteral node) { - dart2js.InterfaceType type = converter.convertType(node.staticType); - // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue - // 18630 has been resolved. - Iterable values = node.elements.map((e) => build(e)); - return irBuilder.buildListLiteral(type, values); - } - - @override - ir.Node visitMapLiteral(MapLiteral node) { - dart2js.InterfaceType type = converter.convertType(node.staticType); - return irBuilder.buildMapLiteral( - type, - node.entries.map((e) => e.key), - node.entries.map((e) => e.value), - build); - } - - @override - visitForStatement(ForStatement node) { - // TODO(johnniwinther): Support `for` as a jump target. - List loopVariables = []; - SubbuildFunction buildInitializer; - if (node.variables != null) { - buildInitializer = subbuild(node.variables); - for (VariableDeclaration variable in node.variables.variables) { - loopVariables.add(converter.convertElement(variable.element)); - } - } else { - buildInitializer = subbuild(node.initialization); - } - irBuilder.buildFor(buildInitializer: buildInitializer, - buildCondition: subbuild(node.condition), - buildBody: subbuild(node.body), - buildUpdate: subbuildSequence(node.updaters), - loopVariables: loopVariables); - } - - @override - visitWhileStatement(WhileStatement node) { - // TODO(johnniwinther): Support `while` as a jump target. - irBuilder.buildWhile(buildCondition: subbuild(node.condition), - buildBody: subbuild(node.body)); - } - - @override - visitDeclaredIdentifier(DeclaredIdentifier node) { - giveUp(node, "Unexpected node: DeclaredIdentifier"); - } - - @override - visitForEachStatement(ForEachStatement node) { - SubbuildFunction buildVariableDeclaration; - dart2js.Element variableElement; - Selector variableSelector; - if (node.identifier != null) { - AccessSemantics accessSemantics = - node.identifier.accept(ACCESS_SEMANTICS_VISITOR); - if (accessSemantics.kind == AccessKind.DYNAMIC) { - variableSelector = new Selector.setter( - node.identifier.name, converter.convertElement(currentLibrary)); - } else if (accessSemantics.element != null) { - variableElement = converter.convertElement(accessSemantics.element); - variableSelector = new Selector.setter( - variableElement.name, - converter.convertElement(accessSemantics.element.library)); - } else { - giveUp(node, 'For-in of unresolved variable: $accessSemantics'); - } - } else { - assert(invariant( - node, node.loopVariable != null, "Loop variable expected")); - variableElement = converter.convertElement(node.loopVariable.element); - buildVariableDeclaration = (IrBuilder builder) { - builder.declareLocalVariable(variableElement); - }; - } - // TODO(johnniwinther): Support `for-in` as a jump target. - irBuilder.buildForIn( - buildExpression: subbuild(node.iterable), - buildVariableDeclaration: buildVariableDeclaration, - variableElement: variableElement, - variableSelector: variableSelector, - buildBody: subbuild(node.body)); - } - @override - ir.Primitive visitIsExpression(IsExpression node) { - return irBuilder.buildTypeOperator( - visit(node.expression), - converter.convertType(node.type.type), - isTypeTest: true, - isNotCheck: node.notOperator != null); - } - - @override - ir.Primitive visitAsExpression(AsExpression node) { - return irBuilder.buildTypeOperator( - visit(node.expression), - converter.convertType(node.type.type), - isTypeTest: false); - } - - @override - visitTryStatement(TryStatement node) { - List catchClauseInfos = []; - for (CatchClause catchClause in node.catchClauses) { - catchClauseInfos.add(new CatchClauseInfo( - exceptionVariable: converter.convertElement( - catchClause.exceptionParameter.staticElement), - buildCatchBlock: subbuild(catchClause.body))); - - } - irBuilder.buildTry( - tryStatementInfo: new TryStatementInfo(), - buildTryBlock: subbuild(node.body), - catchClauseInfos: catchClauseInfos); - } -} +// Copyright (c) 2014, 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. + +library analyzer2dart.cps_generator; + +import 'package:analyzer/analyzer.dart'; + +import 'package:compiler/src/dart_types.dart' as dart2js; +import 'package:compiler/src/elements/elements.dart' as dart2js; +import 'package:analyzer/src/generated/source.dart'; +import 'package:analyzer/src/generated/element.dart' as analyzer; + +import 'package:compiler/src/constant_system_dart.dart' + show DART_CONSTANT_SYSTEM; +import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; +import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; +import 'package:compiler/src/universe/universe.dart'; + +import 'semantic_visitor.dart'; +import 'element_converter.dart'; +import 'util.dart'; +import 'identifier_semantics.dart'; + +/// Visitor that converts the AST node of an analyzer element into a CPS ir +/// node. +class CpsElementVisitor extends analyzer.SimpleElementVisitor { + final ElementConverter converter; + final AstNode node; + + CpsElementVisitor(this.converter, this.node); + + @override + ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { + CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); + FunctionDeclaration functionDeclaration = node; + return visitor.handleFunctionDeclaration( + element, functionDeclaration.functionExpression.body); + } + + @override + ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { + CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); + MethodDeclaration methodDeclaration = node; + return visitor.handleFunctionDeclaration(element, methodDeclaration.body); + } + + @override + ir.FieldDefinition visitTopLevelVariableElement( + analyzer.TopLevelVariableElement element) { + CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); + VariableDeclaration variableDeclaration = node; + return visitor.handleFieldDeclaration(element, variableDeclaration); + } + + @override + ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { + CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); + if (!element.isFactory) { + ConstructorDeclaration constructorDeclaration = node; + FunctionBody body; + if (constructorDeclaration != null) { + body = constructorDeclaration.body; + } else { + assert(element.isSynthetic); + } + return visitor.handleConstructorDeclaration(element, body); + } + // TODO(johnniwinther): Support factory constructors. + return null; + } +} + +/// Visitor that converts analyzer AST nodes into CPS ir nodes. +class CpsGeneratingVisitor extends SemanticVisitor + with IrBuilderMixin { + /// Promote the type of [irBuilder] to [DartIrBuilder]. + /// The JS backend requires closure conversion which we do not support yet. + DartIrBuilder get irBuilder => super.irBuilder; + final analyzer.Element element; + final ElementConverter converter; + + CpsGeneratingVisitor(this.converter, this.element); + + Source get currentSource => element.source; + + analyzer.LibraryElement get currentLibrary => element.library; + + ir.Node visit(AstNode node) => node.accept(this); + + ir.ConstructorDefinition handleConstructorDeclaration( + analyzer.ConstructorElement constructor, FunctionBody body) { + dart2js.ConstructorElement element = converter.convertElement(constructor); + return withBuilder( + new DartIrBuilder(DART_CONSTANT_SYSTEM, + element, + // TODO(johnniwinther): Support closure variables. + new Set()), + () { + irBuilder.buildFunctionHeader( + constructor.parameters.map(converter.convertElement)); + // Visit the body directly to avoid processing the signature as + // expressions. + // Call to allow for `body == null` in case of synthesized constructors. + build(body); + return irBuilder.makeConstructorDefinition(const [], const []); + }); + } + + ir.FieldDefinition handleFieldDeclaration( + analyzer.PropertyInducingElement field, VariableDeclaration node) { + dart2js.FieldElement element = converter.convertElement(field); + return withBuilder( + new DartIrBuilder(DART_CONSTANT_SYSTEM, + element, + // TODO(johnniwinther): Support closure variables. + new Set()), + () { + irBuilder.buildFieldInitializerHeader(); + ir.Primitive initializer = build(node.initializer); + return irBuilder.makeFieldDefinition(initializer); + }); + } + + ir.FunctionDefinition handleFunctionDeclaration( + analyzer.ExecutableElement function, FunctionBody body) { + dart2js.FunctionElement element = converter.convertElement(function); + return withBuilder( + new DartIrBuilder(DART_CONSTANT_SYSTEM, + element, + // TODO(johnniwinther): Support closure variables. + new Set()), + () { + irBuilder.buildFunctionHeader( + function.parameters.map(converter.convertElement)); + // Visit the body directly to avoid processing the signature as + // expressions. + visit(body); + return irBuilder.makeFunctionDefinition(const []); + }); + } + + @override + ir.Primitive visitFunctionExpression(FunctionExpression node) { + return irBuilder.buildFunctionExpression( + handleFunctionDeclaration(node.element, node.body)); + } + + @override + ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { + return handleFunctionDeclaration( + node.element, node.functionExpression.body); + } + + @override + visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { + FunctionDeclaration functionDeclaration = node.functionDeclaration; + analyzer.FunctionElement function = functionDeclaration.element; + dart2js.FunctionElement element = converter.convertElement(function); + ir.FunctionDefinition definition = handleFunctionDeclaration( + function, functionDeclaration.functionExpression.body); + irBuilder.declareLocalFunction(element, definition); + } + + List visitArguments(ArgumentList argumentList) { + List arguments = []; + for (Expression argument in argumentList.arguments) { + ir.Primitive value = build(argument); + if (value == null) { + giveUp(argument, + 'Unsupported argument: $argument (${argument.runtimeType}).'); + } + arguments.add(value); + } + return arguments; + } + + @override + ir.Node visitMethodInvocation(MethodInvocation node) { + // Overridden to avoid eager visits of the receiver and arguments. + return handleMethodInvocation(node); + } + + @override + ir.Primitive visitDynamicInvocation(MethodInvocation node, + AccessSemantics semantics) { + // TODO(johnniwinther): Handle implicit `this`. + ir.Primitive receiver = build(semantics.target); + List arguments = visitArguments(node.argumentList); + return irBuilder.buildDynamicInvocation( + receiver, + createSelectorFromMethodInvocation( + node.argumentList, node.methodName.name), + arguments); + } + + @override + ir.Primitive visitStaticMethodInvocation(MethodInvocation node, + AccessSemantics semantics) { + analyzer.Element staticElement = semantics.element; + dart2js.Element element = converter.convertElement(staticElement); + List arguments = visitArguments(node.argumentList); + return irBuilder.buildStaticFunctionInvocation( + element, + createCallStructureFromMethodInvocation(node.argumentList), + arguments); + } + + @override + ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { + return handleLocalAccess(node, semantics); + } + + ir.Primitive handleLocalInvocation(MethodInvocation node, + AccessSemantics semantics) { + analyzer.Element staticElement = semantics.element; + dart2js.Element element = converter.convertElement(staticElement); + List arguments = visitArguments(node.argumentList); + CallStructure callStructure = createCallStructureFromMethodInvocation( + node.argumentList); + if (semantics.kind == AccessKind.LOCAL_FUNCTION) { + return irBuilder.buildLocalFunctionInvocation( + element, callStructure, arguments); + } else { + return irBuilder.buildLocalVariableInvocation( + element, callStructure, arguments); + } + } + + @override + ir.Node visitLocalVariableInvocation(MethodInvocation node, + AccessSemantics semantics) { + return handleLocalInvocation(node, semantics); + } + + @override + ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, + AccessSemantics semantics) { + return handleLocalInvocation(node, semantics); + } + + @override + ir.Primitive visitFunctionExpressionInvocation( + FunctionExpressionInvocation node) { + ir.Primitive target = build(node.function); + List arguments = visitArguments(node.argumentList); + return irBuilder.buildCallInvocation( + target, + createCallStructureFromMethodInvocation(node.argumentList), + arguments); + } + + @override + ir.Primitive visitInstanceCreationExpression( + InstanceCreationExpression node) { + analyzer.Element staticElement = node.staticElement; + if (staticElement != null) { + dart2js.Element element = converter.convertElement(staticElement); + dart2js.DartType type = converter.convertType(node.staticType); + List arguments = visitArguments(node.argumentList); + return irBuilder.buildConstructorInvocation( + element, + createCallStructureFromMethodInvocation(node.argumentList), + type, + arguments); + } + return giveUp(node, "Unresolved constructor invocation."); + } + + @override + ir.Constant visitNullLiteral(NullLiteral node) { + return irBuilder.buildNullConstant(); + } + + @override + ir.Constant visitBooleanLiteral(BooleanLiteral node) { + return irBuilder.buildBooleanConstant(node.value); + } + + @override + ir.Constant visitDoubleLiteral(DoubleLiteral node) { + return irBuilder.buildDoubleConstant(node.value); + } + + @override + ir.Constant visitIntegerLiteral(IntegerLiteral node) { + return irBuilder.buildIntegerConstant(node.value); + } + + @override + visitAdjacentStrings(AdjacentStrings node) { + String value = node.stringValue; + if (value != null) { + return irBuilder.buildStringConstant(value); + } + giveUp(node, "Non constant adjacent strings."); + } + + @override + ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { + return irBuilder.buildStringConstant(node.value); + } + + @override + visitStringInterpolation(StringInterpolation node) { + giveUp(node, "String interpolation."); + } + + @override + visitReturnStatement(ReturnStatement node) { + irBuilder.buildReturn(build(node.expression)); + } + + @override + ir.Node visitPropertyAccess(PropertyAccess node) { + // Overridden to avoid eager visits of the receiver. + return handlePropertyAccess(node); + } + + @override + ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { + return handleLocalAccess(node, semantics); + } + + @override + ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { + return handleLocalAccess(node, semantics); + } + + @override + visitVariableDeclaration(VariableDeclaration node) { + // TODO(johnniwinther): Handle constant local variables. + ir.Node initialValue = build(node.initializer); + irBuilder.declareLocalVariable( + converter.convertElement(node.element), + initialValue: initialValue); + } + + dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { + analyzer.Element element = semantics.element; + dart2js.Element target = converter.convertElement(element); + assert(invariant(node, target.isLocal, '$target expected to be local.')); + return target; + } + + ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { + dart2js.Element local = getLocal(node, semantics); + if (semantics.kind == AccessKind.LOCAL_FUNCTION) { + return irBuilder.buildLocalFunctionGet(local); + } else { + return irBuilder.buildLocalVariableGet(local); + } + } + + ir.Primitive handleLocalAssignment(AssignmentExpression node, + AccessSemantics semantics) { + if (node.operator.lexeme != '=') { + return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); + } + return irBuilder.buildLocalVariableSet( + getLocal(node, semantics), + build(node.rightHandSide)); + } + + @override + ir.Node visitAssignmentExpression(AssignmentExpression node) { + // Avoid eager visiting of left and right hand side. + return handleAssignmentExpression(node); + } + + @override + ir.Node visitLocalVariableAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return handleLocalAssignment(node, semantics); + } + + @override + ir.Node visitParameterAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return handleLocalAssignment(node, semantics); + } + + @override + ir.Node visitStaticFieldAssignment(AssignmentExpression node, + AccessSemantics semantics) { + if (node.operator.lexeme != '=') { + return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); + } + analyzer.Element element = semantics.element; + dart2js.Element target = converter.convertElement(element); + // TODO(johnniwinther): Selector information should be computed in the + // [TreeShaker] and shared with the [CpsGeneratingVisitor]. + assert(invariant(node, target.isTopLevel || target.isStatic, + '$target expected to be top-level or static.')); + return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); + } + + @override + ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { + // TODO(johnniwinther): Handle implicit `this`. + ir.Primitive receiver = build(semantics.target); + return irBuilder.buildDynamicGet(receiver, + new Selector.getter(semantics.identifier.name, + converter.convertElement(element.library))); + } + + @override + ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { + analyzer.Element element = semantics.element; + dart2js.Element target = converter.convertElement(element); + // TODO(johnniwinther): Selector information should be computed in the + // [TreeShaker] and shared with the [CpsGeneratingVisitor]. + assert(invariant(node, target.isTopLevel || target.isStatic, + '$target expected to be top-level or static.')); + return irBuilder.buildStaticFieldLazyGet(target, null); + } + + ir.Primitive handleBinaryExpression(BinaryExpression node, + String op) { + ir.Primitive left = build(node.leftOperand); + ir.Primitive right = build(node.rightOperand); + Selector selector = new Selector.binaryOperator(op); + return irBuilder.buildDynamicInvocation( + left, selector, [right]); + } + + ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { + return irBuilder.buildLogicalOperator( + build(node.leftOperand), + subbuild(node.rightOperand), + isLazyOr: isLazyOr); + } + + @override + ir.Node visitBinaryExpression(BinaryExpression node) { + // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be + // available through an enum. + String op = node.operator.lexeme; + switch (op) { + case '||': + case '&&': + return handleLazyOperator(node, isLazyOr: op == '||'); + case '!=': + return irBuilder.buildNegation(handleBinaryExpression(node, '==')); + default: + return handleBinaryExpression(node, op); + } + } + + @override + ir.Node visitConditionalExpression(ConditionalExpression node) { + return irBuilder.buildConditional( + build(node.condition), + subbuild(node.thenExpression), + subbuild(node.elseExpression)); + } + + @override + visitIfStatement(IfStatement node) { + irBuilder.buildIf( + build(node.condition), + subbuild(node.thenStatement), + subbuild(node.elseStatement)); + } + + @override + visitBlock(Block node) { + irBuilder.buildBlock(node.statements, build); + } + + @override + ir.Node visitListLiteral(ListLiteral node) { + dart2js.InterfaceType type = converter.convertType(node.staticType); + // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue + // 18630 has been resolved. + Iterable values = node.elements.map((e) => build(e)); + return irBuilder.buildListLiteral(type, values); + } + + @override + ir.Node visitMapLiteral(MapLiteral node) { + dart2js.InterfaceType type = converter.convertType(node.staticType); + return irBuilder.buildMapLiteral( + type, + node.entries.map((e) => e.key), + node.entries.map((e) => e.value), + build); + } + + @override + visitForStatement(ForStatement node) { + // TODO(johnniwinther): Support `for` as a jump target. + List loopVariables = []; + SubbuildFunction buildInitializer; + if (node.variables != null) { + buildInitializer = subbuild(node.variables); + for (VariableDeclaration variable in node.variables.variables) { + loopVariables.add(converter.convertElement(variable.element)); + } + } else { + buildInitializer = subbuild(node.initialization); + } + irBuilder.buildFor(buildInitializer: buildInitializer, + buildCondition: subbuild(node.condition), + buildBody: subbuild(node.body), + buildUpdate: subbuildSequence(node.updaters), + loopVariables: loopVariables); + } + + @override + visitWhileStatement(WhileStatement node) { + // TODO(johnniwinther): Support `while` as a jump target. + irBuilder.buildWhile(buildCondition: subbuild(node.condition), + buildBody: subbuild(node.body)); + } + + @override + visitDeclaredIdentifier(DeclaredIdentifier node) { + giveUp(node, "Unexpected node: DeclaredIdentifier"); + } + + @override + visitForEachStatement(ForEachStatement node) { + SubbuildFunction buildVariableDeclaration; + dart2js.Element variableElement; + Selector variableSelector; + if (node.identifier != null) { + AccessSemantics accessSemantics = + node.identifier.accept(ACCESS_SEMANTICS_VISITOR); + if (accessSemantics.kind == AccessKind.DYNAMIC) { + variableSelector = new Selector.setter( + node.identifier.name, converter.convertElement(currentLibrary)); + } else if (accessSemantics.element != null) { + variableElement = converter.convertElement(accessSemantics.element); + variableSelector = new Selector.setter( + variableElement.name, + converter.convertElement(accessSemantics.element.library)); + } else { + giveUp(node, 'For-in of unresolved variable: $accessSemantics'); + } + } else { + assert(invariant( + node, node.loopVariable != null, "Loop variable expected")); + variableElement = converter.convertElement(node.loopVariable.element); + buildVariableDeclaration = (IrBuilder builder) { + builder.declareLocalVariable(variableElement); + }; + } + // TODO(johnniwinther): Support `for-in` as a jump target. + irBuilder.buildForIn( + buildExpression: subbuild(node.iterable), + buildVariableDeclaration: buildVariableDeclaration, + variableElement: variableElement, + variableSelector: variableSelector, + buildBody: subbuild(node.body)); + } + @override + ir.Primitive visitIsExpression(IsExpression node) { + return irBuilder.buildTypeOperator( + visit(node.expression), + converter.convertType(node.type.type), + isTypeTest: true, + isNotCheck: node.notOperator != null); + } + + @override + ir.Primitive visitAsExpression(AsExpression node) { + return irBuilder.buildTypeOperator( + visit(node.expression), + converter.convertType(node.type.type), + isTypeTest: false); + } + + @override + visitTryStatement(TryStatement node) { + List catchClauseInfos = []; + for (CatchClause catchClause in node.catchClauses) { + catchClauseInfos.add(new CatchClauseInfo( + exceptionVariable: converter.convertElement( + catchClause.exceptionParameter.staticElement), + buildCatchBlock: subbuild(catchClause.body))); + + } + irBuilder.buildTry( + tryStatementInfo: new TryStatementInfo(), + buildTryBlock: subbuild(node.body), + catchClauseInfos: catchClauseInfos); + } +} diff --git a/pkg/analyzer2dart/lib/src/semantic_visitor.dart b/pkg/analyzer2dart/lib/src/semantic_visitor.dart index 2e1c170b930..b5edd6a583d 100644 --- a/pkg/analyzer2dart/lib/src/semantic_visitor.dart +++ b/pkg/analyzer2dart/lib/src/semantic_visitor.dart @@ -1,271 +1,271 @@ -// Copyright (c) 2014, 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. - -library analyzer2dart.semantic_visitor; - -import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/source.dart'; - -import 'util.dart'; -import 'identifier_semantics.dart'; - -/// An AST visitor which uses the [AccessSemantics] of invocations and accesses -/// to fine-grain visitor methods. -abstract class SemanticVisitor extends RecursiveAstVisitor { - - Source get currentSource; - - void reportMessage(AstNode node, String message) { - reportSourceMessage(currentSource, node, message); - } - - giveUp(AstNode node, String message) { - reportMessage(node, message); - throw new UnimplementedError(message); - } - - bool invariant(AstNode node, condition, String message) { - if (condition is Function) { - condition = condition(); - } - if (!condition) { - reportMessage(node, message); - return false; - } - return true; - } - - R visitDynamicInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitDynamicInvocation of $semantics'); - } - - R visitLocalFunctionInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitLocalFunctionInvocation of $semantics'); - } - - R visitLocalVariableInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitLocalVariableInvocation of $semantics'); - } - - R visitParameterInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitParameterInvocation of $semantics'); - } - - R visitStaticFieldInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticFieldInvocation of $semantics'); - } - - R visitStaticMethodInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticMethodInvocation of $semantics'); - } - - R visitStaticPropertyInvocation(MethodInvocation node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticPropertyInvocation of $semantics'); - } - - @override - R visitMethodInvocation(MethodInvocation node) { - if (node.target != null) { - node.target.accept(this); - } - node.argumentList.accept(this); - return handleMethodInvocation(node); - } - - R handleMethodInvocation(MethodInvocation node) { - AccessSemantics semantics = node.accept(ACCESS_SEMANTICS_VISITOR); - switch (semantics.kind) { - case AccessKind.DYNAMIC: - return visitDynamicInvocation(node, semantics); - case AccessKind.LOCAL_FUNCTION: - return visitLocalFunctionInvocation(node, semantics); - case AccessKind.LOCAL_VARIABLE: - return visitLocalVariableInvocation(node, semantics); - case AccessKind.PARAMETER: - return visitParameterInvocation(node, semantics); - case AccessKind.STATIC_FIELD: - return visitStaticFieldInvocation(node, semantics); - case AccessKind.STATIC_METHOD: - return visitStaticMethodInvocation(node, semantics); - case AccessKind.STATIC_PROPERTY: - return visitStaticPropertyInvocation(node, semantics); - default: - // Unexpected access kind. - return giveUp(node, - 'Unexpected ${semantics} in visitMethodInvocation.'); - } - } - - @override - R visitPropertyAccess(PropertyAccess node) { - if (node.target != null) { - node.target.accept(this); - } - return handlePropertyAccess(node); - } - - R handlePropertyAccess(PropertyAccess node) { - return _handlePropertyAccess(node, node.accept(ACCESS_SEMANTICS_VISITOR)); - } - - @override - R visitPrefixedIdentifier(PrefixedIdentifier node) { - node.prefix.accept(this); - return handlePrefixedIdentifier(node); - } - - R handlePrefixedIdentifier(PrefixedIdentifier node) { - return _handlePropertyAccess(node, node.accept(ACCESS_SEMANTICS_VISITOR)); - } - - @override - R visitSimpleIdentifier(SimpleIdentifier node) { - AccessSemantics semantics = node.accept(ACCESS_SEMANTICS_VISITOR); - if (semantics != null) { - return _handlePropertyAccess(node, semantics); - } else { - return null; - } - } - - R visitDynamicAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitDynamicAccess of $semantics'); - } - - R visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitLocalFunctionAccess of $semantics'); - } - - R visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitLocalVariableAccess of $semantics'); - } - - R visitParameterAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitParameterAccess of $semantics'); - } - - R visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitStaticFieldAccess of $semantics'); - } - - R visitStaticMethodAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitStaticMethodAccess of $semantics'); - } - - R visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitStaticPropertyAccess of $semantics'); - } - - R visitToplevelClassAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitToplevelClassAccess of $semantics'); - } - - R visitTypeParameterAccess(AstNode node, AccessSemantics semantics) { - return giveUp(node, 'visitTypeParameterAccess of $semantics'); - } - - R _handlePropertyAccess(AstNode node, AccessSemantics semantics) { - switch (semantics.kind) { - case AccessKind.DYNAMIC: - return visitDynamicAccess(node, semantics); - case AccessKind.LOCAL_FUNCTION: - return visitLocalFunctionAccess(node, semantics); - case AccessKind.LOCAL_VARIABLE: - return visitLocalVariableAccess(node, semantics); - case AccessKind.PARAMETER: - return visitParameterAccess(node, semantics); - case AccessKind.STATIC_FIELD: - return visitStaticFieldAccess(node, semantics); - case AccessKind.STATIC_METHOD: - return visitStaticMethodAccess(node, semantics); - case AccessKind.STATIC_PROPERTY: - return visitStaticPropertyAccess(node, semantics); - case AccessKind.TOPLEVEL_TYPE: - return visitToplevelClassAccess(node, semantics); - case AccessKind.TYPE_PARAMETER: - return visitTypeParameterAccess(node, semantics); - default: - // Unexpected access kind. - return giveUp(node, - 'Unexpected ${semantics} in _handlePropertyAccess.'); - } - } - - R visitDynamicPropertyAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitDynamicPropertyAssignment of $semantics'); - } - - R visitLocalFunctionAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitLocalFunctionAssignment of $semantics'); - } - - R visitLocalVariableAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitLocalVariableAssignment of $semantics'); - } - - R visitParameterAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitParameterAssignment of $semantics'); - } - - R visitStaticFieldAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticFieldAssignment of $semantics'); - } - - R visitStaticMethodAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticMethodAssignment of $semantics'); - } - - R visitStaticPropertyAssignment(AssignmentExpression node, - AccessSemantics semantics) { - return giveUp(node, 'visitStaticPropertyAssignment of $semantics'); - } - - @override - R visitAssignmentExpression(AssignmentExpression node) { - super.visitAssignmentExpression(node); - return handleAssignmentExpression(node); - } - - R handleAssignmentExpression(AssignmentExpression node) { - AccessSemantics semantics = - node.leftHandSide.accept(ACCESS_SEMANTICS_VISITOR); - if (semantics == null) { - return giveUp(node, 'handleAssignmentExpression with no AccessSemantics'); - } else { - switch (semantics.kind) { - case AccessKind.DYNAMIC: - return visitDynamicPropertyAssignment(node, semantics); - case AccessKind.LOCAL_FUNCTION: - return visitLocalFunctionAssignment(node, semantics); - case AccessKind.LOCAL_VARIABLE: - return visitLocalVariableAssignment(node, semantics); - case AccessKind.PARAMETER: - return visitParameterAssignment(node, semantics); - case AccessKind.STATIC_FIELD: - return visitStaticFieldAssignment(node, semantics); - case AccessKind.STATIC_METHOD: - return visitStaticMethodAssignment(node, semantics); - case AccessKind.STATIC_PROPERTY: - return visitStaticPropertyAssignment(node, semantics); - default: - // Unexpected access kind. - return giveUp(node, - 'Unexpected ${semantics} in _handlePropertyAccess.'); - } - } - } -} +// Copyright (c) 2014, 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. + +library analyzer2dart.semantic_visitor; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/source.dart'; + +import 'util.dart'; +import 'identifier_semantics.dart'; + +/// An AST visitor which uses the [AccessSemantics] of invocations and accesses +/// to fine-grain visitor methods. +abstract class SemanticVisitor extends RecursiveAstVisitor { + + Source get currentSource; + + void reportMessage(AstNode node, String message) { + reportSourceMessage(currentSource, node, message); + } + + giveUp(AstNode node, String message) { + reportMessage(node, message); + throw new UnimplementedError(message); + } + + bool invariant(AstNode node, condition, String message) { + if (condition is Function) { + condition = condition(); + } + if (!condition) { + reportMessage(node, message); + return false; + } + return true; + } + + R visitDynamicInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitDynamicInvocation of $semantics'); + } + + R visitLocalFunctionInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitLocalFunctionInvocation of $semantics'); + } + + R visitLocalVariableInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitLocalVariableInvocation of $semantics'); + } + + R visitParameterInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitParameterInvocation of $semantics'); + } + + R visitStaticFieldInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticFieldInvocation of $semantics'); + } + + R visitStaticMethodInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticMethodInvocation of $semantics'); + } + + R visitStaticPropertyInvocation(MethodInvocation node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticPropertyInvocation of $semantics'); + } + + @override + R visitMethodInvocation(MethodInvocation node) { + if (node.target != null) { + node.target.accept(this); + } + node.argumentList.accept(this); + return handleMethodInvocation(node); + } + + R handleMethodInvocation(MethodInvocation node) { + AccessSemantics semantics = node.accept(ACCESS_SEMANTICS_VISITOR); + switch (semantics.kind) { + case AccessKind.DYNAMIC: + return visitDynamicInvocation(node, semantics); + case AccessKind.LOCAL_FUNCTION: + return visitLocalFunctionInvocation(node, semantics); + case AccessKind.LOCAL_VARIABLE: + return visitLocalVariableInvocation(node, semantics); + case AccessKind.PARAMETER: + return visitParameterInvocation(node, semantics); + case AccessKind.STATIC_FIELD: + return visitStaticFieldInvocation(node, semantics); + case AccessKind.STATIC_METHOD: + return visitStaticMethodInvocation(node, semantics); + case AccessKind.STATIC_PROPERTY: + return visitStaticPropertyInvocation(node, semantics); + default: + // Unexpected access kind. + return giveUp(node, + 'Unexpected ${semantics} in visitMethodInvocation.'); + } + } + + @override + R visitPropertyAccess(PropertyAccess node) { + if (node.target != null) { + node.target.accept(this); + } + return handlePropertyAccess(node); + } + + R handlePropertyAccess(PropertyAccess node) { + return _handlePropertyAccess(node, node.accept(ACCESS_SEMANTICS_VISITOR)); + } + + @override + R visitPrefixedIdentifier(PrefixedIdentifier node) { + node.prefix.accept(this); + return handlePrefixedIdentifier(node); + } + + R handlePrefixedIdentifier(PrefixedIdentifier node) { + return _handlePropertyAccess(node, node.accept(ACCESS_SEMANTICS_VISITOR)); + } + + @override + R visitSimpleIdentifier(SimpleIdentifier node) { + AccessSemantics semantics = node.accept(ACCESS_SEMANTICS_VISITOR); + if (semantics != null) { + return _handlePropertyAccess(node, semantics); + } else { + return null; + } + } + + R visitDynamicAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitDynamicAccess of $semantics'); + } + + R visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitLocalFunctionAccess of $semantics'); + } + + R visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitLocalVariableAccess of $semantics'); + } + + R visitParameterAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitParameterAccess of $semantics'); + } + + R visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitStaticFieldAccess of $semantics'); + } + + R visitStaticMethodAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitStaticMethodAccess of $semantics'); + } + + R visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitStaticPropertyAccess of $semantics'); + } + + R visitToplevelClassAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitToplevelClassAccess of $semantics'); + } + + R visitTypeParameterAccess(AstNode node, AccessSemantics semantics) { + return giveUp(node, 'visitTypeParameterAccess of $semantics'); + } + + R _handlePropertyAccess(AstNode node, AccessSemantics semantics) { + switch (semantics.kind) { + case AccessKind.DYNAMIC: + return visitDynamicAccess(node, semantics); + case AccessKind.LOCAL_FUNCTION: + return visitLocalFunctionAccess(node, semantics); + case AccessKind.LOCAL_VARIABLE: + return visitLocalVariableAccess(node, semantics); + case AccessKind.PARAMETER: + return visitParameterAccess(node, semantics); + case AccessKind.STATIC_FIELD: + return visitStaticFieldAccess(node, semantics); + case AccessKind.STATIC_METHOD: + return visitStaticMethodAccess(node, semantics); + case AccessKind.STATIC_PROPERTY: + return visitStaticPropertyAccess(node, semantics); + case AccessKind.TOPLEVEL_TYPE: + return visitToplevelClassAccess(node, semantics); + case AccessKind.TYPE_PARAMETER: + return visitTypeParameterAccess(node, semantics); + default: + // Unexpected access kind. + return giveUp(node, + 'Unexpected ${semantics} in _handlePropertyAccess.'); + } + } + + R visitDynamicPropertyAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitDynamicPropertyAssignment of $semantics'); + } + + R visitLocalFunctionAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitLocalFunctionAssignment of $semantics'); + } + + R visitLocalVariableAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitLocalVariableAssignment of $semantics'); + } + + R visitParameterAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitParameterAssignment of $semantics'); + } + + R visitStaticFieldAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticFieldAssignment of $semantics'); + } + + R visitStaticMethodAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticMethodAssignment of $semantics'); + } + + R visitStaticPropertyAssignment(AssignmentExpression node, + AccessSemantics semantics) { + return giveUp(node, 'visitStaticPropertyAssignment of $semantics'); + } + + @override + R visitAssignmentExpression(AssignmentExpression node) { + super.visitAssignmentExpression(node); + return handleAssignmentExpression(node); + } + + R handleAssignmentExpression(AssignmentExpression node) { + AccessSemantics semantics = + node.leftHandSide.accept(ACCESS_SEMANTICS_VISITOR); + if (semantics == null) { + return giveUp(node, 'handleAssignmentExpression with no AccessSemantics'); + } else { + switch (semantics.kind) { + case AccessKind.DYNAMIC: + return visitDynamicPropertyAssignment(node, semantics); + case AccessKind.LOCAL_FUNCTION: + return visitLocalFunctionAssignment(node, semantics); + case AccessKind.LOCAL_VARIABLE: + return visitLocalVariableAssignment(node, semantics); + case AccessKind.PARAMETER: + return visitParameterAssignment(node, semantics); + case AccessKind.STATIC_FIELD: + return visitStaticFieldAssignment(node, semantics); + case AccessKind.STATIC_METHOD: + return visitStaticMethodAssignment(node, semantics); + case AccessKind.STATIC_PROPERTY: + return visitStaticPropertyAssignment(node, semantics); + default: + // Unexpected access kind. + return giveUp(node, + 'Unexpected ${semantics} in _handlePropertyAccess.'); + } + } + } +} diff --git a/pkg/analyzer2dart/lib/src/util.dart b/pkg/analyzer2dart/lib/src/util.dart index 67ee97e1152..fd1c20b72ef 100644 --- a/pkg/analyzer2dart/lib/src/util.dart +++ b/pkg/analyzer2dart/lib/src/util.dart @@ -1,42 +1,42 @@ -// Copyright (c) 2014, 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. - -// Utility function shared between different parts of analyzer2dart. - -library analyzer2dart.util; - -import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/source.dart'; -import 'package:compiler/src/elements/elements.dart' show PublicName; -import 'package:compiler/src/universe/universe.dart'; -import 'package:compiler/src/io/source_file.dart'; - -CallStructure createCallStructureFromMethodInvocation(ArgumentList node) { - int arity = 0; - List namedArguments = []; - for (Expression argument in node.arguments) { - if (argument is NamedExpression) { - namedArguments.add(argument.name.label.name); - } else { - arity++; - } - } - return new CallStructure(arity, namedArguments); -} - -Selector createSelectorFromMethodInvocation(ArgumentList node, - String name) { - CallStructure callStructure = createCallStructureFromMethodInvocation(node); - // TODO(johnniwinther): Support private names. - return new Selector(SelectorKind.CALL, new PublicName(name), callStructure); -} - -/// Prints [message] together with source code pointed to by [node] from -/// [source]. -void reportSourceMessage(Source source, AstNode node, String message) { - SourceFile sourceFile = - new StringSourceFile.fromName(source.fullName, source.contents.data); - - print(sourceFile.getLocationMessage(message, node.offset, node.end)); -} +// Copyright (c) 2014, 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. + +// Utility function shared between different parts of analyzer2dart. + +library analyzer2dart.util; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/source.dart'; +import 'package:compiler/src/elements/elements.dart' show PublicName; +import 'package:compiler/src/universe/universe.dart'; +import 'package:compiler/src/io/source_file.dart'; + +CallStructure createCallStructureFromMethodInvocation(ArgumentList node) { + int arity = 0; + List namedArguments = []; + for (Expression argument in node.arguments) { + if (argument is NamedExpression) { + namedArguments.add(argument.name.label.name); + } else { + arity++; + } + } + return new CallStructure(arity, namedArguments); +} + +Selector createSelectorFromMethodInvocation(ArgumentList node, + String name) { + CallStructure callStructure = createCallStructureFromMethodInvocation(node); + // TODO(johnniwinther): Support private names. + return new Selector(SelectorKind.CALL, new PublicName(name), callStructure); +} + +/// Prints [message] together with source code pointed to by [node] from +/// [source]. +void reportSourceMessage(Source source, AstNode node, String message) { + SourceFile sourceFile = + new StringSourceFile.fromName(source.fullName, source.contents.data); + + print(sourceFile.getLocationMessage(message, node.offset, node.end)); +} diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart index 13ea3b6ccad..8c8c4ffb208 100644 --- a/pkg/compiler/lib/src/elements/common.dart +++ b/pkg/compiler/lib/src/elements/common.dart @@ -1,472 +1,472 @@ -// Copyright (c) 2015, 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. - -/// Mixins that implement convenience methods on [Element] subclasses. - -library elements.common; - -import '../dart2jslib.dart' show Compiler, isPrivateName; -import '../dart_types.dart' show DartType, InterfaceType, FunctionType; -import '../util/util.dart' show Link; - -import 'elements.dart'; - -abstract class ElementCommon implements Element { - @override - bool get isLibrary => kind == ElementKind.LIBRARY; - - @override - bool get isCompilationUnit => kind == ElementKind.COMPILATION_UNIT; - - @override - bool get isPrefix => kind == ElementKind.PREFIX; - - @override - bool get isClass => kind == ElementKind.CLASS; - - @override - bool get isTypeVariable => kind == ElementKind.TYPE_VARIABLE; - - @override - bool get isTypedef => kind == ElementKind.TYPEDEF; - - @override - bool get isFunction => kind == ElementKind.FUNCTION; - - @override - bool get isAccessor => isGetter || isSetter; - - @override - bool get isGetter => kind == ElementKind.GETTER; - - @override - bool get isSetter => kind == ElementKind.SETTER; - - @override - bool get isConstructor => isGenerativeConstructor || isFactoryConstructor; - - @override - bool get isGenerativeConstructor => - kind == ElementKind.GENERATIVE_CONSTRUCTOR; - - @override - bool get isGenerativeConstructorBody => - kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY; - - @override - bool get isVariable => kind == ElementKind.VARIABLE; - - @override - bool get isField => kind == ElementKind.FIELD; - - @override - bool get isAbstractField => kind == ElementKind.ABSTRACT_FIELD; - - @override - bool get isParameter => kind == ElementKind.PARAMETER; - - @override - bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL; - - @override - bool get isErroneous => kind == ElementKind.ERROR; - - @override - bool get isAmbiguous => kind == ElementKind.AMBIGUOUS; - - @override - bool get isWarnOnUse => kind == ElementKind.WARN_ON_USE; - - @override - bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; - - @override - Element get declaration => this; - - @override - Element get implementation => this; - - @override - bool get isDeclaration => true; - - @override - bool get isPatched => false; - - @override - bool get isPatch => false; - - @override - bool get isImplementation => true; - - @override - bool get isInjected => !isPatch && implementationLibrary.isPatch; - - @override - Element get patch { - throw new UnsupportedError('patch is not supported on $this'); - } - - @override - Element get origin { - throw new UnsupportedError('origin is not supported on $this'); - } -} - -abstract class LibraryElementCommon implements LibraryElement { - @override - bool get isDartCore => canonicalUri == Compiler.DART_CORE; - - @override - bool get isPlatformLibrary => canonicalUri.scheme == 'dart'; - - @override - bool get isPackageLibrary => canonicalUri.scheme == 'package'; - - @override - bool get isInternalLibrary => - isPlatformLibrary && canonicalUri.path.startsWith('_'); -} - -abstract class ClassElementCommon implements ClassElement { - - @override - Link get allSupertypes => allSupertypesAndSelf.supertypes; - - @override - int get hierarchyDepth => allSupertypesAndSelf.maxDepth; - - @override - InterfaceType asInstanceOf(ClassElement cls) { - if (cls == this) return thisType; - return allSupertypesAndSelf.asInstanceOf(cls); - } - - @override - ConstructorElement lookupConstructor(String name) { - Element result = localLookup(name); - return result != null && result.isConstructor ? result : null; - } - - - /** - * Find the first member in the class chain with the given [memberName]. - * - * This method is NOT to be used for resolving - * unqualified sends because it does not implement the scoping - * rules, where library scope comes before superclass scope. - * - * When called on the implementation element both members declared in the - * origin and the patch class are returned. - */ - Element lookupByName(Name memberName) { - return internalLookupByName(memberName, isSuperLookup: false); - } - - Element lookupSuperByName(Name memberName) { - return internalLookupByName(memberName, isSuperLookup: true); - } - - Element internalLookupByName(Name memberName, {bool isSuperLookup}) { - String name = memberName.text; - bool isPrivate = memberName.isPrivate; - LibraryElement library = memberName.library; - for (ClassElement current = isSuperLookup ? superclass : this; - current != null; - current = current.superclass) { - Element member = current.lookupLocalMember(name); - if (member == null && current.isPatched) { - // Doing lookups on selectors is done after resolution, so it - // is safe to look in the patch class. - member = current.patch.lookupLocalMember(name); - } - if (member == null) continue; - // Private members from a different library are not visible. - if (isPrivate && !identical(library, member.library)) continue; - // Static members are not inherited. - if (member.isStatic && !identical(this, current)) continue; - // If we find an abstract field we have to make sure that it has - // the getter or setter part we're actually looking - // for. Otherwise, we continue up the superclass chain. - if (member.isAbstractField) { - AbstractFieldElement field = member; - FunctionElement getter = field.getter; - FunctionElement setter = field.setter; - if (memberName.isSetter) { - // Abstract members can be defined in a super class. - if (setter != null && !setter.isAbstract) { - return setter; - } - } else { - if (getter != null && !getter.isAbstract) { - return getter; - } - } - // Abstract members can be defined in a super class. - } else if (!member.isAbstract) { - return member; - } - } - return null; - } - - /** - * Find the first member in the class chain with the given - * [memberName]. This method is NOT to be used for resolving - * unqualified sends because it does not implement the scoping - * rules, where library scope comes before superclass scope. - */ - @override - Element lookupMember(String memberName) { - Element localMember = lookupLocalMember(memberName); - return localMember == null ? lookupSuperMember(memberName) : localMember; - } - - @override - Link get constructors { - // TODO(ajohnsen): See if we can avoid this method at some point. - Link result = const Link(); - // TODO(johnniwinther): Should we include injected constructors? - forEachMember((_, Element member) { - if (member.isConstructor) result = result.prepend(member); - }); - return result; - } - - /** - * Lookup super members for the class. This will ignore constructors. - */ - @override - Element lookupSuperMember(String memberName) { - return lookupSuperMemberInLibrary(memberName, library); - } - - /** - * Lookup super members for the class that is accessible in [library]. - * This will ignore constructors. - */ - @override - Element lookupSuperMemberInLibrary(String memberName, - LibraryElement library) { - bool isPrivate = isPrivateName(memberName); - for (ClassElement s = superclass; s != null; s = s.superclass) { - // Private members from a different library are not visible. - if (isPrivate && !identical(library, s.library)) continue; - Element e = s.lookupLocalMember(memberName); - if (e == null) continue; - // Static members are not inherited. - if (e.isStatic) continue; - return e; - } - return null; - } - - /** - * Lookup local members in the class. This will ignore constructors. - */ - @override - Element lookupLocalMember(String memberName) { - var result = localLookup(memberName); - if (result != null && result.isConstructor) return null; - return result; - } - - /** - * Runs through all members of this class. - * - * The enclosing class is passed to the callback. This is useful when - * [includeSuperAndInjectedMembers] is [:true:]. - * - * When called on an implementation element both the members in the origin - * and patch class are included. - */ - // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. - @override - void forEachMember(void f(ClassElement enclosingClass, Element member), - {includeBackendMembers: false, - includeSuperAndInjectedMembers: false}) { - bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch; - ClassElement classElement = declaration; - do { - // Iterate through the members in textual order, which requires - // to reverse the data structure [localMembers] we created. - // Textual order may be important for certain operations, for - // example when emitting the initializers of fields. - classElement.forEachLocalMember((e) => f(classElement, e)); - if (includeBackendMembers) { - classElement.forEachBackendMember((e) => f(classElement, e)); - } - if (includeInjectedMembers) { - if (classElement.patch != null) { - classElement.patch.forEachLocalMember((e) { - if (!e.isPatch) f(classElement, e); - }); - } - } - classElement = includeSuperAndInjectedMembers - ? classElement.superclass - : null; - } while (classElement != null); - } - - /** - * Runs through all instance-field members of this class. - * - * The enclosing class is passed to the callback. This is useful when - * [includeSuperAndInjectedMembers] is [:true:]. - * - * When called on the implementation element both the fields declared in the - * origin and in the patch are included. - */ - @override - void forEachInstanceField(void f(ClassElement enclosingClass, - FieldElement field), - {bool includeSuperAndInjectedMembers: false}) { - // Filters so that [f] is only invoked with instance fields. - void fieldFilter(ClassElement enclosingClass, Element member) { - if (member.isInstanceMember && member.kind == ElementKind.FIELD) { - f(enclosingClass, member); - } - } - - forEachMember(fieldFilter, - includeSuperAndInjectedMembers: includeSuperAndInjectedMembers); - } - - /// Similar to [forEachInstanceField] but visits static fields. - @override - void forEachStaticField(void f(ClassElement enclosingClass, Element field)) { - // Filters so that [f] is only invoked with static fields. - void fieldFilter(ClassElement enclosingClass, Element member) { - if (!member.isInstanceMember && member.kind == ElementKind.FIELD) { - f(enclosingClass, member); - } - } - - forEachMember(fieldFilter); - } - - /** - * Returns true if the [fieldMember] shadows another field. The given - * [fieldMember] must be a member of this class, i.e. if there is a field of - * the same name in the superclass chain. - * - * This method also works if the [fieldMember] is private. - */ - @override - bool hasFieldShadowedBy(Element fieldMember) { - assert(fieldMember.isField); - String fieldName = fieldMember.name; - bool isPrivate = isPrivateName(fieldName); - LibraryElement memberLibrary = fieldMember.library; - ClassElement lookupClass = this.superclass; - while (lookupClass != null) { - Element foundMember = lookupClass.lookupLocalMember(fieldName); - if (foundMember != null) { - if (foundMember.isField) { - if (!isPrivate || memberLibrary == foundMember.library) { - // Private fields can only be shadowed by a field declared in the - // same library. - return true; - } - } - } - lookupClass = lookupClass.superclass; - } - return false; - } - - @override - bool implementsInterface(ClassElement intrface) { - for (DartType implementedInterfaceType in allSupertypes) { - ClassElement implementedInterface = implementedInterfaceType.element; - if (identical(implementedInterface, intrface)) { - return true; - } - } - return false; - } - - /** - * Returns true if [this] is a subclass of [cls]. - * - * This method is not to be used for checking type hierarchy and - * assignments, because it does not take parameterized types into - * account. - */ - bool isSubclassOf(ClassElement cls) { - // Use [declaration] for both [this] and [cls], because - // declaration classes hold the superclass hierarchy. - cls = cls.declaration; - for (ClassElement s = declaration; s != null; s = s.superclass) { - if (identical(s, cls)) return true; - } - return false; - } - - FunctionType get callType { - MemberSignature member = - lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME)); - return member != null && member.isMethod ? member.type : null; - } -} - -abstract class FunctionSignatureCommon implements FunctionSignature { - void forEachRequiredParameter(void function(Element parameter)) { - requiredParameters.forEach(function); - } - - void forEachOptionalParameter(void function(Element parameter)) { - optionalParameters.forEach(function); - } - - Element get firstOptionalParameter => optionalParameters.first; - - void forEachParameter(void function(Element parameter)) { - forEachRequiredParameter(function); - forEachOptionalParameter(function); - } - - void orderedForEachParameter(void function(Element parameter)) { - forEachRequiredParameter(function); - orderedOptionalParameters.forEach(function); - } - - int get parameterCount => requiredParameterCount + optionalParameterCount; - - /** - * Check whether a function with this signature can be used instead of a - * function with signature [signature] without causing a `noSuchMethod` - * exception/call. - */ - bool isCompatibleWith(FunctionSignature signature) { - if (optionalParametersAreNamed) { - if (!signature.optionalParametersAreNamed) { - return requiredParameterCount == signature.parameterCount; - } - // If both signatures have named parameters, then they must have - // the same number of required parameters, and the names in - // [signature] must all be in [:this:]. - if (requiredParameterCount != signature.requiredParameterCount) { - return false; - } - Set names = optionalParameters.map( - (Element element) => element.name).toSet(); - for (Element namedParameter in signature.optionalParameters) { - if (!names.contains(namedParameter.name)) { - return false; - } - } - } else { - if (signature.optionalParametersAreNamed) return false; - // There must be at least as many arguments as in the other signature, but - // this signature must not have more required parameters. Having more - // optional parameters is not a problem, they simply are never provided - // by call sites of a call to a method with the other signature. - int otherTotalCount = signature.parameterCount; - return requiredParameterCount <= otherTotalCount - && parameterCount >= otherTotalCount; - } - return true; - } -} +// Copyright (c) 2015, 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. + +/// Mixins that implement convenience methods on [Element] subclasses. + +library elements.common; + +import '../dart2jslib.dart' show Compiler, isPrivateName; +import '../dart_types.dart' show DartType, InterfaceType, FunctionType; +import '../util/util.dart' show Link; + +import 'elements.dart'; + +abstract class ElementCommon implements Element { + @override + bool get isLibrary => kind == ElementKind.LIBRARY; + + @override + bool get isCompilationUnit => kind == ElementKind.COMPILATION_UNIT; + + @override + bool get isPrefix => kind == ElementKind.PREFIX; + + @override + bool get isClass => kind == ElementKind.CLASS; + + @override + bool get isTypeVariable => kind == ElementKind.TYPE_VARIABLE; + + @override + bool get isTypedef => kind == ElementKind.TYPEDEF; + + @override + bool get isFunction => kind == ElementKind.FUNCTION; + + @override + bool get isAccessor => isGetter || isSetter; + + @override + bool get isGetter => kind == ElementKind.GETTER; + + @override + bool get isSetter => kind == ElementKind.SETTER; + + @override + bool get isConstructor => isGenerativeConstructor || isFactoryConstructor; + + @override + bool get isGenerativeConstructor => + kind == ElementKind.GENERATIVE_CONSTRUCTOR; + + @override + bool get isGenerativeConstructorBody => + kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY; + + @override + bool get isVariable => kind == ElementKind.VARIABLE; + + @override + bool get isField => kind == ElementKind.FIELD; + + @override + bool get isAbstractField => kind == ElementKind.ABSTRACT_FIELD; + + @override + bool get isParameter => kind == ElementKind.PARAMETER; + + @override + bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL; + + @override + bool get isErroneous => kind == ElementKind.ERROR; + + @override + bool get isAmbiguous => kind == ElementKind.AMBIGUOUS; + + @override + bool get isWarnOnUse => kind == ElementKind.WARN_ON_USE; + + @override + bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; + + @override + Element get declaration => this; + + @override + Element get implementation => this; + + @override + bool get isDeclaration => true; + + @override + bool get isPatched => false; + + @override + bool get isPatch => false; + + @override + bool get isImplementation => true; + + @override + bool get isInjected => !isPatch && implementationLibrary.isPatch; + + @override + Element get patch { + throw new UnsupportedError('patch is not supported on $this'); + } + + @override + Element get origin { + throw new UnsupportedError('origin is not supported on $this'); + } +} + +abstract class LibraryElementCommon implements LibraryElement { + @override + bool get isDartCore => canonicalUri == Compiler.DART_CORE; + + @override + bool get isPlatformLibrary => canonicalUri.scheme == 'dart'; + + @override + bool get isPackageLibrary => canonicalUri.scheme == 'package'; + + @override + bool get isInternalLibrary => + isPlatformLibrary && canonicalUri.path.startsWith('_'); +} + +abstract class ClassElementCommon implements ClassElement { + + @override + Link get allSupertypes => allSupertypesAndSelf.supertypes; + + @override + int get hierarchyDepth => allSupertypesAndSelf.maxDepth; + + @override + InterfaceType asInstanceOf(ClassElement cls) { + if (cls == this) return thisType; + return allSupertypesAndSelf.asInstanceOf(cls); + } + + @override + ConstructorElement lookupConstructor(String name) { + Element result = localLookup(name); + return result != null && result.isConstructor ? result : null; + } + + + /** + * Find the first member in the class chain with the given [memberName]. + * + * This method is NOT to be used for resolving + * unqualified sends because it does not implement the scoping + * rules, where library scope comes before superclass scope. + * + * When called on the implementation element both members declared in the + * origin and the patch class are returned. + */ + Element lookupByName(Name memberName) { + return internalLookupByName(memberName, isSuperLookup: false); + } + + Element lookupSuperByName(Name memberName) { + return internalLookupByName(memberName, isSuperLookup: true); + } + + Element internalLookupByName(Name memberName, {bool isSuperLookup}) { + String name = memberName.text; + bool isPrivate = memberName.isPrivate; + LibraryElement library = memberName.library; + for (ClassElement current = isSuperLookup ? superclass : this; + current != null; + current = current.superclass) { + Element member = current.lookupLocalMember(name); + if (member == null && current.isPatched) { + // Doing lookups on selectors is done after resolution, so it + // is safe to look in the patch class. + member = current.patch.lookupLocalMember(name); + } + if (member == null) continue; + // Private members from a different library are not visible. + if (isPrivate && !identical(library, member.library)) continue; + // Static members are not inherited. + if (member.isStatic && !identical(this, current)) continue; + // If we find an abstract field we have to make sure that it has + // the getter or setter part we're actually looking + // for. Otherwise, we continue up the superclass chain. + if (member.isAbstractField) { + AbstractFieldElement field = member; + FunctionElement getter = field.getter; + FunctionElement setter = field.setter; + if (memberName.isSetter) { + // Abstract members can be defined in a super class. + if (setter != null && !setter.isAbstract) { + return setter; + } + } else { + if (getter != null && !getter.isAbstract) { + return getter; + } + } + // Abstract members can be defined in a super class. + } else if (!member.isAbstract) { + return member; + } + } + return null; + } + + /** + * Find the first member in the class chain with the given + * [memberName]. This method is NOT to be used for resolving + * unqualified sends because it does not implement the scoping + * rules, where library scope comes before superclass scope. + */ + @override + Element lookupMember(String memberName) { + Element localMember = lookupLocalMember(memberName); + return localMember == null ? lookupSuperMember(memberName) : localMember; + } + + @override + Link get constructors { + // TODO(ajohnsen): See if we can avoid this method at some point. + Link result = const Link(); + // TODO(johnniwinther): Should we include injected constructors? + forEachMember((_, Element member) { + if (member.isConstructor) result = result.prepend(member); + }); + return result; + } + + /** + * Lookup super members for the class. This will ignore constructors. + */ + @override + Element lookupSuperMember(String memberName) { + return lookupSuperMemberInLibrary(memberName, library); + } + + /** + * Lookup super members for the class that is accessible in [library]. + * This will ignore constructors. + */ + @override + Element lookupSuperMemberInLibrary(String memberName, + LibraryElement library) { + bool isPrivate = isPrivateName(memberName); + for (ClassElement s = superclass; s != null; s = s.superclass) { + // Private members from a different library are not visible. + if (isPrivate && !identical(library, s.library)) continue; + Element e = s.lookupLocalMember(memberName); + if (e == null) continue; + // Static members are not inherited. + if (e.isStatic) continue; + return e; + } + return null; + } + + /** + * Lookup local members in the class. This will ignore constructors. + */ + @override + Element lookupLocalMember(String memberName) { + var result = localLookup(memberName); + if (result != null && result.isConstructor) return null; + return result; + } + + /** + * Runs through all members of this class. + * + * The enclosing class is passed to the callback. This is useful when + * [includeSuperAndInjectedMembers] is [:true:]. + * + * When called on an implementation element both the members in the origin + * and patch class are included. + */ + // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. + @override + void forEachMember(void f(ClassElement enclosingClass, Element member), + {includeBackendMembers: false, + includeSuperAndInjectedMembers: false}) { + bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch; + ClassElement classElement = declaration; + do { + // Iterate through the members in textual order, which requires + // to reverse the data structure [localMembers] we created. + // Textual order may be important for certain operations, for + // example when emitting the initializers of fields. + classElement.forEachLocalMember((e) => f(classElement, e)); + if (includeBackendMembers) { + classElement.forEachBackendMember((e) => f(classElement, e)); + } + if (includeInjectedMembers) { + if (classElement.patch != null) { + classElement.patch.forEachLocalMember((e) { + if (!e.isPatch) f(classElement, e); + }); + } + } + classElement = includeSuperAndInjectedMembers + ? classElement.superclass + : null; + } while (classElement != null); + } + + /** + * Runs through all instance-field members of this class. + * + * The enclosing class is passed to the callback. This is useful when + * [includeSuperAndInjectedMembers] is [:true:]. + * + * When called on the implementation element both the fields declared in the + * origin and in the patch are included. + */ + @override + void forEachInstanceField(void f(ClassElement enclosingClass, + FieldElement field), + {bool includeSuperAndInjectedMembers: false}) { + // Filters so that [f] is only invoked with instance fields. + void fieldFilter(ClassElement enclosingClass, Element member) { + if (member.isInstanceMember && member.kind == ElementKind.FIELD) { + f(enclosingClass, member); + } + } + + forEachMember(fieldFilter, + includeSuperAndInjectedMembers: includeSuperAndInjectedMembers); + } + + /// Similar to [forEachInstanceField] but visits static fields. + @override + void forEachStaticField(void f(ClassElement enclosingClass, Element field)) { + // Filters so that [f] is only invoked with static fields. + void fieldFilter(ClassElement enclosingClass, Element member) { + if (!member.isInstanceMember && member.kind == ElementKind.FIELD) { + f(enclosingClass, member); + } + } + + forEachMember(fieldFilter); + } + + /** + * Returns true if the [fieldMember] shadows another field. The given + * [fieldMember] must be a member of this class, i.e. if there is a field of + * the same name in the superclass chain. + * + * This method also works if the [fieldMember] is private. + */ + @override + bool hasFieldShadowedBy(Element fieldMember) { + assert(fieldMember.isField); + String fieldName = fieldMember.name; + bool isPrivate = isPrivateName(fieldName); + LibraryElement memberLibrary = fieldMember.library; + ClassElement lookupClass = this.superclass; + while (lookupClass != null) { + Element foundMember = lookupClass.lookupLocalMember(fieldName); + if (foundMember != null) { + if (foundMember.isField) { + if (!isPrivate || memberLibrary == foundMember.library) { + // Private fields can only be shadowed by a field declared in the + // same library. + return true; + } + } + } + lookupClass = lookupClass.superclass; + } + return false; + } + + @override + bool implementsInterface(ClassElement intrface) { + for (DartType implementedInterfaceType in allSupertypes) { + ClassElement implementedInterface = implementedInterfaceType.element; + if (identical(implementedInterface, intrface)) { + return true; + } + } + return false; + } + + /** + * Returns true if [this] is a subclass of [cls]. + * + * This method is not to be used for checking type hierarchy and + * assignments, because it does not take parameterized types into + * account. + */ + bool isSubclassOf(ClassElement cls) { + // Use [declaration] for both [this] and [cls], because + // declaration classes hold the superclass hierarchy. + cls = cls.declaration; + for (ClassElement s = declaration; s != null; s = s.superclass) { + if (identical(s, cls)) return true; + } + return false; + } + + FunctionType get callType { + MemberSignature member = + lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME)); + return member != null && member.isMethod ? member.type : null; + } +} + +abstract class FunctionSignatureCommon implements FunctionSignature { + void forEachRequiredParameter(void function(Element parameter)) { + requiredParameters.forEach(function); + } + + void forEachOptionalParameter(void function(Element parameter)) { + optionalParameters.forEach(function); + } + + Element get firstOptionalParameter => optionalParameters.first; + + void forEachParameter(void function(Element parameter)) { + forEachRequiredParameter(function); + forEachOptionalParameter(function); + } + + void orderedForEachParameter(void function(Element parameter)) { + forEachRequiredParameter(function); + orderedOptionalParameters.forEach(function); + } + + int get parameterCount => requiredParameterCount + optionalParameterCount; + + /** + * Check whether a function with this signature can be used instead of a + * function with signature [signature] without causing a `noSuchMethod` + * exception/call. + */ + bool isCompatibleWith(FunctionSignature signature) { + if (optionalParametersAreNamed) { + if (!signature.optionalParametersAreNamed) { + return requiredParameterCount == signature.parameterCount; + } + // If both signatures have named parameters, then they must have + // the same number of required parameters, and the names in + // [signature] must all be in [:this:]. + if (requiredParameterCount != signature.requiredParameterCount) { + return false; + } + Set names = optionalParameters.map( + (Element element) => element.name).toSet(); + for (Element namedParameter in signature.optionalParameters) { + if (!names.contains(namedParameter.name)) { + return false; + } + } + } else { + if (signature.optionalParametersAreNamed) return false; + // There must be at least as many arguments as in the other signature, but + // this signature must not have more required parameters. Having more + // optional parameters is not a problem, they simply are never provided + // by call sites of a call to a method with the other signature. + int otherTotalCount = signature.parameterCount; + return requiredParameterCount <= otherTotalCount + && parameterCount >= otherTotalCount; + } + return true; + } +} diff --git a/pkg/compiler/lib/src/io/line_column_provider.dart b/pkg/compiler/lib/src/io/line_column_provider.dart index 4d17583fb9f..fb3d5db513e 100644 --- a/pkg/compiler/lib/src/io/line_column_provider.dart +++ b/pkg/compiler/lib/src/io/line_column_provider.dart @@ -1,77 +1,77 @@ -// 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. - -library dart2js.io.line_column; - -import 'code_output.dart'; - -/// Interface for providing line/column information. -abstract class LineColumnProvider { - /// Returns the line number (0-based) for [offset]. - int getLine(int offset); - - /// Returns the column number (0-based) for [offset] at the given [line]. - int getColumn(int line, int offset); -} - -/// [CodeOutputListener] that collects line information. -class LineColumnCollector extends CodeOutputListener - implements LineColumnProvider { - int length = 0; - List lineStarts = [0]; - - void _collect(String text) { - int index = 0; - while (index < text.length) { - // Unix uses '\n' and Windows uses '\r\n', so this algorithm works for - // both platforms. - index = text.indexOf('\n', index) + 1; - if (index <= 0) break; - lineStarts.add(length + index); - } - length += text.length; - } - - @override - void onText(String text) { - _collect(text); - } - - @override - int getLine(int offset) { - List starts = lineStarts; - if (offset < 0 || starts.last <= offset) { - throw 'bad position #$offset in buffer with length ${length}.'; - } - int first = 0; - int count = starts.length; - while (count > 1) { - int step = count ~/ 2; - int middle = first + step; - int lineStart = starts[middle]; - if (offset < lineStart) { - count = step; - } else { - first = middle; - count -= step; - } - } - return first; - } - - @override - int getColumn(int line, int offset) { - return offset - lineStarts[line]; - } - - @override - void onDone(int length) { - lineStarts.add(length + 1); - this.length = length; - } - - String toString() { - return 'lineStarts=$lineStarts,length=$length'; - } -} +// 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. + +library dart2js.io.line_column; + +import 'code_output.dart'; + +/// Interface for providing line/column information. +abstract class LineColumnProvider { + /// Returns the line number (0-based) for [offset]. + int getLine(int offset); + + /// Returns the column number (0-based) for [offset] at the given [line]. + int getColumn(int line, int offset); +} + +/// [CodeOutputListener] that collects line information. +class LineColumnCollector extends CodeOutputListener + implements LineColumnProvider { + int length = 0; + List lineStarts = [0]; + + void _collect(String text) { + int index = 0; + while (index < text.length) { + // Unix uses '\n' and Windows uses '\r\n', so this algorithm works for + // both platforms. + index = text.indexOf('\n', index) + 1; + if (index <= 0) break; + lineStarts.add(length + index); + } + length += text.length; + } + + @override + void onText(String text) { + _collect(text); + } + + @override + int getLine(int offset) { + List starts = lineStarts; + if (offset < 0 || starts.last <= offset) { + throw 'bad position #$offset in buffer with length ${length}.'; + } + int first = 0; + int count = starts.length; + while (count > 1) { + int step = count ~/ 2; + int middle = first + step; + int lineStart = starts[middle]; + if (offset < lineStart) { + count = step; + } else { + first = middle; + count -= step; + } + } + return first; + } + + @override + int getColumn(int line, int offset) { + return offset - lineStarts[line]; + } + + @override + void onDone(int length) { + lineStarts.add(length + 1); + this.length = length; + } + + String toString() { + return 'lineStarts=$lineStarts,length=$length'; + } +}