From 960b07c47ac803d7e697c69efc13f9072a64884e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Galland?= Date: Mon, 20 Aug 2018 13:58:27 +0200 Subject: [PATCH] [lang] Detection of the invalid and discouraged uses of occurrences is refactored. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to take into account variadic arguments, the validation algorithm that is related to the invalid or discouraged uses of ocurrence is refactored. The tool IImmutableTypeValidator is provided in order to determine if a given type is assumed to be immutable (primitive types, String, etc.). close #847 Signed-off-by: Stéphane Galland --- .../DefaultImmutableTypeValidator.java | 81 ++++ .../typesystem/IImmutableTypeValidator.java | 50 +++ .../src/io/sarl/lang/util/Utils.java | 42 +++ .../src/io/sarl/lang/validation/Messages.java | 1 + .../sarl/lang/validation/SARLValidator.java | 351 ++++++++++++------ .../sarl/lang/validation/messages.properties | 9 +- .../io.sarl.lang.targetplatform.target | 2 +- .../sarl/lang/tests/bugs/to00699/Bug483.java | 102 +++++ .../sarl/lang/tests/bugs/to00999/Bug846.java | 18 - .../sarl/lang/tests/bugs/to00999/Bug847.java | 274 ++++++++++++++ 10 files changed, 786 insertions(+), 144 deletions(-) create mode 100644 main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/DefaultImmutableTypeValidator.java create mode 100644 main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/IImmutableTypeValidator.java create mode 100644 tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug847.java diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/DefaultImmutableTypeValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/DefaultImmutableTypeValidator.java new file mode 100644 index 0000000000..d0e8077637 --- /dev/null +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/DefaultImmutableTypeValidator.java @@ -0,0 +1,81 @@ +/* + * $Id$ + * + * SARL is an general-purpose agent programming language. + * More details on http://www.sarl.io + * + * Copyright (C) 2014-2018 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.typesystem; + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; +import java.net.URL; +import java.util.Date; +import java.util.Locale; +import java.util.UUID; + +import com.google.inject.Singleton; +import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference; + +/** + * Tool for validating the types against their immutability. + * + *

An immutable type is a type those state cannot be changed after it is constructed. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.8 + */ +@Singleton +public class DefaultImmutableTypeValidator implements IImmutableTypeValidator { + + private static final Class[] IMMUTABLE_TYPES = { + String.class, + UUID.class, + URL.class, + URI.class, + Enum.class, + Number.class, + Date.class, + File.class, + Locale.class, + InetAddress.class, + StackTraceElement.class, + }; + + @Override + public boolean isImmutable(LightweightTypeReference type) { + assert type != null; + final LightweightTypeReference ref = type.getPrimitiveIfWrapperType(); + if (ref.isArray()) { + return false; + } + if (ref.isPrimitive() || ref.isPrimitiveVoid()) { + return true; + } + for (final Class jvmType : IMMUTABLE_TYPES) { + if (type.isSubtypeOf(jvmType)) { + return true; + } + } + return false; + } + +} diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/IImmutableTypeValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/IImmutableTypeValidator.java new file mode 100644 index 0000000000..9bc578b3a7 --- /dev/null +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/typesystem/IImmutableTypeValidator.java @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * SARL is an general-purpose agent programming language. + * More details on http://www.sarl.io + * + * Copyright (C) 2014-2018 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.typesystem; + +import com.google.inject.ImplementedBy; +import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference; + +/** + * Tool for validating the types against their immutability. + * + *

An immutable type is a type those state cannot be changed after it is constructed. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.8 + */ +@ImplementedBy(DefaultImmutableTypeValidator.class) +public interface IImmutableTypeValidator { + + /** Replies if the given type is associated to an immutable type. + * + *

An unmodifiable type is a primitive type or an object type those state cannot + * be changed after is it created in memory, e.g. {@link String}. + * @param type the type to test. + * @return {@code true} if the given type is known as unmodifiable. Otherwise {@code false}. + */ + boolean isImmutable(LightweightTypeReference type); + +} diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java index 93366b15c5..038bbb201c 100644 --- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java @@ -1261,6 +1261,48 @@ public static boolean getContainerNotOfType(EObject element, Class container, OutParameter directContainerChild, + Class... types) { + EObject previous = element; + EObject elt = element.eContainer(); + while (elt != null) { + if (isInstance(types, elt)) { + if (directContainerChild != null) { + directContainerChild.set(previous); + } + if (container != null) { + container.set(elt); + } + return true; + } + previous = elt; + elt = elt.eContainer(); + } + return false; + } + + private static boolean isInstance(Class[] types, Object element) { + for (final Class type : types) { + if (type.isInstance(element)) { + return true; + } + } + return false; + } + /** * Returns the closest {@link EObject#eContainer() container object} that is validating the predicate. * diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java index e788db9536..4199320880 100644 --- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java @@ -128,6 +128,7 @@ private Messages() { public static String SARLValidator_9; public static String SARLValidator_90; public static String SARLValidator_91; + public static String SARLValidator_92; public static String SARLSyntaxErrorMessageProvider_0; public static String SARLSyntaxErrorMessageProvider_1; } diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java index 158bb29f14..d55c871ad5 100644 --- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java @@ -102,7 +102,6 @@ import com.google.common.collect.Sets; import com.google.inject.Inject; import org.eclipse.emf.common.notify.Notifier; -import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; @@ -133,7 +132,9 @@ import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.common.types.JvmConstructor; import org.eclipse.xtext.common.types.JvmDeclaredType; +import org.eclipse.xtext.common.types.JvmExecutable; import org.eclipse.xtext.common.types.JvmField; +import org.eclipse.xtext.common.types.JvmFormalParameter; import org.eclipse.xtext.common.types.JvmGenericType; import org.eclipse.xtext.common.types.JvmIdentifiableElement; import org.eclipse.xtext.common.types.JvmOperation; @@ -162,6 +163,8 @@ import org.eclipse.xtext.xbase.XExpression; import org.eclipse.xtext.xbase.XFeatureCall; import org.eclipse.xtext.xbase.XForLoopExpression; +import org.eclipse.xtext.xbase.XMemberFeatureCall; +import org.eclipse.xtext.xbase.XPostfixOperation; import org.eclipse.xtext.xbase.XSynchronizedExpression; import org.eclipse.xtext.xbase.XTypeLiteral; import org.eclipse.xtext.xbase.XVariableDeclaration; @@ -171,6 +174,7 @@ import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Inline; import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; 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; @@ -217,6 +221,7 @@ import io.sarl.lang.sarl.actionprototype.ActionParameterTypes; import io.sarl.lang.sarl.actionprototype.IActionPrototypeProvider; import io.sarl.lang.services.SARLGrammarKeywordAccess; +import io.sarl.lang.typesystem.IImmutableTypeValidator; import io.sarl.lang.typesystem.IOperationHelper; import io.sarl.lang.typesystem.InheritanceHelper; import io.sarl.lang.typesystem.SARLExpressionHelper; @@ -254,42 +259,42 @@ public class SARLValidator extends AbstractSARLValidator { @SuppressWarnings("synthetic-access") private final SARLModifierValidator agentModifierValidator = new SARLModifierValidator( newArrayList("public", "package", "abstract", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - "final")); //$NON-NLS-1$ + "final")); //$NON-NLS-1$ @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$ + "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$ @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$ + "package", //$NON-NLS-1$ + "protected", "private", //$NON-NLS-1$//$NON-NLS-2$ + "final", "val", "var")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ @SuppressWarnings("synthetic-access") private final SARLModifierValidator behaviorModifierValidator = new SARLModifierValidator( newArrayList("public", "package", "abstract", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - "final")); //$NON-NLS-1$ + "final")); //$NON-NLS-1$ @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$ + "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$ @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$ + "package", //$NON-NLS-1$ + "protected", "private", //$NON-NLS-1$//$NON-NLS-2$ + "final", "val", "var")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ @SuppressWarnings("synthetic-access") private final SARLModifierValidator capacityModifierValidator = new SARLModifierValidator( @@ -298,7 +303,7 @@ public class SARLValidator extends AbstractSARLValidator { @SuppressWarnings("synthetic-access") private final SARLModifierValidator methodInCapacityModifierValidator = new SARLModifierValidator( newArrayList( - "public", "def", "override")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + "public", "def", "override")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ @SuppressWarnings("synthetic-access") private final SARLModifierValidator eventModifierValidator = new SARLModifierValidator( @@ -307,53 +312,53 @@ public class SARLValidator extends AbstractSARLValidator { @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$ + "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")); //$NON-NLS-1$ + "final")); //$NON-NLS-1$ @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$ + "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$ @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$ + "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$ @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")); //$NON-NLS-1$ + "package", "protected", //$NON-NLS-1$ //$NON-NLS-2$ + "private", "static", "final", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "abstract")); //$NON-NLS-1$ @SuppressWarnings("synthetic-access") private final SARLModifierValidator nestedInterfaceInAgentModifierValidator = new SARLModifierValidator( newArrayList( - "package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "static", "abstract")); //$NON-NLS-1$ //$NON-NLS-2$ + "package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "static", "abstract")); //$NON-NLS-1$ //$NON-NLS-2$ @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$ + "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$ + "package", "protected", "private", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "static", "abstract")); //$NON-NLS-1$ //$NON-NLS-2$ @Inject private SarlJvmModelAssociations associations; @@ -394,6 +399,9 @@ public class SARLValidator extends AbstractSARLValidator { @Inject private IDefaultVisibilityProvider defaultVisibilityProvider; + @Inject + private IImmutableTypeValidator immutableTypeValidator; + // Update the annotation target information { final ImmutableMultimap.Builder, ElementType> result = ImmutableMultimap.builder(); @@ -490,10 +498,10 @@ protected String canonicalName(EObject object) { @Check public void checkSpaceUse(SarlSpace space) { error(MessageFormat.format( - Messages.SARLValidator_0, - this.grammarAccess.getSpaceKeyword()), - space, - null); + Messages.SARLValidator_0, + this.grammarAccess.getSpaceKeyword()), + space, + null); } /** Artifact keyword is reserved. @@ -503,10 +511,10 @@ public void checkSpaceUse(SarlSpace space) { @Check public void checkArtifactUse(SarlArtifact artifact) { error(MessageFormat.format( - Messages.SARLValidator_0, - this.grammarAccess.getSpaceKeyword()), - artifact, - null); + Messages.SARLValidator_0, + this.grammarAccess.getSpaceKeyword()), + artifact, + null); } /** Emit a warning when the "fires" keyword is used. @@ -564,8 +572,8 @@ public void checkClassPath(XtendFile sarlScript) { final JavaVersion javaVersion = JavaVersion.fromQualifier(SARLVersion.MINIMAL_JDK_VERSION); final JavaVersion generatorVersion = generatorConfiguration.getJavaSourceVersion(); if (generatorVersion == null - || javaVersion == null - || !generatorVersion.isAtLeast(javaVersion)) { + || javaVersion == null + || !generatorVersion.isAtLeast(javaVersion)) { error( MessageFormat.format( Messages.SARLValidator_4, @@ -634,7 +642,7 @@ public void checkClassPath(XtendFile sarlScript) { } else if (!Utils.isCompatibleSARLLibraryVersion(sarlLibraryVersion.get())) { error( MessageFormat.format(Messages.SARLValidator_8, - sarlLibraryVersion.get(), SARLVersion.SPECIFICATION_RELEASE_VERSION), + sarlLibraryVersion.get(), SARLVersion.SPECIFICATION_RELEASE_VERSION), sarlScript, XtendPackage.Literals.XTEND_FILE__PACKAGE, io.sarl.lang.validation.IssueCodes.INVALID_SARL_LIB_ON_CLASSPATH); @@ -790,8 +798,8 @@ protected void checkModifiers(XtendClass oopClass) { // This constraint should be never removed from Xtend: https://www.eclipse.org/forums/index.php/m/1774946/ if (!oopClass.isStatic() && ((econtainer instanceof SarlAgent) - || (econtainer instanceof SarlBehavior) - || (econtainer instanceof SarlSkill))) { + || (econtainer instanceof SarlBehavior) + || (econtainer instanceof SarlSkill))) { error(Messages.SARLValidator_25, XTEND_TYPE_DECLARATION__NAME, -1, MISSING_STATIC_MODIFIER); } } @@ -960,7 +968,7 @@ public void checkFinalFieldInitialization(SarlAgent agent) { * @param defaultSignatures the signatures of the default constructors for the given container. */ @SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity", - "checkstyle:nestedifdepth"}) + "checkstyle:nestedifdepth"}) protected void checkSuperConstructor( XtendTypeDeclaration container, EStructuralFeature feature, @@ -1125,8 +1133,8 @@ public void checkForbiddenCalls(XAbstractFeatureCall expression) { if (this.featureCallValidator.isDisallowedCall(expression)) { error( MessageFormat.format( - Messages.SARLValidator_36, - expression.getFeature().getIdentifier()), + Messages.SARLValidator_36, + expression.getFeature().getIdentifier()), expression, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, @@ -1146,7 +1154,7 @@ public void checkDiscouragedCalls(XAbstractFeatureCall expression) { && this.featureCallValidator.isDiscouragedCall(expression)) { addIssue( MessageFormat.format(Messages.SARLValidator_37, - expression.getConcreteSyntaxFeatureName()), + expression.getConcreteSyntaxFeatureName()), expression, DISCOURAGED_REFERENCE); } @@ -1819,7 +1827,7 @@ public void checkSuperType(SarlSkill skill) { skill.getImplements(), Capacity.class, nbSuperTypes > 0 ? 0 : 1, - true); + true); } /** Check if the supertype of the given event is a subtype of Event. @@ -1889,7 +1897,7 @@ protected boolean checkImplementedTypes( final LightweightTypeReference ref = toLightweightTypeReference(superType); if (ref != null && (!ref.isInterfaceType() || !ref.isSubtypeOf(expectedType) - || (onlySubTypes && ref.isType(expectedType)))) { + || (onlySubTypes && ref.isType(expectedType)))) { final String msg; if (onlySubTypes) { msg = Messages.SARLValidator_72; @@ -2210,86 +2218,186 @@ public void checkManualInlineDefinition(XtendAnnotationTarget annotationTarget) } } - @SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:nestedifdepth"}) - private void checkUnmodifiableEventAccess(boolean enable1, XFeatureCall child) { - EObject previous = child; - EObject elt = child.eContainer(); - EObject container = null; - while (elt != null && container == null) { - final EClass type = elt.eClass(); - if (XbasePackage.Literals.XASSIGNMENT.equals(type)) { - final XAssignment assign = (XAssignment) elt; - if (previous == assign.getActualReceiver()) { - error(Messages.SARLValidator_2, - child, + /** Replies the member feature call that is the root of a sequence of member feature calls. + * + *

While the current feature call is the actual receiver of a member feature call, the sequence is still active. + * Otherwise, the sequence is stopped. + * + * @param leaf the expression at the leaf of the feature call. + * @param container the top most container that cannot be part of the sequence. Could be {@code null}. + * @param feedback the function that is invoked on each discovered member feature call within the sequence. Could be {@code null}. + * @return the root of a member feature call sequence. + */ + protected static XMemberFeatureCall getRootOfMemberFeatureCallSequence(EObject leaf, EObject container, + Procedure1 feedback) { + EObject call = leaf; + EObject obj = EcoreUtil2.getContainerOfType(leaf.eContainer(), XExpression.class); + while (obj != null && (container == null || obj != container)) { + if (!(obj instanceof XMemberFeatureCall)) { + obj = null; + } else { + final EObject previous = call; + final XMemberFeatureCall fcall = (XMemberFeatureCall) obj; + call = fcall; + if (fcall.getActualReceiver() == previous) { + if (feedback != null) { + feedback.apply(fcall); + } + obj = EcoreUtil2.getContainerOfType(call.eContainer(), XExpression.class); + } else { + obj = null; + } + } + } + return call instanceof XMemberFeatureCall ? (XMemberFeatureCall) call : null; + } + + @SuppressWarnings({"checkstyle:nestedifdepth", "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity"}) + private void checkUnmodifiableFeatureAccess(boolean enableWarning, EObject readOnlyKeyword, String keywordName) { + final OutParameter container = new OutParameter<>(); + final OutParameter directContainerChild = new OutParameter<>(); + + final OutParameter failure = new OutParameter<>(false); + final XMemberFeatureCall sequence = getRootOfMemberFeatureCallSequence(readOnlyKeyword, null, it -> { + // Function call: if one of the functions called on the read-only keyword is not pure => WARNING + if (getExpressionHelper().hasSideEffects(it)) { + addIssue(MessageFormat.format(Messages.SARLValidator_11, keywordName), + it, + IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); + failure.set(true); + } + }); + if (failure.get().booleanValue()) { + return; + } + final EObject expression = sequence == null ? readOnlyKeyword : sequence; + + if (Utils.getContainerOfType(expression, container, directContainerChild, + XAssignment.class, XVariableDeclaration.class)) { + if (container.get() instanceof XAssignment) { + // Assignment: occurrence in left side => ERROR + final XAssignment assignment = (XAssignment) container.get(); + if (directContainerChild.get() == assignment.getActualReceiver()) { + error(MessageFormat.format(Messages.SARLValidator_2, keywordName), + readOnlyKeyword, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, IssueCodes.INVALID_OCCURRENCE_READONLY_USE); return; } - container = elt; - } else if (XbasePackage.Literals.XBINARY_OPERATION.equals(type) - || XbasePackage.Literals.XUNARY_OPERATION.equals(type) - || XbasePackage.Literals.XPOSTFIX_OPERATION.equals(type)) { - if (enable1 && getExpressionHelper().hasSideEffects((XExpression) elt)) { - addIssue(Messages.SARLValidator_11, - elt, + } else if (enableWarning && container.get() instanceof XVariableDeclaration) { + final XVariableDeclaration declaration = (XVariableDeclaration) container.get(); + if (directContainerChild.get() == declaration.getRight()) { + // Inside the initial value of a variable. + // If the variable has a primitive type => No problem. + // If the keyword is used in member feature calls => Warning + final LightweightTypeReference variableType = getActualType(sequence); + if (!this.immutableTypeValidator.isImmutable(variableType)) { + if (expression == null || expression == declaration.getRight()) { + addIssue(MessageFormat.format(Messages.SARLValidator_12, keywordName), + sequence, + IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); + return; + } + } + } + } + } + + if (enableWarning) { + if (Utils.getContainerOfType(expression, container, directContainerChild, + XFeatureCall.class, XMemberFeatureCall.class, XConstructorCall.class, + XPostfixOperation.class)) { + // Side effect Operator: occurrence in one of the operands => WARNING + if (container.get() instanceof XPostfixOperation) { + error(MessageFormat.format(Messages.SARLValidator_13, keywordName), + readOnlyKeyword, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, - IssueCodes.DISCOURAGED_BOOLEAN_EXPRESSION); + IssueCodes.INVALID_OCCURRENCE_READONLY_USE); return; } - container = elt; - } else if (elt instanceof XAbstractFeatureCall) { - final XAbstractFeatureCall featureCall = (XAbstractFeatureCall) elt; - if (featureCall.getFeature() instanceof JvmOperation && featureCall instanceof XFeatureCall) { - if (enable1) { - final XFeatureCall xfeatureCall = (XFeatureCall) featureCall; - final JvmOperation operation = (JvmOperation) featureCall.getFeature(); - boolean stopCheck = false; - int paramIndex = 0; - for (final XExpression arg : xfeatureCall.getActualArguments()) { - if (arg == previous) { - final LightweightTypeReference paramType = getActualType(operation.getParameters().get(paramIndex)); - if (!paramType.isPrimitive()) { - addIssue( - Messages.SARLValidator_12, - arg, - IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); - stopCheck = true; - } - } - ++paramIndex; + // Function argument: direct passing, if function has side effect => WARNING + final List arguments; + final List parameters; + final boolean hasSideEffects; + final boolean isVariadic; + if (container.get() instanceof XConstructorCall) { + final XConstructorCall cons = (XConstructorCall) container.get(); + arguments = cons.getArguments(); + final JvmConstructor constructor = cons.getConstructor(); + parameters = getParamTypeReferences(constructor, false, true); + hasSideEffects = false; + isVariadic = constructor.isVarArgs(); + } else { + final XAbstractFeatureCall call = (XAbstractFeatureCall) container.get(); + if (call.getFeature() instanceof JvmOperation) { + arguments = call.getActualArguments(); + final JvmOperation operation = (JvmOperation) call.getFeature(); + parameters = getParamTypeReferences(operation, false, true); + hasSideEffects = getExpressionHelper().hasSideEffects(call); + isVariadic = operation.isVarArgs(); + } else { + arguments = null; + parameters = null; + hasSideEffects = false; + isVariadic = false; + } + } + if (arguments != null && hasSideEffects) { + assert parameters != null; + final int index = arguments.indexOf(directContainerChild.get()); + if (index >= 0 && !parameters.isEmpty()) { + final boolean isPrimitive; + final int endIndex = parameters.size() - 1; + if (index < endIndex || (!isVariadic && index == endIndex)) { + isPrimitive = this.immutableTypeValidator.isImmutable(parameters.get(index)); + } else if (isVariadic && index == endIndex) { + // Assume argument for the variadic parameter. + LightweightTypeReference parameter = parameters.get(endIndex); + assert parameter.isArray(); + parameter = parameter.getComponentType().getWrapperTypeIfPrimitive(); + isPrimitive = this.immutableTypeValidator.isImmutable(parameter); + } else { + // Problem in the calling syntax: invalid number of arguments. + // Avoid to output the warning. + isPrimitive = true; } - if (stopCheck) { + if (!isPrimitive) { + addIssue(MessageFormat.format(Messages.SARLValidator_92, keywordName), + sequence, + IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); return; } } - container = elt; - } else { - if (enable1 && getExpressionHelper().hasSideEffects(featureCall)) { - addIssue( - Messages.SARLValidator_13, - elt, - IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); - return; - } - previous = elt; - elt = elt.eContainer(); } - } else { - container = elt; } } - if (container instanceof XVariableDeclaration && previous instanceof XExpression) { - final LightweightTypeReference variableType = getActualType((XExpression) previous); - if (!variableType.isPrimitive()) { - addIssue( - Messages.SARLValidator_12, - previous, - IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); + } + + /** Retrieve the types of the formal parameters of the given JVM executable object. + * + * @param jvmExecutable the JVM executable. + * @param wrapFromPrimitives indicates if the primitive types must be wrapped to object type equivalent. + * @param wrapToPrimitives indicates if the object types must be wrapped to primitive type equivalent. + * @return the list of types. + * @since 0.8 + * @see #getParamTypes(JvmOperation, boolean) + */ + protected List getParamTypeReferences(JvmExecutable jvmExecutable, + boolean wrapFromPrimitives, boolean wrapToPrimitives) { + assert (wrapFromPrimitives && !wrapToPrimitives) || (wrapToPrimitives && !wrapFromPrimitives); + final List types = newArrayList(); + for (final JvmFormalParameter parameter : jvmExecutable.getParameters()) { + LightweightTypeReference typeReference = toLightweightTypeReference(parameter.getParameterType()); + if (wrapFromPrimitives) { + typeReference = typeReference.getWrapperTypeIfPrimitive(); + } else if (wrapToPrimitives) { + typeReference = typeReference.getPrimitiveIfWrapperType(); } + types.add(typeReference); } + return types; } /** Check for usage of the event functions in the behavior units. @@ -2300,9 +2408,10 @@ private void checkUnmodifiableEventAccess(boolean enable1, XFeatureCall child) { public void checkUnmodifiableEventAccess(SarlBehaviorUnit unit) { final boolean enable1 = !isIgnored(IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); final XExpression root = unit.getExpression(); + final String occurrenceKw = this.grammarAccess.getOccurrenceKeyword(); for (final XFeatureCall child : EcoreUtil2.getAllContentsOfType(root, XFeatureCall.class)) { - if (this.grammarAccess.getOccurrenceKeyword().equals(child.getFeature().getIdentifier())) { - checkUnmodifiableEventAccess(enable1, child); + if (occurrenceKw.equals(child.getFeature().getIdentifier())) { + checkUnmodifiableFeatureAccess(enable1, child, occurrenceKw); } } } @@ -2597,7 +2706,7 @@ protected void checkAssignment(XExpression expression, EStructuralFeature featur if (container != null && container instanceof JvmOperation) { final JvmOperation operation = (JvmOperation) container; if (operation.isStatic() && field.getDeclaringType() == operation.getDeclaringType() - && Utils.STATIC_CONSTRUCTOR_NAME.equals(operation.getSimpleName())) { + && Utils.STATIC_CONSTRUCTOR_NAME.equals(operation.getSimpleName())) { return; } } diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/messages.properties b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/messages.properties index 650edc8ca5..5df7eea9d7 100644 --- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/messages.properties +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/messages.properties @@ -1,16 +1,16 @@ SARLValidator_0=The statement ''{0}'' is not yet supported by the SARL compiler. SARLValidator_1=The ''{0}'' declaration is not used by the SARL compiler yet. SARLValidator_10=definition of {0} in {1} -SARLValidator_11=Invalid use of the read-only occurrence. You cannot invoke a not-pure function on occurrence's component. -SARLValidator_12=Discouraged use of occurrence in a not read-only context. The called function could change the internal state of the argument, when occurrence's value is supposed to be immutable. -SARLValidator_13=Discouraged use of occurrence in a not read-only context. +SARLValidator_11=Discouraged use of the feature ''{0}'. You should not call a not-pure action on the feature ''{0}''. +SARLValidator_12=Discouraged use of the feature ''{0}'. The value of the feature ''{0}'', or not of its component seems to be copied within a local variable. It means cause unexpected border effects on the value of ''{0}''. +SARLValidator_13=Invalid use of the unmodifiable feature ''{0}''. You cannot use ''{0}'' as the operand of a postfix operator because it causes a border effect. SARLValidator_14=Invalid parameter name ''{0}''. You must not use a keyword for naming a parameter. SARLValidator_15=Invalid variable name ''{0}''. You must not use a keyword for naming a parameter. SARLValidator_16=Discouraged manual definition of an inline expression. Inline expression definition is reserved for advanced usage. SARLValidator_17=Discouraged use of the {0} keyword inside a basic loop. SARLValidator_18=Invalid use of the {0} keyword. It could only be used inside loops. SARLValidator_19=Forbidden reference to not final field {0} from a default value expression -SARLValidator_2=Invalid use of the read-only occurrence. You cannot use occurrence in the left-side of an assignment operator. +SARLValidator_2=Invalid use of the unmodifiable feature ''{0}''. You cannot use ''{0}'' at the left-side of an assignment operator. SARLValidator_20=Undefined type for the formal parameter {0} SARLValidator_21=Undefined type for the default value of the formal parameter {0} SARLValidator_22=Unnecessary use of the capacity ''{0}'' because it is implemented by the current skill. @@ -85,6 +85,7 @@ SARLValidator_89=Forbidden annotation in a SARL program. SARLValidator_9=definition of {0} SARLValidator_90=Forbidden annotation to an agent-oriented feature. SARLValidator_91=The field {0} should be synchronized for avoiding value inconsistency due to parallel execution. +SARLValidator_92=Discouraged use of the feature ''{0}'. You should not use the feature ''{0}'', or one of its member as argument of an action because it may be change by a border effect. SARLSyntaxErrorMessageProvider_0=''{0}'' is a reserved keyword which is not allowed as identifier. Please choose another word or alternatively confuse your co-workers by escaping it like this: "{1}". SARLSyntaxErrorMessageProvider_1=''{0}'' is a reserved keyword which is not allowed as identifier. Please choose another word. diff --git a/main/targetplatform/io.sarl.lang.targetplatform.target b/main/targetplatform/io.sarl.lang.targetplatform.target index 9fa2c16100..e82c96f932 100644 --- a/main/targetplatform/io.sarl.lang.targetplatform.target +++ b/main/targetplatform/io.sarl.lang.targetplatform.target @@ -36,7 +36,7 @@ - + diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00699/Bug483.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00699/Bug483.java index b7847b5999..b8ca565b62 100644 --- a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00699/Bug483.java +++ b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00699/Bug483.java @@ -127,7 +127,9 @@ public void updateObjectSetter_03() throws Exception { "agent TestAgent {", " on E1 {", " var x = occurrence.attr.setValue(1)", + " fct(p)", " }", + " def fct(p : int) {}", "}")); validate(mas).assertWarning( XbasePackage.eINSTANCE.getXMemberFeatureCall(), @@ -194,6 +196,28 @@ public void updateObjectGetter_02() throws Exception { validate(mas).assertNoIssues(); } + @Test + public void updateObjectGetter_03() throws Exception { + SarlScript mas = file(multilineString( + "package io.sarl.lang.tests.bug483", + "class XXX {", + " def getValue() : Object { null }", + "}", + "event E1 {", + " var attr : XXX", + "}", + "agent TestAgent {", + " on E1 {", + " var x = occurrence.attr.value", + " myfct(x)", + " }", + " def myfct(a : Object) { }", + "}")); + validate(mas).assertWarning( + XbasePackage.eINSTANCE.getXMemberFeatureCall(), + IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); + } + @Test public void updateObjectSetter_05() throws Exception { SarlScript mas = file(multilineString( @@ -234,6 +258,84 @@ public void updateObjectSetter_06() throws Exception { IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE); } + @Test + public void updateObjectSetter_07() throws Exception { + SarlScript mas = file(multilineString( + "package io.sarl.lang.tests.bug483", + "class XXX {", + " def getValue() : int { 0 }", + "}", + "event E1 {", + " var attr : XXX", + "}", + "agent TestAgent {", + " on E1 {", + " myfct(occurrence.attr.value);", + " }", + " def myfct(p : Integer) { }", + "}")); + validate(mas).assertNoIssues(); + } + + @Test + public void updateObjectSetter_08() throws Exception { + SarlScript mas = file(multilineString( + "package io.sarl.lang.tests.bug483", + "class XXX {", + " def getValue() : String { null }", + "}", + "event E1 {", + " var attr : XXX", + "}", + "agent TestAgent {", + " on E1 {", + " myfct(occurrence.attr.value);", + " }", + " def myfct(p : String) { }", + "}")); + validate(mas).assertNoIssues(); + } + + @Test + public void updateObjectSetter_09() throws Exception { + SarlScript mas = file(multilineString( + "package io.sarl.lang.tests.bug483", + "import java.math.BigInteger", + "class XXX {", + " def getValue() : BigInteger { null }", + "}", + "event E1 {", + " var attr : XXX", + "}", + "agent TestAgent {", + " on E1 {", + " myfct(occurrence.attr.value);", + " }", + " def myfct(p : BigInteger) { }", + "}")); + validate(mas).assertNoIssues(); + } + + @Test + public void updateObjectSetter_10() throws Exception { + SarlScript mas = file(multilineString( + "package io.sarl.lang.tests.bug483", + "enum MyEnum { CST1, CST2 }", + "class XXX {", + " def getValue() : MyEnum { MyEnum.CST2 }", + "}", + "event E1 {", + " var attr : XXX", + "}", + "agent TestAgent {", + " on E1 {", + " myfct(occurrence.attr.value);", + " }", + " def myfct(p : MyEnum) { }", + "}")); + validate(mas).assertNoIssues(); + } + @Test public void iterableInForStatement_01() throws Exception { SarlScript mas = file(multilineString( diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug846.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug846.java index 0977381d85..aa64209989 100644 --- a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug846.java +++ b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug846.java @@ -16,34 +16,16 @@ package io.sarl.lang.tests.bugs.to00999; -import static org.junit.Assert.*; - -import java.util.ArrayList; - import com.google.inject.Inject; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.jdt.core.dom.Type; -import org.eclipse.xtend.core.xtend.XtendClass; -import org.eclipse.xtext.common.types.JvmTypeReference; -import org.eclipse.xtext.common.types.TypesPackage; import org.eclipse.xtext.diagnostics.Diagnostic; -import org.eclipse.xtext.testing.util.ParseHelper; import org.eclipse.xtext.xbase.XbasePackage; import org.eclipse.xtext.xbase.testing.CompilationTestHelper; -import org.eclipse.xtext.xbase.typesystem.util.CommonTypeComputationServices; -import org.eclipse.xtext.xbase.validation.UIStrings; -import org.eclipse.xtext.xtype.XtypePackage; import org.junit.Test; import io.sarl.lang.SARLVersion; -import io.sarl.lang.annotation.SarlSpecification; -import io.sarl.lang.sarl.SarlField; import io.sarl.lang.sarl.SarlPackage; import io.sarl.lang.sarl.SarlScript; -import io.sarl.lang.util.Utils; -import io.sarl.lang.validation.IssueCodes; import io.sarl.tests.api.AbstractSarlTest; -import io.sarl.tests.api.AbstractSarlTest.Validator; /** Testing class for issue: Check power operator's priority over unrary minus operator. * diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug847.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug847.java new file mode 100644 index 0000000000..c35926afa4 --- /dev/null +++ b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00999/Bug847.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2014-2018 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.tests.bugs.to00999; + +import static org.junit.Assert.*; + +import java.util.ArrayList; + +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.xtend.core.xtend.XtendClass; +import org.eclipse.xtext.common.types.JvmTypeReference; +import org.eclipse.xtext.common.types.TypesPackage; +import org.eclipse.xtext.diagnostics.Diagnostic; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.xbase.XbasePackage; +import org.eclipse.xtext.xbase.testing.CompilationTestHelper; +import org.eclipse.xtext.xbase.typesystem.util.CommonTypeComputationServices; +import org.eclipse.xtext.xbase.validation.UIStrings; +import org.eclipse.xtext.xtype.XtypePackage; +import org.junit.Test; + +import io.sarl.lang.SARLVersion; +import io.sarl.lang.annotation.SarlSpecification; +import io.sarl.lang.sarl.SarlField; +import io.sarl.lang.sarl.SarlPackage; +import io.sarl.lang.sarl.SarlScript; +import io.sarl.lang.util.Utils; +import io.sarl.lang.validation.IssueCodes; +import io.sarl.tests.api.AbstractSarlTest; +import io.sarl.tests.api.AbstractSarlTest.Validator; + +/** Testing class for issue: Unexpected ERROR at Validating the SARL source files. + * + *

https://github.com/sarl/sarl/issues/847 + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/847" + */ +@SuppressWarnings("all") +public class Bug847 extends AbstractSarlTest { + + private static final String SNIPSET01 = multilineString( + "package io.sarl.lang.tests.bug847", + "import io.sarl.core.AgentSpawned", + "import io.sarl.core.Logging", + "agent SomeAgent{", + " uses Logging", + " on AgentSpawned {", + " info(\"Agent {0} of type {1} has been created successfully and is now alive!\",", + " occurrence.agentIdentifiers, occurrence.agentType)", + " }", + "}"); + + private static final String EXPECTED01 = multilineString( + "package io.sarl.lang.tests.bug847;", + "", + "import io.sarl.core.AgentSpawned;", + "import io.sarl.core.Logging;", + "import io.sarl.lang.annotation.ImportedCapacityFeature;", + "import io.sarl.lang.annotation.PerceptGuardEvaluator;", + "import io.sarl.lang.annotation.SarlElementType;", + "import io.sarl.lang.annotation.SarlSpecification;", + "import io.sarl.lang.annotation.SyntheticMember;", + "import io.sarl.lang.core.Agent;", + "import io.sarl.lang.core.BuiltinCapacitiesProvider;", + "import io.sarl.lang.core.DynamicSkillProvider;", + "import io.sarl.lang.core.Skill;", + "import io.sarl.lang.util.ClearableReference;", + "import java.util.Collection;", + "import java.util.UUID;", + "import javax.inject.Inject;", + "import org.eclipse.xtext.xbase.lib.Extension;", + "import org.eclipse.xtext.xbase.lib.Inline;", + "import org.eclipse.xtext.xbase.lib.Pure;", + "", + "@SarlSpecification(\"" + SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING+ "\")", + "@SarlElementType(" + SarlPackage.SARL_AGENT + ")", + "@SuppressWarnings(\"all\")", + "public class SomeAgent extends Agent {", + " @SyntheticMember", + " private void $behaviorUnit$AgentSpawned$0(final AgentSpawned occurrence) {", + " Logging _$CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER = this.$castSkill(Logging.class, (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || this.$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) ? (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING = this.$getSkill(Logging.class)) : this.$CAPACITY_USE$IO_SARL_CORE_LOGGING);", + " _$CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER.info(\"Agent {0} of type {1} has been created successfully and is now alive!\", ", + " occurrence.agentIdentifiers, occurrence.agentType);", + " }", + " ", + " @Extension", + " @ImportedCapacityFeature(Logging.class)", + " @SyntheticMember", + " private transient ClearableReference $CAPACITY_USE$IO_SARL_CORE_LOGGING;", + " ", + " @SyntheticMember", + " @Pure", + " @Inline(value = \"$castSkill(Logging.class, ($0$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || $0$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) ? ($0$CAPACITY_USE$IO_SARL_CORE_LOGGING = $0$getSkill(Logging.class)) : $0$CAPACITY_USE$IO_SARL_CORE_LOGGING)\", imported = Logging.class)", + " private Logging $CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER() {", + " if (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || this.$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) {", + " this.$CAPACITY_USE$IO_SARL_CORE_LOGGING = $getSkill(Logging.class);", + " }", + " return $castSkill(Logging.class, this.$CAPACITY_USE$IO_SARL_CORE_LOGGING);", + " }", + " ", + " @SyntheticMember", + " @PerceptGuardEvaluator", + " private void $guardEvaluator$AgentSpawned(final AgentSpawned occurrence, final Collection ___SARLlocal_runnableCollection) {", + " assert occurrence != null;", + " assert ___SARLlocal_runnableCollection != null;", + " ___SARLlocal_runnableCollection.add(() -> $behaviorUnit$AgentSpawned$0(occurrence));", + " }", + " ", + " @SyntheticMember", + " public SomeAgent(final UUID arg0, final UUID arg1) {", + " super(arg0, arg1);", + " }", + " ", + " @SyntheticMember", + " @Deprecated", + " @Inject", + " public SomeAgent(final BuiltinCapacitiesProvider arg0, final UUID arg1, final UUID arg2) {", + " super(arg0, arg1, arg2);", + " }", + " ", + " @SyntheticMember", + " @Inject", + " public SomeAgent(final UUID arg0, final UUID arg1, final DynamicSkillProvider arg2) {", + " super(arg0, arg1, arg2);", + " }", + "}", + ""); + + @Inject + private CompilationTestHelper compiler; + + @Test + public void parsing_01() throws Exception { + SarlScript mas = file(SNIPSET01); + final Validator validator = validate(mas); + validator.assertNoErrors(); + } + + @Test + public void compiling_01() throws Exception { + this.compiler.compile(SNIPSET01, (it) -> { + final String actual = it.getGeneratedCode("io.sarl.lang.tests.bug847.SomeAgent"); + assertEquals(EXPECTED01, actual); + }); + } + + private static final String SNIPSET02 = multilineString( + "package io.sarl.lang.tests.bug847;", + "import io.sarl.core.AgentSpawned", + "import io.sarl.core.Logging", + "agent SomeAgent{", + " uses Logging", + " on AgentSpawned {", + " val agent_ids = occurrence.agentIdentifiers", + " val agent_type = occurrence.agentType", + " info(\"Agent {0} of type {1} has been created successfully and is now alive!\",", + " agent_ids, agent_type)", + " }", + "}"); + + private static final String EXPECTED02 = multilineString( + "package io.sarl.lang.tests.bug847;", + "", + "import io.sarl.core.AgentSpawned;", + "import io.sarl.core.Logging;", + "import io.sarl.lang.annotation.ImportedCapacityFeature;", + "import io.sarl.lang.annotation.PerceptGuardEvaluator;", + "import io.sarl.lang.annotation.SarlElementType;", + "import io.sarl.lang.annotation.SarlSpecification;", + "import io.sarl.lang.annotation.SyntheticMember;", + "import io.sarl.lang.core.Agent;", + "import io.sarl.lang.core.BuiltinCapacitiesProvider;", + "import io.sarl.lang.core.DynamicSkillProvider;", + "import io.sarl.lang.core.Skill;", + "import io.sarl.lang.util.ClearableReference;", + "import java.util.Collection;", + "import java.util.UUID;", + "import javax.inject.Inject;", + "import org.eclipse.xtext.xbase.lib.Extension;", + "import org.eclipse.xtext.xbase.lib.Inline;", + "import org.eclipse.xtext.xbase.lib.Pure;", + "", + "@SarlSpecification(\"" + SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING+ "\")", + "@SarlElementType(" + SarlPackage.SARL_AGENT + ")", + "@SuppressWarnings(\"all\")", + "public class SomeAgent extends Agent {", + " @SyntheticMember", + " private void $behaviorUnit$AgentSpawned$0(final AgentSpawned occurrence) {", + " final Collection agent_ids = occurrence.agentIdentifiers;", + " final String agent_type = occurrence.agentType;", + " Logging _$CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER = this.$castSkill(Logging.class, (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || this.$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) ? (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING = this.$getSkill(Logging.class)) : this.$CAPACITY_USE$IO_SARL_CORE_LOGGING);", + " _$CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER.info(\"Agent {0} of type {1} has been created successfully and is now alive!\", agent_ids, agent_type);", + " }", + " ", + " @Extension", + " @ImportedCapacityFeature(Logging.class)", + " @SyntheticMember", + " private transient ClearableReference $CAPACITY_USE$IO_SARL_CORE_LOGGING;", + " ", + " @SyntheticMember", + " @Pure", + " @Inline(value = \"$castSkill(Logging.class, ($0$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || $0$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) ? ($0$CAPACITY_USE$IO_SARL_CORE_LOGGING = $0$getSkill(Logging.class)) : $0$CAPACITY_USE$IO_SARL_CORE_LOGGING)\", imported = Logging.class)", + " private Logging $CAPACITY_USE$IO_SARL_CORE_LOGGING$CALLER() {", + " if (this.$CAPACITY_USE$IO_SARL_CORE_LOGGING == null || this.$CAPACITY_USE$IO_SARL_CORE_LOGGING.get() == null) {", + " this.$CAPACITY_USE$IO_SARL_CORE_LOGGING = $getSkill(Logging.class);", + " }", + " return $castSkill(Logging.class, this.$CAPACITY_USE$IO_SARL_CORE_LOGGING);", + " }", + " ", + " @SyntheticMember", + " @PerceptGuardEvaluator", + " private void $guardEvaluator$AgentSpawned(final AgentSpawned occurrence, final Collection ___SARLlocal_runnableCollection) {", + " assert occurrence != null;", + " assert ___SARLlocal_runnableCollection != null;", + " ___SARLlocal_runnableCollection.add(() -> $behaviorUnit$AgentSpawned$0(occurrence));", + " }", + " ", + " @SyntheticMember", + " public SomeAgent(final UUID arg0, final UUID arg1) {", + " super(arg0, arg1);", + " }", + " ", + " @SyntheticMember", + " @Deprecated", + " @Inject", + " public SomeAgent(final BuiltinCapacitiesProvider arg0, final UUID arg1, final UUID arg2) {", + " super(arg0, arg1, arg2);", + " }", + " ", + " @SyntheticMember", + " @Inject", + " public SomeAgent(final UUID arg0, final UUID arg1, final DynamicSkillProvider arg2) {", + " super(arg0, arg1, arg2);", + " }", + "}", + ""); + + @Test + public void parsing_02() throws Exception { + SarlScript mas = file(SNIPSET02); + final Validator validator = validate(mas); + validator.assertNoErrors(); + } + + @Test + public void compiling_02() throws Exception { + this.compiler.compile(SNIPSET02, (it) -> { + final String actual = it.getGeneratedCode("io.sarl.lang.tests.bug847.SomeAgent"); + assertEquals(EXPECTED02, actual); + }); + } + +} +