| Index: dart/compiler/java/com/google/dart/compiler/resolver/Resolver.java
|
| diff --git a/dart/compiler/java/com/google/dart/compiler/resolver/Resolver.java b/dart/compiler/java/com/google/dart/compiler/resolver/Resolver.java
|
| deleted file mode 100644
|
| index 9a4cbf1e295641360ee8a560d6cf512e42f8d93b..0000000000000000000000000000000000000000
|
| --- a/dart/compiler/java/com/google/dart/compiler/resolver/Resolver.java
|
| +++ /dev/null
|
| @@ -1,2523 +0,0 @@
|
| -// 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.
|
| -
|
| -package com.google.dart.compiler.resolver;
|
| -
|
| -import com.google.common.annotations.VisibleForTesting;
|
| -import com.google.common.base.Objects;
|
| -import com.google.common.collect.Lists;
|
| -import com.google.common.collect.Sets;
|
| -import com.google.dart.compiler.DartCompilationPhase;
|
| -import com.google.dart.compiler.DartCompilerContext;
|
| -import com.google.dart.compiler.ErrorCode;
|
| -import com.google.dart.compiler.Source;
|
| -import com.google.dart.compiler.ast.ASTNodes;
|
| -import com.google.dart.compiler.ast.ASTVisitor;
|
| -import com.google.dart.compiler.ast.DartArrayLiteral;
|
| -import com.google.dart.compiler.ast.DartBinaryExpression;
|
| -import com.google.dart.compiler.ast.DartBlock;
|
| -import com.google.dart.compiler.ast.DartBooleanLiteral;
|
| -import com.google.dart.compiler.ast.DartBreakStatement;
|
| -import com.google.dart.compiler.ast.DartCase;
|
| -import com.google.dart.compiler.ast.DartCatchBlock;
|
| -import com.google.dart.compiler.ast.DartClass;
|
| -import com.google.dart.compiler.ast.DartClassTypeAlias;
|
| -import com.google.dart.compiler.ast.DartComment;
|
| -import com.google.dart.compiler.ast.DartCommentNewName;
|
| -import com.google.dart.compiler.ast.DartCommentRefName;
|
| -import com.google.dart.compiler.ast.DartContinueStatement;
|
| -import com.google.dart.compiler.ast.DartDirective;
|
| -import com.google.dart.compiler.ast.DartDoWhileStatement;
|
| -import com.google.dart.compiler.ast.DartDoubleLiteral;
|
| -import com.google.dart.compiler.ast.DartExprStmt;
|
| -import com.google.dart.compiler.ast.DartExpression;
|
| -import com.google.dart.compiler.ast.DartField;
|
| -import com.google.dart.compiler.ast.DartFieldDefinition;
|
| -import com.google.dart.compiler.ast.DartForInStatement;
|
| -import com.google.dart.compiler.ast.DartForStatement;
|
| -import com.google.dart.compiler.ast.DartFunction;
|
| -import com.google.dart.compiler.ast.DartFunctionExpression;
|
| -import com.google.dart.compiler.ast.DartFunctionObjectInvocation;
|
| -import com.google.dart.compiler.ast.DartFunctionTypeAlias;
|
| -import com.google.dart.compiler.ast.DartGotoStatement;
|
| -import com.google.dart.compiler.ast.DartIdentifier;
|
| -import com.google.dart.compiler.ast.DartIfStatement;
|
| -import com.google.dart.compiler.ast.DartImportDirective;
|
| -import com.google.dart.compiler.ast.DartInitializer;
|
| -import com.google.dart.compiler.ast.DartIntegerLiteral;
|
| -import com.google.dart.compiler.ast.DartInvocation;
|
| -import com.google.dart.compiler.ast.DartLabel;
|
| -import com.google.dart.compiler.ast.DartMapLiteral;
|
| -import com.google.dart.compiler.ast.DartMethodDefinition;
|
| -import com.google.dart.compiler.ast.DartMethodInvocation;
|
| -import com.google.dart.compiler.ast.DartNamedExpression;
|
| -import com.google.dart.compiler.ast.DartNativeBlock;
|
| -import com.google.dart.compiler.ast.DartNewExpression;
|
| -import com.google.dart.compiler.ast.DartNode;
|
| -import com.google.dart.compiler.ast.DartParameter;
|
| -import com.google.dart.compiler.ast.DartParameterizedTypeNode;
|
| -import com.google.dart.compiler.ast.DartPartOfDirective;
|
| -import com.google.dart.compiler.ast.DartPropertyAccess;
|
| -import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
|
| -import com.google.dart.compiler.ast.DartReturnStatement;
|
| -import com.google.dart.compiler.ast.DartStatement;
|
| -import com.google.dart.compiler.ast.DartStringInterpolation;
|
| -import com.google.dart.compiler.ast.DartStringLiteral;
|
| -import com.google.dart.compiler.ast.DartSuperConstructorInvocation;
|
| -import com.google.dart.compiler.ast.DartSuperExpression;
|
| -import com.google.dart.compiler.ast.DartSwitchMember;
|
| -import com.google.dart.compiler.ast.DartSwitchStatement;
|
| -import com.google.dart.compiler.ast.DartThisExpression;
|
| -import com.google.dart.compiler.ast.DartThrowExpression;
|
| -import com.google.dart.compiler.ast.DartTryStatement;
|
| -import com.google.dart.compiler.ast.DartTypeExpression;
|
| -import com.google.dart.compiler.ast.DartTypeNode;
|
| -import com.google.dart.compiler.ast.DartTypeParameter;
|
| -import com.google.dart.compiler.ast.DartUnaryExpression;
|
| -import com.google.dart.compiler.ast.DartUnit;
|
| -import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
|
| -import com.google.dart.compiler.ast.DartVariable;
|
| -import com.google.dart.compiler.ast.DartVariableStatement;
|
| -import com.google.dart.compiler.ast.DartWhileStatement;
|
| -import com.google.dart.compiler.ast.LibraryImport;
|
| -import com.google.dart.compiler.ast.LibraryUnit;
|
| -import com.google.dart.compiler.ast.Modifiers;
|
| -import com.google.dart.compiler.common.HasSourceInfo;
|
| -import com.google.dart.compiler.common.SourceInfo;
|
| -import com.google.dart.compiler.parser.Token;
|
| -import com.google.dart.compiler.resolver.LabelElement.LabeledStatementType;
|
| -import com.google.dart.compiler.type.InterfaceType;
|
| -import com.google.dart.compiler.type.InterfaceType.Member;
|
| -import com.google.dart.compiler.type.Type;
|
| -import com.google.dart.compiler.type.TypeAnalyzer;
|
| -import com.google.dart.compiler.type.TypeKind;
|
| -import com.google.dart.compiler.type.TypeQuality;
|
| -import com.google.dart.compiler.type.TypeVariable;
|
| -import com.google.dart.compiler.type.Types;
|
| -
|
| -import java.util.EnumSet;
|
| -import java.util.Iterator;
|
| -import java.util.List;
|
| -import java.util.Set;
|
| -/**
|
| - * Resolves unqualified elements in a compilation unit.
|
| - */
|
| -public class Resolver {
|
| -
|
| - private final ResolutionContext topLevelContext;
|
| - private final CoreTypeProvider typeProvider;
|
| - private final InterfaceType rawArrayType;
|
| - private final InterfaceType defaultLiteralMapType;
|
| -
|
| -
|
| - private static final EnumSet<ElementKind> INVOKABLE_ELEMENTS = EnumSet.<ElementKind>of(
|
| - ElementKind.FIELD,
|
| - ElementKind.PARAMETER,
|
| - ElementKind.VARIABLE,
|
| - ElementKind.FUNCTION_OBJECT,
|
| - ElementKind.METHOD);
|
| -
|
| - @VisibleForTesting
|
| - public Resolver(DartCompilerContext compilerContext, Scope libraryScope,
|
| - CoreTypeProvider typeProvider) {
|
| - compilerContext.getClass(); // Fast null-check.
|
| - libraryScope.getClass(); // Fast null-check.
|
| - typeProvider.getClass(); // Fast null-check.
|
| - this.topLevelContext = new ResolutionContext(libraryScope, compilerContext, typeProvider);
|
| - this.typeProvider = typeProvider;
|
| - Type dynamicType = typeProvider.getDynamicType();
|
| - Type stringType = typeProvider.getStringType();
|
| - this.defaultLiteralMapType = typeProvider.getMapType(stringType, dynamicType);
|
| - this.rawArrayType = typeProvider.getArrayType(dynamicType);
|
| - }
|
| -
|
| - @VisibleForTesting
|
| - public DartUnit exec(DartUnit unit) {
|
| - // Visits all top level elements of a compilation unit and resolves names used in method
|
| - // bodies.
|
| - LibraryElement library = unit.getLibrary() != null ? unit.getLibrary().getElement() : null;
|
| - unit.accept(new ResolveElementsVisitor(topLevelContext, library));
|
| - return unit;
|
| - }
|
| -
|
| - /**
|
| - * Main entry point for IDE. Resolves a member (method or field)
|
| - * incrementally in the given context.
|
| - *
|
| - * @param classElement the class enclosing the member.
|
| - * @param member the member to resolve.
|
| - * @param context a resolution context corresponding to classElement.
|
| - */
|
| - public void resolveMember(ClassNodeElement classElement, NodeElement member, ResolutionContext context) {
|
| - ResolveElementsVisitor visitor;
|
| - if(member == null) {
|
| - return;
|
| - }
|
| - switch (member.getKind()) {
|
| - case CONSTRUCTOR:
|
| - case METHOD:
|
| - ResolutionContext methodContext = context.extend(member.getName());
|
| - visitor = new ResolveElementsVisitor(methodContext, classElement,
|
| - (MethodElement) member);
|
| - break;
|
| -
|
| - case FIELD:
|
| - ResolutionContext fieldContext = context;
|
| - if (member.getModifiers().isAbstractField()) {
|
| - fieldContext = context.extend(member.getName());
|
| - }
|
| - visitor = new ResolveElementsVisitor(fieldContext, classElement);
|
| - break;
|
| -
|
| - default:
|
| - throw topLevelContext.internalError(member,
|
| - "unexpected element kind: %s", member.getKind());
|
| - }
|
| - member.getNode().accept(visitor);
|
| - }
|
| -
|
| - /**
|
| - * Resolves names in a method body.
|
| - *
|
| - * TODO(ngeoffray): Errors reported:
|
| - * - A default implementation not providing the default methods.
|
| - * - An interface with default methods but without a default implementation.
|
| - * - A member method shadowing a super property.
|
| - * - A member property shadowing a super method.
|
| - * - A formal parameter in a non-constructor shadowing a member.
|
| - * - A local variable shadowing another variable.
|
| - * - A local variable shadowing a formal parameter.
|
| - * - A local variable shadowing a class member.
|
| - * - Using 'this' or 'super' in a static or factory method, or in an initializer.
|
| - * - Using 'super' in a class without a super class.
|
| - * - Incorrectly using a resolved element.
|
| - */
|
| - @VisibleForTesting
|
| - public class ResolveElementsVisitor extends ResolveVisitor {
|
| - private EnclosingElement currentHolder;
|
| - private EnclosingElement enclosingElement;
|
| - private MethodElement currentMethod;
|
| - private boolean inInstanceVariableInitializer;
|
| - private boolean inInitializer;
|
| - private MethodElement innermostFunction;
|
| - private ResolutionContext context;
|
| - private Set<LabelElement> referencedLabels = Sets.newHashSet();
|
| - private Set<LabelElement> labelsInScopes = Sets.newHashSet();
|
| - private Set<FieldElement> finalsNeedingInitializing = Sets.newHashSet();
|
| - private Set<FieldElement> resolvedFields = Sets.newHashSet();
|
| -
|
| - @VisibleForTesting
|
| - public ResolveElementsVisitor(ResolutionContext context,
|
| - EnclosingElement currentHolder,
|
| - MethodElement currentMethod) {
|
| - super(typeProvider);
|
| - this.context = context;
|
| - this.currentMethod = currentMethod;
|
| - this.innermostFunction = currentMethod;
|
| - this.currentHolder = currentHolder;
|
| - this.enclosingElement = currentHolder;
|
| - this.inInitializer = false;
|
| - }
|
| -
|
| - private ResolveElementsVisitor(ResolutionContext context, EnclosingElement currentHolder) {
|
| - this(context, currentHolder, null);
|
| - }
|
| -
|
| - @Override
|
| - ResolutionContext getContext() {
|
| - return context;
|
| - }
|
| -
|
| - @Override
|
| - protected EnclosingElement getEnclosingElement() {
|
| - return enclosingElement;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitUnit(DartUnit unit) {
|
| - List<DartImportDirective> importDirectives = Lists.newArrayList();
|
| - for (DartDirective directive : unit.getDirectives()) {
|
| - if (directive instanceof DartImportDirective) {
|
| - importDirectives.add((DartImportDirective) directive);
|
| - }
|
| - if (directive instanceof DartPartOfDirective) {
|
| - directive.accept(this);
|
| - }
|
| - }
|
| - // set LibraryElement for "import" directives
|
| - {
|
| - LibraryUnit library = unit.getLibrary();
|
| - if (library != null) {
|
| - Iterator<LibraryImport> importIterator = library.getImports().iterator();
|
| - Iterator<DartImportDirective> directiveIterator = importDirectives.iterator();
|
| - while (importIterator.hasNext() && directiveIterator.hasNext()) {
|
| - LibraryImport imp = importIterator.next();
|
| - DartImportDirective dir = directiveIterator.next();
|
| - DartStringLiteral uri = dir.getLibraryUri();
|
| - LibraryUnit impLibrary = imp.getLibrary();
|
| - if (uri != null && impLibrary != null) {
|
| - uri.setElement(impLibrary.getElement());
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // visit top-level nodes
|
| - for (DartNode node : unit.getTopLevelNodes()) {
|
| - node.accept(this);
|
| - }
|
| - checkRedirectingFactoryConstructorsCycle(unit);
|
| - return null;
|
| - }
|
| -
|
| - private void checkRedirectingFactoryConstructorsCycle(DartUnit unit) {
|
| - unit.accept(new ASTVisitor<Void>() {
|
| - @Override
|
| - public Void visitMethodDefinition(DartMethodDefinition node) {
|
| - MethodNodeElement element = node.getElement();
|
| - if (ElementKind.of(element) == ElementKind.CONSTRUCTOR) {
|
| - ConstructorElement constructor = (ConstructorElement) element;
|
| - if (hasRedirectingFactoryConstructorCycle(constructor)) {
|
| - onError(constructor.getNameLocation(),
|
| - ResolverErrorCode.REDIRECTION_CONSTRUCTOR_CYCLE);
|
| - }
|
| - }
|
| - return super.visitMethodDefinition(node);
|
| - }
|
| - });
|
| - }
|
| -
|
| - private boolean hasRedirectingFactoryConstructorCycle(ConstructorElement element) {
|
| - Set<ConstructorElement> constructors = Sets.newHashSet();
|
| - while (element != null) {
|
| - if (constructors.contains(element)) {
|
| - return true;
|
| - }
|
| - constructors.add(element);
|
| - element = element.getRedirectingFactoryConstructor();
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitFunctionTypeAlias(DartFunctionTypeAlias alias) {
|
| - alias.getMetadata().accept(this);
|
| - getContext().pushFunctionAliasScope(alias);
|
| - resolveFunctionAlias(alias);
|
| -
|
| - getContext().pushScope("<parameters>");
|
| - try {
|
| - List<DartParameter> parameters = alias.getParameters();
|
| - for (DartParameter parameter : parameters) {
|
| - assert parameter.getElement() != null;
|
| - if (parameter.getQualifier() instanceof DartThisExpression) {
|
| - onError(parameter.getName(), ResolverErrorCode.PARAMETER_INIT_OUTSIDE_CONSTRUCTOR);
|
| - } else {
|
| - if (DartIdentifier.isPrivateName(parameter.getElement().getName())) {
|
| - if (parameter.getModifiers().isOptional()) {
|
| - onError(parameter.getName(),
|
| - ResolverErrorCode.OPTIONAL_PARAMETERS_CANNOT_START_WITH_UNDER);
|
| - }
|
| - if (parameter.getModifiers().isNamed()) {
|
| - onError(parameter.getName(),
|
| - ResolverErrorCode.NAMED_PARAMETERS_CANNOT_START_WITH_UNDER);
|
| - }
|
| - }
|
| - getContext().declare(parameter.getElement(), ResolverErrorCode.DUPLICATE_PARAMETER);
|
| - }
|
| - }
|
| - } finally {
|
| - getContext().popScope();
|
| - }
|
| -
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitCommentRefName(DartCommentRefName node) {
|
| - Scope scope = getContext().getScope();
|
| - String name = node.getName();
|
| - Element element = scope.findElement(scope.getLibrary(), name);
|
| - return recordElement(node, element);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitCommentNewName(DartCommentNewName node) {
|
| - String className = node.getClassName();
|
| - String constructorName = node.getConstructorName();
|
| - Scope scope = getContext().getScope();
|
| - Element element = scope.findElement(scope.getLibrary(), className);
|
| - if (ElementKind.of(element) == ElementKind.CLASS) {
|
| - ClassElement classElement = (ClassElement) element;
|
| - for (ConstructorElement constructor : classElement.getConstructors()) {
|
| - if (constructor.getName().equals(constructorName)) {
|
| - node.setElements(classElement, constructor);
|
| - return constructor;
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitClassTypeAlias(DartClassTypeAlias cls) {
|
| - ClassNodeElement classElement = cls.getElement();
|
| - try {
|
| - classElement.getAllSupertypes();
|
| - } catch (CyclicDeclarationException e) {
|
| - HasSourceInfo errorTarget = e.getElement();
|
| - if (errorTarget == null) {
|
| - errorTarget = cls;
|
| - }
|
| - onError(errorTarget, ResolverErrorCode.CYCLIC_CLASS, e.getElement().getName());
|
| - }
|
| - checkMixinObjectIsSupertype(cls.getMixins());
|
| - checkMixinNoConstructors(cls.getMixins());
|
| - checkMixinNoSuperInvocations(cls.getMixins());
|
| - return classElement;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitClass(DartClass cls) {
|
| - assert currentMethod == null : "nested class?";
|
| - ClassNodeElement classElement = cls.getElement();
|
| - try {
|
| - classElement.getAllSupertypes();
|
| - } catch (CyclicDeclarationException e) {
|
| - HasSourceInfo errorTarget = e.getElement();
|
| - if (errorTarget == null) {
|
| - errorTarget = cls;
|
| - }
|
| - onError(errorTarget, ResolverErrorCode.CYCLIC_CLASS, e.getElement().getName());
|
| - }
|
| - checkClassTypeVariables(classElement);
|
| - cls.getMetadata().accept(this);
|
| -
|
| - // Push new resolution context.
|
| - ResolutionContext previousContext = context;
|
| - EnclosingElement previousHolder = currentHolder;
|
| - EnclosingElement previousEnclosingElement = enclosingElement;
|
| - currentHolder = classElement;
|
| - enclosingElement = classElement;
|
| - context = topLevelContext.extend(classElement);
|
| -
|
| - // members
|
| - this.finalsNeedingInitializing.clear();
|
| - for (DartNode member : cls.getMembers()) {
|
| - if (ElementKind.of(member.getElement()) == ElementKind.CONSTRUCTOR) {
|
| - continue;
|
| - }
|
| - member.accept(this);
|
| - }
|
| -
|
| - // constructors
|
| - boolean testForAllConstantFields = false;
|
| - for (DartNode member : cls.getMembers()) {
|
| - if (member instanceof DartMethodDefinition) {
|
| - DartMethodDefinition method = (DartMethodDefinition) member;
|
| - if (method.getElement().isConstructor()) {
|
| - method.accept(this);
|
| - if (method.getModifiers().isConstant()) {
|
| - testForAllConstantFields = true;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (testForAllConstantFields) {
|
| - InterfaceType interfaceType = classElement.getType();
|
| - while (interfaceType != null && interfaceType != typeProvider.getObjectType()) {
|
| - ClassElement interfaceElement = interfaceType.getElement();
|
| - constVerifyMembers(interfaceElement.getMembers(), classElement, interfaceElement);
|
| - interfaceType = interfaceElement.getSupertype();
|
| - }
|
| - }
|
| -
|
| - checkRedirectConstructorCycle(classElement.getConstructors(), context);
|
| - if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - checkImplicitDefaultDefaultSuperInvocation(cls, classElement);
|
| - }
|
| -
|
| - if (cls.getDefaultClass() != null && classElement.getDefaultClass() == null) {
|
| - onError(cls.getDefaultClass(), ResolverErrorCode.NO_SUCH_TYPE, cls.getDefaultClass());
|
| - } else if (classElement.getDefaultClass() != null) {
|
| - recordElement(cls.getDefaultClass().getExpression(),
|
| - classElement.getDefaultClass().getElement());
|
| - bindDefaultTypeParameters(classElement.getDefaultClass().getElement().getTypeParameters(),
|
| - cls.getDefaultClass().getTypeParameters(),
|
| - context);
|
| -
|
| - // Make sure the 'default' clause matches the referenced class type parameters
|
| - checkDefaultClassTypeParamsToDefaultDecl(classElement.getDefaultClass(),
|
| - cls.getDefaultClass());
|
| -
|
| - ClassElement defaultClass = classElement.getDefaultClass().getElement();
|
| - if (defaultClass.isInterface()) {
|
| - onError(cls.getDefaultClass().getExpression(),
|
| - ResolverErrorCode.DEFAULT_MUST_SPECIFY_CLASS);
|
| - }
|
| -
|
| - // Make sure the default class matches the interface type parameters
|
| - checkInterfaceTypeParamsToDefault(classElement, defaultClass);
|
| - }
|
| -
|
| - if (!classElement.isInterface() && Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - // Check to see that all final fields are initialized when no explicit
|
| - // generative constructor is declared
|
| - cls.accept(new ASTVisitor<DartNode>() {
|
| - @Override
|
| - public DartNode visitField(DartField node) {
|
| - FieldElement fieldElement = node.getElement();
|
| - if (fieldElement != null && fieldElement.getModifiers().isFinal()
|
| - && !fieldElement.isStatic()
|
| - && !fieldElement.getModifiers().isConstant()
|
| - && !fieldElement.getModifiers().isGetter()
|
| - && !fieldElement.getModifiers().isSetter()
|
| - && !fieldElement.getModifiers().isInitialized()) {
|
| - onError(node, ResolverErrorCode.FINAL_FIELD_MUST_BE_INITIALIZED,
|
| - fieldElement.getName());
|
| - }
|
| - return null;
|
| - }
|
| - });
|
| - }
|
| -
|
| - {
|
| - DartComment comment = cls.getDartDoc();
|
| - if (comment != null) {
|
| - comment.accept(this);
|
| - }
|
| - }
|
| -
|
| - // check mixins
|
| - checkMixinObjectIsSupertype(cls.getMixins());
|
| - checkMixinNoConstructors(cls.getMixins());
|
| - checkMixinNoSuperInvocations(cls.getMixins());
|
| -
|
| - context = previousContext;
|
| - currentHolder = previousHolder;
|
| - enclosingElement = previousEnclosingElement;
|
| - return classElement;
|
| - }
|
| -
|
| - /**
|
| - * Checks that the types of the given mixin type node don't have explicit constructors.
|
| - */
|
| - private void checkMixinNoConstructors(List<DartTypeNode> mixins) {
|
| - for (DartTypeNode mixNode : mixins) {
|
| - if (mixNode.getType() instanceof InterfaceType) {
|
| - InterfaceType mixType = (InterfaceType) mixNode.getType();
|
| - for (ConstructorElement constructor : mixType.getElement().getConstructors()) {
|
| - if (!constructor.getModifiers().isFactory()) {
|
| - topLevelContext.onError(mixNode, ResolverErrorCode.CANNOT_MIXIN_CLASS_WITH_CONSTRUCTOR);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Checks that the types of the given mixin type nodes se subtypes of Object.
|
| - */
|
| - private void checkMixinObjectIsSupertype(List<DartTypeNode> mixins) {
|
| - for (DartTypeNode mixNode : mixins) {
|
| - if (mixNode.getType() instanceof InterfaceType) {
|
| - InterfaceType mixType = (InterfaceType) mixNode.getType();
|
| - ClassElement mixElement = mixType.getElement();
|
| - if (!mixElement.getMixins().isEmpty()) {
|
| - topLevelContext.onError(mixNode, ResolverErrorCode.CANNOT_MIXIN_CLASS_WITH_MIXINS);
|
| - continue;
|
| - }
|
| - if (!Objects.equal(mixElement.getSupertype(), typeProvider.getObjectType())) {
|
| - topLevelContext.onError(mixNode, ResolverErrorCode.ONLY_OBJECT_MIXIN_SUPERCLASS);
|
| - continue;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Checks that the types of the given mixin type nodes don't have super invocations.
|
| - */
|
| - private void checkMixinNoSuperInvocations(List<DartTypeNode> mixins) {
|
| - for (DartTypeNode mixNode : mixins) {
|
| - if (mixNode.getType() instanceof InterfaceType) {
|
| - InterfaceType mixType = (InterfaceType) mixNode.getType();
|
| - if (mixType.getElement() instanceof ClassElement) {
|
| - ClassElement mixElement = (ClassElement) mixType.getElement();
|
| - if (mixElement.hasSuperInvocation()) {
|
| - topLevelContext.onError(mixNode, ResolverErrorCode.CANNOT_MIXIN_CLASS_WITH_SUPER);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - private void constVerifyMembers(Iterable<? extends Element> members, ClassElement originalClass,
|
| - ClassElement currentClass) {
|
| - for (Element element : members) {
|
| - Modifiers modifiers = element.getModifiers();
|
| - if (ElementKind.of(element).equals(ElementKind.FIELD) && !modifiers.isFinal()
|
| - && !modifiers.isStatic() && !modifiers.isAbstractField()) {
|
| - FieldElement field = (FieldElement) element;
|
| - HasSourceInfo errorNode = field.getSetter() == null ? element : field.getSetter();
|
| - onError(errorNode, currentClass == originalClass
|
| - ? ResolverErrorCode.CONST_CLASS_WITH_NONFINAL_FIELDS
|
| - : ResolverErrorCode.CONST_CLASS_WITH_INHERITED_NONFINAL_FIELDS,
|
| - originalClass.getName(), field.getName(), currentClass.getName());
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Sets the type in the AST of the default clause of an interface so that the type
|
| - * parameters to resolve back to the default class.
|
| - */
|
| - private void bindDefaultTypeParameters(List<Type> parameterTypes,
|
| - List<DartTypeParameter> parameterNodes,
|
| - ResolutionContext classContext) {
|
| - Iterator<? extends Type> typeIterator = parameterTypes.iterator();
|
| - Iterator<DartTypeParameter> nodeIterator = parameterNodes.iterator();
|
| -
|
| - while(typeIterator.hasNext() && nodeIterator.hasNext()) {
|
| -
|
| - Type type = typeIterator.next();
|
| - DartTypeParameter node = nodeIterator.next();
|
| -
|
| - if (type.getElement().getName().equals(node.getName().getName())) {
|
| - node.setType(type);
|
| - recordElement(node.getName(), type.getElement());
|
| - } else {
|
| - node.setType(typeProvider.getDynamicType());
|
| - }
|
| -
|
| - DartTypeNode boundNode = node.getBound();
|
| - if (boundNode != null) {
|
| - Type bound =
|
| - classContext.resolveType(
|
| - boundNode,
|
| - false,
|
| - false,
|
| - true,
|
| - ResolverErrorCode.NO_SUCH_TYPE,
|
| - ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
|
| - boundNode.setType(bound);
|
| - }
|
| - }
|
| -
|
| - while (nodeIterator.hasNext()) {
|
| - DartTypeParameter node = nodeIterator.next();
|
| - node.setType(typeProvider.getDynamicType());
|
| - }
|
| - }
|
| - /**
|
| - * If type parameters are present, the type parameters of the default statement
|
| - * must exactly match those of those declared in the class it references.
|
| - *
|
| - */
|
| - private void checkDefaultClassTypeParamsToDefaultDecl(InterfaceType defaultClassType,
|
| - DartParameterizedTypeNode defaultClassRef) {
|
| - if (defaultClassRef.getTypeParameters().isEmpty()) {
|
| - return;
|
| - }
|
| - ClassElement defaultClassElement = defaultClassType.getElement();
|
| - boolean match = true;
|
| - if (defaultClassElement.getTypeParameters().isEmpty()) {
|
| - match = false;
|
| - } else {
|
| - // TODO(zundel): This is effective in catching mistakes, but highlights the entire type
|
| - // expression - A more specific indication of where the error started might be appreciated.
|
| - String defaultClassSource = defaultClassElement.getDeclarationNameWithTypeParameters();
|
| - String refSource = defaultClassRef.toSource();
|
| - if (!refSource.equals(defaultClassSource)) {
|
| - match = false;
|
| - }
|
| - }
|
| - if (!match) {
|
| - // TODO(zundel): work harder to point out where the type param match failure starts.
|
| - onError(defaultClassRef, ResolverErrorCode.TYPE_PARAMETERS_MUST_MATCH_EXACTLY);
|
| - }
|
| - }
|
| -
|
| - private void checkInterfaceTypeParamsToDefault(ClassElement interfaceElement,
|
| - ClassElement defaultClassElement) {
|
| -
|
| - List<Type> interfaceTypeParams = interfaceElement.getTypeParameters();
|
| -
|
| - List<Type> defaultTypeParams = defaultClassElement.getTypeParameters();
|
| -
|
| -
|
| - if (defaultTypeParams.size() != interfaceTypeParams.size()) {
|
| -
|
| - onError(interfaceElement.getNameLocation(),
|
| - ResolverErrorCode.DEFAULT_CLASS_MUST_HAVE_SAME_TYPE_PARAMS);
|
| - } else {
|
| - Iterator<? extends Type> interfaceIterator = interfaceTypeParams.iterator();
|
| - Iterator<? extends Type> defaultIterator = defaultTypeParams.iterator();
|
| - while (interfaceIterator.hasNext()) {
|
| - Type iVar = interfaceIterator.next();
|
| - Type dVar = defaultIterator.next();
|
| - String iVarName = iVar.getElement().getName();
|
| - String dVarName = dVar.getElement().getName();
|
| - if (!iVarName.equals(dVarName)) {
|
| - onError(iVar.getElement(), ResolverErrorCode.TYPE_VARIABLE_DOES_NOT_MATCH,
|
| - iVarName, dVarName, defaultClassElement.getName());
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Check that used type variables are unique and don't shadow and existing elements.
|
| - */
|
| - private void checkClassTypeVariables(ClassElement classElement) {
|
| - Set<String> declaredVariableNames = Sets.newHashSet();
|
| - for (Type type : classElement.getTypeParameters()) {
|
| - if (type instanceof TypeVariable) {
|
| - Element typeVariableElement = type.getElement();
|
| - String name = typeVariableElement.getName();
|
| - // Check that type variables are unique in this Class declaration.
|
| - if (declaredVariableNames.contains(name)) {
|
| - onError(typeVariableElement, ResolverErrorCode.DUPLICATE_TYPE_VARIABLE, name);
|
| - } else {
|
| - declaredVariableNames.add(name);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns <code>true</code> if the {@link ClassElement} has an implicit or a declared
|
| - * default constructor.
|
| - */
|
| - boolean hasDefaultConstructor(ClassElement classElement) {
|
| - if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - return true;
|
| - }
|
| -
|
| - ConstructorElement defaultCtor = Elements.lookupConstructor(classElement, "");
|
| - if (defaultCtor != null) {
|
| - return defaultCtor.getParameters().isEmpty();
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - private void checkImplicitDefaultDefaultSuperInvocation(DartClass cls,
|
| - ClassElement classElement) {
|
| - assert (Elements.needsImplicitDefaultConstructor(classElement));
|
| -
|
| - InterfaceType supertype = classElement.getSupertype();
|
| - if (supertype != null) {
|
| - ClassElement superElement = supertype.getElement();
|
| - if (!superElement.isDynamic()) {
|
| - ConstructorElement superCtor = Elements.lookupConstructor(superElement, "");
|
| - boolean superHasDefaultCtor =
|
| - (superCtor != null && superCtor.getParameters().isEmpty())
|
| - || (superCtor == null && Elements.needsImplicitDefaultConstructor(superElement));
|
| - if (!superHasDefaultCtor) {
|
| - onError(cls.getName(),
|
| - ResolverErrorCode.CANNOT_RESOLVE_IMPLICIT_CALL_TO_SUPER_CONSTRUCTOR,
|
| - cls.getSuperclass());
|
| - }
|
| - if (superCtor != null && superCtor.getModifiers().isFactory()) {
|
| - onError(cls.getName(), ResolverErrorCode.NOT_GENERATIVE_SUPER_CONSTRUCTOR, "<default>",
|
| - supertype);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - private Element resolve(DartNode node) {
|
| - if (node == null) {
|
| - return null;
|
| - } else {
|
| - return node.accept(this);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public Element visitTypeParameter(DartTypeParameter node) {
|
| - node.getMetadata().accept(this);
|
| - return super.visitTypeParameter(node);
|
| - }
|
| -
|
| - @Override
|
| - public MethodElement visitMethodDefinition(DartMethodDefinition node) {
|
| - node.getMetadata().accept(this);
|
| - MethodElement member = node.getElement();
|
| - ResolutionContext previousContext = context;
|
| - context = context.extend(member.getName());
|
| - assert currentMethod == null : "Nested methods?";
|
| - innermostFunction = currentMethod = member;
|
| - EnclosingElement previousEnclosingElement = enclosingElement;
|
| - enclosingElement = member;
|
| -
|
| - DartFunction functionNode = node.getFunction();
|
| - List<DartParameter> parameters = functionNode.getParameters();
|
| - Set<FieldElement> initializedFields = Sets.newHashSet();
|
| -
|
| - // remember field with initializers
|
| - if (previousEnclosingElement instanceof ClassElement) {
|
| - ClassElement classElement = (ClassElement) previousEnclosingElement;
|
| - for (Element classMember : classElement.getMembers()) {
|
| - if (ElementKind.of(classMember) == ElementKind.FIELD) {
|
| - FieldElement fieldMember = (FieldElement) classMember;
|
| - if (fieldMember.getModifiers().isFinal() && fieldMember.getModifiers().isInitialized()) {
|
| - initializedFields.add(fieldMember);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // First declare all normal parameters in the scope, putting them in the
|
| - // scope of the default expressions so we can report better errors.
|
| - for (DartParameter parameter : parameters) {
|
| - assert parameter.getElement() != null;
|
| - parameter.getMetadata().accept(this);
|
| -
|
| - if (!(parameter.getQualifier() instanceof DartThisExpression)) {
|
| - getContext().declare(
|
| - parameter.getElement(),
|
| - ResolverErrorCode.DUPLICATE_PARAMETER);
|
| - }
|
| - }
|
| - for (DartParameter parameter : parameters) {
|
| - // Then resolve the default values.
|
| - resolve(parameter.getDefaultExpr());
|
| - if (parameter.getQualifier() instanceof DartThisExpression && parameter.getElement() != null
|
| - && !initializedFields.add(parameter.getElement().getParameterInitializerElement())) {
|
| - onError(parameter, ResolverErrorCode.DUPLICATE_INITIALIZATION, parameter.getName());
|
| - }
|
| - }
|
| -
|
| - {
|
| - DartComment comment = node.getDartDoc();
|
| - if (comment != null) {
|
| - comment.accept(this);
|
| - }
|
| - }
|
| -
|
| - DartBlock body = functionNode.getBody();
|
| - if (body == null) {
|
| - if (member.getModifiers().isStatic() && !member.getModifiers().isExternal()) {
|
| - onError(functionNode, ResolverErrorCode.STATIC_METHOD_MUST_HAVE_BODY);
|
| - }
|
| - }
|
| - resolve(functionNode.getBody());
|
| -
|
| - if (Elements.isNonFactoryConstructor(member) && !(body instanceof DartNativeBlock)) {
|
| - resolveInitializers(node, initializedFields);
|
| - }
|
| -
|
| - // only generative constructor can have initializers, so resolve them, but report error
|
| - if (!member.isConstructor() || member.getModifiers().isFactory()) {
|
| - for (DartInitializer initializer : node.getInitializers()) {
|
| - resolve(initializer);
|
| - if (initializer.getName() != null) {
|
| - onError(initializer, ResolverErrorCode.INITIALIZER_ONLY_IN_GENERATIVE_CONSTRUCTOR);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // resolve redirecting factory constructor
|
| - {
|
| - DartTypeNode rcTypeName = node.getRedirectedTypeName();
|
| - if (rcTypeName != null) {
|
| - Type rcType = resolveType(rcTypeName, true, true, false,
|
| - TypeErrorCode.NO_SUCH_TYPE, ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
|
| - switch (TypeKind.of(rcType)) {
|
| - case INTERFACE:
|
| - ConstructorElement targetConstructor = null;
|
| - Element element = recordType(rcTypeName, rcType);
|
| - DartIdentifier rcName = node.getRedirectedConstructorName();
|
| - if (rcName != null) {
|
| - element = ((ClassElement) element).lookupConstructor(rcName.getName());
|
| - switch (ElementKind.of(element)) {
|
| - case CONSTRUCTOR:
|
| - targetConstructor = (ConstructorElement) element;
|
| - recordElement(rcName, element);
|
| - if (member.getModifiers().isConstant() && !element.getModifiers().isConstant()) {
|
| - onError(rcName,
|
| - ResolverErrorCode.REDIRECTION_CONSTRUCTOR_TARGET_MUST_BE_CONST);
|
| - }
|
| - break;
|
| - }
|
| - } else {
|
| - targetConstructor = ((ClassElement) element).lookupConstructor("");
|
| - }
|
| - Elements.setRedirectingFactoryConstructor(((ConstructorElement) member),
|
| - targetConstructor);
|
| - break;
|
| - default:
|
| - onError(rcTypeName, ResolverErrorCode.REDIRECTION_CONSTRUCTOR_TARGET_TYPE);
|
| - }
|
| - }
|
| - }
|
| -
|
| - context = previousContext;
|
| - innermostFunction = currentMethod = null;
|
| - enclosingElement = previousEnclosingElement;
|
| - return member;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitField(DartField node) {
|
| - DartExpression expression = node.getValue();
|
| - Modifiers modifiers = node.getModifiers();
|
| - boolean isFinal = modifiers.isFinal();
|
| - boolean isTopLevel = ElementKind.of(currentHolder).equals(ElementKind.LIBRARY);
|
| - boolean isStatic = modifiers.isStatic();
|
| -
|
| - if (expression != null) {
|
| - inInstanceVariableInitializer = !isTopLevel;
|
| - try {
|
| - resolve(expression);
|
| - } finally {
|
| - inInstanceVariableInitializer = false;
|
| - }
|
| - // Now, this constant has a type. Save it for future reference.
|
| - Element element = node.getElement();
|
| - Type expressionType = expression.getType();
|
| - if (isFinal && expressionType != null && TypeKind.of(element.getType()) == TypeKind.DYNAMIC) {
|
| - TypeQuality typeQuality = TypeAnalyzer.getTypeQuality(expression);
|
| - Type fieldType = Types.makeInferred(expressionType, typeQuality);
|
| - Elements.setType(element, fieldType);
|
| - }
|
| - } else if (isFinal) {
|
| - if (modifiers.isConstant()) {
|
| - onError(node, ResolverErrorCode.CONST_REQUIRES_VALUE);
|
| - } else if (isStatic) {
|
| - onError(node, ResolverErrorCode.STATIC_FINAL_REQUIRES_VALUE);
|
| - } else if (isTopLevel) {
|
| - onError(node, ResolverErrorCode.TOPLEVEL_FINAL_REQUIRES_VALUE);
|
| - } else {
|
| - // If a final instance field wasn't initialized at declaration, we must check
|
| - // at construction time.
|
| - this.finalsNeedingInitializing.add(node.getElement());
|
| - }
|
| - }
|
| -
|
| - // If field is an accessor, both getter and setter need to be visited (if present).
|
| - // We check for duplicates because top-level fields are visited twice - for each accessor.
|
| - FieldNodeElement field = node.getElement();
|
| - if (!resolvedFields.contains(field)) {
|
| - resolvedFields.add(field);
|
| - if (field.getGetter() != null) {
|
| - resolve(field.getGetter().getNode());
|
| - }
|
| - if (field.getSetter() != null) {
|
| - resolve(field.getSetter().getNode());
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitFieldDefinition(DartFieldDefinition node) {
|
| - node.getMetadata().accept(this);
|
| - visit(node.getFields());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitFunction(DartFunction node) {
|
| - throw context.internalError(node, "should not be called.");
|
| - }
|
| -
|
| - @Override
|
| - public Element visitParameter(DartParameter x) {
|
| - x.getMetadata().accept(this);
|
| - Element element = super.visitParameter(x);
|
| - resolve(x.getDefaultExpr());
|
| - getContext().declare(
|
| - element,
|
| - ResolverErrorCode.DUPLICATE_PARAMETER);
|
| - return element;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitVariable(DartVariable node) {
|
| - node.getMetadata().accept(this);
|
| - return super.visitVariable(node);
|
| - }
|
| -
|
| - public VariableElement resolveVariable(DartVariable x, Modifiers modifiers) {
|
| - final DartIdentifier nameNode = x.getName();
|
| - final String name = nameNode.getName();
|
| - // Visit the initializer first.
|
| - DartExpression value = x.getValue();
|
| - if (value != null) {
|
| - // It is a compile-time error if e refers to the name v or the name v=.
|
| - value.accept(new ASTVisitor<Void>() {
|
| - @Override
|
| - public Void visitIdentifier(DartIdentifier node) {
|
| - // ignore cases when name is used with some qualifier
|
| - if (node.getParent() instanceof DartPropertyAccess) {
|
| - DartPropertyAccess x = (DartPropertyAccess) node.getParent();
|
| - if (x.getName() == node) {
|
| - return null;
|
| - }
|
| - }
|
| - if (node.getParent() instanceof DartMethodInvocation) {
|
| - DartMethodInvocation x = (DartMethodInvocation) node.getParent();
|
| - if (x.getFunctionName() == node) {
|
| - return null;
|
| - }
|
| - }
|
| - // TODO(scheglov) remove this after http://code.google.com/p/dart/issues/detail?id=6869
|
| - {
|
| - Source source = node.getSourceInfo().getSource();
|
| - if (Elements.isSourceName(source, "dart://json/json.dart/json.dart")) {
|
| - return null;
|
| - }
|
| - }
|
| - if (Objects.equal(node.getName(), name)) {
|
| - onError(node, ResolverErrorCode.VARIABLE_REFERENCES_SAME_NAME_IN_INITIALIZER, name,
|
| - name);
|
| - node.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - }
|
| - return null;
|
| - }
|
| - });
|
| - // do resolve
|
| - resolve(value);
|
| - }
|
| - // declare variable
|
| - VariableElement element = Elements.variableElement(enclosingElement, x, name, modifiers);
|
| - getContext().declare(recordElement(x, element),
|
| - ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_ERROR);
|
| - recordElement(nameNode, element);
|
| - return element;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitVariableStatement(DartVariableStatement node) {
|
| - resolveVariableStatement(node, false);
|
| - return null;
|
| - }
|
| -
|
| - private void resolveVariableStatement(DartVariableStatement node,
|
| - boolean isImplicitlyInitialized) {
|
| - Type type =
|
| - resolveType(
|
| - node.getTypeNode(),
|
| - ASTNodes.isStaticContext(node),
|
| - ASTNodes.isFactoryContext(node),
|
| - true,
|
| - TypeErrorCode.NO_SUCH_TYPE,
|
| - TypeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
|
| - for (DartVariable variable : node.getVariables()) {
|
| - String name = variable.getVariableName();
|
| - getContext().getScope().removeDeclaredButNotReachedVariable(name);
|
| - Elements.setType(resolveVariable(variable, node.getModifiers()), type);
|
| - checkVariableStatement(node, variable, isImplicitlyInitialized);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public Element visitLabel(DartLabel x) {
|
| - DartNode parent = x.getParent();
|
| - if (!(parent instanceof DartSwitchMember && ((DartSwitchMember) parent).getLabels().contains(
|
| - x))) {
|
| - LabelElement labelElement;
|
| - DartStatement childStatement = x.getStatement();
|
| - while (childStatement instanceof DartLabel) {
|
| - childStatement = ((DartLabel) childStatement).getStatement();
|
| - }
|
| - if (childStatement instanceof DartSwitchStatement) {
|
| - labelElement = Elements.switchLabelElement(x, x.getName(), innermostFunction);
|
| - } else {
|
| - labelElement = Elements.statementLabelElement(x, x.getName(), innermostFunction);
|
| - }
|
| - recordElement(x.getLabel(), labelElement);
|
| - recordElement(x, labelElement);
|
| - }
|
| - x.visitChildren(this);
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitFunctionExpression(DartFunctionExpression x) {
|
| - MethodElement element;
|
| - if (x.isStatement()) {
|
| - // Function statement names live in the outer scope.
|
| - element = getContext().declareFunction(x);
|
| - getContext().pushFunctionScope(x);
|
| - } else {
|
| - // Function expression names live in their own scope.
|
| - getContext().pushFunctionScope(x);
|
| - element = getContext().declareFunction(x);
|
| - }
|
| - // record element
|
| - if (x.getName() != null) {
|
| - recordElement(x.getName(), element);
|
| - }
|
| - recordElement(x, element);
|
| - // visit function
|
| - MethodElement previousFunction = innermostFunction;
|
| - innermostFunction = element;
|
| - {
|
| - DartFunction functionNode = x.getFunction();
|
| - EnclosingElement previousEnclosingElement = enclosingElement;
|
| - enclosingElement = element;
|
| - getContext().pushFunctionScope(x);
|
| - try {
|
| - resolveFunction(functionNode, element);
|
| - resolve(functionNode.getBody());
|
| - } finally {
|
| - getContext().popScope();
|
| - enclosingElement = previousEnclosingElement;
|
| - }
|
| - }
|
| - innermostFunction = previousFunction;
|
| - getContext().popScope();
|
| - return element;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitBlock(DartBlock x) {
|
| - getContext().pushScope("<block>");
|
| - addLabelToStatement(x);
|
| - // Remember names of Block variables.
|
| - for (DartStatement statement : x.getStatements()) {
|
| - if (statement instanceof DartVariableStatement) {
|
| - DartVariableStatement node = (DartVariableStatement) statement;
|
| - List<DartVariable> variables = node.getVariables();
|
| - for (DartVariable variable : variables) {
|
| - String name = variable.getVariableName();
|
| - getContext().getScope().addDeclaredButNotReachedVariable(name);
|
| - }
|
| - }
|
| - }
|
| - // Visit statements.
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitBreakStatement(DartBreakStatement x) {
|
| - // Handle corner case of L: break L;
|
| - DartNode parent = x.getParent();
|
| - if (parent instanceof DartLabel && x.getLabel() != null) {
|
| - if (((DartLabel) parent).getLabel().getName().equals(x.getLabel().getName())) {
|
| - getContext().pushScope("<break>");
|
| - addLabelToStatement(x);
|
| - visitGotoStatement(x);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| - }
|
| - return visitGotoStatement(x);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitTryStatement(DartTryStatement x) {
|
| - getContext().pushScope("<try>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitCatchBlock(DartCatchBlock x) {
|
| - getContext().pushScope("<block>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitDoWhileStatement(DartDoWhileStatement x) {
|
| - getContext().pushScope("<do>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitWhileStatement(DartWhileStatement x) {
|
| - getContext().pushScope("<while>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitIfStatement(DartIfStatement x) {
|
| - getContext().pushScope("<if>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitForInStatement(DartForInStatement x) {
|
| - getContext().pushScope("<for in>");
|
| - addLabelToStatement(x);
|
| -
|
| - x.getIterable().accept(this);
|
| - if (x.introducesVariable()) {
|
| - resolveVariableStatement(x.getVariableStatement(), true);
|
| - } else {
|
| - x.getIdentifier().accept(this);
|
| - }
|
| - x.getBody().accept(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - private void addLabelToStatement(DartNode x) {
|
| - DartNode parent = x.getParent();
|
| - while (parent instanceof DartLabel) {
|
| - DartLabel label = (DartLabel) parent;
|
| - LabelElement currentLabel = label.getElement();
|
| - getContext().getScope().addLabel(currentLabel);
|
| - labelsInScopes.add(currentLabel);
|
| - parent = parent.getParent();
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public Element visitForStatement(DartForStatement x) {
|
| - getContext().pushScope("<for>");
|
| - addLabelToStatement(x);
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| -
|
| - @Override
|
| - public Element visitSwitchStatement(DartSwitchStatement x) {
|
| - getContext().pushScope("<switch>");
|
| - addLabelToStatement(x);
|
| - // The scope of a label on the case statement is the case statement itself. These labels
|
| - // need to be resolved before the continue <label>; statements can be resolved.
|
| - for (DartSwitchMember member : x.getMembers()) {
|
| - recordSwitchMemberLabel(member);
|
| - }
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - private boolean isValidLastSwitchCaseStatement(DartStatement statement) {
|
| - if (statement instanceof DartExprStmt) {
|
| - DartExprStmt exprStmt = (DartExprStmt) statement;
|
| - if (exprStmt.getExpression() instanceof DartThrowExpression) {
|
| - return true;
|
| - }
|
| - }
|
| - return statement instanceof DartBreakStatement || statement instanceof DartContinueStatement
|
| - || statement instanceof DartReturnStatement;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitSwitchMember(DartSwitchMember x) {
|
| - getContext().pushScope("<switch member>");
|
| - x.visitChildren(this);
|
| - getContext().popScope();
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitCase(DartCase x) {
|
| - super.visitCase(x);
|
| - // check fall-through
|
| - {
|
| - List<DartStatement> statements = x.getStatements();
|
| - // the last statement should be: break, continue, return, throw
|
| - if (!statements.isEmpty()) {
|
| - DartStatement lastStatement = statements.get(statements.size() - 1);
|
| - if (!isValidLastSwitchCaseStatement(lastStatement)) {
|
| - onError(lastStatement, ResolverErrorCode.SWITCH_CASE_FALL_THROUGH);
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - private void recordSwitchMemberLabel(DartSwitchMember x) {
|
| - List<DartLabel> labels = x.getLabels();
|
| - for (DartLabel label : labels) {
|
| - LabelElement labelElement = Elements.switchMemberLabelElement(label, label.getName(),
|
| - innermostFunction);
|
| - recordElement(label.getLabel(), labelElement);
|
| - recordElement(label, labelElement);
|
| - if (getContext().getScope().hasLocalLabel(label.getName())) {
|
| - onError(label, ResolverErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT);
|
| - }
|
| - getContext().getScope().addLabel(labelElement);
|
| - labelsInScopes.add(labelElement);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public Element visitThisExpression(DartThisExpression x) {
|
| - if (ElementKind.of(currentHolder).equals(ElementKind.LIBRARY)) {
|
| - onError(x, ResolverErrorCode.THIS_ON_TOP_LEVEL);
|
| - } else if (currentMethod == null) {
|
| - onError(x, ResolverErrorCode.THIS_OUTSIDE_OF_METHOD);
|
| - } else if (currentMethod.getModifiers().isStatic()) {
|
| - onError(x, ResolverErrorCode.THIS_IN_STATIC_METHOD);
|
| - } else if (currentMethod.getModifiers().isFactory()) {
|
| - onError(x, ResolverErrorCode.THIS_IN_FACTORY_CONSTRUCTOR);
|
| - } else if (inInitializer) {
|
| - onError(x, ResolverErrorCode.THIS_IN_INITIALIZER_AS_EXPRESSION);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitDirective(DartDirective node) {
|
| - node.getMetadata().accept(this);
|
| - return super.visitDirective(node);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitPartOfDirective(DartPartOfDirective node) {
|
| - node.getMetadata().accept(this);
|
| - String elementName = "__library_" + node.getLibraryName();
|
| - Element element = context.getScope().findElement(null, elementName);
|
| - if (ElementKind.of(element) == ElementKind.LIBRARY) {
|
| - node.getName().setElement(element);
|
| - return element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitSuperExpression(DartSuperExpression x) {
|
| - if (ElementKind.of(currentHolder).equals(ElementKind.LIBRARY)) {
|
| - onError(x, ResolverErrorCode.SUPER_ON_TOP_LEVEL);
|
| - } else if (currentMethod == null) {
|
| - onError(x, ResolverErrorCode.SUPER_OUTSIDE_OF_METHOD);
|
| - } else if (currentMethod.getModifiers().isStatic()) {
|
| - onError(x, ResolverErrorCode.SUPER_IN_STATIC_METHOD);
|
| - } else if (currentMethod.getModifiers().isFactory()) {
|
| - onError(x, ResolverErrorCode.SUPER_IN_FACTORY_CONSTRUCTOR);
|
| - } else {
|
| - return recordElement(x, Elements.superElement(
|
| - x, ((ClassElement) currentHolder).getSupertype().getElement()));
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitSuperConstructorInvocation(DartSuperConstructorInvocation x) {
|
| - visit(x.getArguments());
|
| - // check if correct place for super()
|
| - if (ElementKind.of(currentHolder) != ElementKind.CLASS || currentMethod == null
|
| - || !currentMethod.isConstructor()) {
|
| - onError(x, ResolverErrorCode.SUPER_OUTSIDE_OF_CONSTRUCTOR);
|
| - return recordElement(x, null);
|
| - }
|
| - InterfaceType supertype = ((ClassElement) currentHolder).getSupertype();
|
| - // prepare ConstructorElement
|
| - String name = x.getName() == null ? "" : x.getName().getName();
|
| - ConstructorElement element;
|
| - if (supertype == null) {
|
| - element = null;
|
| - } else {
|
| - ClassElement classElement = supertype.getElement();
|
| - element = Elements.lookupConstructor(classElement, name);
|
| - if (element != null && element.getModifiers().isFactory()) {
|
| - onError(x, ResolverErrorCode.NOT_GENERATIVE_SUPER_CONSTRUCTOR, name, supertype);
|
| - }
|
| - if (element == null && "".equals(name) && x.getArguments().isEmpty()
|
| - && Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - element = new SyntheticDefaultConstructorElement(null, classElement, typeProvider);
|
| - }
|
| - }
|
| - if (element == null) {
|
| - onError(x, ResolverErrorCode.CANNOT_RESOLVE_SUPER_CONSTRUCTOR, name);
|
| - }
|
| - if (x.getName() != null) {
|
| - recordElement(x.getName(), element);
|
| - }
|
| - return recordElement(x, element);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitNamedExpression(DartNamedExpression node) {
|
| - // Intentionally skip the expression's name -- it's stored as an identifier, but doesn't need
|
| - // to be resolved.
|
| - return node.getExpression().accept(this);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitIdentifier(DartIdentifier x) {
|
| - return resolveIdentifier(x, false);
|
| - }
|
| -
|
| - private Element resolveIdentifier(DartIdentifier x, boolean isQualifier) {
|
| - if (x.getParent() instanceof DartLabel) {
|
| - return x.getElement();
|
| - }
|
| - Scope scope = getContext().getScope();
|
| - String name = x.getName();
|
| - Element element = scope.findElement(scope.getLibrary(), name);
|
| - if (element == null) {
|
| - element = scope.findElement(scope.getLibrary(), "setter " + name);
|
| - }
|
| - if (element == null) {
|
| - // A private identifier could refer to a field in a different library. In this case
|
| - // we want to provide a more useful error message in the type analyzer.
|
| - if (DartIdentifier.isPrivateName(name)) {
|
| - Element found = scope.findElement(null, name);
|
| - if (found != null) {
|
| - Element enclosingElement = found.getEnclosingElement();
|
| - String referencedElementName = enclosingElement == null
|
| - ? name : String.format("%s.%s", enclosingElement.getName(), name);
|
| - onError(x, ResolverErrorCode.ILLEGAL_ACCESS_TO_PRIVATE_MEMBER,
|
| - name, referencedElementName);
|
| - }
|
| - }
|
| - if (isStaticOrFactoryContextOrInitializer(x) && !isQualifier) {
|
| - if (!x.isResolutionAlreadyReportedThatTheMethodCouldNotBeFound()) {
|
| - onError(x, TypeErrorCode.CANNOT_BE_RESOLVED, name);
|
| - x.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - }
|
| - }
|
| - } else if (x.getParent() instanceof DartComment) {
|
| - } else {
|
| - element = checkResolvedIdentifier(x, isQualifier, scope, name, element);
|
| - }
|
| -
|
| - if (ElementKind.of(element) == ElementKind.DUPLICATE) {
|
| - DuplicateElement duplicateElement = (DuplicateElement) element;
|
| - List<String> locations = duplicateElement.getLocations();
|
| - onError(x, ResolverErrorCode.DUPLICATE_IMPORTED_NAME, element.getName(), locations.size(),
|
| - locations);
|
| - return null;
|
| - }
|
| -
|
| - if (inInitializer && ElementKind.of(element) == ElementKind.FIELD) {
|
| - if (!element.getModifiers().isStatic() && !Elements.isTopLevel(element)) {
|
| - onError(x, ResolverErrorCode.CANNOT_ACCESS_FIELD_IN_INIT);
|
| - }
|
| - }
|
| -
|
| - if (ElementKind.of(element) == ElementKind.FIELD) {
|
| - FieldElement fieldElement = (FieldElement) element;
|
| - if (fieldElement.getModifiers().isAbstractField()) {
|
| - if (fieldElement.getGetter() == null && ASTNodes.inGetterContext(x)) {
|
| - topLevelContext.onError(x, ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER);
|
| - x.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - }
|
| - if (fieldElement.getSetter() == null && ASTNodes.inSetterContext(x)) {
|
| - topLevelContext.onError(x, ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER);
|
| - x.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - }
|
| - }
|
| - }
|
| -
|
| - // May be local variable declared in lexical scope, but its declaration is not visited yet.
|
| - if (getContext().getScope().isDeclaredButNotReachedVariable(name)) {
|
| - onError(x, ResolverErrorCode.USING_LOCAL_VARIABLE_BEFORE_DECLARATION, x);
|
| - }
|
| -
|
| - if (!isQualifier && !(x.getParent() instanceof DartComment)) {
|
| - switch (ElementKind.of(element)) {
|
| - case FUNCTION_TYPE_ALIAS:
|
| - onError(x, ResolverErrorCode.CANNOT_USE_TYPE, name);
|
| - break;
|
| - case TYPE_VARIABLE:
|
| - onError(x, ResolverErrorCode.CANNOT_USE_TYPE_VARIABLE, name);
|
| - break;
|
| - case DUPLICATE:
|
| - DuplicateElement duplicateElement = (DuplicateElement) element;
|
| - List<String> locations = duplicateElement.getLocations();
|
| - onError(x, ResolverErrorCode.DUPLICATE_IMPORTED_NAME, element.getName(),
|
| - locations.size(), locations);
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - // If we we haven't resolved the identifier, it will be normalized to
|
| - // this.<identifier>.
|
| -
|
| - checkDeprecated(x, element);
|
| - return recordElement(x, element);
|
| - }
|
| -
|
| - /**
|
| - * Possibly recursive check on the resolved identifier.
|
| - */
|
| - private Element checkResolvedIdentifier(DartIdentifier x, boolean isQualifier, Scope scope,
|
| - String name, Element element) {
|
| - switch (element.getKind()) {
|
| - case FIELD:
|
| - if (!Elements.isStaticContext(element)) {
|
| - if (!element.getModifiers().isConstant()) {
|
| - if (inInstanceVariableInitializer) {
|
| - onError(x, ResolverErrorCode.CANNOT_USE_INSTANCE_FIELD_IN_INSTANCE_FIELD_INITIALIZER);
|
| - }
|
| - }
|
| - if (ASTNodes.isStaticContext(x)) {
|
| - onError(x, ResolverErrorCode.ILLEGAL_FIELD_ACCESS_FROM_STATIC, name);
|
| - }
|
| - if (ASTNodes.isFactoryContext(x)) {
|
| - onError(x, ResolverErrorCode.ILLEGAL_FIELD_ACCESS_FROM_FACTORY, name);
|
| - }
|
| - }
|
| - if (isIllegalPrivateAccess(x, enclosingElement, element, x.getName())) {
|
| - return null;
|
| - }
|
| - break;
|
| - case METHOD:
|
| - if (ASTNodes.isStaticContext(x) && !Elements.isStaticContext(element)) {
|
| - onError(x, ResolverErrorCode.ILLEGAL_METHOD_ACCESS_FROM_STATIC,
|
| - name);
|
| - }
|
| - if (isIllegalPrivateAccess(x, enclosingElement, element, x.getName())) {
|
| - return null;
|
| - }
|
| - if (!element.getModifiers().isStatic() && !Elements.isTopLevel(element)) {
|
| - if (referencedFromInitializer(x)) {
|
| - onError(x, ResolverErrorCode.INSTANCE_METHOD_FROM_INITIALIZER);
|
| - }
|
| - }
|
| - break;
|
| - case CLASS:
|
| - if (!isQualifier) {
|
| - return typeProvider.getTypeType().getElement();
|
| - }
|
| - break;
|
| - case FUNCTION_TYPE_ALIAS:
|
| - case TYPE_VARIABLE:
|
| - return typeProvider.getTypeType().getElement();
|
| - default:
|
| - break;
|
| - }
|
| - return element;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitTypeNode(DartTypeNode x) {
|
| - // prepare ErrorCode, depends on the context
|
| - ErrorCode errorCode = ResolverErrorCode.NO_SUCH_TYPE;
|
| - ErrorCode wrongNumberErrorCode = ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
|
| - {
|
| - DartNode p = x.getParent();
|
| - if (p instanceof DartTypeExpression) {
|
| - DartTypeExpression typeExpression = (DartTypeExpression) p;
|
| - if (typeExpression.getTypeNode() == x) {
|
| - DartNode pp = p.getParent();
|
| - if (pp instanceof DartBinaryExpression) {
|
| - Token operator = ((DartBinaryExpression) pp).getOperator();
|
| - if (operator == Token.AS || operator == Token.IS) {
|
| - errorCode = TypeErrorCode.NO_SUCH_TYPE;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // do Type resolve
|
| - return resolveType(x, ASTNodes.isStaticContext(x), ASTNodes.isFactoryContext(x), false,
|
| - errorCode, wrongNumberErrorCode).getElement();
|
| - }
|
| -
|
| - @Override
|
| - public Element visitPropertyAccess(DartPropertyAccess x) {
|
| - Element qualifier = resolveQualifier(x.getRealTarget());
|
| - Element element = null;
|
| - switch (ElementKind.of(qualifier)) {
|
| - case CLASS:
|
| - // Must be a static field.
|
| - element = Elements.findElement(((ClassElement) qualifier), x.getPropertyName());
|
| - if (element == null) {
|
| - element = Elements.findElement(((ClassElement) qualifier), "setter " + x.getPropertyName());
|
| - }
|
| - if (isIllegalPrivateAccess(x.getName(), qualifier, element, x.getPropertyName())) {
|
| - // break;
|
| - return null;
|
| - }
|
| - switch (ElementKind.of(element)) {
|
| - case FIELD:
|
| - FieldElement field = (FieldElement) element;
|
| - x.setType(field.getType());
|
| - if (!field.getModifiers().isStatic()) {
|
| - onError(x.getName(), ResolverErrorCode.NOT_A_STATIC_FIELD,
|
| - x.getPropertyName());
|
| - }
|
| - if (ASTNodes.inSetterContext(x)) {
|
| - if (field.getGetter() != null) {
|
| - if (field.getSetter() == null) {
|
| - onError(x.getName(), ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER);
|
| - }
|
| - }
|
| - }
|
| - if (ASTNodes.inGetterContext(x)) {
|
| - if (field.getSetter() != null) {
|
| - if (field.getGetter() == null) {
|
| - onError(x.getName(), ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER);
|
| - }
|
| - }
|
| - }
|
| - break;
|
| -
|
| - case NONE:
|
| - x.getName().markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - onError(x.getName(), TypeErrorCode.CANNOT_BE_RESOLVED,
|
| - x.getPropertyName());
|
| - break;
|
| -
|
| - case METHOD:
|
| - MethodElement method = (MethodElement) element;
|
| - if (!method.getModifiers().isStatic()) {
|
| - onError(x.getName(), ResolverErrorCode.NOT_A_STATIC_METHOD,
|
| - x.getPropertyName());
|
| - }
|
| - break;
|
| -
|
| - default:
|
| - onError(x.getName(), ResolverErrorCode.EXPECTED_STATIC_FIELD,
|
| - element.getKind());
|
| - break;
|
| - }
|
| - break;
|
| -
|
| - case SUPER:
|
| - if (isIllegalPrivateAccess(x.getName(), qualifier, element, x.getPropertyName())) {
|
| - return null;
|
| - }
|
| - ClassElement cls = ((SuperElement) qualifier).getClassElement();
|
| - Member member = cls.getType().lookupMember(x.getPropertyName());
|
| - if (member != null) {
|
| - element = member.getElement();
|
| - }
|
| - switch (ElementKind.of(element)) {
|
| - case FIELD:
|
| - FieldElement field = (FieldElement) element;
|
| - if (field.getModifiers().isStatic()) {
|
| - onError(x.getName(), ResolverErrorCode.NOT_AN_INSTANCE_FIELD,
|
| - x.getPropertyName());
|
| - }
|
| - break;
|
| - case METHOD:
|
| - MethodElement method = (MethodElement) element;
|
| - if (method.isStatic()) {
|
| - onError(x.getName(), ResolverErrorCode.NOT_AN_INSTANCE_FIELD,
|
| - x.getPropertyName());
|
| - }
|
| - break;
|
| -
|
| - case NONE:
|
| - onError(x.getName(), TypeErrorCode.CANNOT_BE_RESOLVED,
|
| - x.getPropertyName());
|
| - break;
|
| -
|
| - default:
|
| - onError(x.getName(),
|
| - ResolverErrorCode.EXPECTED_AN_INSTANCE_FIELD_IN_SUPER_CLASS,
|
| - element.getKind());
|
| - break;
|
| - }
|
| - break;
|
| -
|
| - case LIBRARY_PREFIX:
|
| - // Library prefix, lookup the element in the referenced library.
|
| - Scope scope = ((LibraryPrefixElement) qualifier).getScope();
|
| - element = scope.findElement(scope.getLibrary(), x.getPropertyName());
|
| - if (element != null) {
|
| - recordElement(x.getQualifier(), element.getEnclosingElement());
|
| - } else {
|
| - onError(x, ResolverErrorCode.CANNOT_BE_RESOLVED_LIBRARY,
|
| - x.getPropertyName(), qualifier.getName());
|
| - }
|
| - break;
|
| -
|
| - case NONE: {
|
| - // TODO(zundel): This is a bit awkward. Maybe it would be better to have an
|
| - // ElementKind of THIS just like we have for SUPER?
|
| - if (x.getRealTarget() instanceof DartThisExpression) {
|
| - Element foundElement = Elements.findElement(currentHolder, x.getPropertyName());
|
| - if (foundElement != null && !foundElement.getModifiers().isStatic()) {
|
| - if (ElementKind.of(foundElement) == ElementKind.TYPE_VARIABLE) {
|
| - onError(x.getRealTarget(), ResolverErrorCode.TYPE_VARIABLE_NOT_ALLOWED_IN_IDENTIFIER);
|
| - break;
|
| - }
|
| - element = foundElement;
|
| - }
|
| - }
|
| - }
|
| -
|
| - default:
|
| - break;
|
| - }
|
| - if (ElementKind.of(element) == ElementKind.DUPLICATE) {
|
| - DuplicateElement duplicateElement = (DuplicateElement) element;
|
| - List<String> locations = duplicateElement.getLocations();
|
| - onError(x.getName(), ResolverErrorCode.DUPLICATE_IMPORTED_NAME, duplicateElement.getName(),
|
| - locations.size(), locations);
|
| - return null;
|
| - }
|
| - return recordElement(x, element);
|
| - }
|
| -
|
| - private boolean isIllegalPrivateAccess(DartNode diagnosticNode, Element qualifier,
|
| - Element element, String name) {
|
| - if (DartIdentifier.isPrivateName(name)) {
|
| - if (element == null) {
|
| - element = getContext().getScope().findElement(null, name);
|
| - }
|
| - if (!Elements.areSameLibrary(enclosingElement, element)) {
|
| - onError(diagnosticNode, ResolverErrorCode.ILLEGAL_ACCESS_TO_PRIVATE, name);
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private Element resolveQualifier(DartNode qualifier) {
|
| - if (qualifier == null) {
|
| - return null;
|
| - }
|
| - return (qualifier instanceof DartIdentifier)
|
| - ? resolveIdentifier((DartIdentifier) qualifier, true)
|
| - : qualifier.accept(this);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitMethodInvocation(DartMethodInvocation x) {
|
| - DartIdentifier name = x.getFunctionName();
|
| - Element target = resolveQualifier(x.getRealTarget());
|
| - Element element = null;
|
| -
|
| - switch (ElementKind.of(target)) {
|
| - case CLASS: {
|
| - // Must be a static method or field.
|
| - ClassElement classElement = (ClassElement) target;
|
| - element = Elements.lookupLocalMethod(classElement, x.getFunctionNameString());
|
| - if (element == null) {
|
| - element = Elements.lookupLocalField(classElement, x.getFunctionNameString());
|
| - }
|
| - if (element == null || !element.getModifiers().isStatic()) {
|
| - diagnoseErrorInMethodInvocation(x, classElement, element);
|
| - } else {
|
| - if (isIllegalPrivateAccess(x.getFunctionName(), target, element,
|
| - x.getFunctionNameString())) {
|
| - break;
|
| - }
|
| - }
|
| - break;
|
| - }
|
| -
|
| - case SUPER: {
|
| - if (x.getParent() instanceof DartInitializer) {
|
| - onError(x, ResolverErrorCode.SUPER_METHOD_INVOCATION_IN_CONSTRUCTOR_INITIALIZER);
|
| - }
|
| - // Must be a superclass' method or field.
|
| - ClassElement classElement = ((SuperElement) target).getClassElement();
|
| - InterfaceType type = classElement.getType();
|
| - Member member = type.lookupMember(x.getFunctionNameString());
|
| - if (member != null) {
|
| - if (!member.getElement().getModifiers().isStatic()) {
|
| - element = member.getElement();
|
| - // Must be accessible.
|
| - if (!Elements.isAccessible(context.getScope().getLibrary(), element)) {
|
| - name.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - onError(name, ResolverErrorCode.CANNOT_ACCESS_METHOD, x.getFunctionNameString());
|
| - }
|
| - }
|
| - }
|
| - break;
|
| - }
|
| -
|
| - case LIBRARY_PREFIX:
|
| - // Library prefix, lookup the element in the reference library.
|
| - LibraryPrefixElement library = ((LibraryPrefixElement) target);
|
| - element = library.getScope().findElement(context.getScope().getLibrary(),
|
| - x.getFunctionNameString());
|
| - if (element == null) {
|
| - diagnoseErrorInMethodInvocation(x, library, null);
|
| - } else {
|
| - recordElement(x.getTarget(), element.getEnclosingElement());
|
| - name.setElement(element);
|
| - }
|
| - break;
|
| - }
|
| -
|
| - checkInvocationTarget(x, currentMethod, target);
|
| - visit(x.getArguments());
|
| - if (name != null) {
|
| - recordElement(name, element);
|
| - }
|
| - return recordElement(x, element);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitUnqualifiedInvocation(DartUnqualifiedInvocation x) {
|
| - Scope scope = getContext().getScope();
|
| - Element element = scope.findElement(scope.getLibrary(), x.getTarget().getName());
|
| - if (element == null) {
|
| - element = scope.findElement(scope.getLibrary(), "setter " + x.getTarget().getName());
|
| - }
|
| - ElementKind kind = ElementKind.of(element);
|
| - if (kind == ElementKind.DUPLICATE) {
|
| - DuplicateElement duplicateElement = (DuplicateElement) element;
|
| - List<String> locations = duplicateElement.getLocations();
|
| - onError(x.getTarget(), ResolverErrorCode.DUPLICATE_IMPORTED_NAME, element.getName(),
|
| - locations.size(), locations);
|
| - return null;
|
| - } else if (!INVOKABLE_ELEMENTS.contains(kind)) {
|
| - diagnoseErrorInUnqualifiedInvocation(x);
|
| - } else {
|
| - checkInvocationTarget(x, currentMethod, element);
|
| - }
|
| - if (Elements.isAbstractFieldWithoutGetter(element)) {
|
| - String name = element.getName();
|
| - if (isStaticOrFactoryContextOrInitializer(x)) {
|
| - onError(x.getTarget(), ResolverErrorCode.USE_ASSIGNMENT_ON_SETTER, name);
|
| - } else {
|
| - onError(x.getTarget(), TypeErrorCode.USE_ASSIGNMENT_ON_SETTER, name);
|
| - }
|
| - }
|
| - recordElement(x, element);
|
| - recordElement(x.getTarget(), element);
|
| - visit(x.getArguments());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitFunctionObjectInvocation(DartFunctionObjectInvocation x) {
|
| - x.getTarget().accept(this);
|
| - visit(x.getArguments());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitNewExpression(final DartNewExpression x) {
|
| - this.visit(x.getArguments());
|
| -
|
| - Element element = x.getConstructor().accept(getContext().new Selector() {
|
| - // Only 'new' expressions can have a type in a property access.
|
| - @Override
|
| - public Element visitTypeNode(DartTypeNode type) {
|
| - ErrorCode errorCode = x.isConst() ? ResolverErrorCode.NO_SUCH_TYPE_CONST : TypeErrorCode.NO_SUCH_TYPE;
|
| - return recordType(type, resolveType(type, ASTNodes.isStaticContext(x),
|
| - ASTNodes.isFactoryContext(x),
|
| - false,
|
| - errorCode,
|
| - ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS));
|
| - }
|
| -
|
| - @Override public Element visitPropertyAccess(DartPropertyAccess node) {
|
| - Element element = node.getQualifier().accept(this);
|
| - if (ElementKind.of(element).equals(ElementKind.CLASS)) {
|
| - assert node.getQualifier() instanceof DartTypeNode;
|
| - recordType(node, node.getQualifier().getType());
|
| - return Elements.lookupConstructor(((ClassElement) element), node.getPropertyName());
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| - });
|
| -
|
| -
|
| - switch (ElementKind.of(element)) {
|
| - case DYNAMIC:
|
| - return null;
|
| - case CLASS:
|
| - // Check for default constructor.
|
| - ClassElement classElement = (ClassElement) element;
|
| - element = Elements.lookupConstructor(classElement, "");
|
| - // If no default constructor, may be use implicit default constructor.
|
| - if (element == null
|
| - && x.getArguments().isEmpty()
|
| - && Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - element = new SyntheticDefaultConstructorElement(null, classElement, typeProvider);
|
| - }
|
| - break;
|
| - case CONSTRUCTOR:
|
| - if (enclosingElement != null) {
|
| - if (element != null && DartIdentifier.isPrivateName(element.getName())
|
| - && !Elements.areSameLibrary(enclosingElement, element)) {
|
| - onError(x.getConstructor(), ResolverErrorCode.ILLEGAL_ACCESS_TO_PRIVATE,
|
| - element.getName());
|
| - return null;
|
| - }
|
| - }
|
| - break;
|
| - case TYPE_VARIABLE:
|
| - if (x.isConst() ) {
|
| - onError(x.getConstructor(), ResolverErrorCode.CONST_EXPRESSION_CANT_USE_TYPE_VAR);
|
| - } else {
|
| - onError(x.getConstructor(), ResolverErrorCode.NEW_EXPRESSION_CANT_USE_TYPE_VAR);
|
| - }
|
| - return null;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - // Will check that element is not null.
|
| - ConstructorElement constructor = checkIsConstructor(x, element);
|
| -
|
| - // Check constructor.
|
| - if (constructor != null) {
|
| - boolean constConstructor = constructor.getModifiers().isConstant();
|
| - // Check for using "const" to non-const constructor.
|
| - if (x.isConst() && !constConstructor) {
|
| - onError(x, ResolverErrorCode.CONST_AND_NONCONST_CONSTRUCTOR);
|
| - }
|
| - // Check for using "const" with type variables as type arguments.
|
| - if (x.isConst() && constConstructor) {
|
| - DartTypeNode typeNode = Types.constructorTypeNode(x);
|
| - List<DartTypeNode> typeArguments = typeNode.getTypeArguments();
|
| - for (DartTypeNode typeArgument : typeArguments) {
|
| - if (typeArgument.getType() instanceof TypeVariable) {
|
| - onError(typeArgument, ResolverErrorCode.CONST_WITH_TYPE_VARIABLE);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - return recordElement(x, constructor);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitGotoStatement(DartGotoStatement x) {
|
| - // Don't bother unless there's a target.
|
| - if (x.getTargetName() != null) {
|
| - Element element = getContext().getScope().findLabel(x.getTargetName(), innermostFunction);
|
| - if (ElementKind.of(element).equals(ElementKind.LABEL)) {
|
| - LabelElement labelElement = (LabelElement) element;
|
| - if (x instanceof DartBreakStatement
|
| - && labelElement.getStatementType() == LabeledStatementType.SWITCH_MEMBER_STATEMENT) {
|
| - onError(x.getLabel(), ResolverErrorCode.BREAK_LABEL_RESOLVES_TO_CASE_OR_DEFAULT);
|
| - return null;
|
| - }
|
| - if (x instanceof DartContinueStatement
|
| - && labelElement.getStatementType() == LabeledStatementType.SWITCH_STATEMENT) {
|
| - onError(x.getLabel(), ResolverErrorCode.CONTINUE_LABEL_RESOLVES_TO_SWITCH);
|
| - return null;
|
| - }
|
| - MethodElement enclosingFunction = (labelElement).getEnclosingFunction();
|
| - if (enclosingFunction == innermostFunction) {
|
| - referencedLabels.add(labelElement);
|
| - return recordElement(x, element);
|
| - }
|
| - }
|
| - diagnoseErrorInGotoStatement(x, element);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - public void diagnoseErrorInGotoStatement(DartGotoStatement x, Element element) {
|
| - if (element == null) {
|
| - onError(x.getLabel(), ResolverErrorCode.CANNOT_RESOLVE_LABEL,
|
| - x.getTargetName());
|
| - } else if (ElementKind.of(element).equals(ElementKind.LABEL)) {
|
| - onError(x.getLabel(), ResolverErrorCode.CANNOT_ACCESS_OUTER_LABEL,
|
| - x.getTargetName());
|
| - } else {
|
| - onError(x.getLabel(), ResolverErrorCode.NOT_A_LABEL, x.getTargetName());
|
| - }
|
| - }
|
| -
|
| - private void diagnoseErrorInMethodInvocation(DartMethodInvocation node, Element classOrLibrary,
|
| - Element element) {
|
| - String name = node.getFunctionNameString();
|
| - ElementKind kind = ElementKind.of(element);
|
| - DartNode errorNode = node.getFunctionName();
|
| - switch (kind) {
|
| - case NONE:
|
| - switch (ElementKind.of(classOrLibrary)) {
|
| - case CLASS:
|
| - onError(errorNode, ResolverErrorCode.CANNOT_RESOLVE_METHOD_IN_CLASS, name,
|
| - classOrLibrary.getName());
|
| - node.getFunctionName().markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - break;
|
| - case LIBRARY:
|
| - onError(errorNode, ResolverErrorCode.CANNOT_RESOLVE_METHOD_IN_LIBRARY, name,
|
| - classOrLibrary.getName());
|
| - break;
|
| - default:
|
| - onError(errorNode, ResolverErrorCode.CANNOT_RESOLVE_METHOD, name);
|
| - }
|
| -
|
| - break;
|
| -
|
| - case CONSTRUCTOR:
|
| - onError(errorNode, ResolverErrorCode.IS_A_CONSTRUCTOR, classOrLibrary.getName(),
|
| - name);
|
| - break;
|
| -
|
| - case METHOD: {
|
| - assert !((MethodElement) element).getModifiers().isStatic();
|
| - onError(errorNode, ResolverErrorCode.IS_AN_INSTANCE_METHOD,
|
| - classOrLibrary.getName(), name);
|
| - break;
|
| - }
|
| -
|
| - case FIELD: {
|
| - onError(errorNode, ResolverErrorCode.IS_AN_INSTANCE_FIELD,
|
| - classOrLibrary.getName(), name);
|
| - break;
|
| - }
|
| -
|
| - default:
|
| - throw context.internalError(errorNode, "Unexpected kind of element: %s", kind);
|
| - }
|
| - }
|
| -
|
| - private void diagnoseErrorInUnqualifiedInvocation(DartUnqualifiedInvocation node) {
|
| - String name = node.getTarget().getName();
|
| - Scope scope = getContext().getScope();
|
| - Element element = scope.findElement(scope.getLibrary(), name);
|
| - ElementKind kind = ElementKind.of(element);
|
| - switch (kind) {
|
| - case NONE:
|
| - if (isStaticOrFactoryContextOrInitializer(node) || ASTNodes.isFactoryContext(node)) {
|
| - node.getTarget().markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - onError(node.getTarget(), ResolverErrorCode.CANNOT_RESOLVE_METHOD, name);
|
| - }
|
| - if (scope.findElement(null, name) != null) {
|
| - node.getTarget().markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
|
| - onError(node.getTarget(), ResolverErrorCode.CANNOT_ACCESS_METHOD, name);
|
| - }
|
| - break;
|
| -
|
| - case CONSTRUCTOR:
|
| - onError(node, ResolverErrorCode.DID_YOU_MEAN_NEW, name, "constructor");
|
| - break;
|
| -
|
| - case CLASS:
|
| - onError(node, ResolverErrorCode.DID_YOU_MEAN_NEW, name, "class");
|
| - break;
|
| -
|
| - case TYPE_VARIABLE:
|
| - onError(node, ResolverErrorCode.DID_YOU_MEAN_NEW, name, "type variable");
|
| - break;
|
| -
|
| - case FUNCTION_TYPE_ALIAS:
|
| - onError(node, ResolverErrorCode.CANNOT_CALL_FUNCTION_TYPE_ALIAS);
|
| - break;
|
| -
|
| - case LIBRARY_PREFIX:
|
| - onError(node, ResolverErrorCode.CANNOT_CALL_LIBRARY_PREFIX);
|
| - break;
|
| -
|
| - default:
|
| - throw context.internalError(node, "Unexpected kind of element: %s", kind);
|
| - }
|
| - }
|
| -
|
| - private void diagnoseErrorInInitializer(DartIdentifier x) {
|
| - String name = x.getName();
|
| - Scope scope = getContext().getScope();
|
| - Element element = scope.findElement(scope.getLibrary(), name);
|
| - ElementKind kind = ElementKind.of(element);
|
| - switch (kind) {
|
| - case NONE:
|
| - onError(x, ResolverErrorCode.CANNOT_RESOLVE_FIELD, name);
|
| - break;
|
| -
|
| - case FIELD:
|
| - FieldElement field = (FieldElement) element;
|
| - recordElement(x, field);
|
| - if (field.isStatic()) {
|
| - onError(x, ResolverErrorCode.CANNOT_INIT_STATIC_FIELD_IN_INITIALIZER);
|
| - } else if (field.getModifiers().isAbstractField()) {
|
| - /*
|
| - * If we get here then we know that this is a property accessor and not a true field.
|
| - * If there was a field and property accessor with the same name a name collision error
|
| - * would keep us from reaching this point.
|
| - */
|
| - onError(x, ResolverErrorCode.CANNOT_INIT_STATIC_FIELD_IN_INITIALIZER);
|
| - } else {
|
| - onError(x, ResolverErrorCode.INIT_FIELD_ONLY_IMMEDIATELY_SURROUNDING_CLASS);
|
| - }
|
| - break;
|
| -
|
| - case METHOD:
|
| - onError(x, ResolverErrorCode.EXPECTED_FIELD_NOT_METHOD, name);
|
| - break;
|
| -
|
| - case CLASS:
|
| - onError(x, ResolverErrorCode.EXPECTED_FIELD_NOT_CLASS, name);
|
| - break;
|
| -
|
| - case PARAMETER:
|
| - onError(x, ResolverErrorCode.EXPECTED_FIELD_NOT_PARAMETER, name);
|
| - break;
|
| -
|
| - case TYPE_VARIABLE:
|
| - onError(x, ResolverErrorCode.EXPECTED_FIELD_NOT_TYPE_VAR, name);
|
| - break;
|
| -
|
| - case VARIABLE:
|
| - case LABEL:
|
| - default:
|
| - throw context.internalError(x, "Unexpected kind of element: %s", kind);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public Element visitInitializer(DartInitializer x) {
|
| - if (x.getName() != null) {
|
| - // Make sure the identifier is a local instance field.
|
| - FieldElement element = Elements.lookupLocalField(
|
| - (ClassElement) currentHolder, x.getName().getName());
|
| - if (element == null || element.isStatic() || element.getModifiers().isAbstractField()) {
|
| - diagnoseErrorInInitializer(x.getName());
|
| - }
|
| - recordElement(x.getName(), element);
|
| - }
|
| -
|
| - assert !inInitializer;
|
| - DartExpression value = x.getValue();
|
| - if (value == null) {
|
| - return null;
|
| - }
|
| - inInitializer = true;
|
| - Element element = value.accept(this);
|
| - inInitializer = false;
|
| - return element;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitRedirectConstructorInvocation(DartRedirectConstructorInvocation x) {
|
| -
|
| - visit(x.getArguments());
|
| - String name = x.getName() != null ? x.getName().getName() : "";
|
| - ConstructorElement element = Elements.lookupConstructor((ClassElement) currentHolder, name);
|
| - if (element == null) {
|
| - onError(x, ResolverErrorCode.CANNOT_RESOLVE_CONSTRUCTOR, name);
|
| - }
|
| - return recordElement(x, element);
|
| - }
|
| -
|
| - @Override
|
| - public Element visitReturnStatement(DartReturnStatement x) {
|
| - if (x.getValue() != null) {
|
| - // Dart Spec v0.03, section 11.10.
|
| - // Generative constructors cannot return arbitrary expressions in the form: 'return e;'
|
| - // they can though have return statement in the form: 'return;'
|
| - if ((currentMethod == innermostFunction)
|
| - && Elements.isNonFactoryConstructor(currentMethod)) {
|
| - onError(x, ResolverErrorCode.INVALID_RETURN_IN_CONSTRUCTOR);
|
| - }
|
| - return x.getValue().accept(this);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitIntegerLiteral(DartIntegerLiteral node) {
|
| - recordType(node, typeProvider.getIntType());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitDoubleLiteral(DartDoubleLiteral node) {
|
| - recordType(node, typeProvider.getDoubleType());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitBooleanLiteral(DartBooleanLiteral node) {
|
| - recordType(node, typeProvider.getBoolType());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitStringLiteral(DartStringLiteral node) {
|
| - recordType(node, typeProvider.getStringType());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitStringInterpolation(DartStringInterpolation node) {
|
| - node.visitChildren(this);
|
| - recordType(node, typeProvider.getStringType());
|
| - return null;
|
| - }
|
| -
|
| - Element recordType(DartNode node, Type type) {
|
| - node.setType(type);
|
| - return type.getElement();
|
| - }
|
| -
|
| - @Override
|
| - public Element visitBinaryExpression(DartBinaryExpression node) {
|
| - Element lhs = resolve(node.getArg1());
|
| - resolve(node.getArg2());
|
| - if (node.getOperator().isAssignmentOperator()) {
|
| - switch (ElementKind.of(lhs)) {
|
| - case FIELD:
|
| - case PARAMETER:
|
| - case VARIABLE:
|
| - if (lhs.getModifiers().isFinal()) {
|
| - if (Elements.isFieldOfSameClassAsEnclosingConstructor(lhs, enclosingElement)) {
|
| - topLevelContext.onError(node.getArg1(),
|
| - ResolverErrorCode.CANNOT_ASSIGN_TO_FINAL_ERROR, lhs.getName());
|
| - } else {
|
| - topLevelContext.onError(node.getArg1(), ResolverErrorCode.CANNOT_ASSIGN_TO_FINAL,
|
| - lhs.getName());
|
| - }
|
| - }
|
| - break;
|
| - case METHOD:
|
| - if (!lhs.getModifiers().isSetter() && !lhs.getModifiers().isGetter()) {
|
| - topLevelContext.onError(node.getArg1(), ResolverErrorCode.CANNOT_ASSIGN_TO_METHOD,
|
| - lhs.getName());
|
| - }
|
| - if (lhs.getModifiers().isSetter()) {
|
| - node.setElement(lhs);
|
| - }
|
| - break;
|
| - }
|
| - }
|
| -
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitUnaryExpression(DartUnaryExpression node) {
|
| - DartExpression arg = node.getArg();
|
| - Element argElement = resolve(arg);
|
| - if (node.getOperator().isCountOperator()) {
|
| - switch (ElementKind.of(argElement)) {
|
| - case FIELD:
|
| - case PARAMETER:
|
| - case VARIABLE:
|
| - if (argElement.getModifiers().isFinal()) {
|
| - topLevelContext.onError(arg, ResolverErrorCode.CANNOT_ASSIGN_TO_FINAL,
|
| - argElement.getName());
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - if (node.getOperator() == Token.CONDITIONAL) {
|
| - if (ElementKind.of(argElement) != ElementKind.PARAMETER) {
|
| - onError(arg, ResolverErrorCode.FORMAL_PARAMETER_NAME_EXPECTED);
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitMapLiteral(DartMapLiteral node) {
|
| - List<DartTypeNode> originalTypeArgs = node.getTypeArguments();
|
| - List<DartTypeNode> typeArgs = Lists.newArrayList();
|
| - DartTypeNode implicitKey = new DartTypeNode(
|
| - new DartIdentifier("String"));
|
| - switch (originalTypeArgs.size()) {
|
| - case 1:
|
| - // Old (pre spec 0.11) map specification
|
| - typeArgs.add(implicitKey);
|
| - typeArgs.add(originalTypeArgs.get(0));
|
| - // TODO(scheglov) enable this warning
|
| -// topLevelContext.onError(originalTypeArgs.get(0), ResolverErrorCode.DEPRECATED_MAP_LITERAL_SYNTAX);
|
| - break;
|
| - case 2:
|
| - typeArgs.add(originalTypeArgs.get(0));
|
| - typeArgs.add(originalTypeArgs.get(1));
|
| - break;
|
| - default:
|
| - topLevelContext.onError(node, ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
| - defaultLiteralMapType,
|
| - originalTypeArgs.size(), 1);
|
| - // fall through
|
| - case 0:
|
| - typeArgs.add(implicitKey);
|
| - DartTypeNode implicitValue = new DartTypeNode(new DartIdentifier("dynamic"));
|
| - typeArgs.add(implicitValue);
|
| - break;
|
| - }
|
| -
|
| - InterfaceType type =
|
| - context.instantiateParameterizedType(
|
| - defaultLiteralMapType.getElement(),
|
| - node,
|
| - typeArgs,
|
| - ASTNodes.isStaticContext(node),
|
| - ASTNodes.isFactoryContext(node),
|
| - ResolverErrorCode.NO_SUCH_TYPE,
|
| - ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
|
| - // instantiateParametersType() will complain for wrong number of parameters (!=2)
|
| - if (node.isConst()) {
|
| - checkTypeArgumentsInConstLiteral(typeArgs, ResolverErrorCode.CONST_MAP_WITH_TYPE_VARIABLE);
|
| - }
|
| - recordType(node, type);
|
| - visit(node.getEntries());
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - public Element visitArrayLiteral(DartArrayLiteral node) {
|
| - List<DartTypeNode> typeArgs = node.getTypeArguments();
|
| - InterfaceType type =
|
| - context.instantiateParameterizedType(
|
| - rawArrayType.getElement(),
|
| - node,
|
| - typeArgs,
|
| - ASTNodes.isStaticContext(node),
|
| - ASTNodes.isFactoryContext(node),
|
| - ResolverErrorCode.NO_SUCH_TYPE,
|
| - ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
|
| - // instantiateParametersType() will complain for wrong number of parameters (!=1)
|
| - if (node.isConst()) {
|
| - checkTypeArgumentsInConstLiteral(typeArgs, ResolverErrorCode.CONST_ARRAY_WITH_TYPE_VARIABLE);
|
| - }
|
| - recordType(node, type);
|
| - visit(node.getExpressions());
|
| - return null;
|
| - }
|
| -
|
| - private void checkTypeArgumentsInConstLiteral(List<DartTypeNode> typeArgs, ErrorCode errorCode) {
|
| - for (DartTypeNode typeNode : typeArgs) {
|
| - Type type = typeNode.getType();
|
| - if (type != null && type.getKind() == TypeKind.VARIABLE) {
|
| - onError(typeNode, errorCode);
|
| - }
|
| - }
|
| - }
|
| -
|
| - private ConstructorElement checkIsConstructor(DartNewExpression node, Element element) {
|
| - if (!ElementKind.of(element).equals(ElementKind.CONSTRUCTOR)) {
|
| - ErrorCode errorCode = node.isConst()
|
| - ? ResolverErrorCode.NEW_EXPRESSION_NOT_CONST_CONSTRUCTOR
|
| - : TypeErrorCode.NEW_EXPRESSION_NOT_CONSTRUCTOR;
|
| - onError(ASTNodes.getConstructorNameNode(node), errorCode);
|
| - return null;
|
| - }
|
| - return (ConstructorElement) element;
|
| - }
|
| -
|
| - private void checkConstructor(DartMethodDefinition node,
|
| - ConstructorElement superCall) {
|
| - ClassElement currentClass = (ClassElement) currentHolder;
|
| - if (superCall == null) {
|
| - // Look for a default constructor in our super type
|
| - InterfaceType supertype = currentClass.getSupertype();
|
| - if (supertype != null) {
|
| - superCall = Elements.lookupConstructor(supertype.getElement(), "");
|
| - }
|
| - if (superCall != null) {
|
| -
|
| - // Do positional parameters match?
|
| - int superPositionalCount = Elements.getNumberOfRequiredParameters(superCall);
|
| - if (superPositionalCount > 0) {
|
| - onError(node, ResolverErrorCode.TOO_FEW_ARGUMENTS_IN_IMPLICIT_SUPER,
|
| - superCall.getType().toString());
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (superCall == null
|
| - && !currentClass.isObject()
|
| - && !currentClass.isObjectChild()) {
|
| - InterfaceType supertype = currentClass.getSupertype();
|
| - if (supertype != null) {
|
| - ClassElement superElement = supertype.getElement();
|
| - if (superElement != null) {
|
| - if (!hasDefaultConstructor(superElement)) {
|
| - onError(node,
|
| - ResolverErrorCode.CANNOT_RESOLVE_IMPLICIT_CALL_TO_SUPER_CONSTRUCTOR,
|
| - superElement.getName());
|
| - }
|
| - }
|
| - }
|
| - } else if (superCall != null
|
| - && node.getModifiers().isConstant()
|
| - && !superCall.getModifiers().isConstant()) {
|
| - onError(node.getName(),
|
| - ResolverErrorCode.CONST_CONSTRUCTOR_MUST_CALL_CONST_SUPER);
|
| - }
|
| - }
|
| -
|
| - private void checkInvocationTarget(DartInvocation node,
|
| - MethodElement callSite,
|
| - Element target) {
|
| -
|
| - if (ElementKind.of(target).equals(ElementKind.METHOD)) {
|
| - if (callSite != null && callSite.isStatic())
|
| - if (!target.getModifiers().isStatic() && !Elements.isTopLevel(target)) {
|
| - onError(node, ResolverErrorCode.INSTANCE_METHOD_FROM_STATIC);
|
| - }
|
| - if (!target.getModifiers().isStatic() && !Elements.isTopLevel(target)) {
|
| - if (referencedFromRedirectConstructor(node)) {
|
| - onError(node, ResolverErrorCode.INSTANCE_METHOD_FROM_REDIRECT);
|
| - } else if (referencedFromInitializer(node)) {
|
| - onError(node, ResolverErrorCode.INSTANCE_METHOD_FROM_INITIALIZER);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - private boolean referencedFromInitializer(DartNode node) {
|
| - do {
|
| - if (node instanceof DartInitializer) {
|
| - return true;
|
| - }
|
| - node = node.getParent();
|
| - } while (node != null);
|
| - return false;
|
| - }
|
| -
|
| - private boolean referencedFromRedirectConstructor(DartNode node) {
|
| - do {
|
| - if (node instanceof DartRedirectConstructorInvocation) {
|
| - return true;
|
| - }
|
| - node = node.getParent();
|
| - } while (node != null);
|
| - return false;
|
| - }
|
| -
|
| - private void checkVariableStatement(DartVariableStatement node,
|
| - DartVariable variable,
|
| - boolean isImplicitlyInitialized) {
|
| - Modifiers modifiers = node.getModifiers();
|
| - if (modifiers.isFinal()) {
|
| - if (!isImplicitlyInitialized && (variable.getValue() == null)) {
|
| - onError(variable.getName(), ResolverErrorCode.CONSTANTS_MUST_BE_INITIALIZED);
|
| - } else if (modifiers.isStatic() && variable.getValue() != null) {
|
| - resolve(variable.getValue());
|
| - node.setType(variable.getValue().getType());
|
| - }
|
| - }
|
| - }
|
| -
|
| - private void resolveInitializers(DartMethodDefinition node, Set<FieldElement> initializedFields) {
|
| - ClassElement classElement = (ClassElement) enclosingElement.getEnclosingElement();
|
| -
|
| - ConstructorElement constructorElement = null;
|
| - boolean hasSuperInvocation = false;
|
| - for (DartInitializer initializer : node.getInitializers()) {
|
| - hasSuperInvocation |= initializer.getValue() instanceof DartSuperConstructorInvocation;
|
| - Element element = resolve(initializer);
|
| - if ((ElementKind.of(element) == ElementKind.CONSTRUCTOR) && initializer.isInvocation()) {
|
| - constructorElement = (ConstructorElement) element;
|
| - } else if (initializer.getName() != null && initializer.getName().getElement() != null
|
| - && initializer.getName().getElement().getModifiers() != null
|
| - && !initializedFields.add((FieldElement)initializer.getName().getElement())) {
|
| - onError(initializer, ResolverErrorCode.DUPLICATE_INITIALIZATION, initializer.getName());
|
| - }
|
| - }
|
| -
|
| - // If no explicit super() invocation, then implicit call of default super-type constructor.
|
| - // Check that it is not factory, i.e. generative.
|
| - if (!hasSuperInvocation && currentHolder instanceof ClassElement) {
|
| - InterfaceType superType = classElement.getSupertype();
|
| - if (superType != null) {
|
| - ClassElement superElement = superType.getElement();
|
| - ConstructorElement superConstructor = Elements.lookupConstructor(superElement, "");
|
| - if (superConstructor != null && superConstructor.getModifiers().isFactory()) {
|
| - onError(node.getName(), ResolverErrorCode.NOT_GENERATIVE_SUPER_CONSTRUCTOR,
|
| - "<default>", superType);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Look for final fields that are not initialized
|
| - Element methodElement = node.getElement();
|
| - if (classElement != null && methodElement != null
|
| - && !classElement.isInterface()
|
| - && !classElement.getModifiers().isNative()
|
| - && !methodElement.getModifiers().isExternal()
|
| - && !methodElement.getModifiers().isRedirectedConstructor()) {
|
| - for (Element member : classElement.getMembers()) {
|
| - switch (ElementKind.of(member)) {
|
| - case FIELD:
|
| - FieldElement fieldMember = (FieldElement)member;
|
| - if (fieldMember.getModifiers().isFinal()
|
| - && !fieldMember.getModifiers().isInitialized()
|
| - && !initializedFields.contains(fieldMember)) {
|
| - FieldNodeElement n = (FieldNodeElement)fieldMember;
|
| - onError(n.getNode(), ResolverErrorCode.FINAL_FIELD_MUST_BE_INITIALIZED,
|
| - fieldMember.getName());
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - checkConstructor(node, constructorElement);
|
| - }
|
| -
|
| - private void onError(HasSourceInfo target, ErrorCode errorCode, Object... arguments) {
|
| - context.onError(target, errorCode, arguments);
|
| - }
|
| -
|
| - private void onError(SourceInfo target, ErrorCode errorCode, Object... arguments) {
|
| - context.onError(target, errorCode, arguments);
|
| - }
|
| -
|
| - boolean isStaticOrFactoryContextOrInitializer(DartNode x) {
|
| - return ASTNodes.isStaticOrFactoryContext(x) || inInitializer;
|
| - }
|
| - }
|
| -
|
| - public static class Phase implements DartCompilationPhase {
|
| - /**
|
| - * Executes element resolution on the given compilation unit.
|
| - *
|
| - * @param context The listener through which compilation errors are reported
|
| - * (not <code>null</code>)
|
| - */
|
| - @Override
|
| - public DartUnit exec(DartUnit unit, DartCompilerContext context,
|
| - CoreTypeProvider typeProvider) {
|
| - Scope unitScope = unit.getLibrary().getElement().getScope();
|
| - return new Resolver(context, unitScope, typeProvider).exec(unit);
|
| - }
|
| - }
|
| -
|
| - private void checkRedirectConstructorCycle(List<ConstructorNodeElement> constructors,
|
| - ResolutionContext context) {
|
| - for (ConstructorNodeElement element : constructors) {
|
| - if (hasRedirectedConstructorCycle(element)) {
|
| - context.onError(element, ResolverErrorCode.REDIRECTED_CONSTRUCTOR_CYCLE);
|
| - }
|
| - }
|
| - }
|
| -
|
| - private boolean hasRedirectedConstructorCycle(ConstructorNodeElement constructorElement) {
|
| - Set<ConstructorNodeElement> visited = Sets.newHashSet();
|
| - ConstructorNodeElement next = getNextConstructorInvocation(constructorElement);
|
| - while (next != null) {
|
| - if (visited.contains(next)) {
|
| - return true;
|
| - }
|
| - if (constructorElement.getName().equals(next.getName())) {
|
| - return true;
|
| - }
|
| - visited.add(next);
|
| - next = getNextConstructorInvocation(next);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private ConstructorNodeElement getNextConstructorInvocation(ConstructorNodeElement constructor) {
|
| - List<DartInitializer> inits = ((DartMethodDefinition) constructor.getNode()).getInitializers();
|
| - // Parser ensures that redirected constructors can be the only item in the initialization list.
|
| - if (inits.size() == 1) {
|
| - DartExpression value = inits.get(0).getValue();
|
| - if (value != null) {
|
| - Element element = value.getElement();
|
| - if (ElementKind.of(element).equals(ElementKind.CONSTRUCTOR)) {
|
| - ConstructorElement nextConstructorElement = (ConstructorElement) element;
|
| - ClassElement nextClass = (ClassElement) nextConstructorElement.getEnclosingElement();
|
| - ClassElement currentClass = (ClassElement) constructor.getEnclosingElement();
|
| - if (nextClass == currentClass) {
|
| - return (ConstructorNodeElement) nextConstructorElement;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -}
|
|
|