Skip to content

Commit

Permalink
Check that Native members have a js name.
Browse files Browse the repository at this point in the history
Change-Id: I64026102ac40fd744b7069042b81548abe643d64
  • Loading branch information
rluble committed Oct 10, 2015
1 parent b478522 commit 983bc3a
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 7 deletions.
7 changes: 6 additions & 1 deletion dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
Expand Up @@ -75,7 +75,7 @@ private static void setJsInteropProperties(JMember member, Annotation... annotat
/* Apply class wide JsInterop annotations */

boolean ignore = JdtUtil.getAnnotation(annotations, JSNOEXPORT_CLASS) != null;
if (ignore || !member.isPublic() || exportName != null) {
if (ignore || (!member.isPublic() && !isNativeConstructor(member)) || exportName != null) {
return;
}

Expand All @@ -89,6 +89,11 @@ private static void setJsInteropProperties(JMember member, Annotation... annotat
member.setJsMemberInfo(namespace, computeName(member), true);
}
}

private static boolean isNativeConstructor(JMember member) {
return member instanceof JConstructor && member.isJsNative();
}

private static void setJsPropertyProperties(JMethod method) {
String methodName = method.getName();
if (startsWithCamelCase(methodName, "set")) {
Expand Down
5 changes: 5 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
Expand Up @@ -203,6 +203,11 @@ public boolean isStatic() {
return isStatic;
}

@Override
public boolean isSynthetic() {
return false;
}

public boolean isThisRef() {
return isThisRef;
}
Expand Down
2 changes: 2 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JMember.java
Expand Up @@ -27,5 +27,7 @@ public interface JMember extends HasEnclosingType, HasName, HasJsInfo, HasType,

boolean needsDynamicDispatch();

boolean isSynthetic();

String getQualifiedName();
}
Expand Up @@ -124,6 +124,10 @@ private boolean isDelegatingToConstructor(JConstructor ctor, JConstructor target
}

private void checkField(JField x) {
if (x.isJsNative()) {
checkNativeJsMember(x);
}

if (!x.isJsProperty()) {
return;
}
Expand All @@ -141,6 +145,10 @@ private void checkMethod(JMethod x) {
}
currentJsTypeProcessedMethods.addAll(x.getOverriddenMethods());

if (x.isJsNative()) {
checkNativeJsMember(x);
}

if (!x.isOrOverridesJsMethod()) {
return;
}
Expand Down Expand Up @@ -189,6 +197,18 @@ private void checkJsTypeFieldName(JField field, String memberName) {
}
}

private void checkNativeJsMember(JMember member) {
if (member.isSynthetic()) {
return;
}

if (member.getJsName() == null) {
logError("Native JsType member '%s' is not public or has @JsNoExport.",
member.getQualifiedName());
return;
}
}

private void checkJsTypeMethod(JMethod method) {
if (method.isSynthetic() && !method.isForwarding()) {
// A name slot taken up by a synthetic method, such as a bridge method for a generic method,
Expand Down Expand Up @@ -292,7 +312,7 @@ public void endVisit(JMethodCall x, Context ctx) {
}.accept(jprogram);
}

private void checkJsNative(JDeclaredType type) {
private void checkNativeJsType(JDeclaredType type) {
// TODO(rluble): add inheritance restrictions.
if (!JjsUtils.isClinitEmpty(type)) {
logError("Native JsType '%s' cannot have static initializer.", type);
Expand Down Expand Up @@ -356,7 +376,7 @@ private void checkType(JDeclaredType type) {
minimalRebuildCache.removeJsInteropNames(type.getName());

if (type.isJsNative()) {
checkJsNative(type);
checkNativeJsType(type);
}

if (type.isJsFunction()) {
Expand Down
Expand Up @@ -94,7 +94,7 @@ public void testCollidingAccidentalOverrideHalfAndHalfFails() throws Exception {

assertBuggyFails(
"Method 'test.EntryPoint$Parent.doIt(Ltest/EntryPoint$Foo;)V' can't be exported in type "
+ "'test.EntryPoint$Buggy' because the member name 'doIt' is already taken.");
+ "'test.EntryPoint$Buggy' because the member name 'doIt' is already taken.");
}

public void testCollidingFieldExportsFails() throws Exception {
Expand Down Expand Up @@ -935,7 +935,7 @@ public void testNativeJsTypeStaticInitializerFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"x\") public static class Buggy {",
" static String s = \"hello\";",
" public static String s = \"hello\";",
" static { s += \"hello\"; }",
"}");

Expand All @@ -947,7 +947,7 @@ public void testNativeJsTypeInlineStaticInitializerFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"x\") public static class Buggy {",
" static final String s = new String(\"hello\");",
" public static final String s = new String(\"hello\");",
"}");

assertBuggyFails(
Expand All @@ -969,7 +969,7 @@ public void testNativeJsTypeCompileTimeConstantSucceeds() throws UnableToComplet
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"x\") public static class Buggy {",
" static final String s = \"hello\";",
" public static final String s = \"hello\";",
"}");

assertBuggySucceeds();
Expand Down Expand Up @@ -1099,6 +1099,84 @@ public void testNativeJsTypeExtendsNaiveJsTypeSucceeds() throws UnableToComplete
assertBuggySucceeds();
}

public void testNativeJsTypeNonPublicFieldFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" int f;",
"}");

assertBuggyFails(
"Native JsType member 'test.EntryPoint$Buggy.f' is not public or has @JsNoExport.");
}

public void testNativeJsTypeJsIgnoredFieldFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetImport("com.google.gwt.core.client.js.JsNoExport");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" @JsNoExport public int x;",
"}");

assertBuggyFails(
"Native JsType member 'test.EntryPoint$Buggy.x' is not public or has @JsNoExport.");
}

public void testNativeJsTypeNonPublicMethodFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" native void m();",
"}");

assertBuggyFails(
"Native JsType member 'test.EntryPoint$Buggy.m()V' is not public or has @JsNoExport.");
}

public void testNativeJsTypeJsIgnoredMethodFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetImport("com.google.gwt.core.client.js.JsNoExport");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" @JsNoExport public native void m();",
"}");

assertBuggyFails(
"Native JsType member 'test.EntryPoint$Buggy.m()V' is not public or has @JsNoExport.");
}

public void testNativeJsTypeJsIgnoredConstructorFails() {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetImport("com.google.gwt.core.client.js.JsNoExport");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" @JsNoExport public Buggy() { }",
"}");

assertBuggyFails(
"Native JsType member 'test.EntryPoint$Buggy.EntryPoint$Buggy() <init>' "
+ "is not public or has @JsNoExport.");
}

public void testNativeJsTypeNonPublicConstructorSucceeds() throws UnableToCompleteException {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
" Buggy() { }",
"}");

assertBuggySucceeds();
}

public void testNativeJsTypeDefaultConstructorSucceeds() throws UnableToCompleteException {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
"@JsType(prototype = \"B\") static class Buggy {",
"}");

assertBuggySucceeds();
}

public void testNonJsTypeExtendsJsTypeSucceeds() throws UnableToCompleteException {
addSnippetImport("com.google.gwt.core.client.js.JsType");
addSnippetClassDecl(
Expand Down

0 comments on commit 983bc3a

Please sign in to comment.