Skip to content

Commit

Permalink
Allow for empty JS namespaces to represent top-level symbols
Browse files Browse the repository at this point in the history
We currently don't have a way to overlay a native type that has form:

``` js
goog.module('TopLevelClass');

exports = class {};
```

With this change you'd now represent this as:

``` java
@jstype(isNative = true, namespace = "", name = "TopLevelClass")
class TopLevelClass {}
```

This all works since we currently treat the first component of the `name`
attribute as the last component of the `goog.require` statement for `@JsType`.

PiperOrigin-RevId: 599223849
  • Loading branch information
kevinoconnor7 authored and copybara-github committed Jan 17, 2024
1 parent 693ef13 commit 659e0bd
Show file tree
Hide file tree
Showing 23 changed files with 668 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1102,7 +1102,16 @@ private void checkQualifiedJsName(Type type) {
}

checkJsName(type);
checkJsNamespace(type);

String namespace = type.getJsNamespace();
// Permit empty namespaces on native JsTypes to represent a top-level non-extern type. This
// works since the first component of the name is always used as the last component of the
// import statement.
boolean isValidEmptyNamespace = namespace.isEmpty() && type.getDeclaration().isNative();

if (!isValidEmptyNamespace) {
checkJsNamespace(type);
}
}

private boolean checkQualifiedJsName(Member member) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,14 @@ public static void testNativeTypeObjectMethods() {
int unusedHash = bar.hashCode();
boolean unusedEq = bar.equals(new Object());
}

public static void testTopLevel() {
TopLevel.x = 2;

TopLevel.Nested nested = new TopLevel.Nested();
nested.x = 3;

TopLevelNestedReference topLevelNestedReference = new TopLevelNestedReference();
topLevelNestedReference.x = 4;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2024 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 nativejstypes;

import jsinterop.annotations.JsType;

@JsType(isNative = true, namespace = "", name = "toplevel")
class TopLevel {
private TopLevel() {}

public static int x;

@JsType(isNative = true)
static class Nested {
public int x;
}
}

@JsType(isNative = true, namespace = "", name = "toplevel.Nested")
class TopLevelNestedReference {
public int x;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2024 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
//
// https://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.
goog.module('toplevel');

exports.Nested = class Nested {
constructor() {
/** @type {number} */
this.x = 1;
}
};

/** @type {number} */
exports.x = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ let Foo = goog.forwardDeclare('com.acme.MyFoo');
let Class = goog.forwardDeclare('java.lang.Class$impl');
let Bar = goog.forwardDeclare('nativejstypes.Bar');
let $synthetic_nativejstypes_Bar = goog.forwardDeclare('nativejstypes.Bar');
let TopLevel = goog.forwardDeclare('toplevel');
let toplevel = goog.forwardDeclare('toplevel');
let $JavaScriptObject = goog.forwardDeclare('vmbootstrap.JavaScriptObject$impl');
let $Objects = goog.forwardDeclare('vmbootstrap.Objects$impl');

Expand Down Expand Up @@ -85,6 +87,15 @@ class Main extends j_l_Object {
let unusedEq = $Objects.m_equals__java_lang_Object__java_lang_Object__boolean(bar, j_l_Object.$create__());
}
/** @nodts */
static m_testTopLevel__void() {
Main.$clinit();
TopLevel.x = 2;
let nested = new TopLevel.Nested();
nested.x = 3;
let topLevelNestedReference = new toplevel.Nested();
topLevelNestedReference.x = 4;
}
/** @nodts */
static $clinit() {
Main.$clinit = () =>{};
Main.$loadModules();
Expand All @@ -101,6 +112,8 @@ class Main extends j_l_Object {
Class = goog.module.get('java.lang.Class$impl');
Bar = goog.module.get('nativejstypes.Bar');
$synthetic_nativejstypes_Bar = goog.module.get('nativejstypes.Bar');
TopLevel = goog.module.get('toplevel');
toplevel = goog.module.get('toplevel');
$JavaScriptObject = goog.module.get('vmbootstrap.JavaScriptObject$impl');
$Objects = goog.module.get('vmbootstrap.Objects$impl');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ goog.require('java.lang.Class');
goog.require('java.lang.Object');
goog.require('nativebootstrap.Util');
goog.require('nativejstypes.Bar');
goog.require('toplevel');
goog.require('vmbootstrap.JavaScriptObject');
goog.require('vmbootstrap.Objects');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@
[unusedHash] => [unusedHash] "unusedHash"
[boolean unusedEq = bar.equals(new Object());] => [let unusedEq = $Objects.m_equals__java_lang_Object__java_lang_Object__boolean(bar, j_l_Object.$create__());] "nativejstypes.Main.testNativeTypeObjectMethods"
[unusedEq] => [unusedEq] "unusedEq"
[testTopLevel] => [m_testTopLevel__void]
[{
TopLevel.x = 2;
... topLevelNestedReference.x = 4;
}] => [Main.$clinit();] "nativejstypes.Main.testTopLevel"
[TopLevel.x = 2;] => [TopLevel.x = 2;] "nativejstypes.Main.testTopLevel"
[TopLevel.Nested nested = new TopLevel.Nested();] => [let nested = new TopLevel.Nested();] "nativejstypes.Main.testTopLevel"
[nested] => [nested] "nested"
[nested.x = 3;] => [nested.x = 3;] "nativejstypes.Main.testTopLevel"
[TopLevelNestedReference topLevelNestedReference = new TopLevelNestedReference();] => [let topLevelNestedReference = new toplevel.Nested();] "nativejstypes.Main.testTopLevel"
[topLevelNestedReference] => [topLevelNestedReference] "topLevelNestedReference"
[topLevelNestedReference.x = 4;] => [topLevelNestedReference.x = 4;] "nativejstypes.Main.testTopLevel"
[Main] => [$clinit]
[Main] => [Main.$clinit = () =>{};] "nativejstypes.Main.<clinit>"
[Main] => [Main.$loadModules();] "nativejstypes.Main.<clinit>"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
goog.module('nativejstypes.TopLevel.$Overlay$impl');

const $Util = goog.require('nativebootstrap.Util$impl');
const TopLevel = goog.require('toplevel');

/** @nodts */
class $Overlay {
/** @nodts */
static $clinit() {
$Overlay.$clinit = () =>{};
$Overlay.$loadModules();
}
/** @nodts @return {boolean} */
static $isInstance(/** ? */ instance) {
return instance instanceof TopLevel;
}

/** @nodts */
static $loadModules() {}
}
$Util.$setClassMetadata($Overlay, 'toplevel');

exports = $Overlay;

//# sourceMappingURL=TopLevel$$Overlay.js.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
goog.module('nativejstypes.TopLevel.$Overlay');

goog.require('nativebootstrap.Util');
goog.require('toplevel');

const $Overlay = goog.require('nativejstypes.TopLevel.$Overlay$impl');
/** @nodts */
exports = $Overlay;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[TopLevel] => [$Overlay]
[TopLevel] => [$clinit]
[TopLevel] => [$Overlay.$clinit = () =>{};] "nativejstypes.TopLevel$$Overlay.<clinit>"
[TopLevel] => [$Overlay.$loadModules();] "nativejstypes.TopLevel$$Overlay.<clinit>"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
goog.module('nativejstypes.TopLevel.Nested.$Overlay$impl');

const $Util = goog.require('nativebootstrap.Util$impl');
const TopLevel = goog.require('toplevel');

/** @nodts */
class $Overlay {
/** @nodts */
static $clinit() {
$Overlay.$clinit = () =>{};
$Overlay.$loadModules();
}
/** @nodts @return {boolean} */
static $isInstance(/** ? */ instance) {
return instance instanceof TopLevel.Nested;
}

/** @nodts */
static $loadModules() {}
}
$Util.$setClassMetadata($Overlay, 'toplevel.Nested');

exports = $Overlay;

//# sourceMappingURL=TopLevel$Nested$$Overlay.js.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
goog.module('nativejstypes.TopLevel.Nested.$Overlay');

goog.require('nativebootstrap.Util');
goog.require('toplevel');

const $Overlay = goog.require('nativejstypes.TopLevel.Nested.$Overlay$impl');
/** @nodts */
exports = $Overlay;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Nested] => [$Overlay]
[Nested] => [$clinit]
[Nested] => [$Overlay.$clinit = () =>{};] "nativejstypes.TopLevel$Nested$$Overlay.<clinit>"
[Nested] => [$Overlay.$loadModules();] "nativejstypes.TopLevel$Nested$$Overlay.<clinit>"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
goog.module('nativejstypes.TopLevelNestedReference.$Overlay$impl');

const $Util = goog.require('nativebootstrap.Util$impl');
const toplevel = goog.require('toplevel');

/** @nodts */
class $Overlay {
/** @nodts */
static $clinit() {
$Overlay.$clinit = () =>{};
$Overlay.$loadModules();
}
/** @nodts @return {boolean} */
static $isInstance(/** ? */ instance) {
return instance instanceof toplevel.Nested;
}

/** @nodts */
static $loadModules() {}
}
$Util.$setClassMetadata($Overlay, 'toplevel.Nested');

exports = $Overlay;

//# sourceMappingURL=TopLevelNestedReference$$Overlay.js.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
goog.module('nativejstypes.TopLevelNestedReference.$Overlay');

goog.require('nativebootstrap.Util');
goog.require('toplevel');

const $Overlay = goog.require('nativejstypes.TopLevelNestedReference.$Overlay$impl');
/** @nodts */
exports = $Overlay;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[TopLevelNestedReference] => [$Overlay]
[TopLevelNestedReference] => [$clinit]
[TopLevelNestedReference] => [$Overlay.$clinit = () =>{};] "nativejstypes.TopLevelNestedReference$$Overlay.<clinit>"
[TopLevelNestedReference] => [$Overlay.$loadModules();] "nativejstypes.TopLevelNestedReference$$Overlay.<clinit>"
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2024 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
//
// https://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.
goog.module('toplevel');

exports.Nested = class Nested {
constructor() {
/** @type {number} */
this.x = 1;
}
}

/** @type {number} */
exports.x = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ NS_INLINE void NativejstypesMain_testNativeTypeObjectMethods(void) {
[J2ktNativejstypesMainCompanion.shared testNativeTypeObjectMethods];
}

NS_INLINE void NativejstypesMain_testTopLevel(void) {
[J2ktNativejstypesMainCompanion.shared testTopLevel];
}

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import nativejstypes.Bar
import nativejstypes.BarInnerWithDotInName
import nativejstypes.Foo
import nativejstypes.Headers
import nativejstypes.TopLevel
import nativejstypes.TopLevelNestedReference

@ObjCName("J2ktNativejstypesMain", exact = true)
open class Main {
Expand Down Expand Up @@ -104,5 +106,15 @@ open class Main {
val unusedHash: Int = bar!!.hashCode()
val unusedEq: Boolean = bar!!.equals(Any())
}

@JvmStatic
@ObjCName("testTopLevel")
fun testTopLevel() {
TopLevel.x = 2
val nested: TopLevel.Nested? = TopLevel.Nested()
nested!!.x = 3
val topLevelNestedReference: TopLevelNestedReference? = TopLevelNestedReference()
topLevelNestedReference!!.x = 4
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Generated from "nativejstypes/TopLevel.java"
@file:Suppress(
"ALWAYS_NULL",
"PARAMETER_NAME_CHANGED_ON_OVERRIDE",
"REPEATED_BOUND",
"SENSELESS_COMPARISON",
"UNCHECKED_CAST",
"UNNECESSARY_LATEINIT",
"UNNECESSARY_NOT_NULL_ASSERTION",
"UNREACHABLE_CODE",
"UNUSED_ANONYMOUS_PARAMETER",
"UNUSED_PARAMETER",
"UNUSED_VARIABLE",
"USELESS_CAST",
"VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL",
"VARIABLE_WITH_REDUNDANT_INITIALIZER")

package nativejstypes

import javaemul.lang.*
import jsinterop.annotations.JsType
import kotlin.Int
import kotlin.Suppress
import kotlin.jvm.JvmField

@JsType(name = "toplevel", namespace = "", isNative = true)
open class TopLevel {
internal constructor()

companion object {
@JvmField
var x: Int = 0
}

@JsType(isNative = true)
open class Nested internal constructor() {
@JvmField
var x: Int = 0
}
}

@JsType(name = "toplevel.Nested", namespace = "", isNative = true)
open class TopLevelNestedReference internal constructor() {
@JvmField
var x: Int = 0
}
Loading

0 comments on commit 659e0bd

Please sign in to comment.