This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new 7c43f5c34 compiler: Missing warning for duplicate function parameter 
names
7c43f5c34 is described below

commit 7c43f5c34ebde4cc1fc340d0198c97633797b717
Author: Josh Tynjala <[email protected]>
AuthorDate: Mon Nov 6 09:05:33 2023 -0800

    compiler: Missing warning for duplicate function parameter names
    
    Flex compiler warned, but Royale compiler seems to have forgotten the same 
check
    
    Plus, new tests for this warning and some other function/parameter problems
---
 .../problems/DuplicateParameterNameProblem.java    |  47 +++++++
 .../semantics/MethodBodySemanticChecker.java       |   1 +
 .../compiler/internal/semantics/SemanticUtils.java |  26 ++++
 compiler/src/test/java/as/ASFunctionTests.java     | 150 +++++++++++++++++++++
 4 files changed, 224 insertions(+)

diff --git 
a/compiler-common/src/main/java/org/apache/royale/compiler/problems/DuplicateParameterNameProblem.java
 
b/compiler-common/src/main/java/org/apache/royale/compiler/problems/DuplicateParameterNameProblem.java
new file mode 100644
index 000000000..3c66c55ad
--- /dev/null
+++ 
b/compiler-common/src/main/java/org/apache/royale/compiler/problems/DuplicateParameterNameProblem.java
@@ -0,0 +1,47 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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 org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * <pre>
+ * Example: 
+ *      function foo(bar : String, bar : Number) : void {
+ *      }
+ * </pre>
+ *          
+ */
+public final class DuplicateParameterNameProblem extends SemanticWarningProblem
+{
+       public static final String DESCRIPTION = "More than one argument named 
'${paramName}' specified for function '${functionName}'. References to that 
argument will always resolve to the last one.";
+    
+    public static final int warningCode = 3584;
+
+       public DuplicateParameterNameProblem(IASNode site, String paramName, 
String functionName)
+    {
+        super(site);
+               this.paramName = paramName;
+               this.functionName = functionName;
+    }
+    
+    public final String paramName;
+    public final String functionName;
+}
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
index ebe11f07f..7ce307905 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
@@ -1340,6 +1340,7 @@ public class MethodBodySemanticChecker
     {
         SemanticUtils.checkReturnValueHasNoTypeDeclaration(this.currentScope, 
iNode, def);
         SemanticUtils.checkParametersHaveNoTypeDeclaration(this.currentScope, 
iNode, def);
+        SemanticUtils.checkParametersHaveUniqueNames(this.currentScope, iNode, 
def);
         
         if (SemanticUtils.isInFunction(iNode))
         {
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
index a1b14f7ed..678c047a9 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
@@ -22,6 +22,7 @@ package org.apache.royale.compiler.internal.semantics;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -108,6 +109,7 @@ import 
org.apache.royale.compiler.problems.DeprecatedAPIWithMessageProblem;
 import org.apache.royale.compiler.problems.DeprecatedAPIWithReplacementProblem;
 import 
org.apache.royale.compiler.problems.DeprecatedAPIWithSinceAndReplacementProblem;
 import org.apache.royale.compiler.problems.DeprecatedAPIWithSinceProblem;
+import org.apache.royale.compiler.problems.DuplicateParameterNameProblem;
 import org.apache.royale.compiler.problems.ICompilerProblem;
 import 
org.apache.royale.compiler.problems.ParameterHasNoTypeDeclarationProblem;
 import 
org.apache.royale.compiler.problems.ReturnValueHasNoTypeDeclarationProblem;
@@ -2748,6 +2750,30 @@ public class SemanticUtils
         }
     }
     
+    /**
+     * Checks that a given function's parameters have unique names, and logs a 
problem if not
+     * 
+     * @param scope is the scope where problems are to be logged
+     * @param node is the function node that is being checked (used for 
location reporting)
+     * @param func is the definition of the function to be checked.
+     */
+    public static void checkParametersHaveUniqueNames(LexicalScope scope, 
IFunctionNode node, IFunctionDefinition func)
+    {
+        Set<String> namesSet = new HashSet<String>();
+        for (IParameterNode paramNode : node.getParameterNodes())
+        {
+            String paramName = paramNode.getName();
+            if (namesSet.contains(paramName))
+            {
+                scope.addProblem(new DuplicateParameterNameProblem(paramNode, 
paramNode.getName(), node.getName()));
+            }
+            else
+            {
+                namesSet.add(paramName);
+            }
+        }
+    }
+    
     /**
      * Checks that a given function's parameters have a type, and logs a 
problem if not
      * 
diff --git a/compiler/src/test/java/as/ASFunctionTests.java 
b/compiler/src/test/java/as/ASFunctionTests.java
new file mode 100644
index 000000000..171f06333
--- /dev/null
+++ b/compiler/src/test/java/as/ASFunctionTests.java
@@ -0,0 +1,150 @@
+package as;
+
+import org.junit.Test;
+
+public class ASFunctionTests extends ASFeatureTestsBase {
+       
+    @Test
+    public void testFunctionWithoutBody()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "function foo():void"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, "Function 
does not have a body.\n");
+    }
+       
+    @Test
+    public void testParameterHasNoTypeDeclaration()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "function foo(bar):void {}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, 
"parameter 'bar' for function 'foo' has no type declaration.\n");
+    }
+       
+    @Test
+    public void testRequiredParameterAfterOptional()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "function foo(bar:Number = 123.4, baz:String):void {}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, "Required 
parameters are not permitted after optional parameters.\n");
+    }
+       
+    @Test
+    public void testRestParameterMustBeLast()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "function foo(...rest, bar:String):void {}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, "Rest 
parameters must be last.\n");
+    }
+       
+    @Test
+    public void testDuplicateParameterNames()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "function foo(bar:String, bar:Number):void {}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, "More 
than one argument named 'bar' specified for function 'foo'. References to that 
argument will always resolve to the last one.\n");
+    }
+
+    @Test
+    public void testDuplicateParameterNames2()
+    {
+        String[] imports = new String[]
+        {
+        };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "var foo:Function = function(bar:String, 
bar:Number):void {}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+
+        String[] options = new String[]
+        {
+        };
+        compileAndExpectErrors(source, false, false, false, options, "More 
than one argument named 'bar' specified for function ''. References to that 
argument will always resolve to the last one.\n");
+    }
+}

Reply via email to