From 7e2f2bd82593997e662a8ca69beb87fc7943750e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Galland?= Date: Fri, 17 Jul 2020 22:42:13 +0200 Subject: [PATCH] [lang] Generate an error when a generic type parameter is hiding another generic type parameter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #1021 Signed-off-by: Stéphane Galland --- .../reference/LanguageComparison.md | 2 + .../reference/issue_descriptions.json | 7 + .../io/sarl/lang/validation/IssueCodes.java | 7 + .../src/io/sarl/lang/validation/Messages.java | 1 + .../sarl/lang/validation/SARLValidator.java | 36 ++ .../sarl/lang/validation/messages.properties | 1 + ...bstractBehaviorGuardEvaluatorRegistry.sarl | 4 +- .../lang/tests/bugs/to01399/Bug1021Test.java | 326 ++++++++++++++++++ 8 files changed, 382 insertions(+), 2 deletions(-) create mode 100644 tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to01399/Bug1021Test.java diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/reference/LanguageComparison.md b/docs/io.sarl.docs.markdown/src/main/documentation/reference/LanguageComparison.md index 55f9f8b664..dbf1ca867c 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/reference/LanguageComparison.md +++ b/docs/io.sarl.docs.markdown/src/main/documentation/reference/LanguageComparison.md @@ -8,6 +8,7 @@ The main features coming from the Java language are supported by SARL too. The f differences between the SARL, Java, Xtend and Scala languages, excluding any feature provided by the development environment (Eclipse, IntelliJ...) + @@ -156,6 +157,7 @@ environment (Eclipse, IntelliJ...)
SARLJavaXtendScala
+ ## References This documentation is based on elements from the following sources: diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/reference/issue_descriptions.json b/docs/io.sarl.docs.markdown/src/main/documentation/reference/issue_descriptions.json index 9442ed64c7..e9a046890e 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/reference/issue_descriptions.json +++ b/docs/io.sarl.docs.markdown/src/main/documentation/reference/issue_descriptions.json @@ -2348,6 +2348,13 @@ "message": "*any-message*", "cause": "This error is generated when your SARL code has an improper syntax, and cannot be parsed by the SARL compiler. The error message provides the detail of the invalid syntax and the position into your source code that is under failure", "level": "error" + }, + { + "code": "io.sarl.lang.validation.IssueCodes.generic_type_name_shadowing", + "message": "The generic type parameter '*name*' is hiding the generic type parameter of '*type-name*'", + "cause": "This error is generated you declared a generic type parameter for an action that has the same name as another generic type parameter that is declared into the enclosing type (class, or interface)", + "solution": "Change the *name*", + "level": "error" } ] diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java index 689df9d2d6..0c7639ad1f 100644 --- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java @@ -232,6 +232,13 @@ public final class IssueCodes { public static final String POTENTIAL_INEFFICIENT_VALUE_CONVERSION = ISSUE_CODE_PREFIX + "potential_inefficient_value_conversion"; //$NON-NLS-1$ + /** + * A generic type name is shadowing another generic type name. + * @since 0.12 + */ + public static final String GENERIC_TYPE_NAME_SHADOWING = + ISSUE_CODE_PREFIX + "generic_type_name_shadowing"; //$NON-NLS-1$ + private IssueCodes() { // } 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 85fe6701f7..a6d45776d0 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 @@ -87,6 +87,7 @@ private Messages() { public static String SARLValidator_47; public static String SARLValidator_48; public static String SARLValidator_49; + public static String SARLValidator_5; public static String SARLValidator_50; public static String SARLValidator_51; public static String SARLValidator_52; 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 32f9184590..c6c6c06664 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 @@ -36,6 +36,7 @@ import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_FUNCTION_NAME; import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_LOOP_BREAKING_KEYWORD_USE; import static io.sarl.lang.validation.IssueCodes.DISCOURAGED_OCCURRENCE_READONLY_USE; +import static io.sarl.lang.validation.IssueCodes.GENERIC_TYPE_NAME_SHADOWING; import static io.sarl.lang.validation.IssueCodes.INVALID_CAPACITY_TYPE; import static io.sarl.lang.validation.IssueCodes.INVALID_DEFAULT_SKILL_ANNOTATION; import static io.sarl.lang.validation.IssueCodes.INVALID_EXTENDED_TYPE; @@ -170,8 +171,10 @@ import org.eclipse.xtext.common.types.JvmParameterizedTypeReference; import org.eclipse.xtext.common.types.JvmStringAnnotationValue; import org.eclipse.xtext.common.types.JvmType; +import org.eclipse.xtext.common.types.JvmTypeParameter; import org.eclipse.xtext.common.types.JvmTypeReference; import org.eclipse.xtext.common.types.JvmVisibility; +import org.eclipse.xtext.common.types.TypesPackage; import org.eclipse.xtext.common.types.util.TypeReferences; import org.eclipse.xtext.naming.IQualifiedNameConverter; import org.eclipse.xtext.naming.QualifiedName; @@ -1304,6 +1307,39 @@ private boolean isReallyDisallowedName(QualifiedName name) { return false; } + /** Check if the given generic type has a name that is shadowing an enclosing generic type. + * + * @param type the generic type parameter to check. + * @since 0.12 + */ + @Check + public void checkGenericTypeNameShadowing(JvmTypeParameter type) { + final XtendMember declarator = EcoreUtil2.getContainerOfType(type.eContainer(), XtendMember.class); + if (declarator instanceof XtendFunction && !Utils.isHiddenMember(type.getName())) { + final XtendTypeDeclaration enclosingType = declarator.getDeclaringType(); + List params = null; + if (enclosingType instanceof XtendClass) { + params = ((XtendClass) enclosingType).getTypeParameters(); + } else if (enclosingType instanceof XtendInterface) { + params = ((XtendInterface) enclosingType).getTypeParameters(); + } + if (params != null && !params.isEmpty()) { + // Do not need to loop on the enclosing types since all the inner types must be declared as static + for (final JvmTypeParameter declaredType : params) { + if (Strings.equal(type.getSimpleName(), declaredType.getSimpleName())) { + error( + MessageFormat.format(Messages.SARLValidator_5, type.getSimpleName(), enclosingType.getName()), + type, + TypesPackage.Literals.JVM_TYPE_PARAMETER__NAME, + ValidationMessageAcceptor.INSIGNIFICANT_INDEX, + GENERIC_TYPE_NAME_SHADOWING); + return; + } + } + } + } + } + /** Check if the given action has a valid name. * * @param action the action to test. 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 65f2fbafe1..65e7ca4e60 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 @@ -46,6 +46,7 @@ SARLValidator_46=Expecting the return type {0}. It is recommended to write the r SARLValidator_47=The method {0} of type {1} must use override keyword since it actually overrides a supertype method. SARLValidator_48=The method {0} of type {1} shadows the method {2} of type {3}, but does not override it. SARLValidator_49=override +SARLValidator_5=The generic type parameter ''{0}'' is hiding the generic type parameter of ''{1}''. SARLValidator_50=Duplicate implemented feature ''{0}''. SARLValidator_51=Unexpected assertion due to its positive test result. SARLValidator_52=The feature ''{0}'' is already implemented by the super-type ''{1}''. diff --git a/sre/io.janusproject/io.janusproject.plugin/src/main/sarl/io/sarl/sre/internal/eventguard/AbstractBehaviorGuardEvaluatorRegistry.sarl b/sre/io.janusproject/io.janusproject.plugin/src/main/sarl/io/sarl/sre/internal/eventguard/AbstractBehaviorGuardEvaluatorRegistry.sarl index 9c0c240fef..6d35c66782 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/main/sarl/io/sarl/sre/internal/eventguard/AbstractBehaviorGuardEvaluatorRegistry.sarl +++ b/sre/io.janusproject/io.janusproject.plugin/src/main/sarl/io/sarl/sre/internal/eventguard/AbstractBehaviorGuardEvaluatorRegistry.sarl @@ -195,8 +195,8 @@ abstract class AbstractBehaviorGuardEvaluatorRegistry implements IBehaviorGua } @Pure - override getRegisteredEventListeners(type : Class) : ConcurrentSkipListSet with T { - var result : ConcurrentSkipListSet = new ConcurrentSkipListSet(ObjectComparator::SINGLETON) + override getRegisteredEventListeners(type : Class) : ConcurrentSkipListSet with TT { + var result : ConcurrentSkipListSet = new ConcurrentSkipListSet(ObjectComparator::SINGLETON) getRegisteredEventListeners(type, result) return result } diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to01399/Bug1021Test.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to01399/Bug1021Test.java new file mode 100644 index 0000000000..d1d81ba908 --- /dev/null +++ b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to01399/Bug1021Test.java @@ -0,0 +1,326 @@ +/* + * $Id$ + * + * SARL is an general-purpose agent programming language. + * More details on http://www.sarl.io + * + * Copyright (C) 2014-2020 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.to01399; + +import static io.sarl.tests.api.tools.TestEObjects.file; +import static io.sarl.tests.api.tools.TestUtils.multilineString; +import static io.sarl.tests.api.tools.TestValidator.validate; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.xtend.core.xtend.XtendPackage; +import org.eclipse.xtext.common.types.TypesPackage; +import org.eclipse.xtext.xbase.XbasePackage; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import io.sarl.lang.SARLVersion; +import io.sarl.lang.sarl.SarlPackage; +import io.sarl.lang.sarl.SarlScript; +import io.sarl.lang.validation.IssueCodes; +import io.sarl.tests.api.AbstractSarlTest; +import io.sarl.tests.api.tools.TestValidator.Validator; + +/** Testing class for issue: Invalid declaration of generic types for functions. + * + *

https://github.com/sarl/sarl/issues/1021 + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/1021" + */ +@DisplayName("Bug #1021") +@SuppressWarnings("all") +@Tag("core") +@Tag("sarlParsing") +public class Bug1021Test { + + /** Inner class. + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/1021" + */ + @Nested + @DisplayName("Inner generic type") + public class InnerClass extends AbstractSarlTest { + + private final String SARL_CODE_01 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " }", + "}"); + + @Test + @DisplayName("Single generic type") + public void parsing01() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_01); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + private final String SARL_CODE_02 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " }", + "}"); + + @Test + @DisplayName("Two generic types") + public void parsing02() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_02); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator + .assertNoIssues(); + } + + } + + /** Inner generic class, Inner-Inner class. + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/1021" + */ + @Nested + public class InnerGenericClassInnerClass extends AbstractSarlTest { + + private final String SARL_CODE_01 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " static class Inner2 {", + " }", + " }", + "}"); + + @Test + @DisplayName("Single generic type") + public void parsing01() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_01); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + } + + /** Inner not-generic class, Inner-Inner class. + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/1021" + */ + @Nested + public class InnerNotGenericClassInnerClass extends AbstractSarlTest { + + private final String SARL_CODE_01 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " static class Inner2 {", + " }", + " }", + "}"); + + + @Test + @DisplayName("No generic type") + public void parsing01() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_01); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + } + + /** Functions. + * + * @author $Author: sgalland$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @see "https://github.com/sarl/sarl/issues/1021" + */ + @Nested + public class Functions extends AbstractSarlTest { + + private final String SARL_CODE_01 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " def fct : void with T {", + " }", + "}"); + + + @Test + @DisplayName("Hiding with SARL notation") + public void parsing01() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_01); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertError( + TypesPackage.eINSTANCE.getJvmTypeParameter(), + IssueCodes.GENERIC_TYPE_NAME_SHADOWING, + "'T'", "is hiding", "'Bug1021Type1'"); + } + + private final String SARL_CODE_02 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " def fct : void {", + " }", + "}"); + + @Test + @DisplayName("Hiding with Java notation") + public void parsing02() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_02); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertError( + TypesPackage.eINSTANCE.getJvmTypeParameter(), + IssueCodes.GENERIC_TYPE_NAME_SHADOWING, + "'T'", "is hiding", "'Bug1021Type1'"); + } + + private final String SARL_CODE_03 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void with T {", + " }", + " }", + "}"); + + @Test + @DisplayName("No generic inner with SARL notation") + public void parsing03() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_03); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + private final String SARL_CODE_04 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void {", + " }", + " }", + "}"); + + + @Test + @DisplayName("No generic inner with Java notation") + public void parsing04() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_04); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + private final String SARL_CODE_05 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void with T {", + " }", + " }", + "}"); + + + @Test + @DisplayName("No inner hiding with SARL notation") + public void parsing05() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_05); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + private final String SARL_CODE_06 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void {", + " }", + " }", + "}"); + + @Test + @DisplayName("No inner hiding with Java notation") + public void parsing06() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_06); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertNoIssues(); + } + + private final String SARL_CODE_07 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void with T {", + " }", + " }", + "}"); + + @Test + @DisplayName("Inner hiding with SARL notation") + public void parsing07() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_07); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertError( + TypesPackage.eINSTANCE.getJvmTypeParameter(), + IssueCodes.GENERIC_TYPE_NAME_SHADOWING, + "'T'", "is hiding", "'Inner'"); + } + + private final String SARL_CODE_08 = multilineString( + "package io.sarl.lang.tests.bug1021", + "class Bug1021Type1 {", + " static class Inner {", + " def fct : void {", + " }", + " }", + "}"); + + @Test + @DisplayName("Inner hiding with Java notation") + public void parsing08() throws Exception { + SarlScript mas = file(getParseHelper(), SARL_CODE_08); + final Validator validator = validate(getValidationHelper(), getInjector(), mas); + validator.assertError( + TypesPackage.eINSTANCE.getJvmTypeParameter(), + IssueCodes.GENERIC_TYPE_NAME_SHADOWING, + "'T'", "is hiding", "'Inner'"); + } + + } + +}