io.sarl.lang.validation.SARLValidator.java Source code

Java tutorial

Introduction

Here is the source code for io.sarl.lang.validation.SARLValidator.java

Source

/*
 * $Id$
 *
 * SARL is an general-purpose agent programming language.
 * More details on http://www.sarl.io
 *
 * Copyright (C) 2014-2016 the original authors or authors.
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * 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 io.sarl.lang.validation;

import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Lists.newArrayList;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_AGENT__EXTENDS;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_BEHAVIOR__EXTENDS;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_CAPACITY_USES__CAPACITIES;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_CAPACITY__EXTENDS;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_EVENT__EXTENDS;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_FORMAL_PARAMETER__DEFAULT_VALUE;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_SKILL__EXTENDS;
import static io.sarl.lang.sarl.SarlPackage.Literals.SARL_SKILL__IMPLEMENTS;
import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_BOOLEAN_EXPRESSION;
import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_CAPACITY_DEFINITION;
import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_FUNCTION_NAME;
import static io.sarl.lang.validation.IssueCodes.INVALID_CAPACITY_TYPE;
import static io.sarl.lang.validation.IssueCodes.INVALID_EXTENDED_TYPE;
import static io.sarl.lang.validation.IssueCodes.INVALID_FIRING_EVENT_TYPE;
import static io.sarl.lang.validation.IssueCodes.INVALID_IMPLEMENTED_TYPE;
import static io.sarl.lang.validation.IssueCodes.INVALID_NESTED_DEFINITION;
import static io.sarl.lang.validation.IssueCodes.REDUNDANT_CAPACITY_USE;
import static io.sarl.lang.validation.IssueCodes.REDUNDANT_INTERFACE_IMPLEMENTATION;
import static io.sarl.lang.validation.IssueCodes.RETURN_TYPE_SPECIFICATION_IS_RECOMMENDED;
import static io.sarl.lang.validation.IssueCodes.UNREACHABLE_BEHAVIOR_UNIT;
import static io.sarl.lang.validation.IssueCodes.UNUSED_AGENT_CAPACITY;
import static org.eclipse.xtend.core.validation.IssueCodes.ABSTRACT_METHOD_WITH_BODY;
import static org.eclipse.xtend.core.validation.IssueCodes.CLASS_EXPECTED;
import static org.eclipse.xtend.core.validation.IssueCodes.CREATE_FUNCTIONS_MUST_NOT_BE_ABSTRACT;
import static org.eclipse.xtend.core.validation.IssueCodes.CYCLIC_INHERITANCE;
import static org.eclipse.xtend.core.validation.IssueCodes.DISPATCH_FUNCTIONS_MUST_NOT_BE_ABSTRACT;
import static org.eclipse.xtend.core.validation.IssueCodes.INTERFACE_EXPECTED;
import static org.eclipse.xtend.core.validation.IssueCodes.INVALID_MEMBER_NAME;
import static org.eclipse.xtend.core.validation.IssueCodes.JDK_NOT_ON_CLASSPATH;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_ABSTRACT;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_ABSTRACT_IN_ANONYMOUS;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_CONSTRUCTOR;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_OVERRIDE;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_STATIC_MODIFIER;
import static org.eclipse.xtend.core.validation.IssueCodes.MUST_INVOKE_SUPER_CONSTRUCTOR;
import static org.eclipse.xtend.core.validation.IssueCodes.OBSOLETE_OVERRIDE;
import static org.eclipse.xtend.core.validation.IssueCodes.OVERRIDDEN_FINAL;
import static org.eclipse.xtend.core.validation.IssueCodes.OVERRIDE_REDUCES_VISIBILITY;
import static org.eclipse.xtend.core.validation.IssueCodes.XBASE_LIB_NOT_ON_CLASSPATH;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_CLASS__IMPLEMENTS;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_FIELD__NAME;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_FUNCTION__NAME;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_INTERFACE__EXTENDS;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_MEMBER__MODIFIERS;
import static org.eclipse.xtend.core.xtend.XtendPackage.Literals.XTEND_TYPE_DECLARATION__NAME;
import static org.eclipse.xtext.util.JavaVersion.JAVA8;
import static org.eclipse.xtext.xbase.validation.IssueCodes.DISCOURAGED_REFERENCE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.FORBIDDEN_REFERENCE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_RETURN_TYPE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_TYPES;
import static org.eclipse.xtext.xbase.validation.IssueCodes.MISSING_TYPE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.TYPE_BOUNDS_MISMATCH;
import static org.eclipse.xtext.xbase.validation.IssueCodes.VARIABLE_NAME_DISALLOWED;
import static org.eclipse.xtext.xbase.validation.IssueCodes.VARIABLE_NAME_SHADOWING;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtend.core.typesystem.LocalClassAwareTypeNames;
import org.eclipse.xtend.core.validation.IssueCodes;
import org.eclipse.xtend.core.validation.ModifierValidator;
import org.eclipse.xtend.core.xtend.XtendAnnotationType;
import org.eclipse.xtend.core.xtend.XtendClass;
import org.eclipse.xtend.core.xtend.XtendConstructor;
import org.eclipse.xtend.core.xtend.XtendEnum;
import org.eclipse.xtend.core.xtend.XtendField;
import org.eclipse.xtend.core.xtend.XtendFile;
import org.eclipse.xtend.core.xtend.XtendFunction;
import org.eclipse.xtend.core.xtend.XtendInterface;
import org.eclipse.xtend.core.xtend.XtendMember;
import org.eclipse.xtend.core.xtend.XtendPackage;
import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
import org.eclipse.xtext.common.types.JvmAnnotationReference;
import org.eclipse.xtext.common.types.JvmAnnotationValue;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmParameterizedTypeReference;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeAnnotationValue;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.validation.CheckType;
import org.eclipse.xtext.validation.ValidationMessageAcceptor;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.XBooleanLiteral;
import org.eclipse.xtext.xbase.XConstructorCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Functions;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
import org.eclipse.xtext.xbase.typesystem.override.IOverrideCheckResult.OverrideCheckDetails;
import org.eclipse.xtext.xbase.typesystem.override.IResolvedOperation;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
import org.eclipse.xtext.xbase.validation.FeatureNameValidator;

import io.sarl.lang.SARLLangActivator;
import io.sarl.lang.SARLVersion;
import io.sarl.lang.actionprototype.ActionParameterTypes;
import io.sarl.lang.actionprototype.IActionPrototypeProvider;
import io.sarl.lang.annotation.ImportedCapacityFeature;
import io.sarl.lang.core.Agent;
import io.sarl.lang.core.Behavior;
import io.sarl.lang.core.Capacity;
import io.sarl.lang.core.Event;
import io.sarl.lang.core.Skill;
import io.sarl.lang.jvmmodel.SarlJvmModelAssociations;
import io.sarl.lang.sarl.SarlAction;
import io.sarl.lang.sarl.SarlAgent;
import io.sarl.lang.sarl.SarlBehavior;
import io.sarl.lang.sarl.SarlBehaviorUnit;
import io.sarl.lang.sarl.SarlCapacity;
import io.sarl.lang.sarl.SarlCapacityUses;
import io.sarl.lang.sarl.SarlClass;
import io.sarl.lang.sarl.SarlConstructor;
import io.sarl.lang.sarl.SarlEvent;
import io.sarl.lang.sarl.SarlField;
import io.sarl.lang.sarl.SarlFormalParameter;
import io.sarl.lang.sarl.SarlInterface;
import io.sarl.lang.sarl.SarlRequiredCapacity;
import io.sarl.lang.sarl.SarlSkill;
import io.sarl.lang.services.SARLGrammarAccess;
import io.sarl.lang.typing.SARLExpressionHelper;
import io.sarl.lang.util.Utils;

/**
 * Validator for the SARL elements.
 *
 * <p>The check type may be one of:<ul>
 * <li>{@link CheckType#FAST}: is executed after a delay of 500ms after ANY editing action (type, enter, delete);</li>
 * <li>{@link CheckType#NORMAL}: is executed after a build (manual, or automatic);</li>
 * <li>{@link CheckType#EXPENSIVE}: is executed by right clicking ANYWHERE in the editor window and chooseing "Validate".</li>
 * </ul>
 *
 * @author $Author: sgalland$
 * @version $FullVersion$
 * @mavengroupid $GroupId$
 * @mavenartifactid $ArtifactId$
 * @see "https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation"
 */
@SuppressWarnings({ "checkstyle:classfanoutcomplexity", "checkstyle:methodcount" })
public class SARLValidator extends AbstractSARLValidator {

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator constructorModifierValidator = new SARLModifierValidator(
            newArrayList(SARLValidator.this.visibilityModifers));

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator agentModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", "abstract", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "final", "strictfp")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator methodInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", //$NON-NLS-1$
                    "protected", "private", "static", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "abstract", "dispatch", "final", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "def", "override", "synchronized", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "strictfp")); //$NON-NLS-1$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator fieldInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", //$NON-NLS-1$
                    "protected", "private", //$NON-NLS-1$//$NON-NLS-2$
                    "final", "val", "var", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "transient", "volatile")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator behaviorModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", "abstract", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "final", "strictfp")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator methodInBehaviorModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", //$NON-NLS-1$ //$NON-NLS-2$
                    "protected", "private", //$NON-NLS-1$//$NON-NLS-2$
                    "abstract", "dispatch", "final", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "def", "override", "synchronized", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "strictfp")); //$NON-NLS-1$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator fieldInBehaviorModifierValidator = new SARLModifierValidator(
            newArrayList("package", //$NON-NLS-1$
                    "protected", "private", //$NON-NLS-1$//$NON-NLS-2$
                    "final", "val", "var", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "transient", "volatile")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator capacityModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator methodInCapacityModifierValidator = new SARLModifierValidator(
            newArrayList("public", "def", "override")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator eventModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", "final")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator fieldInEventModifierValidator = new SARLModifierValidator(
            newArrayList("public", //$NON-NLS-1$
                    "final", "val", "var")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator skillModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", "abstract", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "final", "strictfp")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator methodInSkillModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", //$NON-NLS-1$ //$NON-NLS-2$
                    "protected", "private", //$NON-NLS-1$//$NON-NLS-2$
                    "abstract", "dispatch", "final", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "def", "override", "synchronized", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "strictfp")); //$NON-NLS-1$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator fieldInSkillModifierValidator = new SARLModifierValidator(
            newArrayList("public", "package", //$NON-NLS-1$ //$NON-NLS-2$
                    "protected", "private", //$NON-NLS-1$//$NON-NLS-2$
                    "final", "val", "var", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "volatile", "transient")); //$NON-NLS-1$//$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator nestedClassInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", "protected", //$NON-NLS-1$ //$NON-NLS-2$
                    "private", "static", "final", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    "abstract", "strictfp")); //$NON-NLS-1$ //$NON-NLS-2$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator nestedInterfaceInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    "static", "abstract", "strictfp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator nestedEnumerationInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    "static")); //$NON-NLS-1$

    @SuppressWarnings("synthetic-access")
    private final SARLModifierValidator nestedAnnotationTypeInAgentModifierValidator = new SARLModifierValidator(
            newArrayList("package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    "static", "abstract")); //$NON-NLS-1$ //$NON-NLS-2$

    @Inject
    private SarlJvmModelAssociations associations;

    @Inject
    private FeatureNameValidator featureNames;

    @Inject
    private IActionPrototypeProvider sarlActionSignatures;

    @Inject
    private FeatureCallValidator featureCallValidator;

    @Inject
    private SARLGrammarAccess grammarAccess;

    @Inject
    private TypeReferences typeReferences;

    @Inject
    private LocalClassAwareTypeNames localClassAwareTypeNames;

    @Inject
    private SARLExpressionHelper expressionHelper;

    /** Replies the canonical name of the given object.
     *
     * @param object - the object.
     * @return the canonical name or <code>null</code> if it cannot be computed.
     */
    protected String canonicalName(EObject object) {
        if (object instanceof JvmIdentifiableElement) {
            return ((JvmIdentifiableElement) object).getQualifiedName();
        }
        EObject jvmElement = this.associations.getPrimaryJvmElement(object);
        if (jvmElement instanceof JvmIdentifiableElement) {
            return ((JvmIdentifiableElement) jvmElement).getQualifiedName();
        }
        return null;
    }

    /** Emit a warning when the "fires" keyword is used.
     *
     * @param action - the action to check.
     */
    @Check
    public void checkFiresKeywordUse(SarlAction action) {
        if (!action.getFiredEvents().isEmpty()) {
            warning(MessageFormat.format(Messages.SARLValidator_2,
                    this.grammarAccess.getActionAccess().getFiresKeyword_9_1_0().getValue()), action, null);
        }
    }

    /** Emit a warning when the "requires" keyword is used.
     *
     * @param statement - the statement to check.
     */
    @Check
    public void checkRequiredCapacityUse(SarlRequiredCapacity statement) {
        warning(MessageFormat.format(Messages.SARLJavaValidator_20,
                this.grammarAccess.getRequiredCapacityAccess().getRequiresKeyword_1().getValue()), statement, null);
    }

    /** Check if the JRE, the XBase, and the SARL libraries are on the classpath.
     *
     * <p>This function is overriding the function given by the Xtend validator
     * for having finer tests, and firing a warning in place of an error.
     *
     * @param sarlScript - the SARL script.
     */
    @Check(CheckType.NORMAL)
    @Override
    public void checkClassPath(XtendFile sarlScript) {
        TypeReferences typeReferences = getServices().getTypeReferences();

        String version = System.getProperty("java.specification.version"); //$NON-NLS-1$

        SARLLangActivator sarlLangBundle = SARLLangActivator.getActivator();
        String minJdkVersion = sarlLangBundle.getMinimalJdkVersion();
        String minXtextVersion = sarlLangBundle.getMinimalXtextVersion();

        if (version == null || version.isEmpty() || Utils.compareVersions(version, minJdkVersion) < 0) {
            error(MessageFormat.format(Messages.SARLValidator_0, minJdkVersion), sarlScript,
                    XtendPackage.Literals.XTEND_FILE__PACKAGE, JDK_NOT_ON_CLASSPATH);
        }

        // XXX: Update the following type according to the super type's implementation.
        if (typeReferences.findDeclaredType(ToStringBuilder.class, sarlScript) == null) {
            error(MessageFormat.format(Messages.SARLValidator_1, minXtextVersion), sarlScript,
                    XtendPackage.Literals.XTEND_FILE__PACKAGE, XBASE_LIB_NOT_ON_CLASSPATH);
        }

        String sarlOnClasspath = Utils.getSARLLibraryVersionOnClasspath(typeReferences, sarlScript);
        if (Strings.isNullOrEmpty(sarlOnClasspath)) {
            error(Messages.SARLValidator_39, sarlScript, XtendPackage.Literals.XTEND_FILE__PACKAGE,
                    io.sarl.lang.validation.IssueCodes.SARL_LIB_NOT_ON_CLASSPATH);
        } else if (!Utils.isCompatibleSARLLibraryVersion(sarlOnClasspath)) {
            error(MessageFormat.format(Messages.SARLValidator_40, sarlOnClasspath,
                    SARLVersion.SPECIFICATION_RELEASE_VERSION), sarlScript,
                    XtendPackage.Literals.XTEND_FILE__PACKAGE,
                    io.sarl.lang.validation.IssueCodes.INVALID_SARL_LIB_ON_CLASSPATH);
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendConstructor constructor) {
        XtendTypeDeclaration declaringType = constructor.getDeclaringType();
        if (declaringType != null) {
            if (declaringType instanceof SarlEvent || declaringType instanceof SarlAgent
                    || declaringType instanceof SarlSkill || declaringType instanceof SarlBehavior) {
                String typeName = ((XtendTypeDeclaration) constructor.eContainer()).getName();
                this.constructorModifierValidator.checkModifiers(constructor,
                        MessageFormat.format(Messages.SARLValidator_26, typeName));
            } else {
                super.checkModifiers(constructor);
            }
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendFunction function) {
        XtendTypeDeclaration declaringType = function.getDeclaringType();
        if (declaringType != null) {
            if (declaringType instanceof SarlAgent) {
                String typeName = ((XtendTypeDeclaration) function.eContainer()).getName();
                this.methodInAgentModifierValidator.checkModifiers(function,
                        MessageFormat.format(Messages.SARLValidator_0, function.getName(), typeName));
            } else if (declaringType instanceof SarlCapacity) {
                String typeName = ((XtendTypeDeclaration) function.eContainer()).getName();
                this.methodInCapacityModifierValidator.checkModifiers(function,
                        MessageFormat.format(Messages.SARLValidator_0, function.getName(), typeName));
            } else if (declaringType instanceof SarlSkill) {
                String typeName = ((XtendTypeDeclaration) function.eContainer()).getName();
                this.methodInSkillModifierValidator.checkModifiers(function,
                        MessageFormat.format(Messages.SARLValidator_0, function.getName(), typeName));
            } else if (declaringType instanceof SarlBehavior) {
                String typeName = ((XtendTypeDeclaration) function.eContainer()).getName();
                this.methodInBehaviorModifierValidator.checkModifiers(function,
                        MessageFormat.format(Messages.SARLValidator_0, function.getName(), typeName));
            } else {
                super.checkModifiers(function);
            }
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendField field) {
        XtendTypeDeclaration declaringType = field.getDeclaringType();
        if (declaringType != null) {
            if (declaringType instanceof SarlEvent) {
                String typeName = ((XtendTypeDeclaration) field.eContainer()).getName();
                this.fieldInEventModifierValidator.checkModifiers(field,
                        MessageFormat.format(Messages.SARLValidator_0, field.getName(), typeName));
            } else if (declaringType instanceof SarlAgent) {
                String typeName = ((XtendTypeDeclaration) field.eContainer()).getName();
                this.fieldInAgentModifierValidator.checkModifiers(field,
                        MessageFormat.format(Messages.SARLValidator_0, field.getName(), typeName));
            } else if (declaringType instanceof SarlSkill) {
                String typeName = ((XtendTypeDeclaration) field.eContainer()).getName();
                this.fieldInSkillModifierValidator.checkModifiers(field,
                        MessageFormat.format(Messages.SARLValidator_0, field.getName(), typeName));
            } else if (declaringType instanceof SarlBehavior) {
                String typeName = ((XtendTypeDeclaration) field.eContainer()).getName();
                this.fieldInBehaviorModifierValidator.checkModifiers(field,
                        MessageFormat.format(Messages.SARLValidator_0, field.getName(), typeName));
            } else {
                super.checkModifiers(field);
            }
        }
    }

    /** Check if the modifiers for the SARL events.
     *
     * @param event the event.
     */
    @Check
    protected void checkModifiers(SarlEvent event) {
        this.eventModifierValidator.checkModifiers(event,
                MessageFormat.format(Messages.SARLValidator_26, event.getName()));
    }

    /** Check the modifiers for the SARL agents.
     *
     * @param agent the agent.
     */
    @Check
    protected void checkModifiers(SarlAgent agent) {
        this.agentModifierValidator.checkModifiers(agent,
                MessageFormat.format(Messages.SARLJavaValidator_3, agent.getName()));
    }

    /** Check the modifiers for the SARL behaviors.
     *
     * @param behavior the behavior.
     */
    @Check
    protected void checkModifiers(SarlBehavior behavior) {
        this.behaviorModifierValidator.checkModifiers(behavior,
                MessageFormat.format(Messages.SARLJavaValidator_5, behavior.getName()));
    }

    /** Check the modifiers for the SARL capacities.
     *
     * @param capacity the capacity.
     */
    @Check
    protected void checkModifiers(SarlCapacity capacity) {
        this.capacityModifierValidator.checkModifiers(capacity,
                MessageFormat.format(Messages.SARLJavaValidator_7, capacity.getName()));
    }

    /** Check the modifiers for the SARL skills.
     *
     * @param skill the skill.
     */
    @Check
    protected void checkModifiers(SarlSkill skill) {
        this.skillModifierValidator.checkModifiers(skill,
                MessageFormat.format(Messages.SARLValidator_9, skill.getName()));
    }

    @Check
    @Override
    protected void checkModifiers(XtendInterface oopInterface) {
        EObject econtainer = oopInterface.eContainer();
        if (econtainer instanceof SarlAgent) {
            this.nestedInterfaceInAgentModifierValidator.checkModifiers(oopInterface,
                    MessageFormat.format(Messages.SARLValidator_28, oopInterface.getName()));
        } else {
            super.checkModifiers(oopInterface);
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendClass oopClass) {
        EObject econtainer = oopClass.eContainer();
        if (econtainer instanceof SarlAgent) {
            this.nestedClassInAgentModifierValidator.checkModifiers(oopClass,
                    MessageFormat.format(Messages.SARLValidator_27, oopClass.getName()));
        } else {
            super.checkModifiers(oopClass);
        }
        // TODO remove this constraint when it is removed from the Xtend validator.
        if (!oopClass.isStatic() && ((econtainer instanceof SarlAgent) || (econtainer instanceof SarlBehavior)
                || (econtainer instanceof SarlSkill))) {
            error(Messages.SARLValidator_31, XTEND_TYPE_DECLARATION__NAME, -1, MISSING_STATIC_MODIFIER);
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendEnum oopEnum) {
        EObject econtainer = oopEnum.eContainer();
        if (econtainer instanceof SarlAgent) {
            this.nestedEnumerationInAgentModifierValidator.checkModifiers(oopEnum,
                    MessageFormat.format(Messages.SARLValidator_29, oopEnum.getName()));
        } else {
            super.checkModifiers(oopEnum);
        }
    }

    @Check
    @Override
    protected void checkModifiers(XtendAnnotationType oopAnnotationType) {
        EObject econtainer = oopAnnotationType.eContainer();
        if (econtainer instanceof SarlAgent) {
            this.nestedAnnotationTypeInAgentModifierValidator.checkModifiers(oopAnnotationType,
                    MessageFormat.format(Messages.SARLValidator_30, oopAnnotationType.getName()));
        } else {
            super.checkModifiers(oopAnnotationType);
        }
    }

    /** Check the container for the SARL agents.
     *
     * @param agent the agent.
     */
    @Check
    public void checkContainerType(SarlAgent agent) {
        XtendTypeDeclaration declaringType = agent.getDeclaringType();
        if (declaringType != null) {
            String name = canonicalName(declaringType);
            assert (name != null);
            error(MessageFormat.format(Messages.SARLJavaValidator_4, name), agent, null, INVALID_NESTED_DEFINITION);
        }
    }

    /** Check the container for the SARL behaviors.
     *
     * @param behavior the behavior.
     */
    @Check
    public void checkContainerType(SarlBehavior behavior) {
        XtendTypeDeclaration declaringType = behavior.getDeclaringType();
        if (declaringType != null) {
            String name = canonicalName(declaringType);
            assert (name != null);
            error(MessageFormat.format(Messages.SARLJavaValidator_6, name), behavior, null,
                    INVALID_NESTED_DEFINITION);
        }
    }

    /** Check the container for the SARL capacities.
     *
     * @param capacity the capacity.
     */
    @Check
    public void checkContainerType(SarlCapacity capacity) {
        XtendTypeDeclaration declaringType = capacity.getDeclaringType();
        if (declaringType != null) {
            String name = canonicalName(declaringType);
            assert (name != null);
            error(MessageFormat.format(Messages.SARLJavaValidator_8, name), capacity, null,
                    INVALID_NESTED_DEFINITION);
        }
    }

    /** Check the container for the SARL skills.
     *
     * @param skill the skill.
     */
    @Check
    public void checkContainerType(SarlSkill skill) {
        XtendTypeDeclaration declaringType = skill.getDeclaringType();
        if (declaringType != null) {
            error(Messages.SARLValidator_10, skill, null, INVALID_NESTED_DEFINITION);
        }
    }

    /** Check if the modifiers for the SARL events.
     *
     * @param event the event.
     */
    @Check
    public void checkContainerType(SarlEvent event) {
        XtendTypeDeclaration declaringType = event.getDeclaringType();
        if (declaringType != null) {
            error(Messages.SARLJavaValidator_2, event, null, INVALID_NESTED_DEFINITION);
        }
    }

    /** Check if all the fields are initialized in a SARL event.
     *
     * @param event the event.
     */
    @Check
    public void checkFinalFieldInitialization(SarlEvent event) {
        JvmGenericType inferredType = this.associations.getInferredType(event);
        if (inferredType != null) {
            super.checkFinalFieldInitialization(inferredType);
        }
    }

    /** Check if all the fields are initialized in a SARL behavior.
     *
     * @param behavior the behavior.
     */
    @Check
    public void checkFinalFieldInitialization(SarlBehavior behavior) {
        JvmGenericType inferredType = this.associations.getInferredType(behavior);
        if (inferredType != null) {
            super.checkFinalFieldInitialization(inferredType);
        }
    }

    /** Check if all the fields are initialized in a SARL skill.
     *
     * @param skill the skill.
     */
    @Check
    public void checkFinalFieldInitialization(SarlSkill skill) {
        JvmGenericType inferredType = this.associations.getInferredType(skill);
        if (inferredType != null) {
            super.checkFinalFieldInitialization(inferredType);
        }
    }

    /** Check if all the fields are initialized in a SARL agent.
     *
     * @param agent the agent.
     */
    @Check
    public void checkFinalFieldInitialization(SarlAgent agent) {
        JvmGenericType inferredType = this.associations.getInferredType(agent);
        if (inferredType != null) {
            super.checkFinalFieldInitialization(inferredType);
        }
    }

    /** Check the super constructors.
     *
     * @param container - the container.
     * @param feature - the syntactic feature related to the supertypes.
     * @param defaultSignatures - the signatures of the default constructors for the given container.
     */
    @SuppressWarnings({ "unchecked", "checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity",
            "checkstyle:nestedifdepth" })
    protected void checkSuperConstructor(XtendTypeDeclaration container, EStructuralFeature feature,
            Collection<ActionParameterTypes> defaultSignatures) {
        JvmDeclaredType jvmElement = this.associations.getInferredType(container);
        if (jvmElement != null) {
            Map<ActionParameterTypes, JvmConstructor> superConstructors = CollectionLiterals
                    .newTreeMap((Comparator<ActionParameterTypes>) null);
            JvmTypeReference typeRef = jvmElement.getExtendedClass();
            JvmType supertype = (typeRef == null) ? null : typeRef.getType();
            if (supertype instanceof JvmGenericType) {
                JvmGenericType jvmSuperElement = (JvmGenericType) supertype;
                for (JvmConstructor superConstructor : jvmSuperElement.getDeclaredConstructors()) {
                    ActionParameterTypes sig = this.sarlActionSignatures.createParameterTypesFromJvmModel(
                            superConstructor.isVarArgs(), superConstructor.getParameters());
                    superConstructors.put(sig, superConstructor);
                }
            }

            ActionParameterTypes voidKey = this.sarlActionSignatures.createParameterTypesForVoid();
            boolean hasDeclaredConstructor = false;

            for (XtendMember member : container.getMembers()) {
                if (member instanceof SarlConstructor) {
                    SarlConstructor constructor = (SarlConstructor) member;
                    hasDeclaredConstructor = true;
                    boolean invokeDefaultConstructor = true;
                    XExpression body = constructor.getExpression();
                    if (body instanceof XBlockExpression) {
                        XBlockExpression block = (XBlockExpression) body;
                        if (!block.getExpressions().isEmpty()) {
                            XExpression firstStatement = block.getExpressions().get(0);
                            if (firstStatement instanceof XConstructorCall
                                    || isDelegateConstructorCall(firstStatement)) {
                                invokeDefaultConstructor = false;
                            }
                        }
                    } else if (body instanceof XConstructorCall || isDelegateConstructorCall(body)) {
                        invokeDefaultConstructor = false;
                    }
                    if (invokeDefaultConstructor && !superConstructors.containsKey(voidKey)) {
                        List<String> issueData = newArrayList();
                        for (ActionParameterTypes defaultSignature : defaultSignatures) {
                            issueData.add(defaultSignature.toString());
                        }
                        error(Messages.SARLValidator_19, member, null,
                                ValidationMessageAcceptor.INSIGNIFICANT_INDEX, MUST_INVOKE_SUPER_CONSTRUCTOR,
                                toArray(issueData, String.class));
                    }
                }
            }

            if (!hasDeclaredConstructor) {
                for (ActionParameterTypes defaultSignature : defaultSignatures) {
                    if (!superConstructors.containsKey(defaultSignature)) {
                        List<String> issueData = newArrayList();
                        for (JvmConstructor superConstructor : superConstructors.values()) {
                            issueData.add(EcoreUtil.getURI(superConstructor).toString());
                            issueData.add(
                                    doGetReadableSignature(container.getName(), superConstructor.getParameters()));
                        }
                        error(Messages.SARLValidator_19, container, feature, MISSING_CONSTRUCTOR,
                                toArray(issueData, String.class));
                    }
                }
            }
        }
    }

    /** Check if the super default constructor is correctly invoked.
     *
     * @param agent the SARL element.
     */
    @Check
    public void checkSuperConstructor(SarlAgent agent) {
        checkSuperConstructor(agent, XTEND_TYPE_DECLARATION__NAME,
                doGetConstructorParameterTypes(Agent.class, agent));
    }

    /** Check if the super default constructor is correctly invoked.
     *
     * @param behavior the SARL element.
     */
    @Check
    public void checkSuperConstructor(SarlBehavior behavior) {
        checkSuperConstructor(behavior, XTEND_TYPE_DECLARATION__NAME,
                doGetConstructorParameterTypes(Behavior.class, behavior));
    }

    /** Check if the super default constructor is correctly invoked.
     *
     * @param skill the SARL element.
     */
    @Check
    public void checkSuperConstructor(SarlSkill skill) {
        checkSuperConstructor(skill, XTEND_TYPE_DECLARATION__NAME,
                doGetConstructorParameterTypes(Skill.class, skill));
    }

    /** Check if the super default constructor is correctly invoked.
     *
     * @param event the SARL element.
     */
    @Check
    public void checkSuperConstructor(SarlEvent event) {
        checkSuperConstructor(event, XTEND_TYPE_DECLARATION__NAME,
                doGetConstructorParameterTypes(Event.class, event));
    }

    private Collection<ActionParameterTypes> doGetConstructorParameterTypes(Class<?> type, Notifier context) {
        Collection<ActionParameterTypes> parameters = new ArrayList<>();
        JvmTypeReference typeReference = this.typeReferences.getTypeForName(type, context);
        JvmType jvmType = typeReference.getType();
        if (jvmType instanceof JvmDeclaredType) {
            JvmDeclaredType declaredType = (JvmDeclaredType) jvmType;
            for (JvmConstructor constructor : declaredType.getDeclaredConstructors()) {
                ActionParameterTypes types = this.sarlActionSignatures
                        .createParameterTypesFromJvmModel(constructor.isVarArgs(), constructor.getParameters());
                if (types != null) {
                    parameters.add(types);
                }
            }
        }
        if (parameters.isEmpty()) {
            parameters.add(this.sarlActionSignatures.createParameterTypesForVoid());
        }
        return parameters;
    }

    /** Check if the super default constructor is correctly invoked.
     *
     * @param xtendClass the Xtend element.
     */
    @Check
    @Override
    public void checkDefaultSuperConstructor(XtendClass xtendClass) {
        checkSuperConstructor(xtendClass, XTEND_TYPE_DECLARATION__NAME,
                doGetConstructorParameterTypes(Object.class, xtendClass));
    }

    /** Check if the call is forbidden.
     *
     * <p>One example of a forbidden feature is {@link System#exit(int)}.
     *
     * @param expression - the expression.
     */
    @Check(CheckType.FAST)
    public void checkForbiddenCalls(XAbstractFeatureCall expression) {
        if (this.featureCallValidator.isDisallowedCall(expression)) {
            error(Messages.SARLValidator_39, expression, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
                    FORBIDDEN_REFERENCE);
        }
    }

    /** Check if the call is discouraged.
     *
     * <p>One example of a discouraged feature is {@link System#err}.
     *
     * @param expression - the expression.
     */
    @Check(CheckType.FAST)
    public void checkDiscouragedCalls(XAbstractFeatureCall expression) {
        if (!isIgnored(DISCOURAGED_REFERENCE) && this.featureCallValidator.isDiscouragedCall(expression)) {
            addIssue(MessageFormat.format(Messages.SARLValidator_40,
                    // FIXME: this.serializer.serialize(expression)
                    expression.getConcreteSyntaxFeatureName()), expression, DISCOURAGED_REFERENCE);
        }
    }

    /** Check if the default values of the formal parameters have a compatible type with the formal parameter.
     *
     * @param param - the formal parameter to check.
     */
    @Check
    public void checkDefaultValueTypeCompatibleWithParameterType(SarlFormalParameter param) {
        if (param.getDefaultValue() != null) {
            JvmTypeReference rawType = param.getParameterType();
            assert (rawType != null);
            LightweightTypeReference toType = toLightweightTypeReference(rawType, true);
            LightweightTypeReference fromType = getActualType(param.getDefaultValue());
            if (!Utils.canCast(fromType, toType, true, false, true)) {
                error(MessageFormat.format(Messages.SARLValidator_19, getNameOfTypes(fromType),
                        canonicalName(toType)), param, SARL_FORMAL_PARAMETER__DEFAULT_VALUE,
                        ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INCOMPATIBLE_TYPES, canonicalName(fromType),
                        canonicalName(toType));
            }
        }
    }

    /** Check if the given action has a valid name.
     *
     * @param action - the action to test.
     * @see SARLFeatureNameValidator
     */
    @Check(CheckType.FAST)
    public void checkActionName(SarlAction action) {
        JvmOperation inferredType = this.associations.getDirectlyInferredOperation(action);
        QualifiedName name = QualifiedName.create(inferredType.getQualifiedName('.').split("\\.")); //$NON-NLS-1$
        if (this.featureNames.isDisallowedName(name)) {
            String validName = Utils.fixHiddenMember(action.getName());
            error(MessageFormat.format(Messages.SARLValidator_9, action.getName()), action, XTEND_FUNCTION__NAME,
                    ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_MEMBER_NAME, validName);
        } else if (!isIgnored(DISCOURAGED_FUNCTION_NAME) && this.featureNames.isDiscouragedName(name)) {
            warning(MessageFormat.format(Messages.SARLValidator_9, action.getName()), action, XTEND_FUNCTION__NAME,
                    ValidationMessageAcceptor.INSIGNIFICANT_INDEX, DISCOURAGED_FUNCTION_NAME);
        }
    }

    /** Check if the given field has a valid name.
     *
     * @param field - the field to test.
     * @see SARLFeatureNameValidator
     */
    @Check(CheckType.FAST)
    public void checkFieldName(SarlField field) {
        JvmField inferredType = this.associations.getJvmField(field);
        QualifiedName name = Utils.getQualifiedName(inferredType);
        if (this.featureNames.isDisallowedName(name)) {
            String validName = Utils.fixHiddenMember(field.getName());
            error(MessageFormat.format(Messages.SARLValidator_10, field.getName()), field, XTEND_FIELD__NAME,
                    ValidationMessageAcceptor.INSIGNIFICANT_INDEX, VARIABLE_NAME_DISALLOWED, validName);
        }
    }

    /** Check if the given field has a name that is shadowing an inherited field.
     *
     * @param field - the field to test.
     */
    @Check
    public void checkFieldNameShadowing(SarlField field) {
        if (!isIgnored(VARIABLE_NAME_SHADOWING) && !Utils.isHiddenMember(field.getName())) {
            JvmField inferredField = this.associations.getJvmField(field);
            Map<String, JvmField> inheritedFields = new TreeMap<>();
            Utils.populateInheritanceContext((JvmGenericType) inferredField.getDeclaringType(), null, null,
                    inheritedFields, null, null, this.sarlActionSignatures);

            JvmField inheritedField = inheritedFields.get(field.getName());
            if (inheritedField != null) {
                int nameIndex = 0;
                String newName = field.getName() + nameIndex;
                while (inheritedFields.containsKey(newName)) {
                    ++nameIndex;
                    newName = field.getName() + nameIndex;
                }
                addIssue(MessageFormat.format(Messages.SARLValidator_15, field.getName(),
                        inferredField.getDeclaringType().getQualifiedName(), inheritedField.getQualifiedName()),
                        field, XTEND_FIELD__NAME, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
                        VARIABLE_NAME_SHADOWING, newName);
            }
        }
    }

    /** Caution: This function is overridden for translating the MISSING_OVERRIDE error into a warning,
     * and emit a warning when a return type should be specified.
     *
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings({ "checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity" })
    protected void doCheckFunctionOverrides(EObject sourceElement, IResolvedOperation resolved,
            List<IResolvedOperation> allInherited) {
        boolean overrideProblems = false;
        List<IResolvedOperation> exceptionMismatch = null;
        for (IResolvedOperation inherited : allInherited) {
            if (inherited.getOverrideCheckResult().hasProblems()) {
                overrideProblems = true;
                EnumSet<OverrideCheckDetails> details = inherited.getOverrideCheckResult().getDetails();
                if (details.contains(OverrideCheckDetails.IS_FINAL)) {
                    error(MessageFormat.format(Messages.SARLJavaValidator_11, inherited.getSimpleSignature()),
                            sourceElement, nameFeature(sourceElement), OVERRIDDEN_FINAL);
                } else if (details.contains(OverrideCheckDetails.REDUCED_VISIBILITY)) {
                    error(MessageFormat.format(Messages.SARLJavaValidator_12, inherited.getSimpleSignature()),
                            sourceElement, nameFeature(sourceElement), OVERRIDE_REDUCES_VISIBILITY);
                } else if (details.contains(OverrideCheckDetails.EXCEPTION_MISMATCH)) {
                    if (exceptionMismatch == null) {
                        exceptionMismatch = Lists.newArrayListWithCapacity(allInherited.size());
                    }
                    exceptionMismatch.add(inherited);
                } else if (details.contains(OverrideCheckDetails.RETURN_MISMATCH)) {
                    error(MessageFormat.format(Messages.SARLValidator_13, inherited.getSimpleSignature()),
                            sourceElement, returnTypeFeature(sourceElement), INCOMPATIBLE_RETURN_TYPE,
                            inherited.getResolvedReturnType().getIdentifier());
                }
            } else if (!isIgnored(RETURN_TYPE_SPECIFICATION_IS_RECOMMENDED)
                    && sourceElement instanceof SarlAction) {
                SarlAction function = (SarlAction) sourceElement;
                if (function.getReturnType() == null && !inherited.getResolvedReturnType().isPrimitiveVoid()) {
                    warning(MessageFormat.format(Messages.SARLValidator_14,
                            resolved.getResolvedReturnType().getHumanReadableName()), sourceElement,
                            returnTypeFeature(sourceElement), RETURN_TYPE_SPECIFICATION_IS_RECOMMENDED,
                            inherited.getResolvedReturnType().getIdentifier());
                }
            }
        }
        if (exceptionMismatch != null) {
            createExceptionMismatchError(resolved, sourceElement, exceptionMismatch);
        }
        if (sourceElement instanceof SarlAction) {
            SarlAction function = (SarlAction) sourceElement;
            if (!overrideProblems && !function.isOverride() && !function.isStatic()
                    && !isIgnored(MISSING_OVERRIDE)) {
                warning(MessageFormat.format(Messages.SARLValidator_15, resolved.getSimpleSignature(),
                        getDeclaratorName(resolved)), function, XTEND_FUNCTION__NAME, MISSING_OVERRIDE);
            }
            if (!overrideProblems && function.isOverride() && function.isStatic()) {
                for (IResolvedOperation inherited : allInherited) {
                    error(MessageFormat.format(Messages.SARLJavaValidator_16, resolved.getSimpleSignature(),
                            getDeclaratorName(resolved), resolved.getSimpleSignature(),
                            getDeclaratorName(inherited)), function, XTEND_FUNCTION__NAME,
                            function.getModifiers().indexOf(Messages.SARLJavaValidator_17), OBSOLETE_OVERRIDE);
                }
            }
        }
    }

    private boolean checkRedundantInterface(XtendTypeDeclaration element, EReference structuralElement,
            LightweightTypeReference lightweightInterfaceReference,
            List<LightweightTypeReference> knownInterfaces) {
        int index = 0;
        for (LightweightTypeReference previousInterface : knownInterfaces) {
            if (memberOfTypeHierarchy(previousInterface, lightweightInterfaceReference)) {
                error(MessageFormat.format(Messages.SARLValidator_13, canonicalName(lightweightInterfaceReference)),
                        element, structuralElement,
                        // The index of the element to highlight in the super-types
                        knownInterfaces.size(), REDUNDANT_INTERFACE_IMPLEMENTATION,
                        canonicalName(lightweightInterfaceReference), "pre"); //$NON-NLS-1$
                return true;
            } else if (memberOfTypeHierarchy(lightweightInterfaceReference, previousInterface)) {
                error(MessageFormat.format(Messages.SARLValidator_13, canonicalName(previousInterface)), element,
                        structuralElement, index, REDUNDANT_INTERFACE_IMPLEMENTATION,
                        canonicalName(previousInterface), "post"); //$NON-NLS-1$
            }
            ++index;
        }
        return false;
    }

    private void checkRedundantInterfaces(XtendTypeDeclaration element, EReference structuralElement,
            Iterable<? extends JvmTypeReference> interfaces, Iterable<? extends JvmTypeReference> superTypes) {
        List<LightweightTypeReference> knownInterfaces = CollectionLiterals.newArrayList();
        for (JvmTypeReference interfaceRef : interfaces) {
            LightweightTypeReference lightweightInterfaceReference = toLightweightTypeReference(interfaceRef);
            // Check the interface against the other interfaces
            if (!checkRedundantInterface(element, structuralElement, lightweightInterfaceReference,
                    knownInterfaces)) {
                // Check the interface against the super-types
                if (superTypes != null && !isIgnored(REDUNDANT_INTERFACE_IMPLEMENTATION)) {
                    for (JvmTypeReference superType : superTypes) {
                        LightweightTypeReference lightweightSuperType = toLightweightTypeReference(superType);
                        if (memberOfTypeHierarchy(lightweightSuperType, lightweightInterfaceReference)) {
                            addIssue(
                                    MessageFormat.format(Messages.SARLValidator_14,
                                            canonicalName(lightweightInterfaceReference),
                                            canonicalName(lightweightSuperType)),
                                    element, structuralElement,
                                    // The index of the element to highlight in the super-types
                                    knownInterfaces.size(), REDUNDANT_INTERFACE_IMPLEMENTATION,
                                    canonicalName(lightweightInterfaceReference), "unknow"); //$NON-NLS-1$
                        }
                    }
                }
            }
            // Prepare next loop
            knownInterfaces.add(lightweightInterfaceReference);
        }
    }

    /** Check if implemented interfaces of a skill are redundant.
     *
     * @param skill the skill.
     */
    @Check
    public void checkRedundantImplementedInterfaces(SarlSkill skill) {
        checkRedundantInterfaces(skill, SARL_SKILL__IMPLEMENTS, skill.getImplements(),
                Utils.singletonList(skill.getExtends()));
    }

    /** Check if implemented interfaces of a Xtend Class are redundant.
     *
     * @param xtendClass the class.
     */
    @Check
    public void checkRedundantImplementedInterfaces(SarlClass xtendClass) {
        checkRedundantInterfaces(xtendClass, XTEND_CLASS__IMPLEMENTS, xtendClass.getImplements(),
                Utils.singletonList(xtendClass.getExtends()));
    }

    /** Check if implemented interfaces of a Xtend Interface are redundant.
     *
     * @param xtendInterface the interface.
     */
    @Check
    public void checkRedundantImplementedInterfaces(SarlInterface xtendInterface) {
        checkRedundantInterfaces(xtendInterface, XTEND_INTERFACE__EXTENDS, xtendInterface.getExtends(),
                Collections.<JvmTypeReference>emptyList());
    }

    /** Check the type of the behavior unit's guard.
     *
     * @param behaviorUnit - the behavior unit.
     */
    @Check(CheckType.FAST)
    public void checkBehaviorUnitGuardType(SarlBehaviorUnit behaviorUnit) {
        XExpression guard = behaviorUnit.getGuard();
        if (guard != null) {
            if (this.expressionHelper.hasDeepSideEffects(guard)) {
                error(Messages.SARLJavaValidator_18, guard, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
                        org.eclipse.xtext.xbase.validation.IssueCodes.INVALID_INNER_EXPRESSION);
                return;
            }
            if (guard instanceof XBooleanLiteral) {
                XBooleanLiteral booleanLiteral = (XBooleanLiteral) guard;
                if (booleanLiteral.isIsTrue()) {
                    if (!isIgnored(DISCOURAGED_BOOLEAN_EXPRESSION)) {
                        addIssue(Messages.SARLValidator_21, booleanLiteral, null,
                                ValidationMessageAcceptor.INSIGNIFICANT_INDEX, DISCOURAGED_BOOLEAN_EXPRESSION);
                    }
                } else if (!isIgnored(UNREACHABLE_BEHAVIOR_UNIT)) {
                    addIssue(Messages.SARLValidator_22, behaviorUnit, null,
                            ValidationMessageAcceptor.INSIGNIFICANT_INDEX, UNREACHABLE_BEHAVIOR_UNIT,
                            behaviorUnit.getName().getSimpleName());
                }
                return;
            }

            LightweightTypeReference fromType = getActualType(guard);
            if (!fromType.isAssignableFrom(Boolean.TYPE)) {
                error(MessageFormat.format(Messages.SARLValidator_23, getNameOfTypes(fromType),
                        boolean.class.getName()), guard, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
                        INCOMPATIBLE_TYPES);
            }
        }
    }

    /** Check the type of the capacity uses.
     *
     * @param uses - the capacity uses.
     */
    @Check(CheckType.FAST)
    public void checkCapacityTypeForUses(SarlCapacityUses uses) {
        for (JvmParameterizedTypeReference usedType : uses.getCapacities()) {
            LightweightTypeReference ref = toLightweightTypeReference(usedType);
            if (ref != null && !ref.isSubtypeOf(Capacity.class)) {
                error(MessageFormat.format(Messages.SARLValidator_24, usedType.getQualifiedName(),
                        Messages.SARLValidator_25,
                        this.grammarAccess.getCapacityUsesAccess().getUsesKeyword_1().getValue()), usedType, null,
                        ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_CAPACITY_TYPE,
                        usedType.getSimpleName());
            }
        }
    }

    /** Check the types of the "requires" statement.
     *
     * @param requires - the "requires" statement.
     */
    @Check(CheckType.FAST)
    public void checkCapacityTypeForRequires(SarlRequiredCapacity requires) {
        for (JvmParameterizedTypeReference requiredType : requires.getCapacities()) {
            LightweightTypeReference ref = toLightweightTypeReference(requiredType);
            if (ref != null && !ref.isSubtypeOf(Capacity.class)) {
                error(MessageFormat.format(Messages.SARLValidator_24, requiredType.getQualifiedName(),
                        Messages.SARLValidator_25,
                        this.grammarAccess.getRequiredCapacityAccess().getRequiresKeyword_1().getValue()),
                        requiredType, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_CAPACITY_TYPE,
                        requiredType.getSimpleName());
            }
        }
    }

    /** Check the types of the parameters of the "fires" statement.
     *
     * @param action - the signature that contains the "fires" statement.
     */
    @Check(CheckType.FAST)
    public void checkActionFires(SarlAction action) {
        for (JvmTypeReference event : action.getFiredEvents()) {
            LightweightTypeReference ref = toLightweightTypeReference(event);
            if (ref != null && !ref.isSubtypeOf(Event.class)) {
                error(MessageFormat.format(Messages.SARLValidator_24, event.getQualifiedName(),
                        Messages.SARLValidator_26,
                        this.grammarAccess.getActionAccess().getFiresKeyword_9_1_0().getValue()), event, null,
                        ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_FIRING_EVENT_TYPE,
                        event.getSimpleName());
            }
        }
    }

    /** Check the super type.
     *
     * @param element - the child type.
     * @param feature - the syntactic feature related to the supertypes.
     * @param superTypes - the current super types.
     * @param expectedType - the expected root type.
     * @param onlySubTypes - if <code>true</code> only the subtype of the <code>expectedType</code> are valid;
     * <code>false</code> if the <code>expectedType</code> is allowed.
     * @return the count of supertypes.
     */
    @SuppressWarnings({ "checkstyle:cyclomaticcomplexity" })
    protected int checkSuperTypes(XtendTypeDeclaration element, EReference feature,
            List<? extends JvmTypeReference> superTypes, Class<?> expectedType, boolean onlySubTypes) {
        int nbSuperTypes = 0;
        JvmDeclaredType inferredType = this.associations.getInferredType(element);
        if (inferredType instanceof JvmGenericType) {
            LinkedList<JvmTypeReference> inferredSuperTypes = CollectionLiterals.newLinkedList();
            inferredSuperTypes.addAll(inferredType.getSuperTypes());
            boolean isExpectingInterface = expectedType.isInterface();
            int superTypeIndex = 0;
            for (JvmTypeReference superType : superTypes) {
                boolean success = true;
                JvmType jvmSuperType = (superType == null) ? null : superType.getType();
                if (jvmSuperType != null) {
                    final JvmTypeReference inferredSuperType = (inferredSuperTypes.isEmpty()) ? null
                            : inferredSuperTypes.removeFirst();
                    LightweightTypeReference lighweightSuperType = toLightweightTypeReference(superType);
                    if (!(jvmSuperType instanceof JvmGenericType)
                            || (isExpectingInterface != ((JvmGenericType) jvmSuperType).isInterface())) {
                        if (isExpectingInterface) {
                            error(MessageFormat.format(Messages.SARLValidator_27, Messages.SARLValidator_28),
                                    feature, superTypeIndex, INTERFACE_EXPECTED, jvmSuperType.getIdentifier());
                        } else {
                            error(MessageFormat.format(Messages.SARLValidator_27, Messages.SARLValidator_29),
                                    feature, superTypeIndex, CLASS_EXPECTED, jvmSuperType.getIdentifier());
                        }
                        success = false;
                    } else if (isFinal(lighweightSuperType)) {
                        error(Messages.SARLValidator_30, feature, superTypeIndex, OVERRIDDEN_FINAL,
                                inferredType.getIdentifier(), jvmSuperType.getIdentifier());
                        success = false;
                    } else if (!lighweightSuperType.isSubtypeOf(expectedType)
                            || ((onlySubTypes) && (lighweightSuperType.isType(expectedType)))) {
                        if (onlySubTypes) {
                            error(MessageFormat.format(Messages.SARLValidator_31, expectedType.getName()), feature,
                                    superTypeIndex, INVALID_EXTENDED_TYPE, jvmSuperType.getIdentifier());
                        } else {
                            error(MessageFormat.format(Messages.SARLValidator_32, expectedType.getName()), feature,
                                    superTypeIndex, INVALID_EXTENDED_TYPE, jvmSuperType.getIdentifier());
                        }
                        success = false;
                    } else if (inferredSuperType == null
                            || !Objects.equal(inferredSuperType.getIdentifier(), jvmSuperType.getIdentifier())
                            || Objects.equal(inferredType.getIdentifier(), jvmSuperType.getIdentifier())
                            || hasCycleInHierarchy((JvmGenericType) inferredType,
                                    Sets.<JvmGenericType>newHashSet())) {
                        error(MessageFormat.format(Messages.SARLValidator_33, inferredType.getQualifiedName()),
                                feature, superTypeIndex, CYCLIC_INHERITANCE, jvmSuperType.getIdentifier());
                        success = false;
                    }
                } else if (superType != null) {
                    error(MessageFormat.format(Messages.SARLValidator_33, inferredType.getQualifiedName()), feature,
                            superTypeIndex, CYCLIC_INHERITANCE, superType.getIdentifier());
                    success = false;
                }
                checkWildcardSupertype(element, superType, feature, superTypeIndex);
                ++superTypeIndex;
                if (success) {
                    ++nbSuperTypes;
                }
            }
        }
        return nbSuperTypes;
    }

    /** Check if the supertype of the given capacity is a subtype of Capacity.
     *
     * @param capacity - the type to test.
     */
    @Check(CheckType.FAST)
    public void checkSuperTypes(SarlCapacity capacity) {
        checkSuperTypes(capacity, SARL_CAPACITY__EXTENDS, capacity.getExtends(), Capacity.class, false);
    }

    /** Check if the supertype of the given skill is a subtype of Skill.
     *
     * @param skill - the type to test.
     */
    @Check(CheckType.FAST)
    public void checkSuperType(SarlSkill skill) {
        int nbSuperTypes = checkSuperTypes(skill, SARL_SKILL__EXTENDS, Utils.singletonList(skill.getExtends()),
                Skill.class, false);
        checkImplementedTypes(skill, SARL_SKILL__IMPLEMENTS, skill.getImplements(), Capacity.class,
                ((nbSuperTypes > 0) ? 0 : 1), true);
    }

    /** Check if the supertype of the given event is a subtype of Event.
     *
     * @param event - the type to test.
     */
    @Check(CheckType.FAST)
    public void checkSuperType(SarlEvent event) {
        checkSuperTypes(event, SARL_EVENT__EXTENDS, Utils.singletonList(event.getExtends()), Event.class, false);
    }

    /** Check if the supertype of the given behavior is a subtype of Behavior.
     *
     * @param behavior - the type to test.
     */
    @Check(CheckType.FAST)
    public void checkSuperType(SarlBehavior behavior) {
        checkSuperTypes(behavior, SARL_BEHAVIOR__EXTENDS, Utils.singletonList(behavior.getExtends()),
                Behavior.class, false);
    }

    /** Check if the supertype of the given agent is a subtype of Agent.
     *
     * @param agent - the type to test.
     */
    @Check(CheckType.FAST)
    public void checkSuperType(SarlAgent agent) {
        checkSuperTypes(agent, SARL_AGENT__EXTENDS, Utils.singletonList(agent.getExtends()), Agent.class, false);
    }

    /** Check the implemeted type.
     *
     * @param element - the child type.
     * @param feature - the syntactic feature related to the supertypes.
     * @param implementedTypes - the current super types.
     * @param expectedType - the expected root type.
     * @param mandatoryNumberOfTypes - the minimal number of implemented types.
     * @param onlySubTypes - if <code>true</code> only the subtype of the <code>expectedType</code> are valid;
     * <code>false</code> if the <code>expectedType</code> is allowed.
     * @return the count of supertypes.
     */
    protected boolean checkImplementedTypes(XtendTypeDeclaration element, EReference feature,
            List<? extends JvmTypeReference> implementedTypes, Class<?> expectedType, int mandatoryNumberOfTypes,
            boolean onlySubTypes) {
        boolean success = true;
        int nb = 0;
        int index = 0;
        for (JvmTypeReference superType : implementedTypes) {
            LightweightTypeReference ref = toLightweightTypeReference(superType);
            if (ref != null && (!ref.isInterfaceType() || !ref.isSubtypeOf(expectedType)
                    || (onlySubTypes && ref.isType(expectedType)))) {
                String msg;
                if (onlySubTypes) {
                    msg = Messages.SARLValidator_34;
                } else {
                    msg = Messages.SARLValidator_35;
                }
                error(MessageFormat.format(msg, superType.getQualifiedName(), expectedType.getName(),
                        element.getName()), element, feature, index, INVALID_IMPLEMENTED_TYPE,
                        superType.getSimpleName());
                success = false;
            } else {
                ++nb;
            }
            ++index;
        }
        if (nb < mandatoryNumberOfTypes) {
            error(MessageFormat.format(Messages.SARLValidator_36, expectedType.getName(), element.getName()),
                    element, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, MISSING_TYPE);
            success = false;
        }
        return success;
    }

    /** Check if the parameter of the bahavior unit is an event.
     *
     * @param behaviorUnit - the behavior unit to test.
     */
    @Check(CheckType.FAST)
    public void checkBehaviorUnitEventType(SarlBehaviorUnit behaviorUnit) {
        JvmTypeReference event = behaviorUnit.getName();
        LightweightTypeReference ref = toLightweightTypeReference(event);
        if (ref == null || ref.isInterfaceType() || !ref.isSubtypeOf(Event.class)) {
            error(MessageFormat.format(Messages.SARLValidator_24, event.getQualifiedName(),
                    Messages.SARLValidator_26,
                    this.grammarAccess.getBehaviorUnitAccess().getOnKeyword_2().getValue()), event, null,
                    ValidationMessageAcceptor.INSIGNIFICANT_INDEX, TYPE_BOUNDS_MISMATCH);
        }
    }

    /** Check if a capacity has a feature defined inside.
     *
     * @param capacity - the capacity to test.
     */
    @Check(CheckType.FAST)
    public void checkCapacityFeatures(SarlCapacity capacity) {
        if (capacity.getMembers().isEmpty()) {
            if (!isIgnored(DISCOURAGED_CAPACITY_DEFINITION)) {
                addIssue(Messages.SARLValidator_37, capacity, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
                        DISCOURAGED_CAPACITY_DEFINITION, capacity.getName(), "aFunction"); //$NON-NLS-1$
            }
        }
    }

    private static JvmAnnotationReference doGetFirstAnnotation(JvmOperation operation, final String annotationId) {
        return IterableExtensions.findFirst(operation.getAnnotations(),
                new Functions.Function1<JvmAnnotationReference, Boolean>() {
                    @Override
                    public Boolean apply(JvmAnnotationReference it) {
                        return Objects.equal(it.getAnnotation().getIdentifier(), annotationId);
                    }
                });
    }

    private boolean doGetLocalUsage(Collection<JvmOperation> operations, EObject container) {
        Iterator<JvmOperation> iterator = operations.iterator();
        boolean found = false;
        while (!found && iterator.hasNext()) {
            JvmOperation operation = iterator.next();
            if (isLocallyUsed(operation, container)) {
                found = true;
            }
        }
        return found;
    }

    /** Check for unused capacities.
     *
     * @param uses - the capacity use declaration.
     */
    @SuppressWarnings("unchecked")
    @Check(CheckType.NORMAL)
    public void checkUnusedCapacities(SarlCapacityUses uses) {
        if (!isIgnored(UNUSED_AGENT_CAPACITY)) {
            EObject container = uses.getDeclaringType();
            EObject jvmContainer = this.associations.getPrimaryJvmElement(container);

            final String annotationId = ImportedCapacityFeature.class.getName();
            Multimap<String, JvmOperation> importedFeatures = Multimaps.newMultimap(
                    CollectionLiterals.<String, Collection<JvmOperation>>newHashMap(),
                    new Supplier<Collection<JvmOperation>>() {
                        @Override
                        public Collection<JvmOperation> get() {
                            return CollectionLiterals.<JvmOperation>newArrayList();
                        }
                    });
            Iterable<EObject> fitleredObjects = IterableExtensions.filter(jvmContainer.eContents(),
                    new Functions.Function1<EObject, Boolean>() {
                        @SuppressWarnings("synthetic-access")
                        @Override
                        public Boolean apply(EObject it) {
                            if (it instanceof JvmOperation) {
                                JvmOperation operation = (JvmOperation) it;
                                if (doGetFirstAnnotation(operation, annotationId) != null) {
                                    return Boolean.TRUE;
                                }
                            }
                            return Boolean.FALSE;
                        }

                    });
            for (EObject method : fitleredObjects) {
                JvmOperation operation = (JvmOperation) method;
                EList<JvmAnnotationValue> annotationValues = doGetFirstAnnotation(operation, annotationId)
                        .getValues();
                JvmTypeAnnotationValue annotationType = (JvmTypeAnnotationValue) annotationValues.get(0);
                JvmTypeReference capacityType = annotationType.getValues().get(0);
                importedFeatures.put(capacityType.getIdentifier(), operation);
            }

            int index = 0;
            for (JvmTypeReference capacity : uses.getCapacities()) {
                Collection<JvmOperation> operations = importedFeatures.get(capacity.getIdentifier());
                if (!operations.isEmpty()) {
                    if (!doGetLocalUsage(operations, container)) {
                        addIssue(MessageFormat.format(Messages.SARLValidator_42, capacity.getSimpleName()), uses,
                                SARL_CAPACITY_USES__CAPACITIES, index, UNUSED_AGENT_CAPACITY,
                                capacity.getSimpleName());
                    }
                }
                ++index;
            }
        }
    }

    private static Set<String> doGetPreviousCapacities(SarlCapacityUses uses, Iterator<XtendMember> iterator) {
        boolean continueToFill = true;
        Set<String> capacityUses = CollectionLiterals.newTreeSet((Comparator<String>) null);
        while (continueToFill && iterator.hasNext()) {
            XtendMember elt = iterator.next();
            if (elt instanceof SarlCapacityUses) {
                SarlCapacityUses usesElt = (SarlCapacityUses) elt;
                if (usesElt == uses) {
                    continueToFill = false;
                } else {
                    for (JvmTypeReference use : usesElt.getCapacities()) {
                        capacityUses.add(use.getIdentifier());
                    }
                }
            }
        }
        return capacityUses;
    }

    /** Check for multiple capacity use declaration.
     *
     * @param uses - the capacity use declaration.
     */
    @Check(CheckType.NORMAL)
    public void checkMultipleCapacityUses(SarlCapacityUses uses) {
        if (!isIgnored(REDUNDANT_CAPACITY_USE)) {
            XtendTypeDeclaration declaringType = uses.getDeclaringType();
            if (declaringType != null) {
                Set<String> previousCapacityUses = doGetPreviousCapacities(uses,
                        declaringType.getMembers().iterator());
                int index = 0;
                for (JvmTypeReference capacity : uses.getCapacities()) {
                    if (previousCapacityUses.contains(capacity.getIdentifier())) {
                        addIssue(MessageFormat.format(Messages.SARLValidator_43, capacity.getSimpleName()), uses,
                                SARL_CAPACITY_USES__CAPACITIES, index, REDUNDANT_CAPACITY_USE,
                                capacity.getSimpleName());
                    } else {
                        previousCapacityUses.add(capacity.getIdentifier());
                    }
                    ++index;
                }
            }
        }
    }

    /** Check for abstract methods.
     *
     * <p>Override the Xtend behavior for: <ul>
     * <li>not generating an error when a return type is missed. Indeed, the return type if "void" by default.</li>
     * <li>generating a warning when "abstract" is missed.</li>
     * </ul>
     *
     * <p>XXX: Update this function with the code of the derived function.
     */
    @Check
    @Override
    @SuppressWarnings("checkstyle:cyclomaticcomplexity")
    public void checkAbstract(XtendFunction function) {
        XtendTypeDeclaration declarator = function.getDeclaringType();
        if (function.getExpression() == null || function.isAbstract()) {
            if (declarator instanceof XtendClass || declarator.isAnonymous() || declarator instanceof SarlAgent
                    || declarator instanceof SarlBehavior || declarator instanceof SarlSkill) {
                if (function.isDispatch()) {
                    error(MessageFormat.format(Messages.SARLValidator_32, function.getName(),
                            this.localClassAwareTypeNames.getReadableName(declarator)), XTEND_FUNCTION__NAME, -1,
                            DISPATCH_FUNCTIONS_MUST_NOT_BE_ABSTRACT);
                    return;
                }
                if (function.getCreateExtensionInfo() != null) {
                    error(MessageFormat.format(Messages.SARLValidator_33, function.getName(),
                            this.localClassAwareTypeNames.getReadableName(declarator)), XTEND_FUNCTION__NAME, -1,
                            CREATE_FUNCTIONS_MUST_NOT_BE_ABSTRACT);
                    return;
                }
                if (declarator.isAnonymous()) {
                    error(MessageFormat.format(Messages.SARLValidator_34, function.getName(),
                            this.localClassAwareTypeNames.getReadableName(declarator)), XTEND_FUNCTION__NAME, -1,
                            MISSING_ABSTRACT_IN_ANONYMOUS);
                } else {
                    boolean isAbstract;
                    if (declarator instanceof XtendClass) {
                        isAbstract = ((XtendClass) declarator).isAbstract();
                    } else if (declarator instanceof SarlAgent) {
                        isAbstract = ((SarlAgent) declarator).isAbstract();
                    } else if (declarator instanceof SarlBehavior) {
                        isAbstract = ((SarlBehavior) declarator).isAbstract();
                    } else if (declarator instanceof SarlSkill) {
                        isAbstract = ((SarlSkill) declarator).isAbstract();
                    } else {
                        return;
                    }
                    if (!isAbstract && !function.isNative()) {
                        error(MessageFormat.format(Messages.SARLValidator_35, function.getName(),
                                this.localClassAwareTypeNames.getReadableName(declarator)), XTEND_FUNCTION__NAME,
                                -1, MISSING_ABSTRACT);
                        return;
                    }
                }

                if (!function.getModifiers().contains("abstract")) { //$NON-NLS-1$
                    warning(MessageFormat.format(Messages.SARLValidator_36, function.getName(),
                            this.localClassAwareTypeNames.getReadableName(declarator)), XTEND_FUNCTION__NAME, -1,
                            MISSING_ABSTRACT, function.getName(),
                            this.localClassAwareTypeNames.getReadableName(declarator));
                }

            } else if (declarator instanceof XtendInterface || declarator instanceof SarlCapacity) {
                if (function.getCreateExtensionInfo() != null) {
                    error(MessageFormat.format(Messages.SARLValidator_37, function.getName()), XTEND_FUNCTION__NAME,
                            -1, CREATE_FUNCTIONS_MUST_NOT_BE_ABSTRACT);
                    return;
                }
            }
        } else if (declarator instanceof XtendInterface || declarator instanceof SarlCapacity) {
            if (!getGeneratorConfig(function).getJavaSourceVersion().isAtLeast(JAVA8)) {
                error(Messages.SARLJavaValidator_38, XTEND_FUNCTION__NAME, -1, ABSTRACT_METHOD_WITH_BODY);
                return;
            }
        }
    }

    /** The modifier validator for constructors.
     *
     * @author $Author: sgalland$
     * @version $FullVersion$
     * @mavengroupid $GroupId$
     * @mavenartifactid $ArtifactId$
     */
    protected final class SARLModifierValidator extends ModifierValidator {

        /**
         * @param modifiers - the list of the supported modifiers.
         */
        private SARLModifierValidator(List<String> modifiers) {
            super(modifiers, SARLValidator.this);
        }

        /** Make this function visible for the enclosing class.
         *
         * @param member - the member to check.
         * @param memberName - the name of the member, usually for the issue message.
         */
        @Override
        protected void checkModifiers(XtendMember member, String memberName) {
            super.checkModifiers(member, memberName);
        }

        /** Generate a warning.
         *
         * @param message - the warning message.
         * @param source - the source of the warning.
         * @param index - the index of the modifier.
         */
        protected void warning(String message, EObject source, int index) {
            SARLValidator.this.acceptWarning(message, source, XTEND_MEMBER__MODIFIERS, index,
                    IssueCodes.INVALID_MODIFIER);
        }

    }

}