Fixes more JsExport namespace problems.

Fixes handling of
 - @JsNamespace("")
 - @JsNamespace for nested classes

Change-Id: I58ebb56c1368ad6e95675af0f3f38e163c5d247a
Review-Link: https://gwt-review.googlesource.com/#/c/11930/
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 a594537..5064fed 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
@@ -20,7 +20,6 @@
 import com.google.gwt.dev.util.StringInterner;
 import com.google.gwt.dev.util.collect.Lists;
 import com.google.gwt.thirdparty.guava.common.base.Preconditions;
-import com.google.gwt.thirdparty.guava.common.base.Strings;
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -58,7 +57,7 @@
 
   private final String jsPrototype;
   private final JsInteropType jsInteropType;
-  private String jsNamespace = "";
+  private String jsNamespace;
 
   /**
    * This type's fields. Special serialization treatment.
@@ -248,6 +247,15 @@
   }
 
   /**
+   * Returns the simple source name for the class.
+   * <p>e.g. if the class is a.b.Foo.Bar it returns Bar as opposed to the short name Foo$Bar.
+   */
+  public String getSimpleName() {
+    String[] compoundName = getCompoundName();
+    return compoundName[compoundName.length - 1];
+  }
+
+  /**
    * Returns the type which encloses this type.
    *
    * @return The enclosing type. May be {@code null}.
@@ -401,7 +409,7 @@
   public void resolve(List<JInterfaceType> resolvedInterfaces, String jsNamespace) {
     assert JType.replaces(resolvedInterfaces, superInterfaces);
     superInterfaces = Lists.normalize(resolvedInterfaces);
-    if (Strings.isNullOrEmpty(this.jsNamespace)) {
+    if (this.jsNamespace == null && enclosingType == null) {
       this.jsNamespace = jsNamespace;
     }
   }
@@ -528,12 +536,11 @@
   }
 
   public String getQualifiedExportName() {
-    if (enclosingType == null) {
-      return jsNamespace == null || jsNamespace.isEmpty() ? getName() :
-          jsNamespace + "." + getLeafName();
-    } else {
-      return enclosingType.getQualifiedExportName() + "." + getLeafName();
+    if (enclosingType == null && jsNamespace == null) {
+      return getName();
     }
+    String namespace = jsNamespace == null ? enclosingType.getQualifiedExportName() : jsNamespace;
+    return namespace.isEmpty() ? getSimpleName() : namespace + "." + getSimpleName();
   }
 
   public String getJsNamespace() {
@@ -543,10 +550,4 @@
   public void setJsNamespace(String jsNamespace) {
     this.jsNamespace = jsNamespace;
   }
-
-  private String getLeafName() {
-    String fqName = getName();
-    return getEnclosingType() == null ? fqName.substring(fqName.lastIndexOf('.') + 1) :
-        fqName.substring(getEnclosingType().getName().length() + 1);
-  }
 }
diff --git a/user/src/com/google/gwt/core/client/js/JsNamespace.java b/user/src/com/google/gwt/core/client/js/JsNamespace.java
index f28fb9d..a6590bf 100644
--- a/user/src/com/google/gwt/core/client/js/JsNamespace.java
+++ b/user/src/com/google/gwt/core/client/js/JsNamespace.java
@@ -31,5 +31,5 @@
 @Target({ElementType.TYPE, ElementType.PACKAGE})
 @Documented
 public @interface JsNamespace {
-  String value() default "";
+  String value();
 }
diff --git a/user/test/com/google/gwt/core/client/interop/JsExportTest.java b/user/test/com/google/gwt/core/client/interop/JsExportTest.java
index 5cdd00e..27cb43b 100644
--- a/user/test/com/google/gwt/core/client/interop/JsExportTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsExportTest.java
@@ -237,6 +237,19 @@
     return $wnd.foo.MyExportedClassWithNamespace.BAR;
   }-*/;
 
+  public static void testInheritClassNamespace_empty() {
+    assertEquals(82, getDAN());
+    assertNotNull(createNestedExportedClassWithEmptyNamespace());
+  }
+
+  private static native int getDAN() /*-{
+    return $wnd.MyClassWithEmptyNamespace.DAN;
+  }-*/;
+
+  private static native Object createNestedExportedClassWithEmptyNamespace() /*-{
+    return new $wnd.MyClassWithEmptyNamespace();
+  }-*/;
+
   public static void testInheritClassNamespace_noExport() {
     assertEquals(99, getBAZ());
   }
@@ -245,6 +258,19 @@
     return $wnd.foobaz.MyClassWithNamespace.BAZ;
   }-*/;
 
+  public static void testInheritClassNamespace_nested() {
+    assertEquals(999, getWOOZ());
+    assertNotNull(createNestedExportedClassWithNamespace());
+  }
+
+  private static native int getWOOZ() /*-{
+    return $wnd.zoo.InnerWithNamespace.WOOZ;
+  }-*/;
+
+  private static native Object createNestedExportedClassWithNamespace() /*-{
+    return new $wnd.zoo.InnerWithNamespace();
+  }-*/;
+
   public void testInheritPackageNamespace() {
     assertEquals(1001, getWOO());
   }
diff --git a/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java b/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java
new file mode 100644
index 0000000..77c5db2
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/interop/MyClassWithEmptyNamespace.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.google.gwt.core.client.js.JsExport;
+import com.google.gwt.core.client.js.JsNamespace;
+
+/**
+ * Class with empty namespace.
+ */
+@JsNamespace("")
+public class MyClassWithEmptyNamespace {
+  @JsExport
+  public static final int DAN = 82;
+
+  @JsExport
+  public MyClassWithEmptyNamespace() { }
+}
diff --git a/user/test/com/google/gwt/core/client/interop/MyClassWithNestedExportedClass.java b/user/test/com/google/gwt/core/client/interop/MyClassWithNestedExportedClass.java
index 419a273..fe5a2b9 100644
--- a/user/test/com/google/gwt/core/client/interop/MyClassWithNestedExportedClass.java
+++ b/user/test/com/google/gwt/core/client/interop/MyClassWithNestedExportedClass.java
@@ -16,6 +16,7 @@
 package com.google.gwt.core.client.interop;
 
 import com.google.gwt.core.client.js.JsExport;
+import com.google.gwt.core.client.js.JsNamespace;
 
 /**
  * Class with a nested exported class.
@@ -28,4 +29,13 @@
   public static class Inner {
     public static final int WOO = 99;
   }
+
+  /**
+   * Exported nested class with namespace.
+   */
+  @JsNamespace("zoo")
+  @JsExport
+  public static class InnerWithNamespace {
+    public static final int WOOZ = 999;
+  }
 }