diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java index 1cb26a12..aaeefb94 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java @@ -1300,7 +1300,11 @@ public class JSweetContext extends Context { } return false; } - + + public boolean elementHasAnnotationType(Element element, String... annotationTypes) { + return hasAnnotationType((Symbol)element, annotationTypes); + } + /** * Tells if the given symbol is annotated with one of the given annotation * types. diff --git a/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java b/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java index d89cbebe..c8ced3bb 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java @@ -605,7 +605,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter { private void useModule(boolean require, boolean direct, PackageElement targetPackage, JCTree sourceTree, String targetName, String moduleName, Symbol sourceElement) { - if (context.useModules) { + if (context.useModules && targetPackage != null) { context.packageDependencies.add((PackageSymbol) targetPackage); context.packageDependencies.add(compilationUnit.packge); context.packageDependencies.addEdge(compilationUnit.packge, (PackageSymbol) targetPackage); @@ -1802,6 +1802,9 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter { scanner.scan(defaultMethod.typarams); scanner.scan(defaultMethod.recvparam); } else { + if (defaultMethod.getName().toString().equals("forEach")) { + System.out.println(); + } scanner.scan(defaultMethod); } } @@ -6504,6 +6507,17 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter { checkType(t.type.tsym); } } + // Check the owner of invoked static methods since those may be statically imported + if (t instanceof JCMethodInvocation) { + JCMethodInvocation inv = (JCMethodInvocation) t; + if (inv.meth instanceof JCIdent && ((JCIdent)inv.meth).sym instanceof MethodSymbol) { + MethodSymbol sym = (MethodSymbol)((JCIdent)inv.meth).sym; + if (sym.isStatic()) { + checkType(sym.owner); + } + + } + } super.scan(t); } diff --git a/transpiler/src/main/java/org/jsweet/transpiler/ModuleImportDescriptor.java b/transpiler/src/main/java/org/jsweet/transpiler/ModuleImportDescriptor.java index 044322ea..81289c34 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/ModuleImportDescriptor.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/ModuleImportDescriptor.java @@ -34,6 +34,12 @@ public class ModuleImportDescriptor { this.pathToImportedClass = pathToImportedClass; } + public ModuleImportDescriptor(String importedName, String pathToImportedClass) { + super(); + this.importedName = importedName; + this.pathToImportedClass = pathToImportedClass; + } + public ModuleImportDescriptor(boolean direct, PackageElement targetPackage, String importedName, String pathToImportedClass) { this(targetPackage, importedName, pathToImportedClass); diff --git a/transpiler/src/main/java/org/jsweet/transpiler/extension/Java2TypeScriptAdapter.java b/transpiler/src/main/java/org/jsweet/transpiler/extension/Java2TypeScriptAdapter.java index 3f273a64..2854a820 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/extension/Java2TypeScriptAdapter.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/extension/Java2TypeScriptAdapter.java @@ -1435,16 +1435,59 @@ public class Java2TypeScriptAdapter extends PrinterAdapter { protected final void delegateToEmulLayer(String targetClassName, String targetMethodName, InvocationElement invocation) { - print("javaemul.internal." + targetClassName.substring(10) + "Helper.").print(targetMethodName).print("(") - .printArgList(invocation.getArguments()).print(")"); + String helperClassName = targetClassName.substring(10) + "Helper"; + if (context.useModules) { + String pathToImportedClass = util().getRelativePath( + "@/" + getCompilationUnit().getPackage().toString().replace('.', '/'), + ("@/javaemul.internal." + helperClassName).replace('.', '/')); + if (!pathToImportedClass.startsWith(".")) { + pathToImportedClass = "./" + pathToImportedClass; + } + useModule(new ModuleImportDescriptor(helperClassName, pathToImportedClass)); + print(helperClassName).print(".").print(targetMethodName).print("(") + .printArgList(invocation.getArguments()).print(")"); + } else { + print("javaemul.internal." + helperClassName).print(".").print(targetMethodName).print("(") + .printArgList(invocation.getArguments()).print(")"); + } } protected final void delegateToEmulLayerStatic(String targetClassName, String targetMethodName, ExtendedElement target) { - print("javaemul.internal." + targetClassName.substring(10) + "Helper.").print(targetMethodName).print("("); - printTarget(target).print(")"); + String helperClassName = targetClassName.substring(10) + "Helper"; + if (context.useModules) { + String pathToImportedClass = util().getRelativePath( + "@/" + getCompilationUnit().getPackage().toString().replace('.', '/'), + ("@/javaemul.internal." + helperClassName).replace('.', '/')); + if (!pathToImportedClass.startsWith(".")) { + pathToImportedClass = "./" + pathToImportedClass; + } + useModule(new ModuleImportDescriptor(helperClassName, pathToImportedClass)); + print(helperClassName).print(".").print(targetMethodName).print("("); + printTarget(target).print(")"); + } else { + print("javaemul.internal." + helperClassName).print(".").print(targetMethodName).print("("); + printTarget(target).print(")"); + } } + protected final void delegateToEmulLayer(String targetClassName, VariableAccessElement fieldAccess) { + String helperClassName = targetClassName.substring(10) + "Helper"; + if (context.useModules) { + String pathToImportedClass = util().getRelativePath( + "@/" + getCompilationUnit().getPackage().toString().replace('.', '/'), + ("@/javaemul.internal." + helperClassName).replace('.', '/')); + if (!pathToImportedClass.startsWith(".")) { + pathToImportedClass = "./" + pathToImportedClass; + } + useModule(new ModuleImportDescriptor(helperClassName, pathToImportedClass)); + print(helperClassName).print(".").print(fieldAccess.getVariableName()); + } else { + print("javaemul.internal." + helperClassName).print(".").print(fieldAccess.getVariableName()); + } + } + + protected final void printCastMethodInvocation(InvocationElement invocation) { boolean needsParens = getPrinter().getParent() instanceof JCMethodInvocation; if (needsParens) { @@ -1595,10 +1638,6 @@ public class Java2TypeScriptAdapter extends PrinterAdapter { return super.substituteVariableAccess(variableAccess); } - protected final void delegateToEmulLayer(String targetClassName, VariableAccessElement fieldAccess) { - print("javaemul.internal." + targetClassName.substring(10) + "Helper.").print(fieldAccess.getVariableName()); - } - @Override public boolean substituteNewClass(NewClassElement newClassElement) { JCNewClass newClass = ((NewClassElementSupport) newClassElement).getTree(); @@ -1647,7 +1686,7 @@ public class Java2TypeScriptAdapter extends PrinterAdapter { print(context.getLangTypeMappings().get(identifier.type.toString())); return true; } - if (identifier.type.toString().startsWith("java.lang.")) { + if (!context.useModules && identifier.type.toString().startsWith("java.lang.")) { if (("java.lang." + identifier.toString()).equals(identifier.type.toString())) { // it is a java.lang class being referenced, so we expand // its name @@ -1659,6 +1698,23 @@ public class Java2TypeScriptAdapter extends PrinterAdapter { return super.substituteIdentifier(identifierElement); } + @Override + public boolean substituteExtends(TypeElement type) { + // J4TS hack to avoid name clash between date classes (should be solved automatically) + if ("java.sql.Date".equals(type.getQualifiedName().toString())) { + String pathToImportedClass = util().getRelativePath( + "@/" + getCompilationUnit().getPackage().toString().replace('.', '/'), + ("@/" + Date.class.getName()).replace('.', '/')); + if (!pathToImportedClass.startsWith(".")) { + pathToImportedClass = "./" + pathToImportedClass; + } + useModule(new ModuleImportDescriptor("Date as java_util_Date", pathToImportedClass)); + print(" extends java_util_Date"); + return true; + } + return super.substituteExtends(type); + } + @Override public Set getErasedTypes() { return context.getLangTypeMappings().keySet(); diff --git a/transpiler/src/main/java/org/jsweet/transpiler/extension/PrinterAdapter.java b/transpiler/src/main/java/org/jsweet/transpiler/extension/PrinterAdapter.java index a84b9213..f3a68f52 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/extension/PrinterAdapter.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/extension/PrinterAdapter.java @@ -28,6 +28,7 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; @@ -35,6 +36,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Types; @@ -43,6 +45,7 @@ import org.jsweet.JSweetConfig; import org.jsweet.transpiler.JSweetContext; import org.jsweet.transpiler.JSweetOptions; import org.jsweet.transpiler.JSweetProblem; +import org.jsweet.transpiler.Java2TypeScriptTranslator; import org.jsweet.transpiler.ModuleImportDescriptor; import org.jsweet.transpiler.OverloadScanner.Overload; import org.jsweet.transpiler.model.ArrayAccessElement; @@ -836,6 +839,16 @@ public class PrinterAdapter { : parentAdapter.needsImport(importElement, qualifiedName); } + /** + * Ensures that the current file imports the given module (will have no effects when not using modules). + * + * @param moduleImport a module import descriptor + */ + public void useModule(ModuleImportDescriptor moduleImport) { + ((Java2TypeScriptTranslator)getPrinter()).useModule(moduleImport); + } + + /** * This method implements the default behavior to generate module imports. * It may be overridden by subclasses to implement specific behaviors. @@ -869,7 +882,10 @@ public class PrinterAdapter { importedClass = (ClassSymbol) importedClass.getEnclosingElement(); } - if (parent != null && !hasAnnotationType(importedClass, JSweetConfig.ANNOTATION_ERASED)) { + if (parent != null && !hasAnnotationType(importedClass, JSweetConfig.ANNOTATION_ERASED) + && !(importedClass.getKind() == ElementKind.ANNOTATION_TYPE + && !context.elementHasAnnotationType(importedClass, JSweetConfig.ANNOTATION_DECORATOR))) { + // '@' represents a common root in case there is no common // root // package => pathToImportedClass cannot be null because of