/*******************************************************************************
* 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.mof.eglx.jtopen.validation.annotation;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.edt.compiler.binding.IValidationProxy;
import org.eclipse.edt.compiler.core.ast.Node;
import org.eclipse.edt.compiler.core.ast.Part;
import org.eclipse.edt.compiler.internal.core.builder.IMarker;
import org.eclipse.edt.compiler.internal.core.validation.annotation.AnnotationValidator;
import org.eclipse.edt.compiler.internal.util.BindingUtil;
import org.eclipse.edt.mof.egl.Annotation;
import org.eclipse.edt.mof.egl.ArrayType;
import org.eclipse.edt.mof.egl.FunctionParameter;
import org.eclipse.edt.mof.egl.Member;
import org.eclipse.edt.mof.egl.Type;
import org.eclipse.edt.mof.egl.utils.TypeUtils;
import org.eclipse.edt.mof.eglx.jtopen.ext.Utils;
import org.eclipse.edt.mof.eglx.jtopen.messages.IBMiResourceKeys;
import org.eclipse.edt.mof.utils.NameUtile;
public class StructArrayValidator extends AbstractStructParameterAnnotationValidator {
@Override
protected void validateType(Annotation annotation, Node errorNode, Node target, Type type) {
super.validateType(annotation, errorNode, target, type);
if (type != null && isValidType(type)) {
validateElementTypeNotNullable(type, errorNode, target);
if(annotation.getValue("elementTypeAnnotation") instanceof Annotation) {
validateElementType((Annotation)annotation.getValue("elementTypeAnnotation"), type, errorNode, target);
}
else {
validateElementTypeNotRequired(type, errorNode, target);
}
validateReturnCount(annotation, errorNode, target);
}
}
private boolean isCompatibleWithINT(Type type) {
Type _int = org.eclipse.edt.mof.egl.utils.IRUtils.getEGLType(TypeUtils.Type_EGLInt);
return TypeUtils.areCompatible(_int.getClassifier(), type.getClassifier());
}
private void validateReturnCount(Annotation ann, Node errorNode, Node target) {
Object obj = ann.getValue("returnCountVariable");
if (obj == null || !(obj instanceof Member)) {
return;
}
//Variable must be move compatible with int
if (!isCompatibleWithINT(((Member)obj).getType())) {
problemRequestor.acceptProblem(errorNode,
IBMiResourceKeys.RETURN_COUNT_VAR_MUST_BE_INT_COMPAT,
IMarker.SEVERITY_ERROR,
new String[] {((Member)obj).getCaseSensitiveName()}, IBMiResourceKeys.getResourceBundleForKeys());
}
//Make sure the ReturnCount is defined in the same place as the field that is holding the annoation
//If returnCount is a function parameter, we can assume that it is in the same place
if (obj instanceof FunctionParameter) {
return;
}
Type containerBinding = getContainerBinding(errorNode);
if (((Member)obj).getContainer().equals(containerBinding)) {
return;
}
problemRequestor.acceptProblem(errorNode,
IBMiResourceKeys.RETURN_COUNT_VAR_DEFINED_IN_WRONG_PLACE,
IMarker.SEVERITY_ERROR,
new String[] {((Member)obj).getCaseSensitiveName()}, IBMiResourceKeys.getResourceBundleForKeys());
}
private Type getContainerBinding(Node node) {
if (node == null) {
return null;
}
if (node instanceof Part) {
return ((Part)node).getName().resolveType();
}
return getContainerBinding(node.getParent());
}
private void validateElementTypeNotNullable(Type type, Node errorNode, Node target) {
if (type instanceof ArrayType && ((ArrayType)type).elementsNullable()) {
problemRequestor.acceptProblem(target, IBMiResourceKeys.AS400_ANNOTATION_NULLABLE_TYPE_INVALID, IMarker.SEVERITY_ERROR, new String[] {getName(), BindingUtil.getShortTypeString(type, true) }, IBMiResourceKeys.getResourceBundleForKeys());
}
}
private void validateElementTypeNotRequired(Type type, Node errorNode, Node target) {
if (type instanceof ArrayType &&
Utils.requiresAS400TypeAnnotation(((ArrayType)type).getElementType())) {
problemRequestor.acceptProblem(target, IBMiResourceKeys.AS400_PROPERTY_REQUIRED, IMarker.SEVERITY_ERROR, new String[] {"elementTypeAnnotation", getName()}, IBMiResourceKeys.getResourceBundleForKeys());
}
}
private void validateElementType(Annotation ann, Type type, Node errorNode, Node target) {
boolean hasStructTypeAnnotation = false;
IValidationProxy proxy = AnnotationValidator.getValidationProxy((Annotation)ann);
if (proxy != null) {
for (org.eclipse.edt.compiler.binding.AnnotationValidationRule rule : proxy.getAnnotationValidators()) {
hasStructTypeAnnotation = true;
Map<String, Object> annotations = new HashMap<String, Object>(1);
annotations.put(NameUtile.getAsName(((Annotation) ann).getEClass().getETypeSignature()), ann);
rule.validate(errorNode, errorNode, ((ArrayType)type).getElementType(), annotations, problemRequestor, compilerOptions);
}
}
if(!hasStructTypeAnnotation && Utils.requiresAS400TypeAnnotation(type)) {
problemRequestor.acceptProblem(errorNode,
IBMiResourceKeys.PROGRAM_PARAMETER_ANNOTATION_REQUIRED,
IMarker.SEVERITY_ERROR,
new String[] {BindingUtil.getShortTypeString(type, true)}, IBMiResourceKeys.getResourceBundleForKeys());
}
}
@Override
protected Type getSupportedType() {
return null;
}
@Override
protected String getName() {
return "StructArray";
}
@Override
protected boolean isValidType(Type typeBinding) {
if (typeBinding != null) {
if (typeBinding instanceof ArrayType) {
return Utils.isValidAS400Type(typeBinding);
}
else {
return false;
}
}
else {
return true; //return true to avoid excess error messages
}
}
}