Require JsFunction implementations be marked final. The requirement does not affect current expressivity as there is a restriction in place that JsFunction implementations can not be subclassed. Change-Id: I45ab86af287e746e4ad5d0c0a8fc8c508a52bc9c
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java index 021dd5c..063e6d7 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
@@ -688,6 +688,10 @@ } private void checkJsFunctionImplementation(JDeclaredType type) { + if (!type.isFinal()) { + logError("JsFunction implementation '%s' must be final.", + type); + } if (type.getImplements().size() != 1) { logError("JsFunction implementation '%s' cannot implement more than one interface.", type); @@ -704,11 +708,6 @@ } private void checkJsFunctionSubtype(JDeclaredType type) { - JClassType superClass = type.getSuperClass(); - if (superClass != null && superClass.isJsFunctionImplementation()) { - logError(type, "'%s' cannot extend JsFunction implementation '%s'.", - JjsUtils.getReadableDescription(type), JjsUtils.getReadableDescription(superClass)); - } for (JInterfaceType superInterface : type.getImplements()) { if (superInterface.isJsFunction()) { logError(type, "'%s' cannot extend JsFunction '%s'.",
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java index 3be61df..f76803b 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
@@ -1140,17 +1140,6 @@ assertBuggySucceeds(); } - public void testJsFunctionWithNoExtendsSucceeds() throws Exception { - addSnippetImport("jsinterop.annotations.JsFunction"); - addSnippetClassDecl( - "@JsFunction", - "public interface Buggy {", - " void foo();", - "}"); - - assertBuggySucceeds(); - } - public void testJsFunctionExtendsInterfaceFails() throws Exception { addSnippetImport("jsinterop.annotations.JsFunction"); addSnippetClassDecl( @@ -1185,11 +1174,19 @@ "Line 6: 'EntryPoint.Buggy' cannot be both a JsFunction and a JsType at the same time."); } - public void testJsFunctionImplementationWithSingleInterfaceSucceeds() throws Exception { - addAll(jsFunctionInterface); + public void testJsFunctionImplementationSucceeds() throws Exception { + addSnippetImport("jsinterop.annotations.JsFunction"); addSnippetClassDecl( - "public static class Buggy implements MyJsFunctionInterface {", - " public int foo(int x) { return 0; }", + "@JsFunction", + "public interface Function {", + " void foo();", + "}", + "public static final class Buggy implements Function {", + " public void foo() {", + " new Function() {", + " public void foo() {}", + " }.foo();", + " }", "}"); assertBuggySucceeds(); @@ -1199,7 +1196,7 @@ addAll(jsFunctionInterface); addSnippetClassDecl( "interface AnotherInterface {}", - "public static class Buggy implements MyJsFunctionInterface, AnotherInterface {", + "public static final class Buggy implements MyJsFunctionInterface, AnotherInterface {", " public int foo(int x) { return 0; }", " public int bar(int x) { return 0; }", "}"); @@ -1212,7 +1209,7 @@ addAll(jsFunctionInterface); addSnippetClassDecl( "public static class BaseClass {}", - "public static class Buggy extends BaseClass implements MyJsFunctionInterface {", + "public static final class Buggy extends BaseClass implements MyJsFunctionInterface {", " public int foo(int x) { return 0; }", "}"); @@ -1220,7 +1217,7 @@ + "extend a class."); } - public void testJsFunctionImplementationWithSubclassesFails() throws Exception { + public void testJsFunctionImplementationNotFinalFails() throws Exception { addAll(jsFunctionInterface); addSnippetClassDecl( "public static class BaseClass implements MyJsFunctionInterface {", @@ -1229,8 +1226,7 @@ "public static class Buggy extends BaseClass {", "}"); - assertBuggyFails("Line 6: 'EntryPoint.Buggy' cannot extend " - + "JsFunction implementation 'EntryPoint.BaseClass'."); + assertBuggyFails("Line 3: JsFunction implementation 'EntryPoint.BaseClass' must be final."); } public void testJsFunctionImplementationMarkedAsJsTypeFails() throws Exception { @@ -1238,7 +1234,7 @@ addSnippetImport("jsinterop.annotations.JsType"); addSnippetClassDecl( "@JsType", - "public static class Buggy implements MyJsFunctionInterface {", + "public static final class Buggy implements MyJsFunctionInterface {", " public int foo(int x) { return 0; }", "}");