| /* |
| * Copyright (c) 2013, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.dart.engine.internal.verifier; |
| |
| import com.google.dart.engine.ast.Annotation; |
| import com.google.dart.engine.ast.ArgumentList; |
| import com.google.dart.engine.ast.ClassDeclaration; |
| import com.google.dart.engine.ast.ClassMember; |
| import com.google.dart.engine.ast.ConstructorDeclaration; |
| import com.google.dart.engine.ast.ConstructorFieldInitializer; |
| import com.google.dart.engine.ast.ConstructorInitializer; |
| import com.google.dart.engine.ast.DefaultFormalParameter; |
| import com.google.dart.engine.ast.Expression; |
| import com.google.dart.engine.ast.FieldDeclaration; |
| import com.google.dart.engine.ast.FormalParameter; |
| import com.google.dart.engine.ast.FormalParameterList; |
| import com.google.dart.engine.ast.FunctionExpression; |
| import com.google.dart.engine.ast.InstanceCreationExpression; |
| import com.google.dart.engine.ast.ListLiteral; |
| import com.google.dart.engine.ast.MapLiteral; |
| import com.google.dart.engine.ast.MapLiteralEntry; |
| import com.google.dart.engine.ast.MethodDeclaration; |
| import com.google.dart.engine.ast.NamedExpression; |
| import com.google.dart.engine.ast.NodeList; |
| import com.google.dart.engine.ast.RedirectingConstructorInvocation; |
| import com.google.dart.engine.ast.SimpleIdentifier; |
| import com.google.dart.engine.ast.SuperConstructorInvocation; |
| import com.google.dart.engine.ast.SwitchCase; |
| import com.google.dart.engine.ast.SwitchMember; |
| import com.google.dart.engine.ast.SwitchStatement; |
| import com.google.dart.engine.ast.VariableDeclaration; |
| import com.google.dart.engine.ast.visitor.RecursiveAstVisitor; |
| import com.google.dart.engine.constant.DartObject; |
| import com.google.dart.engine.element.ClassElement; |
| import com.google.dart.engine.element.ConstructorElement; |
| import com.google.dart.engine.element.Element; |
| import com.google.dart.engine.element.LibraryElement; |
| import com.google.dart.engine.element.MethodElement; |
| import com.google.dart.engine.element.ParameterElement; |
| import com.google.dart.engine.error.AnalysisError; |
| import com.google.dart.engine.error.BooleanErrorListener; |
| import com.google.dart.engine.error.CompileTimeErrorCode; |
| import com.google.dart.engine.error.ErrorCode; |
| import com.google.dart.engine.error.StaticWarningCode; |
| import com.google.dart.engine.internal.constant.ConstantVisitor; |
| import com.google.dart.engine.internal.constant.EvaluationResultImpl; |
| import com.google.dart.engine.internal.context.RecordingErrorListener; |
| import com.google.dart.engine.internal.element.VariableElementImpl; |
| import com.google.dart.engine.internal.error.ErrorReporter; |
| import com.google.dart.engine.internal.object.BoolState; |
| import com.google.dart.engine.internal.object.DartObjectImpl; |
| import com.google.dart.engine.internal.object.DoubleState; |
| import com.google.dart.engine.internal.object.DynamicState; |
| import com.google.dart.engine.internal.object.GenericState; |
| import com.google.dart.engine.internal.object.IntState; |
| import com.google.dart.engine.internal.object.NumState; |
| import com.google.dart.engine.internal.object.StringState; |
| import com.google.dart.engine.internal.resolver.TypeProvider; |
| import com.google.dart.engine.type.InterfaceType; |
| import com.google.dart.engine.type.Type; |
| import com.google.dart.engine.utilities.ast.DeferredLibraryReferenceDetector; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| |
| /** |
| * Instances of the class {@code ConstantVerifier} traverse an AST structure looking for additional |
| * errors and warnings not covered by the parser and resolver. In particular, it looks for errors |
| * and warnings related to constant expressions. |
| * |
| * @coverage dart.engine.resolver |
| */ |
| public class ConstantVerifier extends RecursiveAstVisitor<Void> { |
| /** |
| * The error reporter by which errors will be reported. |
| */ |
| private ErrorReporter errorReporter; |
| |
| /** |
| * The type provider used to access the known types. |
| */ |
| private TypeProvider typeProvider; |
| |
| /** |
| * The type representing the type 'bool'. |
| */ |
| private InterfaceType boolType; |
| |
| /** |
| * The type representing the type 'int'. |
| */ |
| private InterfaceType intType; |
| |
| /** |
| * The type representing the type 'num'. |
| */ |
| private InterfaceType numType; |
| |
| /** |
| * The type representing the type 'string'. |
| */ |
| private InterfaceType stringType; |
| |
| /** |
| * The current library that is being analyzed. |
| */ |
| private LibraryElement currentLibrary; |
| |
| /** |
| * Initialize a newly created constant verifier. |
| * |
| * @param errorReporter the error reporter by which errors will be reported |
| */ |
| public ConstantVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary, |
| TypeProvider typeProvider) { |
| this.errorReporter = errorReporter; |
| this.currentLibrary = currentLibrary; |
| this.typeProvider = typeProvider; |
| this.boolType = typeProvider.getBoolType(); |
| this.intType = typeProvider.getIntType(); |
| this.numType = typeProvider.getNumType(); |
| this.stringType = typeProvider.getStringType(); |
| } |
| |
| @Override |
| public Void visitAnnotation(Annotation node) { |
| super.visitAnnotation(node); |
| // check annotation creation |
| Element element = node.getElement(); |
| if (element instanceof ConstructorElement) { |
| ConstructorElement constructorElement = (ConstructorElement) element; |
| // should 'const' constructor |
| if (!constructorElement.isConst()) { |
| errorReporter.reportErrorForNode( |
| CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, |
| node); |
| return null; |
| } |
| // should have arguments |
| ArgumentList argumentList = node.getArguments(); |
| if (argumentList == null) { |
| errorReporter.reportErrorForNode( |
| CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, |
| node); |
| return null; |
| } |
| // arguments should be constants |
| validateConstantArguments(argumentList); |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitConstructorDeclaration(ConstructorDeclaration node) { |
| if (node.getConstKeyword() != null) { |
| validateConstructorInitializers(node); |
| validateFieldInitializers((ClassDeclaration) node.getParent(), node); |
| } |
| validateDefaultValues(node.getParameters()); |
| return super.visitConstructorDeclaration(node); |
| } |
| |
| @Override |
| public Void visitFunctionExpression(FunctionExpression node) { |
| super.visitFunctionExpression(node); |
| validateDefaultValues(node.getParameters()); |
| return null; |
| } |
| |
| @Override |
| public Void visitInstanceCreationExpression(InstanceCreationExpression node) { |
| if (node.isConst()) { |
| EvaluationResultImpl evaluationResult = node.getEvaluationResult(); |
| // Note: evaluationResult might be null if there are circular references among constants. |
| if (evaluationResult != null) { |
| reportErrors(evaluationResult.getErrors(), null); |
| } |
| } |
| validateInstanceCreationArguments(node); |
| return super.visitInstanceCreationExpression(node); |
| } |
| |
| @Override |
| public Void visitListLiteral(ListLiteral node) { |
| super.visitListLiteral(node); |
| if (node.getConstKeyword() != null) { |
| DartObjectImpl result; |
| for (Expression element : node.getElements()) { |
| result = validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT); |
| if (result != null) { |
| reportErrorIfFromDeferredLibrary( |
| element, |
| CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY); |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitMapLiteral(MapLiteral node) { |
| super.visitMapLiteral(node); |
| boolean isConst = node.getConstKeyword() != null; |
| boolean reportEqualKeys = true; |
| HashSet<DartObject> keys = new HashSet<DartObject>(); |
| ArrayList<Expression> invalidKeys = new ArrayList<Expression>(); |
| for (MapLiteralEntry entry : node.getEntries()) { |
| Expression key = entry.getKey(); |
| if (isConst) { |
| DartObjectImpl keyResult = validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY); |
| Expression valueExpression = entry.getValue(); |
| DartObjectImpl valueResult = validate( |
| valueExpression, |
| CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE); |
| if (valueResult != null) { |
| reportErrorIfFromDeferredLibrary( |
| valueExpression, |
| CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY); |
| } |
| if (keyResult != null) { |
| reportErrorIfFromDeferredLibrary( |
| key, |
| CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY); |
| if (keys.contains(keyResult)) { |
| invalidKeys.add(key); |
| } else { |
| keys.add(keyResult); |
| } |
| Type type = keyResult.getType(); |
| if (implementsEqualsWhenNotAllowed(type)) { |
| errorReporter.reportErrorForNode( |
| CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, |
| key, |
| type.getDisplayName()); |
| } |
| } |
| } else { |
| // Note: we throw the errors away because this isn't actually a const. |
| BooleanErrorListener errorListener = new BooleanErrorListener(); |
| ErrorReporter subErrorReporter = new ErrorReporter(errorListener, errorReporter.getSource()); |
| DartObjectImpl result = key.accept(new ConstantVisitor(typeProvider, subErrorReporter)); |
| if (result != null) { |
| if (keys.contains(result)) { |
| invalidKeys.add(key); |
| } else { |
| keys.add(result); |
| } |
| } else { |
| reportEqualKeys = false; |
| } |
| } |
| } |
| if (reportEqualKeys) { |
| for (Expression key : invalidKeys) { |
| errorReporter.reportErrorForNode(StaticWarningCode.EQUAL_KEYS_IN_MAP, key); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitMethodDeclaration(MethodDeclaration node) { |
| super.visitMethodDeclaration(node); |
| validateDefaultValues(node.getParameters()); |
| return null; |
| } |
| |
| @Override |
| public Void visitSwitchStatement(SwitchStatement node) { |
| // TODO(paulberry): to minimize error messages, it would be nice to |
| // compare all types with the most popular type rather than the first |
| // type. |
| NodeList<SwitchMember> switchMembers = node.getMembers(); |
| boolean foundError = false; |
| Type firstType = null; |
| for (SwitchMember switchMember : switchMembers) { |
| if (switchMember instanceof SwitchCase) { |
| SwitchCase switchCase = (SwitchCase) switchMember; |
| Expression expression = switchCase.getExpression(); |
| DartObjectImpl caseResult = validate( |
| expression, |
| CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION); |
| if (caseResult != null) { |
| reportErrorIfFromDeferredLibrary( |
| expression, |
| CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY); |
| DartObject value = caseResult; |
| if (firstType == null) { |
| firstType = value.getType(); |
| } else { |
| Type nType = value.getType(); |
| if (!firstType.equals(nType)) { |
| errorReporter.reportErrorForNode( |
| CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, |
| expression, |
| expression.toSource(), |
| firstType.getDisplayName()); |
| foundError = true; |
| } |
| } |
| } |
| } |
| } |
| if (!foundError) { |
| checkForCaseExpressionTypeImplementsEquals(node, firstType); |
| } |
| return super.visitSwitchStatement(node); |
| } |
| |
| @Override |
| public Void visitVariableDeclaration(VariableDeclaration node) { |
| super.visitVariableDeclaration(node); |
| Expression initializer = node.getInitializer(); |
| if (initializer != null && node.isConst()) { |
| VariableElementImpl element = (VariableElementImpl) node.getElement(); |
| EvaluationResultImpl result = element.getEvaluationResult(); |
| if (result == null) { |
| // |
| // Normally we don't need to visit const variable declarations because we have already |
| // computed their values. But if we missed it for some reason, this gives us a second |
| // chance. |
| // |
| result = new EvaluationResultImpl(validate( |
| initializer, |
| CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE)); |
| element.setEvaluationResult(result); |
| return null; |
| } else if (result.getValue() == null) { |
| // TODO(paulberry): report errors even if valid result. |
| reportErrors( |
| result.getErrors(), |
| CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE); |
| return null; |
| } |
| reportErrorIfFromDeferredLibrary( |
| initializer, |
| CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY); |
| } |
| return null; |
| } |
| |
| /** |
| * This verifies that the passed switch statement does not have a case expression with the |
| * operator '==' overridden. |
| * |
| * @param node the switch statement to evaluate |
| * @param type the common type of all 'case' expressions |
| * @return {@code true} if and only if an error code is generated on the passed node |
| * @see CompileTimeErrorCode#CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS |
| */ |
| private boolean checkForCaseExpressionTypeImplementsEquals(SwitchStatement node, Type type) { |
| if (!implementsEqualsWhenNotAllowed(type)) { |
| return false; |
| } |
| // report error |
| errorReporter.reportErrorForToken( |
| CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, |
| node.getKeyword(), |
| type.getDisplayName()); |
| return true; |
| } |
| |
| /** |
| * @return {@code true} if given {@link Type} implements operator <i>==</i>, and it is not |
| * <i>int</i> or <i>String</i>. |
| */ |
| private boolean implementsEqualsWhenNotAllowed(Type type) { |
| // ignore int or String |
| if (type == null || type.equals(intType) || type.equals(typeProvider.getStringType())) { |
| return false; |
| } else if (type.equals(typeProvider.getDoubleType())) { |
| return true; |
| } |
| // prepare ClassElement |
| Element element = type.getElement(); |
| if (!(element instanceof ClassElement)) { |
| return false; |
| } |
| ClassElement classElement = (ClassElement) element; |
| // lookup for == |
| MethodElement method = classElement.lookUpConcreteMethod("==", currentLibrary); |
| if (method == null || method.getEnclosingElement().getType().isObject()) { |
| return false; |
| } |
| // there is == that we don't like |
| return true; |
| } |
| |
| /** |
| * Given some computed {@link Expression}, this method generates the passed {@link ErrorCode} on |
| * the node if its' value consists of information from a deferred library. |
| * |
| * @param expression the expression to be tested for a deferred library reference |
| * @param errorCode the error code to be used if the expression is or consists of a reference to a |
| * deferred library |
| */ |
| private void reportErrorIfFromDeferredLibrary(Expression expression, ErrorCode errorCode) { |
| DeferredLibraryReferenceDetector referenceDetector = new DeferredLibraryReferenceDetector(); |
| expression.accept(referenceDetector); |
| if (referenceDetector.getResult()) { |
| errorReporter.reportErrorForNode(errorCode, expression); |
| } |
| } |
| |
| /** |
| * Report any errors in the given list. Except for special cases, use the given error code rather |
| * than the one reported in the error. |
| * |
| * @param errors the errors that need to be reported |
| * @param errorCode the error code to be used |
| */ |
| private void reportErrors(AnalysisError[] errors, ErrorCode errorCode) { |
| for (AnalysisError data : errors) { |
| ErrorCode dataErrorCode = data.getErrorCode(); |
| if (dataErrorCode == CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION |
| || dataErrorCode == CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE |
| || dataErrorCode == CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING |
| || dataErrorCode == CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL |
| || dataErrorCode == CompileTimeErrorCode.CONST_EVAL_TYPE_INT |
| || dataErrorCode == CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) { |
| errorReporter.reportError(data); |
| } else if (errorCode != null) { |
| errorReporter.reportError(new AnalysisError( |
| data.getSource(), |
| data.getOffset(), |
| data.getLength(), |
| errorCode)); |
| } |
| } |
| } |
| |
| /** |
| * Validate that the given expression is a compile time constant. Return the value of the compile |
| * time constant, or {@code null} if the expression is not a compile time constant. |
| * |
| * @param expression the expression to be validated |
| * @param errorCode the error code to be used if the expression is not a compile time constant |
| * @return the value of the compile time constant |
| */ |
| private DartObjectImpl validate(Expression expression, ErrorCode errorCode) { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| ErrorReporter subErrorReporter = new ErrorReporter(errorListener, errorReporter.getSource()); |
| DartObjectImpl result = expression.accept(new ConstantVisitor(typeProvider, subErrorReporter)); |
| reportErrors(errorListener.getErrors(), errorCode); |
| return result; |
| } |
| |
| /** |
| * Validate that if the passed arguments are constant expressions. |
| * |
| * @param argumentList the argument list to evaluate |
| */ |
| private void validateConstantArguments(ArgumentList argumentList) { |
| for (Expression argument : argumentList.getArguments()) { |
| if (argument instanceof NamedExpression) { |
| argument = ((NamedExpression) argument).getExpression(); |
| } |
| validate(argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT); |
| } |
| } |
| |
| /** |
| * Validates that the expressions of the given initializers (of a constant constructor) are all |
| * compile time constants. |
| * |
| * @param constructor the constant constructor declaration to validate |
| */ |
| private void validateConstructorInitializers(ConstructorDeclaration constructor) { |
| ParameterElement[] parameterElements = constructor.getParameters().getParameterElements(); |
| NodeList<ConstructorInitializer> initializers = constructor.getInitializers(); |
| for (ConstructorInitializer initializer : initializers) { |
| if (initializer instanceof ConstructorFieldInitializer) { |
| ConstructorFieldInitializer fieldInitializer = (ConstructorFieldInitializer) initializer; |
| validateInitializerExpression(parameterElements, fieldInitializer.getExpression()); |
| } |
| if (initializer instanceof RedirectingConstructorInvocation) { |
| RedirectingConstructorInvocation invocation = (RedirectingConstructorInvocation) initializer; |
| validateInitializerInvocationArguments(parameterElements, invocation.getArgumentList()); |
| } |
| if (initializer instanceof SuperConstructorInvocation) { |
| SuperConstructorInvocation invocation = (SuperConstructorInvocation) initializer; |
| validateInitializerInvocationArguments(parameterElements, invocation.getArgumentList()); |
| } |
| } |
| } |
| |
| /** |
| * Validate that the default value associated with each of the parameters in the given list is a |
| * compile time constant. |
| * |
| * @param parameters the list of parameters to be validated |
| */ |
| private void validateDefaultValues(FormalParameterList parameters) { |
| if (parameters == null) { |
| return; |
| } |
| for (FormalParameter parameter : parameters.getParameters()) { |
| if (parameter instanceof DefaultFormalParameter) { |
| DefaultFormalParameter defaultParameter = (DefaultFormalParameter) parameter; |
| Expression defaultValue = defaultParameter.getDefaultValue(); |
| if (defaultValue != null) { |
| DartObjectImpl result = validate( |
| defaultValue, |
| CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE); |
| VariableElementImpl element = (VariableElementImpl) parameter.getElement(); |
| element.setEvaluationResult(new EvaluationResultImpl(result)); |
| if (result != null) { |
| reportErrorIfFromDeferredLibrary( |
| defaultValue, |
| CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Validates that the expressions of any field initializers in the class declaration are all |
| * compile time constants. Since this is only required if the class has a constant constructor, |
| * the error is reported at the constructor site. |
| * |
| * @param classDeclaration the class which should be validated |
| * @param errorSite the site at which errors should be reported. |
| */ |
| private void validateFieldInitializers(ClassDeclaration classDeclaration, |
| ConstructorDeclaration errorSite) { |
| NodeList<ClassMember> members = classDeclaration.getMembers(); |
| for (ClassMember member : members) { |
| if (member instanceof FieldDeclaration) { |
| FieldDeclaration fieldDeclaration = (FieldDeclaration) member; |
| if (!fieldDeclaration.isStatic()) { |
| for (VariableDeclaration variableDeclaration : fieldDeclaration.getFields().getVariables()) { |
| Expression initializer = variableDeclaration.getInitializer(); |
| if (initializer != null) { |
| // Ignore any errors produced during validation--if the constant can't be eavluated |
| // we'll just report a single error. |
| BooleanErrorListener errorListener = new BooleanErrorListener(); |
| ErrorReporter subErrorReporter = new ErrorReporter( |
| errorListener, |
| errorReporter.getSource()); |
| DartObjectImpl result = initializer.accept(new ConstantVisitor( |
| typeProvider, |
| subErrorReporter)); |
| if (result == null) { |
| errorReporter.reportErrorForNode( |
| CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST, |
| errorSite, |
| variableDeclaration.getName().getName()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Validates that the given expression is a compile time constant. |
| * |
| * @param parameterElements the elements of parameters of constant constructor, they are |
| * considered as a valid potentially constant expressions |
| * @param expression the expression to validate |
| */ |
| private void validateInitializerExpression(final ParameterElement[] parameterElements, |
| Expression expression) { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| ErrorReporter subErrorReporter = new ErrorReporter(errorListener, errorReporter.getSource()); |
| DartObjectImpl result = expression.accept(new ConstantVisitor(typeProvider, subErrorReporter) { |
| @Override |
| public DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { |
| Element element = node.getStaticElement(); |
| for (ParameterElement parameterElement : parameterElements) { |
| if (parameterElement == element && parameterElement != null) { |
| Type type = parameterElement.getType(); |
| if (type != null) { |
| if (type.isDynamic()) { |
| return new DartObjectImpl(typeProvider.getObjectType(), DynamicState.DYNAMIC_STATE); |
| } else if (type.isSubtypeOf(boolType)) { |
| return new DartObjectImpl(typeProvider.getBoolType(), BoolState.UNKNOWN_VALUE); |
| } else if (type.isSubtypeOf(typeProvider.getDoubleType())) { |
| return new DartObjectImpl(typeProvider.getDoubleType(), DoubleState.UNKNOWN_VALUE); |
| } else if (type.isSubtypeOf(intType)) { |
| return new DartObjectImpl(typeProvider.getIntType(), IntState.UNKNOWN_VALUE); |
| } else if (type.isSubtypeOf(numType)) { |
| return new DartObjectImpl(typeProvider.getNumType(), NumState.UNKNOWN_VALUE); |
| } else if (type.isSubtypeOf(stringType)) { |
| return new DartObjectImpl(typeProvider.getStringType(), StringState.UNKNOWN_VALUE); |
| } |
| // |
| // We don't test for other types of objects (such as List, Map, Function or Type) |
| // because there are no operations allowed on such types other than '==' and '!=', |
| // which means that we don't need to know the type when there is no specific data |
| // about the state of such objects. |
| // |
| } |
| return new DartObjectImpl(type instanceof InterfaceType ? (InterfaceType) type |
| : typeProvider.getObjectType(), GenericState.UNKNOWN_VALUE); |
| } |
| } |
| return super.visitSimpleIdentifier(node); |
| } |
| }); |
| reportErrors(errorListener.getErrors(), CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER); |
| if (result != null) { |
| reportErrorIfFromDeferredLibrary( |
| expression, |
| CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY); |
| } |
| } |
| |
| /** |
| * Validates that all of the arguments of a constructor initializer are compile time constants. |
| * |
| * @param parameterElements the elements of parameters of constant constructor, they are |
| * considered as a valid potentially constant expressions |
| * @param argumentList the argument list to validate |
| */ |
| private void validateInitializerInvocationArguments(ParameterElement[] parameterElements, |
| ArgumentList argumentList) { |
| if (argumentList == null) { |
| return; |
| } |
| for (Expression argument : argumentList.getArguments()) { |
| validateInitializerExpression(parameterElements, argument); |
| } |
| } |
| |
| /** |
| * Validate that if the passed instance creation is 'const' then all its arguments are constant |
| * expressions. |
| * |
| * @param node the instance creation evaluate |
| */ |
| private void validateInstanceCreationArguments(InstanceCreationExpression node) { |
| if (!node.isConst()) { |
| return; |
| } |
| ArgumentList argumentList = node.getArgumentList(); |
| if (argumentList == null) { |
| return; |
| } |
| validateConstantArguments(argumentList); |
| } |
| } |