/******************************************************************************* * Copyright © 2012, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.compiler.internal.core.validation; import java.util.HashMap; import java.util.Map; import org.eclipse.core.resources.IMarker; import org.eclipse.edt.compiler.binding.IPartBinding; import org.eclipse.edt.compiler.core.IEGLConstants; import org.eclipse.edt.compiler.core.ast.AbstractASTExpressionVisitor; import org.eclipse.edt.compiler.core.ast.AbstractASTVisitor; import org.eclipse.edt.compiler.core.ast.AnnotationExpression; import org.eclipse.edt.compiler.core.ast.ArrayAccess; import org.eclipse.edt.compiler.core.ast.ArrayType; import org.eclipse.edt.compiler.core.ast.AsExpression; import org.eclipse.edt.compiler.core.ast.Assignment; import org.eclipse.edt.compiler.core.ast.BinaryExpression; import org.eclipse.edt.compiler.core.ast.BytesLiteral; import org.eclipse.edt.compiler.core.ast.CallStatement; import org.eclipse.edt.compiler.core.ast.ClassDataDeclaration; import org.eclipse.edt.compiler.core.ast.DecimalLiteral; import org.eclipse.edt.compiler.core.ast.Expression; import org.eclipse.edt.compiler.core.ast.FieldAccess; import org.eclipse.edt.compiler.core.ast.FloatLiteral; import org.eclipse.edt.compiler.core.ast.FunctionDataDeclaration; import org.eclipse.edt.compiler.core.ast.FunctionInvocation; import org.eclipse.edt.compiler.core.ast.FunctionInvocationStatement; import org.eclipse.edt.compiler.core.ast.IntegerLiteral; import org.eclipse.edt.compiler.core.ast.IsAExpression; import org.eclipse.edt.compiler.core.ast.IsNotExpression; import org.eclipse.edt.compiler.core.ast.LiteralExpression; import org.eclipse.edt.compiler.core.ast.NameType; import org.eclipse.edt.compiler.core.ast.NewExpression; import org.eclipse.edt.compiler.core.ast.Node; import org.eclipse.edt.compiler.core.ast.ParenthesizedExpression; import org.eclipse.edt.compiler.core.ast.QualifiedName; import org.eclipse.edt.compiler.core.ast.SetValuesExpression; import org.eclipse.edt.compiler.core.ast.SettingsBlock; import org.eclipse.edt.compiler.core.ast.SubstringAccess; import org.eclipse.edt.compiler.core.ast.SuperExpression; import org.eclipse.edt.compiler.core.ast.ThisExpression; import org.eclipse.edt.compiler.core.ast.UnaryExpression; import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor; import org.eclipse.edt.compiler.internal.core.lookup.DefaultBinder; import org.eclipse.edt.compiler.internal.core.lookup.FunctionArgumentValidator; import org.eclipse.edt.compiler.internal.core.lookup.ICompilerOptions; import org.eclipse.edt.compiler.internal.core.validation.part.FunctionContainerValidator; import org.eclipse.edt.compiler.internal.core.validation.statement.AssignmentStatementValidator; import org.eclipse.edt.compiler.internal.core.validation.type.TypeValidator; import org.eclipse.edt.compiler.internal.util.BindingUtil; import org.eclipse.edt.mof.egl.AnnotationType; import org.eclipse.edt.mof.egl.Delegate; import org.eclipse.edt.mof.egl.FixedPrecisionType; import org.eclipse.edt.mof.egl.Function; import org.eclipse.edt.mof.egl.FunctionMember; import org.eclipse.edt.mof.egl.Member; import org.eclipse.edt.mof.egl.NamedElement; import org.eclipse.edt.mof.egl.Operation; import org.eclipse.edt.mof.egl.Type; import org.eclipse.edt.mof.egl.utils.IRUtils; import org.eclipse.edt.mof.egl.utils.TypeUtils; public class ExpressionValidator extends AbstractASTVisitor { IPartBinding declaringPart; IProblemRequestor problemRequestor; ICompilerOptions compilerOptions; public ExpressionValidator(IPartBinding declaringPart, IProblemRequestor problemRequestor, ICompilerOptions compilerOptions) { this.declaringPart = declaringPart; this.problemRequestor = problemRequestor; this.compilerOptions = compilerOptions; } @Override public void endVisit(BinaryExpression binaryExpression) { // Both the lhs and the rhs can be a ternary expression, in which case both of the ternary's possible results must be checked // against the other side. Map<Expression, Type> lhsMap = new HashMap<Expression, Type>(); Map<Expression, Type> rhsMap = new HashMap<Expression, Type>(); TypeValidator.collectExprsForTypeCompatibility(binaryExpression.getFirstExpression(), lhsMap); TypeValidator.collectExprsForTypeCompatibility(binaryExpression.getSecondExpression(), rhsMap); for (Map.Entry<Expression, Type> lhsEntry : lhsMap.entrySet()) { NamedElement lhsElement = DefaultBinder.getOperandType(lhsEntry.getKey()); if (lhsElement != null) { for (Map.Entry<Expression, Type> rhsEntry : rhsMap.entrySet()) { NamedElement rhsElement = DefaultBinder.getOperandType(rhsEntry.getKey()); if (rhsElement != null) { Operation op = IRUtils.getBinaryOperation(lhsElement, rhsElement, binaryExpression.getOperator().toString()); if (op != null) { // If the parameters are generic, we need to validate the arg type vs the resolved parm type. Expression errorNode = null; // The type that we resolve with is whichever type defined the operation. This could be the lhs or the rhs (array :: mystring, or mystring :: array). Type resolvingType = lhsEntry.getValue(); if (resolvingType == null || resolvingType.getClassifier() == null || !resolvingType.getClassifier().equals(op.getType().getClassifier())) { resolvingType = rhsEntry.getValue(); } if (BindingUtil.isUnresolvedGenericType(op.getParameters().get(0).getType())) { Type t = BindingUtil.resolveGenericType(op.getParameters().get(0).getType(), resolvingType); if (!BindingUtil.isMoveCompatible(t, op.getParameters().get(0), lhsEntry.getValue(), lhsEntry.getKey())) { errorNode = lhsEntry.getKey(); } } if (errorNode == null && BindingUtil.isUnresolvedGenericType(op.getParameters().get(1).getType())) { Type t = BindingUtil.resolveGenericType(op.getParameters().get(1).getType(), resolvingType); if (!BindingUtil.isMoveCompatible(t, op.getParameters().get(1), rhsEntry.getValue(), rhsEntry.getKey())) { errorNode = rhsEntry.getKey(); } } if (errorNode != null) { problemRequestor.acceptProblem(errorNode, IProblemRequestor.ASSIGNMENT_STATEMENT_TYPE_MISMATCH, new String[]{ BindingUtil.getShortTypeString(lhsEntry.getKey(), lhsEntry.getValue()), BindingUtil.getShortTypeString(rhsEntry.getKey(), rhsEntry.getValue()), lhsEntry.getKey().getCanonicalString() + " " + binaryExpression.getOperator().toString() + " " + rhsEntry.getKey().getCanonicalString()}); } } else { problemRequestor.acceptProblem(lhsEntry.getKey(), IProblemRequestor.MISSING_OPERATION_FOR_BINARY_EXPRESSION, new String[]{ lhsEntry.getKey().getCanonicalString(), rhsEntry.getKey().getCanonicalString(), binaryExpression.getOperator().toString(), lhsEntry.getKey().getCanonicalString() + " " + binaryExpression.getOperator().toString() + " " + rhsEntry.getKey().getCanonicalString()}); } } } } } } @Override public void endVisit(UnaryExpression unaryExpression) { Expression operand = unaryExpression.getExpression(); Type operandType = operand.resolveType(); if (operandType != null) { Operation op = IRUtils.getUnaryOperation(operandType.getClassifier(), unaryExpression.getOperator().toString()); if (op == null) { problemRequestor.acceptProblem(operand, IProblemRequestor.MISSING_OPERATION_FOR_UNARY_EXPRESSION, new String[] {operand.getCanonicalString(), unaryExpression.getOperator().toString()}); } } } @Override public void endVisit(final NewExpression newExpression) { org.eclipse.edt.compiler.core.ast.Type type = newExpression.getType(); if (type.resolveType() == null) { return; } TypeValidator.validate(type, declaringPart, problemRequestor, compilerOptions); if (type.isArrayType()) { ArrayType arrayType = (ArrayType)type; // When it's an array and not of initial size 0, the root type must be instantiable. if (arrayType.hasInitialSize() && !BindingUtil.isZeroLiteral(arrayType.getInitialSize())) { // For multidim arrays, the inner-most ArrayType will contain the nullable flag for the root type (e.g. int?[][][]). ArrayType innerArrayType = arrayType; while (innerArrayType.getElementType().isArrayType()) { innerArrayType = (ArrayType)innerArrayType.getElementType(); } TypeValidator.validateInstantiatable(arrayType.getBaseType(), declaringPart, innerArrayType.isNullable(), problemRequestor); } // Initial size must not be negative. final boolean[] hasInitialSize = new boolean[1]; newExpression.getType().accept(new AbstractASTVisitor() { @Override public boolean visit(ArrayType arrayType) { if (arrayType.hasInitialSize()) { Map<Expression, Type> exprMap = new HashMap<Expression, Type>(); TypeValidator.collectExprsForTypeCompatibility(arrayType.getInitialSize(), exprMap); for (Map.Entry<Expression, Type> entry : exprMap.entrySet()) { Type tBinding = entry.getValue(); if (tBinding != null) { if (!IRUtils.isMoveCompatible(TypeUtils.Type_INT, tBinding, entry.getKey().resolveMember())) { problemRequestor.acceptProblem( arrayType.getInitialSize(), IProblemRequestor.ARRAY_SIZE_LESS_THAN_ZERO, new String[] {arrayType.getInitialSize().getCanonicalString()}); } } } } return true; } }); if (hasInitialSize[0] && newExpression.hasSettingsBlock()) { //Disallow a new expression for an array that specifies an initial size and specifies entries in a settings block: //new int[5] {1,2,3} final Node[] errorNode = new Node[1]; newExpression.getSettingsBlock().accept(new AbstractASTExpressionVisitor() { @Override public boolean visit(Assignment assignment) { return false; } @Override public boolean visit(AnnotationExpression annotationExpression) { return false; } @Override public boolean visit(SetValuesExpression setValuesExpression) { return false; } @Override public boolean visitExpression(Expression expression) { if (errorNode[0] != null) { return false; } errorNode[0] = expression; return false; } }); if (errorNode[0] != null) { problemRequestor.acceptProblem(errorNode[0],IProblemRequestor.POSITIONAL_PROPERTY_NOT_ALLOWED_WITH_INITIAL_SIZE, IMarker.SEVERITY_ERROR, new String[] {}); } } } else if (type.isNameType()) { // If there were arguments then the binder already validated they were valid for a public constructor. // No arguments means we need to make sure it can be instantiated. if (!((NameType)type).hasArguments()) { TypeValidator.validateInstantiatable(type, declaringPart, false, problemRequestor); } } if (newExpression.hasSettingsBlock()) { validateSettings(newExpression.getSettingsBlock(), newExpression); } } private void validateSettings(SettingsBlock settings, final Expression expr) { final Type[] arrayElementType = {null}; if (expr.resolveType() instanceof org.eclipse.edt.mof.egl.ArrayType) { arrayElementType[0] = ((org.eclipse.edt.mof.egl.ArrayType)expr.resolveType()).getElementType(); } settings.accept(new AbstractASTExpressionVisitor() { @Override public boolean visit(Assignment assignment) { validateAssignment(assignment); return false; } @Override public boolean visit(SetValuesExpression setValuesExpression) { // SVE is allowed in this location, and is validated in its own endVisit method. return false; } @Override public boolean visit(AnnotationExpression annotationExpression) { // Annotations are allowed in this location, and are validated elsewhere. return false; } @Override public boolean visitExpression(Expression expression) { // Arrays allow "new array[]{element1, element2}" so we need to validate the elements against the array's element type. if (arrayElementType[0] != null) { Type exprType = expression.resolveType(); if (!BindingUtil.isMoveCompatible(arrayElementType[0], null, exprType, expression)) { // Nullability comes from the array qualifier. Check it when the value is null. if (!TypeUtils.Type_NULLTYPE.equals(exprType) || !((org.eclipse.edt.mof.egl.ArrayType)expr.resolveType()).elementsNullable()) { problemRequestor.acceptProblem(expression, IProblemRequestor.ASSIGNMENT_STATEMENT_TYPE_MISMATCH, new String[] { BindingUtil.getShortTypeString(arrayElementType[0]), exprType != null ? BindingUtil.getShortTypeString(exprType) : expression.getCanonicalString(), expr.getCanonicalString() + ".appendElement(" + expression.getCanonicalString() + ")"}); } } } else { problemRequestor.acceptProblem(expression, IProblemRequestor.EXPR_INVALID_IN_THIS_LOCATION, new String[]{expression.getCanonicalString()}); } return false; } }); } @Override public void endVisit(FunctionInvocation functionInvocation) { Expression target = functionInvocation.getTarget(); Object element = null; Type returnType = null; if (target.resolveElement() instanceof FunctionMember) { element = target.resolveElement(); returnType = ((FunctionMember)element).getType(); } else if (target.resolveType() instanceof Delegate) { element = target.resolveType(); returnType = ((Delegate)element).getReturnType(); } if (element == null && (target instanceof ThisExpression || target instanceof SuperExpression)) { // Will be set on the invocation, not the target. element = functionInvocation.resolveElement(); if (element instanceof FunctionMember) { returnType = ((FunctionMember)element).getReturnType(); } } if (element instanceof FunctionMember || element instanceof Delegate) { // returnType is required when the invocation is not part of a FunctionInvocationStatement ("voidFunc();" good, "x int = voidFunc();" bad). if (returnType == null && !(functionInvocation.getParent() instanceof FunctionInvocationStatement)) { problemRequestor.acceptProblem( functionInvocation, IProblemRequestor.FUNCTION_MUST_RETURN_TYPE, new String[] {target.getCanonicalString()}); } if (element instanceof Delegate) { functionInvocation.accept(new FunctionArgumentValidator((Delegate)element, problemRequestor, compilerOptions)); } else if (element instanceof FunctionMember) { functionInvocation.accept(new FunctionArgumentValidator((FunctionMember)element, problemRequestor, compilerOptions)); } } else if (element != null) { problemRequestor.acceptProblem( target, IProblemRequestor.FUNCTION_INVOCATION_TARGET_NOT_FUNCTION_OR_DELEGATE); } if (target instanceof FieldAccess && ((FieldAccess)target).getPrimary() instanceof SuperExpression && element instanceof FunctionMember) { if (((FunctionMember)element).isAbstract()) { //Cannot invoke super.f1() if the super's function is abstract! problemRequestor.acceptProblem( target, IProblemRequestor.CANNOT_INVOKE_ABSTRACT_FUNCTION, new String[] {((FunctionMember)element).getCaseSensitiveName(), ((NamedElement)((FunctionMember)element).getContainer()).getCaseSensitiveName()}); } } } @Override public void endVisit(final SetValuesExpression setValuesExpression) { if (!(setValuesExpression.getExpression() instanceof AnnotationExpression)) { validateSettings(setValuesExpression.getSettingsBlock(), setValuesExpression.getExpression()); } if (setValuesExpression.getExpression().resolveType() instanceof Delegate || setValuesExpression.getExpression().resolveMember() instanceof FunctionMember) { problemRequestor.acceptProblem( setValuesExpression.getSettingsBlock(), IProblemRequestor.SETTINGS_BLOCK_NOT_ALLOWED, new String[] {}); } } @Override public void endVisit(final ClassDataDeclaration classDataDeclaration) { if (classDataDeclaration.hasSettingsBlock()) { validateSettings(classDataDeclaration.getSettingsBlockOpt(), classDataDeclaration.getNames().get(0)); } } @Override public void endVisit(final FunctionDataDeclaration functionDataDeclaration) { if (functionDataDeclaration.hasSettingsBlock()) { validateSettings(functionDataDeclaration.getSettingsBlockOpt(), functionDataDeclaration.getNames().get(0)); } } private void validateAssignment(Assignment assignment) { Expression leftHandSide = assignment.getLeftHandSide(); Expression rightHandSide = assignment.getRightHandSide(); Type lhsType = leftHandSide.resolveType(); if (!(lhsType instanceof AnnotationType)) { new AssignmentStatementValidator(problemRequestor, compilerOptions, declaringPart).validateAssignment( assignment.getOperator(), leftHandSide, rightHandSide, lhsType, rightHandSide.resolveType(), leftHandSide.resolveMember(), rightHandSide.resolveMember()); } } @Override public void endVisit(IsAExpression isAExpression) { checkTypeForIsaOrAs(isAExpression.getType()); } @Override public void endVisit(AsExpression asExpression) { if (asExpression.hasType()) { checkTypeForIsaOrAs(asExpression.getType()); Type toType = asExpression.getType().resolveType(); if (toType != null) { Map<Expression, Type> exprMap = new HashMap<Expression, Type>(); TypeValidator.collectExprsForTypeCompatibility(asExpression.getExpression(), exprMap); for (Map.Entry<Expression, Type> entry : exprMap.entrySet()) { if (entry.getValue() != null) { if (!BindingUtil.isMoveCompatible(toType, null, entry.getValue(), entry.getKey())) { problemRequestor.acceptProblem( entry.getKey(), IProblemRequestor.ASSIGNMENT_STATEMENT_TYPE_MISMATCH, new String[] { BindingUtil.getShortTypeString(entry.getKey(), entry.getValue()), BindingUtil.getShortTypeString(toType, true), entry.getKey().getCanonicalString() + " as " + asExpression.getType().getCanonicalName() }); } } } } } } private void checkTypeForIsaOrAs(org.eclipse.edt.compiler.core.ast.Type type) { TypeValidator.validate(type, declaringPart, problemRequestor, compilerOptions); org.eclipse.edt.compiler.core.ast.Type tempType = type; while (tempType.isArrayType()) { if (((ArrayType)tempType).hasInitialSize()) { problemRequestor.acceptProblem( ((ArrayType)tempType).getInitialSize(), IProblemRequestor.ARRAY_SIZE_NOT_ALLOWED_IN_ISA_OR_AS); } tempType = ((ArrayType)tempType).getElementType(); } } @Override public void endVisit(IntegerLiteral integerLiteral) { String strVal = getSign(integerLiteral.getParent(), false) + integerLiteral.getValue(); if (integerLiteral.getLiteralKind() == LiteralExpression.BIGINT_LITERAL) { try { Long.parseLong(strVal, 10); } catch (NumberFormatException nfe) { problemRequestor.acceptProblem( integerLiteral, IProblemRequestor.BIGINT_LITERAL_OUT_OF_RANGE, new String[] {strVal}); } } else if (integerLiteral.getLiteralKind() == LiteralExpression.SMALLINT_LITERAL) { try { Short.parseShort(strVal, 10); } catch (NumberFormatException nfe) { problemRequestor.acceptProblem( integerLiteral, IProblemRequestor.SMALLINT_LITERAL_OUT_OF_RANGE, new String[] {strVal}); } } else { try { Integer.parseInt(strVal, 10); } catch (NumberFormatException nfe) { problemRequestor.acceptProblem( integerLiteral, IProblemRequestor.INTEGER_LITERAL_OUT_OF_RANGE, new String[] {strVal}); } } } @Override public void endVisit(DecimalLiteral decimalLiteral) { String strVal = decimalLiteral.getValue(); if (strVal.length() > (strVal.indexOf('.') == -1 ? 32 : 33)) { problemRequestor.acceptProblem( decimalLiteral, IProblemRequestor.DECIMAL_LITERAL_OUT_OF_RANGE, new String[] {strVal}); } } @Override public void endVisit(FloatLiteral floatLiteral) { try { if (floatLiteral.getLiteralKind() == LiteralExpression.SMALLFLOAT_LITERAL) { String strVal = floatLiteral.getValue(); if (Float.isInfinite(Float.parseFloat(strVal))) { problemRequestor.acceptProblem( floatLiteral, IProblemRequestor.SMALLFLOAT_LITERAL_OUT_OF_RANGE, new String[] { strVal }); } } else { String strVal = floatLiteral.getValue(); if (Double.isInfinite(Double.parseDouble(strVal))) { problemRequestor.acceptProblem( floatLiteral, IProblemRequestor.FLOATING_POINT_LITERAL_OUT_OF_RANGE, new String[] { strVal }); } } } catch( NumberFormatException e ) { // should be syntax error, so ignore } } @Override public void endVisit(BytesLiteral bytesLiteral) { if (bytesLiteral.getValue().length() % 2 != 0) { problemRequestor.acceptProblem(bytesLiteral, IProblemRequestor.BYTES_LITERAL_LENGTH_MUST_BE_EVEN, new String[] {bytesLiteral.getCanonicalString()}); } } @Override public void endVisit(IsNotExpression isNotExpression) { problemRequestor.acceptProblem( isNotExpression, IProblemRequestor.IS_NOT_UNSUPPORTED, new String[] {}); } private String getSign(Node node, boolean hasNegativeSign) { if (node instanceof ParenthesizedExpression) { return getSign(node.getParent(), hasNegativeSign); } if (node instanceof UnaryExpression) { UnaryExpression unary = (UnaryExpression) node; if (unary.getOperator() == UnaryExpression.Operator.MINUS) { return getSign(unary.getParent(), !hasNegativeSign); } else { if (unary.getOperator() == UnaryExpression.Operator.PLUS) { return getSign(unary.getParent(), hasNegativeSign); } } } if (hasNegativeSign) { return "-"; } return ""; } @Override public void endVisit(SubstringAccess substringAccess) { org.eclipse.edt.mof.egl.Type type = substringAccess.getPrimary().resolveType(); if (type != null) { Operation op = IRUtils.getOperation(type.getClassifier(), Operation.SUBSTRING); if (op == null) { problemRequestor.acceptProblem(substringAccess, IProblemRequestor.MISSING_OPERATION_FOR_SUBSTRING, new String[]{substringAccess.getPrimary().getCanonicalString()}); } } checkSubstringIndex(substringAccess.getExpr(), substringAccess); checkSubstringIndex(substringAccess.getExpr2(), substringAccess); } private void checkSubstringIndex(final Expression index, SubstringAccess parentAccess) { Type tBinding = index.resolveType(); if (tBinding != null) { boolean typeIsValid = false; if (TypeUtils.Type_ANY.equals((tBinding)) || TypeUtils.isNumericType(tBinding)) { if (tBinding instanceof FixedPrecisionType) { typeIsValid = ((FixedPrecisionType)tBinding).getDecimals() == 0; } else { typeIsValid = true; } } if (!typeIsValid) { problemRequestor.acceptProblem( index, IProblemRequestor.SUBSTRING_INDEX_NOT_INTEGER, new String[] {index.getCanonicalString(), parentAccess.getCanonicalString()}); } } } @Override public void endVisit(FieldAccess fieldAccess) { if (fieldAccess.getPrimary().resolveType() instanceof org.eclipse.edt.mof.egl.ArrayType && !(fieldAccess.resolveMember() instanceof FunctionMember)) { problemRequestor.acceptProblem( fieldAccess.getPrimary(), IProblemRequestor.ARRAY_ACCESS_NOT_SUBSCRIPTED, new String[] {fieldAccess.getPrimary().getCanonicalString()}); } final boolean[] dynamicAccessUsed = {false}; fieldAccess.getPrimary().accept(new AbstractASTVisitor() { @Override public boolean visit(ArrayAccess arrayAccess) { if (arrayAccess.getIndices().size() == 1) { Type indexType = ((Expression) arrayAccess.getIndices().get(0)).resolveType(); if (indexType != null && TypeUtils.isTextType(indexType)) { dynamicAccessUsed[0] = true; } } return true; }; }); if (dynamicAccessUsed[0]) { problemRequestor.acceptProblem(fieldAccess, IProblemRequestor.DOT_ACCESS_USED_AFTER_DYNAMIC); } // Check if we have <type>.<member> - in which case <member> must be static. Object element = fieldAccess.resolveElement(); if (element instanceof Member && !((Member)element).isStatic() && fieldAccess.getPrimary().resolveElement() instanceof Type) { if (element instanceof FunctionMember) { if (!(fieldAccess.getParent() instanceof CallStatement) || fieldAccess != ((CallStatement)fieldAccess.getParent()).getInvocationTarget()) { problemRequestor.acceptProblem(fieldAccess, IProblemRequestor.INVALID_REFERENCE_TO_NONSTATIC_FUNCTION, new String[]{fieldAccess.getCaseSensitiveID() + "(" + FunctionContainerValidator.getTypeNamesList(((FunctionMember)element).getParameters()) + ")"}); } } else { problemRequestor.acceptProblem(fieldAccess, IProblemRequestor.INVALID_REFERENCE_TO_NONSTATIC_FIELD, new String[]{fieldAccess.getCaseSensitiveID()}); } } }; @Override public void endVisit(QualifiedName qualifiedName) { if (qualifiedName.getQualifier().resolveType() instanceof org.eclipse.edt.mof.egl.ArrayType && !(qualifiedName.resolveMember() instanceof Function)) { problemRequestor.acceptProblem( qualifiedName.getQualifier(), IProblemRequestor.ARRAY_ACCESS_NOT_SUBSCRIPTED, new String[] {qualifiedName.getQualifier().getCanonicalName()}); } // Check if we have <type>.<member> - in which case <member> must be static. Object element = qualifiedName.resolveElement(); if (element instanceof Member && !((Member)element).isStatic() && qualifiedName.getQualifier().resolveElement() instanceof Type) { if (element instanceof FunctionMember) { if (!(qualifiedName.getParent() instanceof CallStatement) || qualifiedName != ((CallStatement)qualifiedName.getParent()).getInvocationTarget()) { problemRequestor.acceptProblem(qualifiedName, IProblemRequestor.INVALID_REFERENCE_TO_NONSTATIC_FUNCTION, new String[]{qualifiedName.getCaseSensitiveIdentifier() + "(" + FunctionContainerValidator.getTypeNamesList(((FunctionMember)element).getParameters()) + ")"}); } } else { problemRequestor.acceptProblem(qualifiedName, IProblemRequestor.INVALID_REFERENCE_TO_NONSTATIC_FIELD, new String[]{qualifiedName.getCaseSensitiveIdentifier()}); } } } @Override public void endVisit(org.eclipse.edt.compiler.core.ast.TernaryExpression ternaryExpression) { // The first expr is the condition and must be boolean. Type conditionType = ternaryExpression.getFirstExpr().resolveType(); if (conditionType != null && !conditionType.equals(TypeUtils.Type_BOOLEAN)) { problemRequestor.acceptProblem( ternaryExpression.getFirstExpr(), IProblemRequestor.ASSIGNMENT_STATEMENT_TYPE_MISMATCH, new String[] { BindingUtil.getShortTypeString(conditionType), IEGLConstants.KEYWORD_BOOLEAN, ternaryExpression.getFirstExpr().getCanonicalString() }); } }; @Override public void endVisit(ArrayAccess arrayAccess) { if (arrayAccess.getIndices().size() > 1) { problemRequestor.acceptProblem( arrayAccess, IProblemRequestor.MULTI_INDICES_NOT_SUPPORTED, new String[]{arrayAccess.getCanonicalString()}); } else { Expression index = arrayAccess.getIndices().get(0); Type indexType = index.resolveType(); Type arrayType = arrayAccess.getArray().resolveType(); if (indexType != null) { if (TypeUtils.isTextType(indexType)) { // Dynamic access. if (arrayType != null && !BindingUtil.isDynamicallyAccessible(arrayType)) { problemRequestor.acceptProblem( arrayAccess.getArray(), IProblemRequestor.NON_DYNAMIC_ACCESS_ACCESSED_DYNAMICALLY, new String[]{arrayAccess.getArray().getCanonicalString()}); } } else { // Array access. boolean indexTypeIsValid = false; if (TypeUtils.Type_ANY.equals((indexType)) || TypeUtils.isNumericType(indexType)) { if (indexType instanceof FixedPrecisionType) { indexTypeIsValid = ((FixedPrecisionType)indexType).getDecimals() == 0; } else { indexTypeIsValid = true; } } if (!indexTypeIsValid) { problemRequestor.acceptProblem( index, IProblemRequestor.SUBSCRIPT_MUST_BE_INTEGER_ITEM, new String[] {index.getCanonicalString(), arrayAccess.getCanonicalString()}); } if (arrayType != null && (!TypeUtils.Type_ANY.equals(arrayType) && !(arrayType instanceof org.eclipse.edt.mof.egl.ArrayType))) { problemRequestor.acceptProblem( arrayAccess.getArray(), IProblemRequestor.NON_ARRAY_ACCESS_SUBSCRIPTED, new String[] { arrayAccess.getArray().getCanonicalString() }); } } } } } @Override public boolean visit(SetValuesExpression setValuesExpression) { // Do not validate exprs inside annotations or stereotypes. That is already covered in the annotation code, which has different rules. return !(setValuesExpression.getExpression().resolveType() instanceof AnnotationType); // StereotypeType subclasses this, no need to check both } }