diff --git a/src/main/java/org/jsweet/transpiler/JSweetProblem.java b/src/main/java/org/jsweet/transpiler/JSweetProblem.java index 04ab9921..d429a996 100644 --- a/src/main/java/org/jsweet/transpiler/JSweetProblem.java +++ b/src/main/java/org/jsweet/transpiler/JSweetProblem.java @@ -81,6 +81,10 @@ public enum JSweetProblem { * defined in superclasses. */ FIELD_CONFLICTS_METHOD(Severity.ERROR), + /** + * Raised when a method invocation is hidden by a local variable or parameter. + */ + HIDDEN_INVOCATION(Severity.ERROR), /** * Raised when an inner class is found. */ @@ -298,6 +302,8 @@ public enum JSweetProblem { return String.format("synchronization is not allowed in JSweet", params); case METHOD_CONFLICTS_FIELD: return String.format("method %s has the same name as a field in %s", params); + case HIDDEN_INVOCATION: + return String.format("invocation of '%s' is hidden by a local variable", params); case FIELD_CONFLICTS_METHOD: return String.format("field %s has the same name as a method in %s", params); case INNER_CLASS: diff --git a/src/main/java/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java b/src/main/java/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java index e37f3dd5..c8ddee7d 100644 --- a/src/main/java/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java +++ b/src/main/java/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java @@ -1075,6 +1075,13 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter { } else { JCFieldAccess staticFieldAccess = (JCFieldAccess) staticImport.qualid; methSym = Util.findMethodDeclarationInType(context.types, staticFieldAccess.selected.type.tsym, methName, type); + if (methSym != null) { + Map vars = new HashMap<>(); + Util.fillAllVariablesInScope(vars, getStack(), inv, getParent(JCMethodDecl.class)); + if(vars.containsKey(methSym.getSimpleName().toString())) { + report(inv, JSweetProblem.HIDDEN_INVOCATION, methSym.getSimpleName()); + } + } // staticImported = true; if (JSweetConfig.TS_STRICT_MODE_KEYWORDS.contains(methName.toLowerCase())) { // if method is a reserved TS keyword, no "static diff --git a/src/main/java/org/jsweet/transpiler/util/Util.java b/src/main/java/org/jsweet/transpiler/util/Util.java index 8d002c6e..c4d02d93 100644 --- a/src/main/java/org/jsweet/transpiler/util/Util.java +++ b/src/main/java/org/jsweet/transpiler/util/Util.java @@ -260,6 +260,11 @@ public class Util { case ENHANCED_FOR_LOOP: putVar(vars, ((JCEnhancedForLoop) parent).var.sym); break; + case METHOD: + for(JCVariableDecl var : ((JCMethodDecl)parent).params) { + putVar(vars, var.sym); + } + break; default: } diff --git a/src/test/java/org/jsweet/test/transpiler/StructuralTests.java b/src/test/java/org/jsweet/test/transpiler/StructuralTests.java index b85e0511..7661be0e 100644 --- a/src/test/java/org/jsweet/test/transpiler/StructuralTests.java +++ b/src/test/java/org/jsweet/test/transpiler/StructuralTests.java @@ -39,6 +39,7 @@ import source.structural.Inheritance; import source.structural.InnerClass; import source.structural.Name; import source.structural.NameClashes; +import source.structural.NameClashesWithMethodInvocations; import source.structural.NoInstanceofForInterfaces; import source.structural.NoWildcardsInImports; import source.structural.TwoClassesInSameFile; @@ -65,6 +66,13 @@ public class StructuralTests extends AbstractTest { } , getSourceFile(NameClashes.class)); } + @Test + public void testVariableMethodNameClashes() { + transpile(logHandler -> { + logHandler.assertReportedProblems(JSweetProblem.HIDDEN_INVOCATION, JSweetProblem.HIDDEN_INVOCATION); + } , getSourceFile(NameClashesWithMethodInvocations.class)); + } + @Test public void testTwoClassesInSameFile() { transpile(logHandler -> { @@ -203,8 +211,7 @@ public class StructuralTests extends AbstractTest { Assert.assertEquals("invoked", r.get("test")); Assert.assertEquals("invoked1_2", r.get("Static")); Assert.assertEquals("invoked1_2", r.get("test2")); - } , getSourceFile(Globals.class), getSourceFile(source.structural.globalclasses.e.Globals.class), - getSourceFile(GlobalFunctionAccessFromMain.class)); + } , getSourceFile(Globals.class), getSourceFile(source.structural.globalclasses.e.Globals.class), getSourceFile(GlobalFunctionAccessFromMain.class)); } @Test @@ -220,7 +227,7 @@ public class StructuralTests extends AbstractTest { logHandler.assertReportedProblems(); } , getSourceFile(Name.class)); } - + @Test public void testAutoImportClassesInSamePackage() { eval((logHandler, r) -> { diff --git a/src/test/java/source/structural/NameClashesWithMethodInvocations.java b/src/test/java/source/structural/NameClashesWithMethodInvocations.java new file mode 100644 index 00000000..e6bd5b76 --- /dev/null +++ b/src/test/java/source/structural/NameClashesWithMethodInvocations.java @@ -0,0 +1,41 @@ +/* + * JSweet - http://www.jsweet.org + * Copyright (C) 2015 CINCHEO SAS + * + * 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 source.structural; + +import static jsweet.dom.Globals.alert; + +public class NameClashesWithMethodInvocations { + + public void m1(boolean alert) { + // name clash between parameter and method call + alert("test"); + } + + public void m2() { + // name clash between local variable and method call + String alert = "test"; + alert(alert); + } + + public void m3() { + // name clash between local variable and method call + @SuppressWarnings("unused") + String m2 = "test"; + m2(); + } + +}