Enforce JsPackage.GLOBAL to access global object.
Change-Id: I7e9c076a7f3e7bba7a818a206e2ec41c6b244928
Review-Link: https://gwt-review.googlesource.com/#/c/14021/
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
index 4b4a335..22a958b 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
@@ -42,6 +42,10 @@
public static final String UNUSABLE_BY_JS = "unusable-by-js";
public static final String INVALID_JSNAME = "<invalid>";
+ public static boolean isGlobal(String jsNamespace) {
+ return "<global>".equals(jsNamespace);
+ }
+
public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation... annotations) {
AnnotationBinding jsType = JdtUtil.getAnnotation(annotations, JSTYPE_CLASS);
String namespace = maybeGetJsNamespace(annotations);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 535ff13..4d26cec 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.impl.GwtAstBuilder;
import com.google.gwt.dev.jjs.impl.JjsUtils;
@@ -623,7 +624,7 @@
@Override
public String getQualifiedJsName() {
- return jsNamespace.isEmpty() ? getJsName() : jsNamespace + "." + getJsName();
+ return JsInteropUtil.isGlobal(jsNamespace) ? getJsName() : jsNamespace + "." + getJsName();
}
public NestedClassDisposition getClassDisposition() {
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 c9ec78c..400e1c6 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.SourceOrigin;
import com.google.gwt.dev.util.StringInterner;
@@ -174,7 +175,7 @@
@Override
public String getQualifiedJsName() {
String namespace = getJsNamespace();
- return namespace.isEmpty() ? jsName : namespace + "." + jsName;
+ return JsInteropUtil.isGlobal(namespace) ? jsName : namespace + "." + jsName;
}
@Override
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 fa3def1..8e2af23 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
@@ -16,6 +16,7 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.common.InliningMode;
+import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.SourceOrigin;
@@ -111,7 +112,7 @@
if (jsName.isEmpty()) {
assert !needsDynamicDispatch();
return namespace;
- } else if (namespace.isEmpty()) {
+ } else if (JsInteropUtil.isGlobal(namespace)) {
assert !needsDynamicDispatch();
return jsName;
} else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
index f6823f0..0ae3aa3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
@@ -13,6 +13,7 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.HasName;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
@@ -97,7 +98,7 @@
}
private void ensureGoogProvide(String namespace, SourceInfo info) {
- if (!providedNamespaces.add(namespace) || namespace.isEmpty()) {
+ if (JsInteropUtil.isGlobal(namespace) || !providedNamespaces.add(namespace)) {
return;
}
@@ -114,6 +115,7 @@
}
private static JsExpression createExportQualifier(String namespace, SourceInfo sourceInfo) {
- return JsUtils.createQualifiedNameRef(namespace.isEmpty() ? "window" : namespace, sourceInfo);
+ return JsUtils.createQualifiedNameRef(
+ JsInteropUtil.isGlobal(namespace) ? "window" : namespace, sourceInfo);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
index f4fb795..97083fe 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
@@ -15,6 +15,7 @@
import static com.google.gwt.dev.js.JsUtils.createAssignment;
+import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
@@ -85,6 +86,7 @@
private void ensureProvideNamespace(JMember member, JsExpression ctor) {
String namespace = member.getJsNamespace();
+ namespace = JsInteropUtil.isGlobal(namespace) ? "" : namespace;
if (namespace.equals(lastExportedNamespace)) {
return;
}
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 bc9cc5b..3625162 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
@@ -387,18 +387,19 @@
private <T extends HasJsName & HasSourceInfo> void checkJsName(T item) {
if (item.getJsName().isEmpty()) {
logError(item, "%s cannot have an empty name.", getDescription(item));
- return;
- }
- if (!JsUtils.isValidJsIdentifier(item.getJsName())) {
+ } else if (!JsUtils.isValidJsIdentifier(item.getJsName())) {
logError(item, "%s has invalid name '%s'.", getDescription(item), item.getJsName());
- return;
}
}
private <T extends HasJsName & HasSourceInfo> void checkJsNamespace(T item) {
- String jsNamespace = item.getJsNamespace();
- if (!jsNamespace.isEmpty() && !JsUtils.isValidJsQualifiedName(jsNamespace)) {
- logError(item, "%s has invalid namespace '%s'.", getDescription(item), jsNamespace);
+ if (JsInteropUtil.isGlobal(item.getJsNamespace())) {
+ return;
+ }
+ if (item.getJsNamespace().isEmpty()) {
+ logError(item, "%s cannot have an empty namespace.", getDescription(item));
+ } else if (!JsUtils.isValidJsQualifiedName(item.getJsNamespace())) {
+ logError(item, "%s has invalid namespace '%s'.", getDescription(item), item.getJsNamespace());
}
}
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 9e479b4..00d0880 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
@@ -1000,6 +1000,7 @@
"@JsType(namespace = \"a.b.\") public static class Buggy {",
" @JsMethod(namespace = \"34s\") public static void m() {}",
" @JsProperty(namespace = \"s^\") public static int n;",
+ " @JsMethod(namespace = \"\") public static void o() {}",
" @JsProperty(namespace = \"\") public int p;",
" @JsMethod(namespace = \"a\") public void q() {}",
"}");
@@ -1008,18 +1009,20 @@
"Line 6: 'EntryPoint.Buggy' has invalid namespace 'a.b.'.",
"Line 7: 'void EntryPoint.Buggy.m()' has invalid namespace '34s'.",
"Line 8: 'int EntryPoint.Buggy.n' has invalid namespace 's^'.",
- "Line 9: Instance member 'int EntryPoint.Buggy.p' cannot declare a namespace.",
- "Line 10: Instance member 'void EntryPoint.Buggy.q()' cannot declare a namespace.");
+ "Line 9: 'void EntryPoint.Buggy.o()' cannot have an empty namespace.",
+ "Line 10: Instance member 'int EntryPoint.Buggy.p' cannot declare a namespace.",
+ "Line 11: Instance member 'void EntryPoint.Buggy.q()' cannot declare a namespace.");
}
- public void testJsNameEmptyNamespacesSucceeds() throws Exception {
+ public void testJsNameGlobalNamespacesSucceeds() throws Exception {
addSnippetImport("jsinterop.annotations.JsType");
addSnippetImport("jsinterop.annotations.JsMethod");
addSnippetImport("jsinterop.annotations.JsProperty");
+ addSnippetImport("jsinterop.annotations.JsPackage");
addSnippetClassDecl(
- "@JsType(namespace = \"\") public static class Buggy {",
- " @JsMethod(namespace = \"\") public static void m() {}",
- " @JsProperty(namespace = \"\") public static int n;",
+ "@JsType(namespace = JsPackage.GLOBAL) public static class Buggy {",
+ " @JsMethod(namespace = JsPackage.GLOBAL) public static void m() {}",
+ " @JsProperty(namespace = JsPackage.GLOBAL) public static int n;",
"}");
assertBuggySucceeds();
diff --git a/user/src/jsinterop/annotations/JsPackage.java b/user/src/jsinterop/annotations/JsPackage.java
index 92be8ec..d7c766c 100644
--- a/user/src/jsinterop/annotations/JsPackage.java
+++ b/user/src/jsinterop/annotations/JsPackage.java
@@ -29,7 +29,10 @@
@Target(ElementType.PACKAGE)
@Documented
public @interface JsPackage {
- String GLOBAL = "";
+ /**
+ * Namespace for the global JavaScript object.
+ */
+ String GLOBAL = "<global>";
String namespace();
}
diff --git a/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java b/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java
index 560d787..189ddfb 100644
--- a/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java
+++ b/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java
@@ -16,13 +16,14 @@
package com.google.gwt.core.client.interop;
import jsinterop.annotations.JsConstructor;
+import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
/**
* Class with empty namespace.
*/
-@JsType(namespace = "")
+@JsType(namespace = JsPackage.GLOBAL)
public class MyClassWithEmptyNamespace {
@JsProperty
public static final int DAN = 82;