diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index c43fab5..1cae877 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -14,7 +14,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Setup Chrome - uses: browser-actions/setup-chrome@v1.2.3 + uses: browser-actions/setup-chrome@v1.7.1 - name: Checkout uses: actions/checkout@v2 - name: Set up Java 11 diff --git a/annotations/pom.xml b/annotations/pom.xml index 8dbfba4..6ff9876 100644 --- a/annotations/pom.xml +++ b/annotations/pom.xml @@ -4,7 +4,7 @@ org.treblereel.j2cl.processors parent - 0.6.3 + 0.7 annotations diff --git a/common/pom.xml b/common/pom.xml index d52696b..7251b70 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.treblereel.j2cl.processors parent - 0.6.3 + 0.7 common diff --git a/pom.xml b/pom.xml index 4da26cf..6b2cf06 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.treblereel.j2cl.processors parent - 0.6.3 + 0.7 pom GWT3 processors parent @@ -42,8 +42,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -57,9 +57,9 @@ 3.2.4 3.0 - 1.1.0 + 1.2.1 2.0.0 - 0.11.0-9336533b6 + v20240622-2 0.11 1.0-rc7 4.8.141 @@ -67,7 +67,7 @@ 2.8.0 1.2 3.3.9 - 1.1.0 + 1.9.20 4.11 @@ -87,41 +87,26 @@ ${com.google.elemental2.version} - com.vertispan.j2cl + org.kie.j2cl.tools frontend-common ${j2cl.version} - com.vertispan.j2cl + org.kie.j2cl.tools frontend-javac ${j2cl.version} - org.apache.maven - maven-aether-provider - ${maven.aether.provider.version} + org.apache.maven.resolver + maven-resolver-api + ${maven.resolver.version} - org.eclipse.aether - aether-impl - ${org.eclipse.aether.version} - - - org.eclipse.aether - aether-transport-file - ${org.eclipse.aether.version} - - - org.eclipse.aether - aether-transport-http - ${org.eclipse.aether.version} - - - org.eclipse.aether - aether-connector-basic - ${org.eclipse.aether.version} + org.apache.maven.resolver + maven-resolver-supplier + ${maven.resolver.version} diff --git a/processor/pom.xml b/processor/pom.xml index 5899aa6..c0aa280 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl.processors parent - 0.6.3 + 0.7 processors @@ -87,24 +87,12 @@ v20221004 - org.apache.maven - maven-aether-provider + org.apache.maven.resolver + maven-resolver-api - org.eclipse.aether - aether-impl - - - org.eclipse.aether - aether-transport-file - - - org.eclipse.aether - aether-transport-http - - - org.eclipse.aether - aether-connector-basic + org.apache.maven.resolver + maven-resolver-supplier junit diff --git a/processor/src/main/java/org/treblereel/j2cl/processors/GWT3Processor.java b/processor/src/main/java/org/treblereel/j2cl/processors/GWT3Processor.java index b59f4f1..31a2649 100644 --- a/processor/src/main/java/org/treblereel/j2cl/processors/GWT3Processor.java +++ b/processor/src/main/java/org/treblereel/j2cl/processors/GWT3Processor.java @@ -33,7 +33,7 @@ import org.treblereel.j2cl.processors.generator.resources.GWT3ResourceGenerator; @AutoService(Processor.class) -@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedSourceVersion(SourceVersion.RELEASE_11) @SupportedAnnotationTypes({ "org.treblereel.j2cl.processors.annotations.GWT3EntryPoint", "org.treblereel.j2cl.processors.annotations.ES6Module", diff --git a/processor/src/main/java/org/treblereel/j2cl/processors/generator/GWT3ExportGenerator.java b/processor/src/main/java/org/treblereel/j2cl/processors/generator/GWT3ExportGenerator.java index 6286b6d..35739cb 100644 --- a/processor/src/main/java/org/treblereel/j2cl/processors/generator/GWT3ExportGenerator.java +++ b/processor/src/main/java/org/treblereel/j2cl/processors/generator/GWT3ExportGenerator.java @@ -29,7 +29,9 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.stream.Collectors; import javax.lang.model.element.Element; @@ -112,13 +114,13 @@ public void generate(Set elements) { exports.put(checkClazz(parent), new HashSet<>()); exports.get(parent).addAll(methods); - ElementFilter.methodsIn(parent.getEnclosedElements()).stream() + getAllMethodsIn(parent).stream() .filter(elm -> !elm.getModifiers().contains(Modifier.PRIVATE)) .filter(elm -> !elm.getModifiers().contains(Modifier.NATIVE)) .filter(elm -> !elm.getModifiers().contains(Modifier.ABSTRACT)) .forEach(elm -> exportDTOs.get(parent).addMethod(getMethodDTO(parent, elm))); - ElementFilter.fieldsIn(parent.getEnclosedElements()).stream() + getAllFieldsIn(parent).stream() .filter(elm -> !elm.getModifiers().contains(Modifier.PRIVATE)) .filter(elm -> !elm.getModifiers().contains(Modifier.NATIVE)) .filter(elm -> !elm.getModifiers().contains(Modifier.ABSTRACT)) @@ -287,9 +289,8 @@ private TypeElement checkClazz(TypeElement parent) { + ", mustn't be annotated with @ES6Module"); } Set constructors = - ElementFilter.constructorsIn(parent.getEnclosedElements()).stream() - .collect(Collectors.toSet()); - if (!constructors.isEmpty()) { + new HashSet<>(ElementFilter.constructorsIn(parent.getEnclosedElements())); + if (parent.getAnnotation(JsType.class) == null && !constructors.isEmpty()) { constructors.stream() .filter(elm -> elm.getModifiers().contains(Modifier.PUBLIC)) .filter(elm -> elm.getParameters().isEmpty()) @@ -305,4 +306,34 @@ private TypeElement checkClazz(TypeElement parent) { return parent; } + + private Set getAllMethodsIn(TypeElement parent) { + Set elements = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.add(parent); + while (!queue.isEmpty()) { + TypeElement current = queue.poll(); + elements.addAll(ElementFilter.methodsIn(current.getEnclosedElements())); + if (!current.getSuperclass().toString().equals("java.lang.Object") + && MoreTypes.asElement(current.getSuperclass()).getKind().isClass()) { + queue.offer((TypeElement) MoreTypes.asElement(current.getSuperclass())); + } + } + return elements; + } + + private Set getAllFieldsIn(TypeElement parent) { + Set elements = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.add(parent); + while (!queue.isEmpty()) { + TypeElement current = queue.poll(); + elements.addAll(ElementFilter.fieldsIn(current.getEnclosedElements())); + if (!current.getSuperclass().toString().equals("java.lang.Object") + && MoreTypes.asElement(current.getSuperclass()).getKind().isClass()) { + queue.offer((TypeElement) MoreTypes.asElement(current.getSuperclass())); + } + } + return elements; + } } diff --git a/processor/src/main/java/org/treblereel/j2cl/processors/generator/resources/MavenArtifactDownloader.java b/processor/src/main/java/org/treblereel/j2cl/processors/generator/resources/MavenArtifactDownloader.java index 14cbf29..fdfbb4f 100644 --- a/processor/src/main/java/org/treblereel/j2cl/processors/generator/resources/MavenArtifactDownloader.java +++ b/processor/src/main/java/org/treblereel/j2cl/processors/generator/resources/MavenArtifactDownloader.java @@ -29,25 +29,19 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.tools.FileObject; -import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.eclipse.aether.AbstractRepositoryListener; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; -import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.supplier.RepositorySystemSupplier; import org.eclipse.aether.transfer.AbstractTransferListener; -import org.eclipse.aether.transport.file.FileTransporterFactory; -import org.eclipse.aether.transport.http.HttpTransporterFactory; import org.treblereel.j2cl.processors.exception.GenerationException; class MavenArtifactDownloader { @@ -137,19 +131,18 @@ private void download() { this.artifact = artifactResult.getArtifact(); } catch (ArtifactResolutionException e) { throw new GenerationException(e); + } finally { + system.shutdown(); } } private RepositorySystem newRepositorySystem() { - DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); - locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); - locator.addService(TransporterFactory.class, FileTransporterFactory.class); - locator.addService(TransporterFactory.class, HttpTransporterFactory.class); - return locator.getService(RepositorySystem.class); + RepositorySystemSupplier supplier = new RepositorySystemSupplier(); + return supplier.get(); } private RepositorySystemSession newSession(RepositorySystem system) { - DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); + DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); LocalRepository localRepo = new LocalRepository(tempDir); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); session.setTransferListener(new ConsoleTransferListener()); diff --git a/processor/src/main/resources/templates/resources/export.ftlh b/processor/src/main/resources/templates/resources/export.ftlh index 3ea900d..b6f3691 100644 --- a/processor/src/main/resources/templates/resources/export.ftlh +++ b/processor/src/main/resources/templates/resources/export.ftlh @@ -1,25 +1,33 @@ +<#if !isNative> +/** +* @fileoverview +* @suppress {missingProperties} +*/ + goog.module('${module}$GWT3Export'); const EXPORT = goog.require('${target}'); <#if isNative> goog.exportSymbol('${type}', EXPORT); -<#else> -const j_l_Object = goog.require('java.lang.Object$impl'); -const $Util = goog.require('nativebootstrap.Util$impl'); -class _EXPORT extends EXPORT { - constructor() { - EXPORT.$clinit(); - super(); - this.${ctor}(); +<#list methods as method> +goog.exportSymbol('${type}.<#if !method.isStatic>prototype.${method.name}', EXPORT.<#if !method.isStatic>prototype.${method.mangleName}); + +<#else> +const classProxy = new Proxy(EXPORT, { + construct(target, args) { + return EXPORT.$create__(); } -} - -$Util.$setClassMetadata(_EXPORT, '${module}'); -goog.exportSymbol('${type}', _EXPORT); - +}); +EXPORT.$clinit(); +goog.exportSymbol('${type}', classProxy); <#list methods as method> -goog.exportSymbol('${type}.<#if !method.isStatic>prototype.${method.name}', EXPORT.<#if !method.isStatic>prototype.${method.mangleName}); +<#if method.isStatic> +goog.exportProperty(EXPORT, '${method.name}', EXPORT.${method.mangleName}); +<#else> +goog.exportSymbol('${type}.prototype.${method.name}', classProxy.prototype.${method.mangleName}); + + diff --git a/tests/commons/pom.xml b/tests/commons/pom.xml index de7dd15..53dde33 100644 --- a/tests/commons/pom.xml +++ b/tests/commons/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl common-tests - 0.6.3 + 0.7 Common test cases Common test cases @@ -15,8 +15,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -24,13 +24,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -58,20 +58,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -85,7 +85,7 @@ org.treblereel.j2cl.processors common - 0.6.3 + 0.7 test @@ -107,7 +107,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/entrypoint/jstype/pom.xml b/tests/entrypoint/jstype/pom.xml index bd1007d..c2fa6f0 100644 --- a/tests/entrypoint/jstype/pom.xml +++ b/tests/entrypoint/jstype/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl entrypoint-jstype-tests - 0.6.3 + 0.7 GWT3 Entry Point Tests for @JsType class Test cases for the GWT3 Entry Point for @JsType class @@ -15,8 +15,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -24,14 +24,14 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 4.12.1 4.13.1 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -91,7 +91,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/entrypoint/pojo/pom.xml b/tests/entrypoint/pojo/pom.xml index 50aa4e6..7f3b301 100644 --- a/tests/entrypoint/pojo/pom.xml +++ b/tests/entrypoint/pojo/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl entrypoint-pojo-tests - 0.6.3 + 0.7 GWT3 Entry Point Tests for Pojo class Test cases for the GWT3 Entry Point for Pojo class @@ -15,8 +15,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -24,14 +24,14 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 4.12.1 4.13.1 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -92,7 +92,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/entrypoint/pom.xml b/tests/entrypoint/pom.xml index 442241c..432f763 100644 --- a/tests/entrypoint/pom.xml +++ b/tests/entrypoint/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl entrypoint-tests - 0.6.3 + 0.7 pom GWT3 Entry Point Tests diff --git a/tests/es6shim/pom.xml b/tests/es6shim/pom.xml index 11eb9d2..0dd8b5b 100644 --- a/tests/es6shim/pom.xml +++ b/tests/es6shim/pom.xml @@ -5,7 +5,7 @@ es6shim-tests org.treblereel.j2cl - 0.6.3 + 0.7 jar ES6SHIM Tests @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -25,13 +25,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -62,20 +62,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -99,7 +99,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/exports/javaenv/pom-advanced.xml b/tests/exports/javaenv/pom-advanced.xml index f8ff91c..bddff2f 100644 --- a/tests/exports/javaenv/pom-advanced.xml +++ b/tests/exports/javaenv/pom-advanced.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl javaenv-advanced - 0.6.3 + 0.7 jar GWTExports java env Tests ADVANCED mode @@ -26,9 +26,9 @@ 3.1.0 3.0.1 3.0 - 0.21.0 + 0.23.1 - 0.11.0-9336533b6 + v20240622-2 4.12.1 4.13.1 @@ -75,20 +75,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -120,7 +120,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/exports/javaenv/pom.xml b/tests/exports/javaenv/pom.xml index f5a2adb..ac1f420 100644 --- a/tests/exports/javaenv/pom.xml +++ b/tests/exports/javaenv/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl javaenv - 0.6.3 + 0.7 jar GWTExports java env Tests BUNDLE_JAR mode @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -26,15 +26,15 @@ 3.1.0 3.0.1 3.0 - 0.21.0 + 0.23.1 - 0.11.0-9336533b6 + v20240622-2 4.12.1 4.13.1 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -75,20 +75,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -120,7 +120,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/exports/jsenv/bundle_jar_pom.xml b/tests/exports/jsenv/bundle_jar_pom.xml index e8e39bf..13aff21 100644 --- a/tests/exports/jsenv/bundle_jar_pom.xml +++ b/tests/exports/jsenv/bundle_jar_pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl exports-bundle_jar - 0.6.3 + 0.7 jar GWTExports Tests BUNDLE_JAR mode @@ -25,7 +25,7 @@ 3.1.0 3.0.1 3.0 - 0.21.0 + 0.23.1 4.12.1 4.13.1 @@ -90,7 +90,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/exports/jsenv/pom.xml b/tests/exports/jsenv/pom.xml index 5bb94f8..2ea6be0 100644 --- a/tests/exports/jsenv/pom.xml +++ b/tests/exports/jsenv/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl jsenv - 0.6.3 + 0.7 jar GWTExports Tests ADVANCED mode @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -25,14 +25,14 @@ 3.1.0 3.0.1 3.0 - 0.21.0 + 0.23.1 4.12.1 4.13.1 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -90,7 +90,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/exports/pom.xml b/tests/exports/pom.xml index d6ca4a4..a2414dd 100644 --- a/tests/exports/pom.xml +++ b/tests/exports/pom.xml @@ -6,7 +6,7 @@ org.treblereel.j2cl tests-parent - 0.6.3 + 0.7 pom diff --git a/tests/pom.xml b/tests/pom.xml index 4e7a89d..379670c 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl tests-parent - 0.6.3 + 0.7 pom GWT3 processors Tests @@ -16,19 +16,19 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 - 0.21.0 + 0.23.1 2.17 2.8.2 3.8.0 2.0.0 1.0.0 - 1.1.0 + 1.2.1 - 0.11.0-9336533b6 + v20240622-2 4.11 4.12.1 @@ -76,23 +76,23 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${j2cl.version} - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${j2cl.version} - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${j2cl.version} sources - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${j2cl.version} diff --git a/tests/resources/pom.xml b/tests/resources/pom.xml index d4a902a..b0572e0 100644 --- a/tests/resources/pom.xml +++ b/tests/resources/pom.xml @@ -6,7 +6,7 @@ org.treblereel.j2cl tests-parent - 0.6.3 + 0.7 resources diff --git a/tests/resources/src/test/java/org/treblereel/j2cl/processors/test/TextResourcesTest.java b/tests/resources/src/test/java/org/treblereel/j2cl/processors/test/TextResourcesTest.java index abc24b2..7330183 100644 --- a/tests/resources/src/test/java/org/treblereel/j2cl/processors/test/TextResourcesTest.java +++ b/tests/resources/src/test/java/org/treblereel/j2cl/processors/test/TextResourcesTest.java @@ -45,14 +45,14 @@ private String readFileAsString(String fileName) { @Test public void testEscape() { - String content = readFileAsString("escape.txt"); - assertEquals(content, TextTestResourceImpl.INSTANCE.escape().getText()); + String content = readFileAsString("escape.txt"); + assertEquals(content, TextTestResourceImpl.INSTANCE.escape().getText()); } @Test public void testBigTxt() { - String content = readFileAsString("bigtextresource.txt"); - assertEquals(content, TextTestResourceImpl.INSTANCE.getBig().getText()); + String content = readFileAsString("bigtextresource.txt"); + assertEquals(content, TextTestResourceImpl.INSTANCE.getBig().getText()); } @Test @@ -108,6 +108,6 @@ private void assertEquals(String str1, String str2) { } private String normalize(String s) { - return s.replace("\r\n","\n"); + return s.replace("\r\n", "\n"); } } diff --git a/tests/translation/default/pom.xml b/tests/translation/default/pom.xml index 49ebe03..4c36471 100644 --- a/tests/translation/default/pom.xml +++ b/tests/translation/default/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl translation-default - 0.6.3 + 0.7 jar Translation Tests en @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -25,13 +25,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -60,19 +60,19 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -121,7 +121,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/translation/fr/pom.xml b/tests/translation/fr/pom.xml index 74677e9..69b77d5 100644 --- a/tests/translation/fr/pom.xml +++ b/tests/translation/fr/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl translation-fr - 0.6.3 + 0.7 jar Translation Tests fr @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -25,13 +25,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -62,20 +62,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -118,7 +118,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/translation/fr_nr/pom.xml b/tests/translation/fr_nr/pom.xml index c092c85..78344d6 100644 --- a/tests/translation/fr_nr/pom.xml +++ b/tests/translation/fr_nr/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl translation-fr-nr - 0.6.3 + 0.7 jar Translation Tests fr-nr @@ -16,8 +16,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -25,13 +25,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -62,20 +62,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -118,7 +118,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/translation/no_bundle/pom.xml b/tests/translation/no_bundle/pom.xml index 562ea35..7e08cb4 100644 --- a/tests/translation/no_bundle/pom.xml +++ b/tests/translation/no_bundle/pom.xml @@ -6,7 +6,7 @@ org.treblereel.j2cl translation-tests - 0.6.3 + 0.7 translation-no_bundle @@ -20,8 +20,8 @@ UTF-8 UTF-8 - 1.8 - 1.8 + 11 + 11 3.8.0 2.17 2.8.2 @@ -29,13 +29,13 @@ 3.1.0 3.0.1 3.0 - 0.21.0 - 0.11.0-9336533b6 + 0.23.1 + v20240622-2 3.0-beta-02 2.0.0 1.0.0 - 1.1.0 + 1.2.1 @@ -66,20 +66,20 @@ - com.vertispan.j2cl + org.kie.j2cl.tools junit-annotations ${maven.j2cl.version} test - com.vertispan.j2cl + org.kie.j2cl.tools gwttestcase-emul ${maven.j2cl.version} sources test - com.vertispan.j2cl + org.kie.j2cl.tools junit-emul ${maven.j2cl.version} test @@ -122,7 +122,7 @@ - com.vertispan.j2cl + org.kie.j2cl.tools j2cl-maven-plugin ${maven.j2cl.plugin} diff --git a/tests/translation/pom.xml b/tests/translation/pom.xml index 0f11fa6..5c106d6 100644 --- a/tests/translation/pom.xml +++ b/tests/translation/pom.xml @@ -5,7 +5,7 @@ org.treblereel.j2cl translation-tests - 0.6.3 + 0.7 pom GWT3 Entry Point Tests diff --git a/utils/pom.xml b/utils/pom.xml index b7fee8c..ea96aa5 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -5,7 +5,7 @@ parent org.treblereel.j2cl.processors - 0.6.3 + 0.7 4.0.0 @@ -43,12 +43,12 @@ ${auto.common.version} - com.vertispan.j2cl + org.kie.j2cl.tools frontend-common - com.vertispan.j2cl + org.kie.j2cl.tools frontend-javac diff --git a/utils/src/main/java/org/treblereel/j2cl/processors/utils/J2CLUtils.java b/utils/src/main/java/org/treblereel/j2cl/processors/utils/J2CLUtils.java index 48bcd92..bc3f9b2 100644 --- a/utils/src/main/java/org/treblereel/j2cl/processors/utils/J2CLUtils.java +++ b/utils/src/main/java/org/treblereel/j2cl/processors/utils/J2CLUtils.java @@ -17,10 +17,12 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.j2cl.transpiler.ast.TypeDeclaration.Kind; +import static com.google.j2cl.transpiler.ast.TypeDeclaration.newBuilder; -import com.google.auto.common.MoreElements; import com.google.auto.common.MoreTypes; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.google.common.collect.Streams; import com.google.j2cl.common.InternalCompilerError; import com.google.j2cl.transpiler.ast.ArrayTypeDescriptor; @@ -29,8 +31,7 @@ import com.google.j2cl.transpiler.ast.FieldDescriptor; import com.google.j2cl.transpiler.ast.JsEnumInfo; import com.google.j2cl.transpiler.ast.JsInfo; -import com.google.j2cl.transpiler.ast.JsMemberType; -import com.google.j2cl.transpiler.ast.Kind; +import com.google.j2cl.transpiler.ast.Literal; import com.google.j2cl.transpiler.ast.MemberDescriptor; import com.google.j2cl.transpiler.ast.MethodDescriptor; import com.google.j2cl.transpiler.ast.MethodDescriptor.ParameterDescriptor; @@ -43,8 +44,11 @@ import com.google.j2cl.transpiler.frontend.javac.JsInteropAnnotationUtils; import com.google.j2cl.transpiler.frontend.javac.JsInteropUtils; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.function.Predicate; +import java.util.Map; import java.util.function.Supplier; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.AnnotatedConstruct; @@ -66,7 +70,6 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; -import jsinterop.annotations.JsPackage; /** * Utility functions to interact with JavaC internal representations. @@ -74,35 +77,120 @@ *

it's taken from J2CL project */ public class J2CLUtils { - private final Types types; + private final Types javacTypes; private final Elements elements; private final ProcessingEnvironment processingEnv; + private final Map + cachedDeclaredTypeDescriptorByDeclaredTypeInNullMarkedScope = new HashMap<>(); + private final Map + cachedDeclaredTypeDescriptorByDeclaredTypeOutOfNullMarkedScope = new HashMap<>(); public J2CLUtils(ProcessingEnvironment processingEnv) { - this.types = processingEnv.getTypeUtils(); + this.javacTypes = processingEnv.getTypeUtils(); this.elements = processingEnv.getElementUtils(); this.processingEnv = processingEnv; + initWellKnownTypes(TypeDescriptors.getWellKnownTypeNames()); } - public static boolean hasJsMemberAnnotation(ExecutableElement method) { - return JsInteropAnnotationUtils.getJsMethodAnnotation(method) != null - || JsInteropAnnotationUtils.getJsPropertyAnnotation(method) != null - || JsInteropAnnotationUtils.getJsConstructorAnnotation(method) != null; + private boolean isNonNullAnnotation(AnnotationMirror annotation) { + DeclaredType annotationType = annotation.getAnnotationType(); + String name = annotationType.asElement().getSimpleName().toString(); + return name.equals("NonNull") || name.equals("JsNonNull"); } - public static boolean isAnonymous(TypeMirror type) { - if (type.getKind().equals(TypeKind.DECLARED)) { - DeclaredType declaredType = (DeclaredType) type; - TypeElement typeElem = (TypeElement) declaredType.asElement(); - if (typeElem.getNestingKind().equals(NestingKind.ANONYMOUS)) { - return true; + private boolean isNullableAnnotation(AnnotationMirror annotation) { + DeclaredType annotationType = annotation.getAnnotationType(); + return annotationType.asElement().getSimpleName().toString().equals("Nullable"); + } + + private DeclaredTypeDescriptor withNullability( + DeclaredTypeDescriptor typeDescriptor, boolean nullable) { + return nullable ? typeDescriptor.toNullable() : typeDescriptor.toNonNullable(); + } + + /** + * In case the given type element is nested, return the outermost possible enclosing type element. + */ + private TypeElement toTopLevelTypeBinding(Element element) { + if (element.getEnclosingElement().getKind() == ElementKind.PACKAGE) { + return (TypeElement) element; + } + return toTopLevelTypeBinding(element.getEnclosingElement()); + } + + private boolean isValuesMethod(ExecutableElement methodElement) { + return methodElement.getSimpleName().contentEquals("values") + && methodElement.getParameters().isEmpty(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Utility methods to process nullability annotations on classes that are compiled separately. + // Javac does not present TYPE_USE annotation in the returned type instances. + private TypeDescriptor applyParameterNullabilityAnnotations( + TypeDescriptor typeDescriptor, ExecutableElement declarationMethodElement, int index) { + return typeDescriptor; + } + + private int getInnerDepth(DeclaredTypeDescriptor innerType) { + if (innerType.getTypeDeclaration().isCapturingEnclosingInstance()) { + return getInnerDepth(innerType.getEnclosingTypeDescriptor()) + 1; + } + return 0; + } + + /** Returns true if the element is annotated with @UncheckedCast. */ + private boolean hasUncheckedCastAnnotation(Element element) { + return false; + } + + /** Returns true if the element is annotated with @HasNoSideEffects. */ + private boolean isAnnotatedWithHasNoSideEffects(Element element) { + return true; + } + + private List getTypeArguments(DeclaredType declaredType) { + List typeArguments = new ArrayList<>(); + DeclaredType currentType = declaredType; + do { + typeArguments.addAll(currentType.getTypeArguments()); + Element enclosingElement = currentType.asElement().getEnclosingElement(); + if (enclosingElement.getKind() == ElementKind.METHOD + || enclosingElement.getKind() == ElementKind.CONSTRUCTOR) { + typeArguments.addAll( + ((Parameterizable) enclosingElement) + .getTypeParameters().stream().map(Element::asType).collect(toImmutableList())); } + currentType = + currentType.getEnclosingType() instanceof DeclaredType + ? (DeclaredType) currentType.getEnclosingType() + : null; + } while (currentType != null); + return typeArguments; + } + + private Kind getKindFromTypeBinding(TypeElement typeElement) { + if (isEnum(typeElement) && !isAnonymous(typeElement)) { + // Do not consider the anonymous classes that constitute enum values as Enums, only the + // enum "class" itself is considered Kind.ENUM. + return Kind.ENUM; + } else if (isClass(typeElement) || (isEnum(typeElement) && isAnonymous(typeElement))) { + return Kind.CLASS; + } else if (isInterface(typeElement)) { + return Kind.INTERFACE; } + throw new InternalCompilerError("Type binding %s not handled.", typeElement); + } + + private String getJsName(final TypeElement classSymbol) { + return JsInteropAnnotationUtils.getJsName(classSymbol); + } + + private boolean hasNullMarkedAnnotation(TypeElement classSymbol) { return false; } - private static List getTypeParameters(TypeElement typeElement) { + private List getTypeParameters(TypeElement typeElement) { List typeParameterElements = new ArrayList<>(typeElement.getTypeParameters()); Element currentElement = typeElement; @@ -125,7 +213,7 @@ private static List getTypeParameters(TypeElement typeElem return typeParameterElements; } - public static TypeElement getEnclosingType(Element typeElement) { + public TypeElement getEnclosingType(Element typeElement) { Element enclosing = typeElement.getEnclosingElement(); while (enclosing != null && !(enclosing instanceof TypeElement)) { enclosing = enclosing.getEnclosingElement(); @@ -133,23 +221,40 @@ public static TypeElement getEnclosingType(Element typeElement) { return (TypeElement) enclosing; } - public static String getJsName(final TypeElement classSymbol) { - return JsInteropAnnotationUtils.getJsName(classSymbol); + private TypeElement getEnclosingType(TypeElement typeElement) { + Element enclosing = typeElement.getEnclosingElement(); + while (enclosing != null && !(enclosing instanceof TypeElement)) { + enclosing = enclosing.getEnclosingElement(); + } + return (TypeElement) enclosing; } - public static boolean isLocal(TypeElement typeElement) { - return typeElement.getNestingKind() == NestingKind.LOCAL; + private boolean isEnum(TypeElement typeElement) { + return typeElement.getKind() == ElementKind.ENUM; } - public static boolean isStatic(Element element) { - return element.getModifiers().contains(Modifier.STATIC); + private boolean isAnnotation(TypeElement typeElement) { + return typeElement.getKind() == ElementKind.ANNOTATION_TYPE; } - public static boolean isNative(Element element) { - return element.getModifiers().contains(Modifier.NATIVE); + private boolean isAnonymous(TypeElement typeElement) { + return typeElement.getNestingKind() == NestingKind.ANONYMOUS; + } + + private boolean isClass(TypeElement typeElement) { + return typeElement.getKind() == ElementKind.CLASS; + } + + private boolean isInterface(TypeElement typeElement) { + return typeElement.getKind() == ElementKind.INTERFACE + || typeElement.getKind() == ElementKind.ANNOTATION_TYPE; + } + + private boolean isLocal(TypeElement typeElement) { + return typeElement.getNestingKind() == NestingKind.LOCAL; } - public static Visibility getVisibility(Element element) { + public Visibility getVisibility(Element element) { if (element.getModifiers().contains(Modifier.PUBLIC)) { return Visibility.PUBLIC; } else if (element.getModifiers().contains(Modifier.PROTECTED)) { @@ -161,296 +266,325 @@ public static Visibility getVisibility(Element element) { } } - public static String getJsNamespace(TypeElement classSymbol) { - String jsNamespace = JsInteropAnnotationUtils.getJsNamespace(classSymbol); - if (jsNamespace != null) { - return jsNamespace; - } - - // Maybe namespace is set via package-info file? - boolean isTopLevelType = classSymbol.getEnclosingElement().getKind() == ElementKind.PACKAGE; - if (isTopLevelType) { - JsPackage jsPackage = classSymbol.getEnclosingElement().getAnnotation(JsPackage.class); - return jsPackage != null ? jsPackage.namespace() : null; - } - return null; + private boolean isDeprecated(AnnotatedConstruct binding) { + return binding.getAnnotation(Deprecated.class) != null; } - private static List getTypeArguments(DeclaredType declaredType) { - List typeArguments = new ArrayList<>(); - DeclaredType currentType = declaredType; - do { - typeArguments.addAll(currentType.getTypeArguments()); - Element enclosingElement = currentType.asElement().getEnclosingElement(); - if (enclosingElement.getKind() == ElementKind.METHOD - || enclosingElement.getKind() == ElementKind.CONSTRUCTOR) { - typeArguments.addAll( - ((Parameterizable) enclosingElement) - .getTypeParameters().stream().map(Element::asType).collect(toImmutableList())); - } - currentType = - currentType.getEnclosingType() instanceof DeclaredType - ? (DeclaredType) currentType.getEnclosingType() - : null; - } while (currentType != null); - return typeArguments; + private boolean isDefaultMethod(Element element) { + return element.getModifiers().contains(Modifier.DEFAULT); } - private static DeclaredTypeDescriptor withNullability( - DeclaredTypeDescriptor typeDescriptor, boolean nullable) { - return nullable ? typeDescriptor.toNullable() : typeDescriptor.toNonNullable(); + private boolean isAbstract(Element element) { + return element.getModifiers().contains(Modifier.ABSTRACT); } - private static boolean isNonNullAnnotation(AnnotationMirror annotation) { - DeclaredType annotationType = annotation.getAnnotationType(); - String name = annotationType.asElement().getSimpleName().toString(); - return name.equals("NonNull") || name.equals("JsNonNull"); + private boolean isFinal(Element element) { + return element.getModifiers().contains(Modifier.FINAL); } - private static boolean isNullableAnnotation(AnnotationMirror annotation) { - DeclaredType annotationType = annotation.getAnnotationType(); - return annotationType.asElement().getSimpleName().toString().equals("Nullable"); + public boolean isStatic(Element element) { + return element.getModifiers().contains(Modifier.STATIC); } - public static boolean isStatic(VariableElement variableElement) { - return variableElement.getModifiers().contains(Modifier.STATIC); + private boolean isNative(Element element) { + return element.getModifiers().contains(Modifier.NATIVE); } - public static boolean isFinal(Element declarationMethodElement) { - return declarationMethodElement.getModifiers().contains(Modifier.FINAL); + private boolean isSynthetic(Element element) { + return false; + // return element instanceof Symbol && (((Symbol) element).flags() & Flags.SYNTHETIC) != 0; } - public static boolean isInterface(TypeElement typeElement) { - return typeElement.getKind().isInterface(); + private MethodDescriptor ctorMethodDescriptorFromJavaConstructor(MethodDescriptor constructor) { + return constructor.transform( + builder -> + builder + .setReturnTypeDescriptor(PrimitiveTypes.VOID) + .setName(getCtorName(constructor)) + .setConstructor(false) + .setStatic(false) + .setOriginalJsInfo(JsInfo.NONE) + .removeParameterOptionality() + .setOrigin(MethodDescriptor.MethodOrigin.SYNTHETIC_CTOR_FOR_CONSTRUCTOR) + .setVisibility(Visibility.PUBLIC)); } - public static boolean isInterface(TypeMirror typeElement) { - return isInterface(MoreTypes.asTypeElement(typeElement)); + private String getCtorName(MethodDescriptor methodDescriptor) { + // Synthesize a name that is unique per class to avoid property clashes in JS. + return MethodDescriptor.CTOR_METHOD_PREFIX + + "__" + + methodDescriptor.getEnclosingTypeDescriptor().getMangledName(); } - public static boolean isDeprecated(AnnotatedConstruct binding) { - return hasAnnotation(binding, Deprecated.class.getName()); - } + private void initWellKnownTypes(Collection wellKnownQualifiedBinaryNames) { + if (TypeDescriptors.isInitialized()) { + return; + } + TypeDescriptors.SingletonBuilder builder = new TypeDescriptors.SingletonBuilder(); + // Add well-known, non-primitive types. + wellKnownQualifiedBinaryNames.forEach( + binaryName -> { + String qualifiedSourceName = binaryName.replace('$', '.'); + TypeElement element = getTypeElement(qualifiedSourceName); + if (element != null) { + builder.addReferenceType(createDeclaredTypeDescriptor(element.asType())); + } + }); + + DeclaredTypeDescriptor typeDescriptor = + createSyntheticJavaEmulInternalExceptionsTypeDescriptor(); + builder.addReferenceType(typeDescriptor); + builder.buildSingleton(); + } + + private DeclaredTypeDescriptor createSyntheticJavaEmulInternalExceptionsTypeDescriptor() { + TypeDeclaration typeDeclaration = + TypeDeclaration.newBuilder() + .setClassComponents(ImmutableList.of("Exceptions")) + .setNative(false) + .setCustomizedJsNamespace("javaemul.internal") + .setPackageName("javaemul.internal") + .setTypeParameterDescriptors(ImmutableList.of()) + .setVisibility(Visibility.PUBLIC) + .setKind(Kind.CLASS) + .build(); - public static boolean hasAnnotation(AnnotatedConstruct construct, String annotationSourceName) { - return findAnnotationBindingByName(construct.getAnnotationMirrors(), annotationSourceName) - != null; + return DeclaredTypeDescriptor.newBuilder() + .setTypeDeclaration(typeDeclaration) + .setTypeArgumentDescriptors(Collections.EMPTY_LIST) + .build(); } - public static AnnotationMirror findAnnotationBindingByName( - List annotations, String name) { - if (annotations == null) { - return null; - } - for (AnnotationMirror annotationBinding : annotations) { - if (((TypeElement) annotationBinding.getAnnotationType().asElement()) - .getQualifiedName() - .contentEquals(name)) { - return annotationBinding; - } - } - return null; + public DeclaredTypeDescriptor createDeclaredTypeDescriptor(TypeMirror typeMirror) { + return createDeclaredTypeDescriptor(typeMirror, /* inNullMarkedScope= */ false); } - public static boolean isDefaultMethod(Element element) { - return element.getModifiers().contains(Modifier.DEFAULT); + private DeclaredTypeDescriptor createDeclaredTypeDescriptor( + TypeMirror typeMirror, boolean inNullMarkedScope) { + return createTypeDescriptor(typeMirror, inNullMarkedScope, DeclaredTypeDescriptor.class); } - public static boolean isClass(TypeElement typeElement) { - return typeElement.getKind().isClass(); + /** Creates a specific subclass of TypeDescriptor from a TypeMirror. */ + public T createTypeDescriptor(TypeMirror typeMirror, Class clazz) { + return createTypeDescriptor(typeMirror, /* inNullMarkedScope= */ false, clazz); } - public static boolean isEnum(TypeElement typeElement) { - return typeElement.getKind().equals(ElementKind.ENUM); + /** Creates a specific subclass of TypeDescriptor from a TypeMirror. */ + private T createTypeDescriptor( + TypeMirror typeMirror, boolean inNullMarkedScope, Class clazz) { + return clazz.cast(createTypeDescriptor(typeMirror, inNullMarkedScope)); } - public static boolean isAbstract(Element element) { - return element.getModifiers().contains(Modifier.ABSTRACT); + /** Creates a TypeDescriptor from a TypeMirror. */ + public TypeDescriptor createTypeDescriptor(TypeMirror typeMirror) { + return createTypeDescriptor(typeMirror, /* inNullMarkedScope= */ false); } - public static boolean isJsEnum(TypeElement typeElement) { - return JsInteropUtils.isJsEnum(typeElement); + /** Creates a TypeDescriptor from a TypeMirror. */ + private TypeDescriptor createTypeDescriptor(TypeMirror typeMirror, boolean inNullMarkedScope) { + return createTypeDescriptorWithNullability(typeMirror, ImmutableList.of(), inNullMarkedScope); } - public TypeDeclaration createDeclarationForType(final TypeElement typeElement) { - if (typeElement == null) { + /** Creates a type descriptor for the given TypeMirror, taking into account nullability. */ + private TypeDescriptor createTypeDescriptorWithNullability( + TypeMirror typeMirror, + List elementAnnotations, + boolean inNullMarkedScope) { + if (typeMirror == null || typeMirror.getKind() == TypeKind.NONE) { return null; } + if (typeMirror.getKind().isPrimitive()) { + return PrimitiveTypes.get(typeMirror.toString()); + } - boolean isFromSource = false; - // Compute these first since they're reused in other calculations. - String packageName = getPackageOf(typeElement).getQualifiedName().toString(); - boolean isAbstract = isAbstract(typeElement) && !isInterface(typeElement); - boolean isFinal = isFinal(typeElement); - - Supplier> declaredMethods = - () -> { - ImmutableList.Builder listBuilder = ImmutableList.builder(); - for (ExecutableElement methodElement : - ElementFilter.methodsIn(typeElement.getEnclosedElements())) { - MethodDescriptor methodDescriptor = createDeclarationMethodDescriptor(methodElement); - listBuilder.add(methodDescriptor); - } - return listBuilder.build(); - }; + if (typeMirror.getKind() == TypeKind.VOID) { + return PrimitiveTypes.VOID; + } - Supplier> declaredFields = - () -> - typeElement.getEnclosedElements().stream() - .filter( - element -> - element.getKind() == ElementKind.FIELD - || element.getKind() == ElementKind.ENUM_CONSTANT) - .map(VariableElement.class::cast) - .map(this::createFieldDescriptor) - .collect(toImmutableList()); + if (typeMirror.getKind() == TypeKind.INTERSECTION) { + throw new InternalCompilerError("Intersection types are not supported."); + // return createIntersectionType((IntersectionClassType) typeMirror); + } - JsEnumInfo jsEnumInfo = JsInteropUtils.getJsEnumInfo(typeElement); + if (typeMirror.getKind() == TypeKind.UNION) { + throw new InternalCompilerError("Union types are not supported."); + // return createUnionType((UnionClassType) typeMirror); + } - List typeParameterElements = getTypeParameters(typeElement); + if (typeMirror.getKind() == TypeKind.NULL) { + return TypeDescriptors.get().javaLangObject; + } - boolean isNullMarked = isNullMarked(typeElement); - return TypeDeclaration.newBuilder() - .setClassComponents(getClassComponents(typeElement)) - .setEnclosingTypeDeclaration(createDeclarationForType(getEnclosingType(typeElement))) - .setInterfaceTypeDescriptorsFactory( - () -> - createTypeDescriptors( - typeElement.getInterfaces(), - isNullMarked, - DeclaredTypeDescriptor.class, - typeElement)) - .setUnparameterizedTypeDescriptorFactory( - () -> createDeclaredTypeDescriptor(typeElement.asType())) - .setHasAbstractModifier(isAbstract) - .setKind(getKindFromTypeBinding(typeElement)) - .setCapturingEnclosingInstance(capturesEnclosingInstance(typeElement)) - .setFinal(isFinal) - .setFunctionalInterface(isFunctionalInterface(typeElement.asType())) - .setJsFunctionInterface(JsInteropUtils.isJsFunction(typeElement)) - .setJsType(JsInteropUtils.isJsType(typeElement)) - .setJsEnumInfo(jsEnumInfo) - .setNative(JsInteropUtils.isJsNativeType(typeElement)) - .setAnonymous(isAnonymous(typeElement)) - .setLocal(isLocal(typeElement)) - .setSimpleJsName(getJsName(typeElement)) - .setCustomizedJsNamespace(getJsNamespace(typeElement)) - .setNullMarked(isNullMarked) - .setPackageName(packageName) - .setSuperTypeDescriptorFactory( - () -> - (DeclaredTypeDescriptor) - applyNullabilityAnnotations( - createDeclaredTypeDescriptor(typeElement.getSuperclass(), isNullMarked), - typeElement, - (obj) -> false)) - .setTypeParameterDescriptors( - typeParameterElements.stream() - .map(TypeParameterElement::asType) - .map(javax.lang.model.type.TypeVariable.class::cast) - .map(this::createTypeVariable) - .collect(toImmutableList())) - .setVisibility(getVisibility(typeElement)) - .setDeclaredMethodDescriptorsFactory(declaredMethods) - .setDeclaredFieldDescriptorsFactory(declaredFields) - .setUnusableByJsSuppressed(JsInteropAnnotationUtils.isUnusableByJsSuppressed(typeElement)) - .setDeprecated(isDeprecated(typeElement)) - .build(); - } + if (typeMirror.getKind() == TypeKind.TYPEVAR) { + return createTypeVariable((javax.lang.model.type.TypeVariable) typeMirror); + } - public MethodDescriptor createDeclarationMethodDescriptor(ExecutableElement methodElement) { - DeclaredTypeDescriptor enclosingTypeDescriptor = - createDeclaredTypeDescriptor(methodElement.getEnclosingElement().asType()); - return createDeclarationMethodDescriptor(methodElement, enclosingTypeDescriptor); - } + if (typeMirror.getKind() == TypeKind.WILDCARD) { + return createWildcardTypeVariable( + ((javax.lang.model.type.WildcardType) typeMirror).getExtendsBound()); + } - ///////////////////////////////////////////////////////////////////////////////////////////////// - // Utility methods to process nullability annotations on classes that are compiled separately. - // Javac does not present TYPE_USE annotation in the returned type instances. - private static TypeDescriptor applyParameterNullabilityAnnotations( - TypeDescriptor typeDescriptor, ExecutableElement declarationMethodElement, int index) { - return applyNullabilityAnnotations(typeDescriptor, declarationMethodElement, (obj) -> false); - // position -> - // position.parameter_index == index - // && position.type == TargetType.METHOD_FORMAL_PARAMETER); - } + boolean isNullable = isNullable(typeMirror, elementAnnotations, inNullMarkedScope); + if (typeMirror.getKind() == TypeKind.ARRAY) { + ArrayType arrayType = (ArrayType) typeMirror; + TypeDescriptor componentTypeDescriptor = + createTypeDescriptor(arrayType.getComponentType(), inNullMarkedScope); + return ArrayTypeDescriptor.newBuilder() + .setComponentTypeDescriptor(componentTypeDescriptor) + .setNullable(isNullable) + .build(); + } - private static TypeDescriptor applyNullabilityAnnotations( - TypeDescriptor typeDescriptor, - Element declarationMethodElement, - Predicate positionSelector) { - return typeDescriptor; + return withNullability( + createDeclaredType(MoreTypes.asDeclared(typeMirror), inNullMarkedScope), isNullable); } - public boolean isSameType(TypeMirror asType, TypeMirror type) { - return types.isSameType(asType, type); - } + /** + * Returns whether the given type binding should be nullable, according to the annotations on it + * and if nullability is enabled for the package containing the binding. + */ + private boolean isNullable( + TypeMirror typeMirror, + List elementAnnotations, + boolean inNullMarkedScope) { + checkArgument(!typeMirror.getKind().isPrimitive()); - public PackageElement getPackageOf(TypeElement typeElement) { - return elements.getPackageOf(typeElement); - } + if (typeMirror.getKind() == TypeKind.VOID) { + return true; + } - /** Create a MethodDescriptor directly based on the given JavaC ExecutableElement. */ - public MethodDescriptor createDeclarationMethodDescriptor( - ExecutableElement methodElement, DeclaredTypeDescriptor enclosingTypeDescriptor) { - return createMethodDescriptor(enclosingTypeDescriptor, methodElement, methodElement); + Iterable allAnnotations = + Iterables.concat(elementAnnotations, typeMirror.getAnnotationMirrors()); + + for (AnnotationMirror annotationMirror : allAnnotations) { + if (isNonNullAnnotation(annotationMirror)) { + return false; + } + if (isNullableAnnotation(annotationMirror)) { + return true; + } + } + + return !inNullMarkedScope; } - MethodDescriptor createMethodDescriptor( - DeclaredTypeDescriptor enclosingTypeDescriptor, - ExecutableElement methodElement, - ExecutableElement declarationMethodElement) { + private TypeVariable createTypeVariable(javax.lang.model.type.TypeVariable typeVariable) { + /* if (typeVariable instanceof CapturedType) { + return createWildcardTypeVariable(typeVariable.getUpperBound()); + }*/ - MethodDescriptor declarationMethodDescriptor = null; + Supplier boundTypeDescriptorFactory = + () -> createTypeDescriptor(typeVariable.getUpperBound()); - ImmutableList parameters = - methodElement.getParameters().stream() - .map(VariableElement::asType) - .collect(toImmutableList()); + List classComponents = getClassComponents(typeVariable); + return TypeVariable.newBuilder() + .setUpperBoundTypeDescriptorSupplier(boundTypeDescriptorFactory) + .setUniqueKey( + String.join("::", classComponents) + + (typeVariable.getUpperBound() != null + ? typeVariable.getUpperBound().toString() + : "")) + .setName(typeVariable.asElement().getSimpleName().toString()) + .build(); + } - TypeMirror returnType = methodElement.getReturnType(); - if (isSpecialized(declarationMethodElement, parameters, returnType)) { - declarationMethodDescriptor = - createDeclarationMethodDescriptor( - declarationMethodElement, enclosingTypeDescriptor.toUnparameterizedTypeDescriptor()); - } + private TypeVariable createWildcardTypeVariable(TypeMirror bound) { + return TypeVariable.newBuilder() + .setUpperBoundTypeDescriptorSupplier(() -> createTypeDescriptor(bound)) + .setWildcard(true) + .setName("?") + .setUniqueKey("::?::" + (bound != null ? bound.toString() : "")) + .build(); + } - TypeDescriptor returnTypeDescriptor = - createTypeDescriptorWithNullability( - returnType, declarationMethodElement.getAnnotationMirrors(), false); + private ImmutableList getClassComponents( + javax.lang.model.type.TypeVariable typeVariable) { + Element enclosingElement = typeVariable.asElement().getEnclosingElement(); + if (enclosingElement.getKind() == ElementKind.CLASS + || enclosingElement.getKind() == ElementKind.INTERFACE + || enclosingElement.getKind() == ElementKind.ENUM) { + return ImmutableList.builder() + .addAll(getClassComponents(enclosingElement)) + .add( + // If it is a class-level type variable, use the simple name (with prefix "C_") as the + // current name component. + "C_" + typeVariable.asElement().getSimpleName()) + .build(); + } else { + return ImmutableList.builder() + .addAll(getClassComponents(enclosingElement.getEnclosingElement())) + .add( + "M_" + + enclosingElement.getSimpleName() + + "_" + + typeVariable.asElement().getSimpleName()) + .build(); + } + } - ImmutableList.Builder parametersBuilder = ImmutableList.builder(); - for (int i = 0; i < parameters.size(); i++) { - parametersBuilder.add( - applyParameterNullabilityAnnotations( - createTypeDescriptorWithNullability( - parameters.get(i), - declarationMethodElement.getParameters().get(i).getAnnotationMirrors(), - false), - declarationMethodElement, - i)); + private ImmutableList getClassComponents(Element element) { + if (!(element instanceof TypeElement)) { + return ImmutableList.of(); + } + TypeElement typeElement = (TypeElement) element; + List classComponents = new ArrayList<>(); + TypeElement currentType = typeElement; + while (currentType != null) { + String simpleName; + if (currentType.getNestingKind() == NestingKind.LOCAL + || currentType.getNestingKind() == NestingKind.ANONYMOUS) { + // JavaC binary name for local class is like package.components.EnclosingClass$1SimpleName + // Extract the generated name by taking the part after the binary name of the declaring + // class. + String binaryName = getBinaryNameFromTypeBinding(currentType); + String declaringClassPrefix = + getBinaryNameFromTypeBinding(getEnclosingType(currentType)) + "$"; + simpleName = binaryName.substring(declaringClassPrefix.length()); + } else { + simpleName = asElement(erasure(currentType.asType())).getSimpleName().toString(); + } + classComponents.add(0, simpleName); + Element enclosingElement = currentType.getEnclosingElement(); + while (enclosingElement != null + && enclosingElement.getKind() != ElementKind.CLASS + && enclosingElement.getKind() != ElementKind.INTERFACE + && enclosingElement.getKind() != ElementKind.ENUM) { + enclosingElement = enclosingElement.getEnclosingElement(); + } + currentType = (TypeElement) enclosingElement; } + return ImmutableList.copyOf(classComponents); + } - return createDeclaredMethodDescriptor( - enclosingTypeDescriptor.toNullable(), - declarationMethodElement, - declarationMethodDescriptor, - parametersBuilder.build(), - returnTypeDescriptor); + /** Returns the binary name for a type element. */ + private String getBinaryNameFromTypeBinding(TypeElement typeElement) { + return elements.getBinaryName(typeElement).toString(); } - public DeclaredTypeDescriptor createDeclaredTypeDescriptor(TypeMirror typeMirror) { - return createDeclaredTypeDescriptor(typeMirror, /* inNullMarkedScope= */ false); + private boolean isEnumSyntheticMethod(ExecutableElement methodElement) { + // Enum synthetic methods are not marked as such because per JLS 13.1 these methods are + // implicitly declared but are not marked as synthetic. + return getEnclosingType(methodElement).getKind() == ElementKind.ENUM + && (isValuesMethod(methodElement) || isValueOfMethod(methodElement)); } - DeclaredTypeDescriptor createDeclaredTypeDescriptor( - TypeMirror typeMirror, boolean inNullMarkedScope) { - return createTypeDescriptor(typeMirror, inNullMarkedScope, DeclaredTypeDescriptor.class); + private boolean isValueOfMethod(ExecutableElement methodElement) { + return methodElement.getSimpleName().contentEquals("valueOf") + && methodElement.getParameters().size() == 1 + && asTypeElement(methodElement.getParameters().get(0).asType()) + .getQualifiedName() + .contentEquals("java.lang.String"); } - T createTypeDescriptor( - TypeMirror typeMirror, boolean inNullMarkedScope, Class clazz) { - return clazz.cast(createTypeDescriptor(typeMirror, inNullMarkedScope)); + /** + * Returns true if instances of this type capture its outer instances; i.e. if it is an non member + * class, or an anonymous or local class defined in an instance context. + */ + private boolean capturesEnclosingInstance(TypeElement typeElement) { + if (isAnonymous(typeElement)) { + return hasOuterInstance(typeElement) || !isStatic(typeElement.getEnclosingElement()); + } + return hasOuterInstance(typeElement); } public boolean hasOuterInstance(TypeElement typeElement) { @@ -458,14 +592,6 @@ public boolean hasOuterInstance(TypeElement typeElement) { && !isInterface((TypeElement) typeElement.getEnclosingElement()); } - public boolean isAnonymous(TypeElement typeElement) { - return isAnonymous(typeElement.asType()); - } - - private boolean isFunctionalInterface(TypeMirror type) { - return false; - } - public FieldDescriptor createFieldDescriptor(VariableElement variableElement) { return createFieldDescriptor(variableElement, variableElement.asType()); } @@ -482,7 +608,7 @@ public FieldDescriptor createFieldDescriptor(VariableElement variableElement, Ty createTypeDescriptorWithNullability( type, variableElement.getAnnotationMirrors(), - isNullMarked(getEnclosingType(variableElement))); + enclosingTypeDescriptor.getTypeDeclaration().isNullMarked()); boolean isEnumConstant = variableElement.getKind().equals(ElementKind.ENUM_CONSTANT); if (isEnumConstant) { @@ -491,14 +617,18 @@ public FieldDescriptor createFieldDescriptor(VariableElement variableElement, Ty } FieldDescriptor declarationFieldDescriptor = null; - if (!isSameType(variableElement.asType(), type)) { + if (!javacTypes.isSameType(variableElement.asType(), type)) { // Field references might be parameterized, and when they are we set the declaration // descriptor to the unparameterized declaration. declarationFieldDescriptor = createFieldDescriptor(variableElement, variableElement.asType()); } JsInfo jsInfo = JsInteropUtils.getJsInfo(variableElement); - boolean isCompileTimeConstant = variableElement.getConstantValue() != null; + Object constantValue = variableElement.getConstantValue(); + boolean isCompileTimeConstant = constantValue != null; + if (isCompileTimeConstant) { + thisTypeDescriptor = thisTypeDescriptor.toNonNullable(); + } boolean isFinal = isFinal(variableElement); return FieldDescriptor.newBuilder() .setEnclosingTypeDescriptor(enclosingTypeDescriptor) @@ -506,9 +636,11 @@ public FieldDescriptor createFieldDescriptor(VariableElement variableElement, Ty .setTypeDescriptor(thisTypeDescriptor) .setStatic(isStatic) .setVisibility(visibility) - .setJsInfo(jsInfo) + .setOriginalJsInfo(jsInfo) .setFinal(isFinal) .setCompileTimeConstant(isCompileTimeConstant) + .setConstantValue( + constantValue != null ? Literal.fromValue(constantValue, thisTypeDescriptor) : null) .setDeclarationDescriptor(declarationFieldDescriptor) .setEnumConstant(isEnumConstant) .setUnusableByJsSuppressed( @@ -517,31 +649,85 @@ public FieldDescriptor createFieldDescriptor(VariableElement variableElement, Ty .build(); } - public TypeDescriptor createTypeDescriptor(TypeMirror typeMirror) { - return createTypeDescriptor(typeMirror, /* inNullMarkedScope= */ false); - } + /** Create a MethodDescriptor directly based on the given JavaC ExecutableElement. */ + MethodDescriptor createMethodDescriptor( + DeclaredTypeDescriptor enclosingTypeDescriptor, + ExecutableElement methodElement, + ExecutableElement declarationMethodElement) { - public Element asElement(TypeMirror typeMirror) { - if (typeMirror.getKind().isPrimitive()) { - return MoreTypes.asElement(typeMirror); + MethodDescriptor declarationMethodDescriptor = null; + + ImmutableList parameters = + methodElement.getParameters().stream() + .map(VariableElement::asType) + .collect(toImmutableList()); + + TypeMirror returnType = methodElement.getReturnType(); + if (isSpecialized(declarationMethodElement, parameters, returnType)) { + declarationMethodDescriptor = + createDeclarationMethodDescriptor( + declarationMethodElement, enclosingTypeDescriptor.toUnparameterizedTypeDescriptor()); } - if (typeMirror.getKind().equals(TypeKind.DECLARED)) { - return MoreTypes.asDeclared(typeMirror).asElement(); + + TypeDescriptor returnTypeDescriptor = + createTypeDescriptorWithNullability( + returnType, + declarationMethodElement.getAnnotationMirrors(), + enclosingTypeDescriptor.getTypeDeclaration().isNullMarked()); + + ImmutableList.Builder parametersBuilder = ImmutableList.builder(); + for (int i = 0; i < parameters.size(); i++) { + parametersBuilder.add( + applyParameterNullabilityAnnotations( + createTypeDescriptorWithNullability( + parameters.get(i), + declarationMethodElement.getParameters().get(i).getAnnotationMirrors(), + enclosingTypeDescriptor.getTypeDeclaration().isNullMarked()), + declarationMethodElement, + i)); } - return types.asElement(typeMirror); + + return createDeclaredMethodDescriptor( + enclosingTypeDescriptor.toNullable(), + declarationMethodElement, + declarationMethodDescriptor, + parametersBuilder.build(), + returnTypeDescriptor); } - public TypeMirror erasure(TypeMirror typeMirror) { - return types.erasure(typeMirror); + /** Create a MethodDescriptor directly based on the given JavaC ExecutableElement. */ + public MethodDescriptor createDeclarationMethodDescriptor(ExecutableElement methodElement) { + DeclaredTypeDescriptor enclosingTypeDescriptor = + createDeclaredTypeDescriptor(methodElement.getEnclosingElement().asType()); + return createDeclarationMethodDescriptor(methodElement, enclosingTypeDescriptor); } - public String getBinaryNameFromTypeBinding(TypeElement typeElement) { - return elements.getBinaryName(typeElement).toString(); + /** Create a MethodDescriptor directly based on the given JavaC ExecutableElement. */ + public MethodDescriptor createDeclarationMethodDescriptor( + ExecutableElement methodElement, DeclaredTypeDescriptor enclosingTypeDescriptor) { + return createMethodDescriptor(enclosingTypeDescriptor, methodElement, methodElement); } - /** Creates a TypeDescriptor from a TypeMirror. */ - TypeDescriptor createTypeDescriptor(TypeMirror typeMirror, boolean inNullMarkedScope) { - return createTypeDescriptorWithNullability(typeMirror, ImmutableList.of(), inNullMarkedScope); + /** + * Returns true if any of the type parameters has been specialized. + * + *

For example the type {@code List} specialized the type variable {@code T} from the + * class declaration. + */ + private boolean isSpecialized( + ExecutableElement declarationMethodElement, + List parameters, + TypeMirror returnType) { + return !isSameType(returnType, declarationMethodElement.getReturnType()) + || !Streams.zip( + parameters.stream(), + declarationMethodElement.getParameters().stream(), + (thisType, thatType) -> isSameType(thisType, thatType.asType())) + .allMatch(equals -> equals); + } + + private boolean isSameType(TypeMirror thisType, TypeMirror thatType) { + return javacTypes.isSameType(thisType, thatType); } private MethodDescriptor createDeclaredMethodDescriptor( @@ -560,7 +746,7 @@ private MethodDescriptor createDeclaredMethodDescriptor( boolean isStatic = isStatic(declarationMethodElement); Visibility visibility = getVisibility(declarationMethodElement); boolean isDefault = isDefaultMethod(declarationMethodElement); - JsInfo jsInfo = computeJsInfo(declarationMethodElement); + JsInfo jsInfo = JsInteropUtils.getJsInfo(declarationMethodElement); boolean isNative = isNative(declarationMethodElement) @@ -582,12 +768,6 @@ private MethodDescriptor createDeclaredMethodDescriptor( .build()); } - if (enclosingTypeDescriptor.getTypeDeclaration().isAnonymous() - && isConstructor - && enclosingTypeDescriptor.getSuperTypeDescriptor().hasJsConstructor()) { - jsInfo = JsInfo.Builder.from(jsInfo).setJsMemberType(JsMemberType.CONSTRUCTOR).build(); - } - boolean hasUncheckedCast = hasUncheckedCastAnnotation(declarationMethodElement); return MethodDescriptor.newBuilder() .setEnclosingTypeDescriptor(enclosingTypeDescriptor) @@ -596,8 +776,7 @@ private MethodDescriptor createDeclaredMethodDescriptor( .setDeclarationDescriptor(declarationMethodDescriptor) .setReturnTypeDescriptor(isConstructor ? enclosingTypeDescriptor : returnTypeDescriptor) .setTypeParameterTypeDescriptors(typeParameterTypeDescriptors) - .setJsInfo(jsInfo) - .setJsFunction(isOrOverridesJsFunctionMethod(declarationMethodElement)) + .setOriginalJsInfo(jsInfo) .setVisibility(visibility) .setStatic(isStatic) .setConstructor(isConstructor) @@ -605,9 +784,9 @@ private MethodDescriptor createDeclaredMethodDescriptor( .setFinal(isFinal(declarationMethodElement)) .setDefaultMethod(isDefault) .setAbstract(isAbstract(declarationMethodElement)) - // .setSynthetic(isSynthetic(declarationMethodElement)) - // .setEnumSyntheticMethod(isEnumSyntheticMethod(declarationMethodElement)) - // .setSideEffectFree(isAnnotatedWithHasNoSideEffects(declarationMethodElement)) + .setSynthetic(isSynthetic(declarationMethodElement)) + .setEnumSyntheticMethod(isEnumSyntheticMethod(declarationMethodElement)) + .setSideEffectFree(isAnnotatedWithHasNoSideEffects(declarationMethodElement)) .setUnusableByJsSuppressed( JsInteropAnnotationUtils.isUnusableByJsSuppressed(declarationMethodElement)) .setDeprecated(isDeprecated(declarationMethodElement)) @@ -615,169 +794,78 @@ private MethodDescriptor createDeclaredMethodDescriptor( .build(); } - private boolean hasUncheckedCastAnnotation(Element element) { - return hasAnnotation(element, "javaemul.internal.annotations.UncheckedCast"); + public ImmutableList createTypeDescriptors( + List typeMirrors, boolean inNullMarkedScope) { + return typeMirrors.stream() + .map(typeMirror -> createTypeDescriptor(typeMirror, inNullMarkedScope)) + .collect(toImmutableList()); } - private boolean isOrOverridesJsFunctionMethod(ExecutableElement methodBinding) { - Element declaringType = methodBinding.getEnclosingElement(); - if (JsInteropUtils.isJsFunction(declaringType)) { - throw new RuntimeException(" not implemented"); - } - return false; - } + public ImmutableList createTypeDescriptors( + List typeMirrors, + boolean inNullMarkedScope, + Class clazz, + Element declarationElement) { + ImmutableList.Builder typeDescriptorsBuilder = ImmutableList.builder(); + for (int i = 0; i < typeMirrors.size(); i++) { + final int index = i; + TypeDescriptor typeDescriptor = + createTypeDescriptor(typeMirrors.get(i), inNullMarkedScope, clazz); + /* typeDescriptorsBuilder.add(typeDescriptor); - private JsInfo computeJsInfo(ExecutableElement method) { - JsInfo originalJsInfo = JsInteropUtils.getJsInfo(method); - if (originalJsInfo.isJsOverlay() - || originalJsInfo.getJsName() != null - || originalJsInfo.getJsNamespace() != null) { - // Do not examine overridden methods if the method is marked as JsOverlay or it has a JsMember - // annotation that customizes the name. - return originalJsInfo; + typeDescriptorsBuilder.add( + clazz.cast( + applyNullabilityAnnotations( + createTypeDescriptor(typeMirrors.get(i), inNullMarkedScope, clazz), + declarationElement, + position -> + position.type == TargetType.CLASS_EXTENDS && position.type_index == index)));*/ } - // Don't inherit @JsAsync annotation from overridden methods. - return JsInfo.Builder.from(originalJsInfo).setJsAsync(originalJsInfo.isJsAsync()).build(); - } - - private boolean isSpecialized( - ExecutableElement declarationMethodElement, - List parameters, - TypeMirror returnType) { - return !isSameType(returnType, declarationMethodElement.getReturnType()) - || !Streams.zip( - parameters.stream(), - declarationMethodElement.getParameters().stream(), - (thisType, thatType) -> isSameType(thisType, thatType.asType())) - .allMatch(equals -> equals); + return typeDescriptorsBuilder.build(); } - private ImmutableList createTypeDescriptors( - List typeMirrors, boolean inNullMarkedScope) { + public ImmutableList createTypeDescriptors( + List typeMirrors, boolean inNullMarkedScope, Class clazz) { return typeMirrors.stream() - .map(typeMirror -> createTypeDescriptor(typeMirror, inNullMarkedScope)) + .map(typeMirror -> createTypeDescriptor(typeMirror, inNullMarkedScope, clazz)) .collect(toImmutableList()); } - private ImmutableList createTypeDescriptors( - List typeMirrors, - boolean inNullMarkedScope, - Class clazz, - Element declarationElement) { - ImmutableList.Builder typeDescriptorsBuilder = ImmutableList.builder(); - for (int i = 0; i < typeMirrors.size(); i++) { - final int index = i; - typeDescriptorsBuilder.add( - createTypeDescriptor(typeMirrors.get(i), inNullMarkedScope, clazz)); - } - return typeDescriptorsBuilder.build(); + private TypeElement getTypeElement(String qualifiedSourceName) { + return elements.getTypeElement(qualifiedSourceName); } - private TypeVariable createTypeVariable(javax.lang.model.type.TypeVariable typeVariable) { - if (typeVariable.getKind().equals(TypeKind.WILDCARD)) { - return createWildcardTypeVariable(typeVariable.getUpperBound()); + private Element asElement(TypeMirror typeMirror) { + if (typeMirror.getKind().isPrimitive()) { + return MoreTypes.asElement(typeMirror); } - - Supplier boundTypeDescriptorFactory = - () -> createTypeDescriptor(typeVariable.getUpperBound()); - - List classComponents = getClassComponents(typeVariable); - - return TypeVariable.newBuilder() - .setUpperBoundTypeDescriptorSupplier(boundTypeDescriptorFactory) // TODO - .setUniqueKey( - String.join("::", classComponents) - + (typeVariable.getUpperBound() != null - ? typeVariable.getUpperBound().toString() - : "")) - .setName(typeVariable.asElement().getSimpleName().toString()) - .build(); - } - - private TypeVariable createWildcardTypeVariable(TypeMirror bound) { - return TypeVariable.newBuilder() - .setUpperBoundTypeDescriptorSupplier(() -> createTypeDescriptor(bound)) - .setWildcardOrCapture(true) - .setName("?") - .setUniqueKey("::?::" + (bound != null ? bound.toString() : "")) - .build(); - } - - private boolean capturesEnclosingInstance(TypeElement typeElement) { - if (isAnonymous(typeElement)) { - return hasOuterInstance(typeElement) || !isStatic(typeElement.getEnclosingElement()); + if (typeMirror.getKind().equals(TypeKind.DECLARED)) { + return MoreTypes.asDeclared(typeMirror).asElement(); } - return hasOuterInstance(typeElement); + return javacTypes.asElement(typeMirror); } - private static boolean isNullMarked(TypeElement classSymbol) { - return hasNullMarkedAnnotation(classSymbol); + private TypeElement asTypeElement(TypeMirror typeMirror) { + return (TypeElement) asElement(typeMirror); } - private static boolean hasNullMarkedAnnotation(TypeElement classSymbol) { - if (findAnnotationBindingByName( - classSymbol.getAnnotationMirrors(), "org.jspecify.nullness.NullMarked") - != null) { - // The type is NullMarked, no need to look further. - return true; - } - - Element enclosingElement = classSymbol.getEnclosingElement(); - return enclosingElement instanceof TypeElement - && hasNullMarkedAnnotation((TypeElement) enclosingElement); + private TypeMirror erasure(TypeMirror typeMirror) { + return javacTypes.erasure(typeMirror); } - private TypeDescriptor createTypeDescriptorWithNullability( - TypeMirror typeMirror, - List elementAnnotations, - boolean inNullMarkedScope) { - if (typeMirror == null || typeMirror.getKind() == TypeKind.NONE) { - return null; - } - - if (typeMirror.getKind().isPrimitive() || typeMirror.getKind() == TypeKind.VOID) { - return PrimitiveTypes.get(typeMirror.toString()); - } - - if (typeMirror.getKind() == TypeKind.INTERSECTION) { - throw new RuntimeException("Not implemented"); - } - - if (typeMirror.getKind() == TypeKind.UNION) { - throw new RuntimeException("Not implemented"); - } - - if (typeMirror.getKind() == TypeKind.NULL) { - return TypeDescriptors.get().javaLangObject; - } - - if (typeMirror.getKind() == TypeKind.TYPEVAR) { - return createTypeVariable((javax.lang.model.type.TypeVariable) typeMirror); - } - - if (typeMirror.getKind() == TypeKind.WILDCARD) { - return createWildcardTypeVariable( - ((javax.lang.model.type.WildcardType) typeMirror).getExtendsBound()); - } - - boolean isNullable = isNullable(typeMirror, elementAnnotations, inNullMarkedScope); - if (typeMirror.getKind() == TypeKind.ARRAY) { - ArrayType arrayType = (ArrayType) typeMirror; - TypeDescriptor componentTypeDescriptor = - createTypeDescriptor(arrayType.getComponentType(), inNullMarkedScope); - return ArrayTypeDescriptor.newBuilder() - .setComponentTypeDescriptor(componentTypeDescriptor) - .setNullable(isNullable) - .build(); - } - - return withNullability( - createDeclaredType(MoreTypes.asDeclared(typeMirror), inNullMarkedScope), isNullable); + private PackageElement getPackageOf(TypeElement typeElement) { + return elements.getPackageOf(typeElement); } private DeclaredTypeDescriptor createDeclaredType( final DeclaredType classType, boolean inNullMarkedScope) { + DeclaredTypeDescriptor cachedTypeDescriptor = + getCachedTypeDescriptor(classType, inNullMarkedScope); + if (cachedTypeDescriptor != null) { + return cachedTypeDescriptor; + } + Supplier> declaredMethods = () -> getDeclaredMethods(classType).stream() @@ -809,159 +897,176 @@ private DeclaredTypeDescriptor createDeclaredType( .setTypeDeclaration(typeDeclaration) .setEnclosingTypeDescriptor(createDeclaredTypeDescriptor(classType.getEnclosingType())) .setSuperTypeDescriptorFactory( - () -> - createDeclaredTypeDescriptor( - types.directSupertypes(classType).stream() - .filter(e -> !isInterface(e)) - .findFirst() - .orElse(null), - inNullMarkedScope)) + td -> + td.isInterface() + ? null + : createDeclaredTypeDescriptor( + javacTypes.directSupertypes(classType).stream() + .filter(type -> !asTypeElement(type).getKind().isInterface()) + .findFirst() + .orElse(null), + inNullMarkedScope)) .setInterfaceTypeDescriptorsFactory( td -> createTypeDescriptors( - types.directSupertypes(classType).stream() - .filter(e -> isInterface(e)) + javacTypes.directSupertypes(classType).stream() + .filter(type -> !asTypeElement(type).getKind().isInterface()) .collect(toImmutableList()), inNullMarkedScope, DeclaredTypeDescriptor.class)) .setSingleAbstractMethodDescriptorFactory( td -> { - ExecutableElement functionalInterfaceMethod = - getFunctionalInterfaceMethod(classType); - - ExecutableElement asMemberOf = - MoreElements.asExecutable( - MoreTypes.asElement( - types.asMemberOf(classType, functionalInterfaceMethod))); - - return createMethodDescriptor( - td, asMemberOf, getFunctionalInterfaceMethodDecl(classType)); + // MethodSymbol functionalInterfaceMethod = + // getFunctionalInterfaceMethod(classType); + throw new UnsupportedOperationException("Not implemented yet"); + /* return createMethodDescriptor( + td, + (MethodSymbol) + functionalInterfaceMethod.asMemberOf( + ((ClassSymbol) classType.asElement()).asType(), internalTypes), + getFunctionalInterfaceMethodDecl(classType));*/ }) .setTypeArgumentDescriptors( createTypeDescriptors(getTypeArguments(classType), inNullMarkedScope)) .setDeclaredFieldDescriptorsFactory(declaredFields) .setDeclaredMethodDescriptorsFactory(declaredMethods) .build(); + putTypeDescriptorInCache(inNullMarkedScope, classType, typeDescriptor); return typeDescriptor; } + private DeclaredTypeDescriptor getCachedTypeDescriptor( + DeclaredType classType, boolean inNullMarkedScope) { + Map cache = + inNullMarkedScope + ? cachedDeclaredTypeDescriptorByDeclaredTypeInNullMarkedScope + : cachedDeclaredTypeDescriptorByDeclaredTypeOutOfNullMarkedScope; + return cache.get(classType); + } + + private void putTypeDescriptorInCache( + boolean inNullMarkedScope, DeclaredType classType, DeclaredTypeDescriptor typeDescriptor) { + Map cache = + inNullMarkedScope + ? cachedDeclaredTypeDescriptorByDeclaredTypeInNullMarkedScope + : cachedDeclaredTypeDescriptorByDeclaredTypeOutOfNullMarkedScope; + cache.put(classType, typeDescriptor); + } + private ImmutableList getDeclaredMethods(DeclaredType classType) { return ElementFilter.methodsIn(classType.asElement().getEnclosedElements()).stream() .collect(toImmutableList()); } - public ImmutableList createTypeDescriptors( - List typeMirrors, boolean inNullMarkedScope, Class clazz) { - return typeMirrors.stream() - .map(typeMirror -> createTypeDescriptor(typeMirror, inNullMarkedScope, clazz)) - .collect(toImmutableList()); - } + private String getJsNamespace(TypeElement classSymbol) { + String jsNamespace = JsInteropAnnotationUtils.getJsNamespace(classSymbol); + if (jsNamespace != null) { + return jsNamespace; + } - private ExecutableElement getFunctionalInterfaceMethodDecl(TypeMirror typeMirror) { - throw new RuntimeException("Not implemented"); + // Maybe namespace is set via package-info file? + boolean isTopLevelType = classSymbol.getEnclosingElement().getKind() == ElementKind.PACKAGE; + if (isTopLevelType) { + return getBinaryNameFromTypeBinding(classSymbol); + } + return null; } - private boolean isNullable( - TypeMirror typeMirror, - List elementAnnotations, - boolean inNullMarkedScope) { - checkArgument(!typeMirror.getKind().isPrimitive()); - - if (typeMirror.getKind().equals(TypeKind.VOID)) { - // Void is always nullable. - return true; + TypeDeclaration createDeclarationForType(final TypeElement typeElement) { + if (typeElement == null) { + return null; } - List allAnnotations = new ArrayList<>(); - allAnnotations.addAll(elementAnnotations); - allAnnotations.addAll(typeMirror.getAnnotationMirrors()); + // Compute these first since they're reused in other calculations. + String packageName = getPackageOf(typeElement).getQualifiedName().toString(); + boolean isAbstract = isAbstract(typeElement) && !isInterface(typeElement); + Kind kind = getKindFromTypeBinding(typeElement); + // TODO(b/341721484): Even though enums can not have the final modifier, turbine make them final + // in the header jars. + boolean isFinal = isFinal(typeElement) && kind != Kind.ENUM; - for (AnnotationMirror annotationMirror : allAnnotations) { - if (isNonNullAnnotation(annotationMirror)) { - return false; - } - if (isNullableAnnotation(annotationMirror)) { - return true; - } - } + Supplier> declaredMethods = + () -> { + ImmutableList.Builder listBuilder = ImmutableList.builder(); + for (ExecutableElement methodElement : + ElementFilter.methodsIn(typeElement.getEnclosedElements())) { + MethodDescriptor methodDescriptor = createDeclarationMethodDescriptor(methodElement); + listBuilder.add(methodDescriptor); + } + return listBuilder.build(); + }; - return !inNullMarkedScope; - } + Supplier> declaredFields = + () -> + typeElement.getEnclosedElements().stream() + .filter( + element -> + element.getKind() == ElementKind.FIELD + || element.getKind() == ElementKind.ENUM_CONSTANT) + .map(VariableElement.class::cast) + .map(this::createFieldDescriptor) + .collect(toImmutableList()); - private ImmutableList getClassComponents( - javax.lang.model.type.TypeVariable typeVariable) { - Element enclosingElement = typeVariable.asElement().getEnclosingElement(); - if (enclosingElement.getKind() == ElementKind.CLASS - || enclosingElement.getKind() == ElementKind.INTERFACE - || enclosingElement.getKind() == ElementKind.ENUM) { - return ImmutableList.builder() - .addAll(getClassComponents(enclosingElement)) - .add( - // If it is a class-level type variable, use the simple name (with prefix "C_") as the - // current name component. - "C_" + typeVariable.asElement().getSimpleName()) - .build(); - } else { - return ImmutableList.builder() - .addAll(getClassComponents(enclosingElement.getEnclosingElement())) - .add( - "M_" - + enclosingElement.getSimpleName() - + "_" - + typeVariable.asElement().getSimpleName()) - .build(); - } - } + JsEnumInfo jsEnumInfo = JsInteropUtils.getJsEnumInfo(typeElement); - private ImmutableList getClassComponents(Element element) { - if (!(element instanceof TypeElement)) { - return ImmutableList.of(); - } - TypeElement typeElement = (TypeElement) element; - List classComponents = new ArrayList<>(); - TypeElement currentType = typeElement; - while (currentType != null) { - String simpleName; - if (currentType.getNestingKind() == NestingKind.LOCAL - || currentType.getNestingKind() == NestingKind.ANONYMOUS) { - // JavaC binary name for local class is like package.components.EnclosingClass$1SimpleName - // Extract the generated name by taking the part after the binary name of the declaring - // class. - String binaryName = getBinaryNameFromTypeBinding(currentType); - String declaringClassPrefix = - getBinaryNameFromTypeBinding(getEnclosingType(currentType)) + "$"; - simpleName = binaryName.substring(declaringClassPrefix.length()); - } else { - simpleName = asElement(erasure(currentType.asType())).getSimpleName().toString(); - } - classComponents.add(0, simpleName); - Element enclosingElement = currentType.getEnclosingElement(); - while (enclosingElement != null - && enclosingElement.getKind() != ElementKind.CLASS - && enclosingElement.getKind() != ElementKind.INTERFACE - && enclosingElement.getKind() != ElementKind.ENUM) { - enclosingElement = enclosingElement.getEnclosingElement(); - } - currentType = (TypeElement) enclosingElement; - } - return ImmutableList.copyOf(classComponents); - } + List typeParameterElements = getTypeParameters(typeElement); - private Kind getKindFromTypeBinding(TypeElement typeElement) { - if (isEnum(typeElement) && !isAnonymous(typeElement)) { - // Do not consider the anonymous classes that constitute enum values as Enums, only the - // enum "class" itself is considered Kind.ENUM. - return Kind.ENUM; - } else if (isClass(typeElement) || (isEnum(typeElement) && isAnonymous(typeElement))) { - return Kind.CLASS; - } else if (isInterface(typeElement)) { - return Kind.INTERFACE; - } - throw new InternalCompilerError("Type binding %s not handled.", typeElement); + // boolean isNullMarked = isNullMarked(typeElement, packageInfoCache); + boolean isNullMarked = false; + return newBuilder() + .setClassComponents(getClassComponents(typeElement)) + .setEnclosingTypeDeclaration(createDeclarationForType(getEnclosingType(typeElement))) + .setInterfaceTypeDescriptorsFactory( + () -> + createTypeDescriptors( + typeElement.getInterfaces(), + isNullMarked, + DeclaredTypeDescriptor.class, + typeElement)) + .setUnparameterizedTypeDescriptorFactory( + () -> createDeclaredTypeDescriptor(typeElement.asType())) + .setHasAbstractModifier(isAbstract) + .setKind(kind) + // .setAnnotation(isAnnotation(typeElement)) + .setCapturingEnclosingInstance(capturesEnclosingInstance(typeElement)) + .setFinal(isFinal) + .setFunctionalInterface(isFunctionalInterface(typeElement.asType())) + .setJsFunctionInterface(JsInteropUtils.isJsFunction(typeElement)) + .setJsType(JsInteropUtils.isJsType(typeElement)) + .setJsEnumInfo(jsEnumInfo) + .setNative(JsInteropUtils.isJsNativeType(typeElement)) + .setAnonymous(isAnonymous(typeElement)) + .setLocal(isLocal(typeElement)) + .setSimpleJsName(getJsName(typeElement)) + .setCustomizedJsNamespace(getJsNamespace(typeElement)) + .setNullMarked(isNullMarked) + /* .setOriginalSimpleSourceName( + typeElement.getSimpleName() != null ? typeElement.getSimpleName().toString() : null)*/ + .setPackageName(packageName) + /* .setSuperTypeDescriptorFactory( + () -> + (DeclaredTypeDescriptor) + applyNullabilityAnnotations( + createDeclaredTypeDescriptor(typeElement.getSuperclass(), isNullMarked), + typeElement, + position -> + position.type == TargetType.CLASS_EXTENDS && position.type_index == -1))*/ + .setTypeParameterDescriptors( + typeParameterElements.stream() + .map(TypeParameterElement::asType) + .map(javax.lang.model.type.TypeVariable.class::cast) + .map(this::createTypeVariable) + .collect(toImmutableList())) + .setVisibility(getVisibility(typeElement)) + .setDeclaredMethodDescriptorsFactory(declaredMethods) + .setDeclaredFieldDescriptorsFactory(declaredFields) + .setUnusableByJsSuppressed(JsInteropAnnotationUtils.isUnusableByJsSuppressed(typeElement)) + .setDeprecated(isDeprecated(typeElement)) + .build(); } - private ExecutableElement getFunctionalInterfaceMethod(TypeMirror typeMirror) { - throw new UnsupportedOperationException(); + private boolean isFunctionalInterface(TypeMirror type) { + return type.getAnnotationsByType(FunctionalInterface.class).length > 0; } public MemberDescriptor getDefaultConstructor(TypeElement clazz) { @@ -976,26 +1081,4 @@ public MemberDescriptor getDefaultConstructor(TypeElement clazz) { .orElseGet(() -> AstUtils.createImplicitConstructorDescriptor(typeDeclaration)); return ctorMethodDescriptorFromJavaConstructor(ctor); } - - private static String getCtorName(MethodDescriptor methodDescriptor) { - // Synthesize a name that is unique per class to avoid property clashes in JS. - return MethodDescriptor.CTOR_METHOD_PREFIX - + "__" - + methodDescriptor.getEnclosingTypeDescriptor().getMangledName(); - } - - private static MethodDescriptor ctorMethodDescriptorFromJavaConstructor( - MethodDescriptor constructor) { - return constructor.transform( - builder -> - builder - .setReturnTypeDescriptor(PrimitiveTypes.VOID) - .setName(getCtorName(constructor)) - .setConstructor(false) - .setStatic(false) - .setJsInfo(JsInfo.NONE) - .removeParameterOptionality() - .setOrigin(MethodDescriptor.MethodOrigin.SYNTHETIC_CTOR_FOR_CONSTRUCTOR) - .setVisibility(Visibility.PUBLIC)); - } }