diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
index b207a63f699..8ca2aa08e68 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
@@ -93,6 +93,11 @@ public boolean isConstructor() {
return true;
}
+ @Override
+ public boolean isJsNative() {
+ return getEnclosingType().isJsNative();
+ }
+
/**
* Returns true
if this constructor does no real work.
*
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
index e5b6bb313a0..276fdd9c216 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
@@ -160,6 +160,7 @@ public boolean isJsProperty() {
return jsName != null;
}
+ @Override
public boolean isJsNative() {
return enclosingType.isJsNative();
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 905904b98b2..f4efae47ea9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -102,7 +102,7 @@ public void setJsMemberInfo(String namespace, String name, boolean exported) {
}
public boolean isJsInteropEntryPoint() {
- return exported && !needsDynamicDispatch();
+ return exported && !needsDynamicDispatch() && !isJsNative();
}
public boolean canBeCalledExternally() {
@@ -242,8 +242,9 @@ public boolean isOrOverridesJsFunctionMethod() {
return false;
}
+ @Override
public boolean isJsNative() {
- return enclosingType != null && enclosingType.isJsNative();
+ return body == null && jsName != null;
}
public void setSyntheticAccidentalOverride() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 6b49d6a1853..f0cfdda3b05 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -2541,6 +2541,7 @@ private List getGlobalStatements() {
*/
private static boolean doesNotHaveConcreteImplementation(JMethod method) {
return method.isAbstract()
+ || method.isJsNative()
|| JjsUtils.isUnnecessarySyntheticAccidentalOverride(method)
|| (JProgram.isClinit(method)
&& method.getEnclosingType().getClinitTarget() != method.getEnclosingType());
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index a45072dad56..1fa838de21e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -3092,6 +3092,7 @@ private void processNativeMethod(MethodDeclaration x) {
JMethod method = curMethod.method;
JsniMethod jsniMethod = jsniMethods.get(x);
if (jsniMethod == null) {
+ method.setBody(null);
return;
}
SourceInfo info = method.getSourceInfo();
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 e332910356c..a2294575e7d 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
@@ -218,8 +218,8 @@ private boolean isDelegatingToConstructor(JConstructor ctor, JConstructor target
}
private void checkField(JField x) {
- if (x.isJsNative()) {
- checkNativeJsMember(x);
+ if (x.getEnclosingType().isJsNative()) {
+ checkMemberOfNativeJsType(x);
}
checkUnusableByJs(x);
@@ -241,8 +241,8 @@ private void checkMethod(JMethod x) {
}
currentProcessedMethods.addAll(x.getOverriddenMethods());
- if (x.isJsNative()) {
- checkNativeJsMember(x);
+ if (x.getEnclosingType().isJsNative()) {
+ checkMemberOfNativeJsType(x);
}
checkUnusableByJs(x);
@@ -281,7 +281,7 @@ private void checkJsPropertyType(String propertyName, String enclosingTypeName,
}
}
- private void checkNativeJsMember(JMember member) {
+ private void checkMemberOfNativeJsType(JMember member) {
if (member.isSynthetic()) {
return;
}
diff --git a/user/test/com/google/gwt/core/CoreJsInteropSuite.java b/user/test/com/google/gwt/core/CoreJsInteropSuite.java
index 82ccbd82673..52f5787d893 100644
--- a/user/test/com/google/gwt/core/CoreJsInteropSuite.java
+++ b/user/test/com/google/gwt/core/CoreJsInteropSuite.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.client.interop.JsExportTest;
import com.google.gwt.core.client.interop.JsFunctionTest;
+import com.google.gwt.core.client.interop.JsMethodTest;
import com.google.gwt.core.client.interop.JsPropertyTest;
import com.google.gwt.core.client.interop.JsTypeArrayTest;
import com.google.gwt.core.client.interop.JsTypeTest;
@@ -33,6 +34,7 @@ public static Test suite() {
suite.addTestSuite(JsTypeTest.class);
suite.addTestSuite(JsPropertyTest.class);
+ suite.addTestSuite(JsMethodTest.class);
suite.addTestSuite(JsTypeArrayTest.class);
suite.addTestSuite(JsExportTest.class);
suite.addTestSuite(JsFunctionTest.class);
diff --git a/user/test/com/google/gwt/core/client/interop/JsMethodTest.java b/user/test/com/google/gwt/core/client/interop/JsMethodTest.java
new file mode 100644
index 00000000000..2eef1042f13
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/interop/JsMethodTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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 com.google.gwt.core.client.interop;
+
+import static jsinterop.annotations.JsPackage.GLOBAL;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import jsinterop.annotations.JsMethod;
+import jsinterop.annotations.JsProperty;
+
+/**
+ * Tests JsMethod functionality.
+ */
+public class JsMethodTest extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.Core";
+ }
+
+ class MyObject {
+ @JsProperty
+ public int mine;
+
+ @JsMethod
+ public native boolean hasOwnProperty(String name);
+ }
+
+ public void testNativeJsMethod() {
+ MyObject obj = new MyObject();
+ obj.mine = 0;
+ assertTrue(obj.hasOwnProperty("mine"));
+ assertFalse(obj.hasOwnProperty("toString"));
+ }
+
+ @JsMethod(namespace = GLOBAL)
+ private static native boolean isFinite(double d);
+
+ public void testStaticNativeJsMethod() {
+ assertFalse(isFinite(Double.POSITIVE_INFINITY));
+ assertFalse(isFinite(Double.NEGATIVE_INFINITY));
+ assertFalse(isFinite(Double.NaN));
+ assertTrue(isFinite(0));
+ assertTrue(isFinite(1));
+ }
+}