mirror of
https://github.com/cincheo/jsweet.git
synced 2025-12-14 23:09:22 +00:00
stable point in using mixins - but does not work yet for compiling J4TS
This commit is contained in:
parent
eb3579a397
commit
fc3b436a31
@ -146,6 +146,9 @@ public class GlobalBeforeTranslationScanner extends AbstractTreeScanner {
|
||||
}
|
||||
}
|
||||
if (def instanceof JCMethodDecl) {
|
||||
if(classdecl.sym.isInterface() && ((JCMethodDecl)def).sym.isDefault()) {
|
||||
context.addInterfaceWithDefaultMethods(classdecl.sym);
|
||||
}
|
||||
if (globals && ((JCMethodDecl) def).sym.isStatic()) {
|
||||
context.registerGlobalMethod(classdecl, (JCMethodDecl) def);
|
||||
} else {
|
||||
|
||||
@ -117,7 +117,30 @@ public class JSweetContext extends Context {
|
||||
}
|
||||
|
||||
private Map<String, TypeMirror> jdkSubclasses = new HashMap<>();
|
||||
|
||||
private Map<String, ClassSymbol> interfacesWithDefaultMethods = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Memorizes an interface to be declaring one or more default methods.
|
||||
*/
|
||||
public void addInterfaceWithDefaultMethods(ClassSymbol interfaceSymbol) {
|
||||
interfacesWithDefaultMethods.put(interfaceSymbol.getQualifiedName().toString(), interfaceSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an interface declares one or more default methods.
|
||||
*/
|
||||
public boolean isInterfaceWithDefaultMethods(ClassSymbol interfaceSymbol) {
|
||||
return interfacesWithDefaultMethods.values().contains(interfaceSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an interface declares one or more default methods.
|
||||
*/
|
||||
public boolean isInterfaceWithDefaultMethods(String interfaceName) {
|
||||
return interfacesWithDefaultMethods.keySet().contains(interfaceName);
|
||||
}
|
||||
|
||||
public StaticInitilializerAnalyzer referenceAnalyzer;
|
||||
|
||||
/**
|
||||
@ -934,11 +957,14 @@ public class JSweetContext extends Context {
|
||||
|
||||
private List<String> footerStatements = new LinkedList<String>();
|
||||
|
||||
private int bottomFooterIndex = 0;
|
||||
|
||||
/**
|
||||
* Clears the footer statements.
|
||||
*/
|
||||
public void clearFooterStatements() {
|
||||
footerStatements.clear();
|
||||
bottomFooterIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -958,7 +984,8 @@ public class JSweetContext extends Context {
|
||||
* Adds a footer statement.
|
||||
*/
|
||||
public void addFooterStatement(String footerStatement) {
|
||||
footerStatements.add(footerStatement);
|
||||
footerStatements.add(bottomFooterIndex, footerStatement);
|
||||
bottomFooterIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -966,8 +993,16 @@ public class JSweetContext extends Context {
|
||||
*/
|
||||
public void addTopFooterStatement(String footerStatement) {
|
||||
footerStatements.add(0, footerStatement);
|
||||
bottomFooterIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a footer statement at the bottom (after regular or top footer statements).
|
||||
*/
|
||||
public void addBottomFooterStatement(String footerStatement) {
|
||||
footerStatements.add(footerStatement);
|
||||
}
|
||||
|
||||
private Map<String, String> headers = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
|
||||
@ -304,6 +304,14 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
|
||||
private boolean interfaceScope = false;
|
||||
|
||||
private boolean isInterfaceWithDefaultMethods = false;
|
||||
|
||||
private boolean mixinScope = false;
|
||||
|
||||
private boolean interfaceForMixinTargetScope = false;
|
||||
|
||||
private boolean mixinTargetClass = false;
|
||||
|
||||
private boolean enumScope = false;
|
||||
|
||||
private boolean isComplexEnum = false;
|
||||
@ -578,6 +586,9 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
private PackageSymbol topLevelPackage;
|
||||
|
||||
public void useModule(ModuleImportDescriptor moduleImport) {
|
||||
if (moduleImport == null) {
|
||||
return;
|
||||
}
|
||||
useModule(false, moduleImport.isDirect(), moduleImport.getTargetPackage(), null, moduleImport.getImportedName(),
|
||||
moduleImport.getPathToImportedClass(), null);
|
||||
}
|
||||
@ -1362,6 +1373,14 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getMixinName(ClassSymbol type) {
|
||||
if (context.useModules) {
|
||||
return type.getSimpleName().toString();
|
||||
} else {
|
||||
return getRootRelativeName(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl classdecl) {
|
||||
if (getAdapter().substituteType(classdecl.sym)) {
|
||||
@ -1381,6 +1400,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
name = getScope().name + ANONYMOUS_PREFIX + getScope().anonymousClasses.indexOf(classdecl);
|
||||
}
|
||||
|
||||
if (scope.size() > 1 && getScope().mixinTargetClass && getScope(1).anonymousClasses.contains(classdecl)) {
|
||||
name = getScope().name;
|
||||
}
|
||||
|
||||
JCTree testParent = getFirstParent(JCClassDecl.class, JCMethodDecl.class);
|
||||
if (testParent != null && testParent instanceof JCMethodDecl) {
|
||||
if (!isLocalClass()) {
|
||||
@ -1411,6 +1434,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
getScope().removedSuperclass = false;
|
||||
getScope().enumScope = false;
|
||||
getScope().enumWrapperClassScope = false;
|
||||
getScope().mixinScope = false;
|
||||
getScope().interfaceForMixinTargetScope = scope.size() > 1 && getScope(1).mixinTargetClass;
|
||||
|
||||
if (getScope().declareClassScope) {
|
||||
if (context.hasAnnotationType(classdecl.sym, JSweetConfig.ANNOTATION_DECORATOR)) {
|
||||
@ -1450,10 +1475,19 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
report(classdecl, JSweetProblem.GLOBALS_CLASS_CANNOT_BE_SUBCLASSED);
|
||||
return;
|
||||
}
|
||||
if (!(classdecl.getKind() == Kind.ENUM && scope.size() > 1 && getScope(1).isComplexEnum)) {
|
||||
if (!(classdecl.getKind() == Kind.ENUM && scope.size() > 1 && getScope(1).isComplexEnum)
|
||||
&& !(context.isInterface(classdecl.sym) && scope.size() > 1
|
||||
&& getScope(1).isInterfaceWithDefaultMethods)) {
|
||||
printDocComment(classdecl);
|
||||
} else {
|
||||
print("/** @ignore */").println().printIndent();
|
||||
if ((context.isInterface(classdecl.sym) && scope.size() > 1
|
||||
&& getScope(1).isInterfaceWithDefaultMethods)) {
|
||||
print("/** @ignore - Mixin class generated to hold default methods for the corresponding interface */")
|
||||
.println().printIndent();
|
||||
} else {
|
||||
print("/** @ignore - Utility class generated to hold extra elements for the corresponding simple enum */")
|
||||
.println().printIndent();
|
||||
}
|
||||
}
|
||||
print(classdecl.mods);
|
||||
|
||||
@ -1462,8 +1496,13 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
print("export ");
|
||||
}
|
||||
if (context.isInterface(classdecl.sym)) {
|
||||
print("interface ");
|
||||
getScope().interfaceScope = true;
|
||||
if (scope.size() > 1 && getScope(1).isInterfaceWithDefaultMethods) {
|
||||
print("class ");
|
||||
getScope().mixinScope = true;
|
||||
} else {
|
||||
print("interface ");
|
||||
getScope().interfaceScope = true;
|
||||
}
|
||||
} else {
|
||||
if (classdecl.getKind() == Kind.ENUM) {
|
||||
if (getScope().declareClassScope && !(getIndent() != 0 && isDefinitionScope)) {
|
||||
@ -1483,12 +1522,16 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
if (getScope().declareClassScope && !(getIndent() != 0 && isDefinitionScope)) {
|
||||
print("declare ");
|
||||
}
|
||||
defaultMethods = new HashSet<>();
|
||||
Util.findDefaultMethodsInType(defaultMethods, context, classdecl.sym);
|
||||
if (classdecl.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
|
||||
print("abstract ");
|
||||
if (getScope().interfaceForMixinTargetScope) {
|
||||
print("interface ");
|
||||
} else {
|
||||
defaultMethods = new HashSet<>();
|
||||
Util.findDefaultMethodsInType(defaultMethods, context, classdecl.sym);
|
||||
if (classdecl.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
|
||||
print("abstract ");
|
||||
}
|
||||
print("class ");
|
||||
}
|
||||
print("class ");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1521,7 +1564,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
|
||||
// print EXTENDS
|
||||
boolean extendsInterface = false;
|
||||
if (classdecl.extending != null) {
|
||||
if (classdecl.extending != null && !getScope().interfaceForMixinTargetScope) {
|
||||
|
||||
boolean removeIterable = false;
|
||||
if (context.hasAnnotationType(classdecl.sym, JSweetConfig.ANNOTATION_SYNTACTIC_ITERABLE)
|
||||
@ -1582,7 +1625,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
|
||||
if (!implementing.isEmpty()) {
|
||||
if (!extendsInterface) {
|
||||
if (getScope().interfaceScope) {
|
||||
if (getScope().interfaceScope || getScope().interfaceForMixinTargetScope) {
|
||||
print(" extends ");
|
||||
} else {
|
||||
print(" implements ");
|
||||
@ -1604,293 +1647,344 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
print(" {").println().startIndent();
|
||||
}
|
||||
|
||||
getAdapter().beforeTypeBody(classdecl.sym);
|
||||
if (!getScope().interfaceForMixinTargetScope) {
|
||||
getAdapter().beforeTypeBody(classdecl.sym);
|
||||
|
||||
if (getScope().innerClassNotStatic && !getScope().interfaceScope && !getScope().enumScope
|
||||
&& !getScope().enumWrapperClassScope) {
|
||||
printIndent().print("public " + PARENT_CLASS_FIELD_NAME + ": any;").println();
|
||||
}
|
||||
if (getScope().innerClassNotStatic && !getScope().interfaceScope && !getScope().enumScope
|
||||
&& !getScope().enumWrapperClassScope) {
|
||||
printIndent().print("public " + PARENT_CLASS_FIELD_NAME + ": any;").println();
|
||||
}
|
||||
|
||||
if (defaultMethods != null && !defaultMethods.isEmpty()) {
|
||||
getScope().defaultMethodScope = true;
|
||||
for (Entry<JCClassDecl, JCMethodDecl> entry : defaultMethods) {
|
||||
if (!(entry.getValue().type instanceof MethodType)) {
|
||||
continue;
|
||||
}
|
||||
MethodSymbol s = Util.findMethodDeclarationInType(context.types, classdecl.sym,
|
||||
entry.getValue().getName().toString(), (MethodType) entry.getValue().type);
|
||||
if (s == null || s == entry.getValue().sym) {
|
||||
getAdapter().typeVariablesToErase
|
||||
.addAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters());
|
||||
// scan for used types to generate imports
|
||||
if (context.useModules) {
|
||||
UsedTypesScanner scanner = new UsedTypesScanner();
|
||||
JCMethodDecl method = entry.getValue();
|
||||
if (!context.hasAnnotationType(method.sym, JSweetConfig.ANNOTATION_ERASED)) {
|
||||
if (context.hasAnnotationType(method.sym, JSweetConfig.ANNOTATION_REPLACE)) {
|
||||
// do not scan the method body
|
||||
scanner.scan(method.params);
|
||||
scanner.scan(method.restype);
|
||||
scanner.scan(method.thrown);
|
||||
scanner.scan(method.typarams);
|
||||
scanner.scan(method.recvparam);
|
||||
} else {
|
||||
scanner.scan(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
printIndent().print(entry.getValue()).println();
|
||||
getAdapter().typeVariablesToErase
|
||||
.removeAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters());
|
||||
}
|
||||
}
|
||||
getScope().defaultMethodScope = false;
|
||||
}
|
||||
/*
|
||||
* if (defaultMethods != null && !defaultMethods.isEmpty()) {
|
||||
* getScope().defaultMethodScope = true; for (Entry<JCClassDecl,
|
||||
* JCMethodDecl> entry : defaultMethods) { if
|
||||
* (!(entry.getValue().type instanceof MethodType)) { continue; }
|
||||
* MethodSymbol s = Util.findMethodDeclarationInType(context.types,
|
||||
* classdecl.sym, entry.getValue().getName().toString(),
|
||||
* (MethodType) entry.getValue().type); if (s == null || s ==
|
||||
* entry.getValue().sym) { getAdapter().typeVariablesToErase
|
||||
* .addAll(((ClassSymbol)
|
||||
* s.getEnclosingElement()).getTypeParameters()); // scan for used
|
||||
* types to generate imports if (context.useModules) {
|
||||
* UsedTypesScanner scanner = new UsedTypesScanner(); JCMethodDecl
|
||||
* method = entry.getValue(); if
|
||||
* (!context.hasAnnotationType(method.sym,
|
||||
* JSweetConfig.ANNOTATION_ERASED)) { if
|
||||
* (context.hasAnnotationType(method.sym,
|
||||
* JSweetConfig.ANNOTATION_REPLACE)) { // do not scan the method
|
||||
* body scanner.scan(method.params); scanner.scan(method.restype);
|
||||
* scanner.scan(method.thrown); scanner.scan(method.typarams);
|
||||
* scanner.scan(method.recvparam); } else { scanner.scan(method); }
|
||||
* } } printIndent().print(entry.getValue()).println();
|
||||
* getAdapter().typeVariablesToErase .removeAll(((ClassSymbol)
|
||||
* s.getEnclosingElement()).getTypeParameters()); } }
|
||||
* getScope().defaultMethodScope = false; }
|
||||
*/
|
||||
|
||||
if (getScope().enumScope) {
|
||||
printIndent();
|
||||
}
|
||||
if (globals) {
|
||||
removeLastIndent();
|
||||
}
|
||||
|
||||
for (JCTree def : classdecl.defs) {
|
||||
if (def instanceof JCClassDecl) {
|
||||
getScope().hasInnerClass = true;
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
JCVariableDecl var = (JCVariableDecl) def;
|
||||
if (!var.sym.isStatic() && var.init != null) {
|
||||
getScope().fieldsWithInitializers.add((JCVariableDecl) def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!globals && !getScope().enumScope && !context.isInterface(classdecl.sym)
|
||||
&& context.getStaticInitializerCount(classdecl.sym) > 0) {
|
||||
printIndent().print("static __static_initialized : boolean = false;").println();
|
||||
int liCount = context.getStaticInitializerCount(classdecl.sym);
|
||||
String prefix = getClassName(classdecl.sym) + ".";
|
||||
printIndent().print("static __static_initialize() { ");
|
||||
print("if(!" + prefix + "__static_initialized) { ");
|
||||
print(prefix + "__static_initialized = true; ");
|
||||
for (int i = 0; i < liCount; i++) {
|
||||
print(prefix + "__static_initializer_" + i + "(); ");
|
||||
}
|
||||
print("} }").println().println();
|
||||
String qualifiedClassName = getQualifiedTypeName(classdecl.sym, globals, true);
|
||||
context.addTopFooterStatement(
|
||||
(isBlank(qualifiedClassName) ? "" : qualifiedClassName + ".__static_initialize();"));
|
||||
}
|
||||
|
||||
boolean hasUninitializedFields = false;
|
||||
|
||||
for (JCTree def : classdecl.defs) {
|
||||
if (getScope().interfaceScope && ((def instanceof JCMethodDecl && ((JCMethodDecl) def).sym.isStatic())
|
||||
|| (def instanceof JCVariableDecl && ((JCVariableDecl) def).sym.isStatic()))) {
|
||||
// static interface members are printed in a namespace
|
||||
continue;
|
||||
}
|
||||
if (getScope().interfaceScope && def instanceof JCMethodDecl) {
|
||||
// object method should not be defined otherwise they will have
|
||||
// to be implemented
|
||||
if (Util.isOverridingBuiltInJavaObjectMethod(((JCMethodDecl) def).sym)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (def instanceof JCClassDecl) {
|
||||
// inner types are be printed in a namespace
|
||||
continue;
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
if (getScope().enumScope && ((JCVariableDecl) def).sym.getKind() != ElementKind.ENUM_CONSTANT) {
|
||||
getScope().isComplexEnum = true;
|
||||
continue;
|
||||
}
|
||||
if (!((JCVariableDecl) def).getModifiers().getFlags().contains(Modifier.STATIC)
|
||||
&& ((JCVariableDecl) def).init == null) {
|
||||
hasUninitializedFields = true;
|
||||
}
|
||||
}
|
||||
if (def instanceof JCBlock && !((JCBlock) def).isStatic()) {
|
||||
hasUninitializedFields = true;
|
||||
}
|
||||
if (!getScope().enumScope) {
|
||||
if (getScope().enumScope) {
|
||||
printIndent();
|
||||
}
|
||||
int pos = getCurrentPosition();
|
||||
print(def);
|
||||
if (getCurrentPosition() == pos) {
|
||||
if (!getScope().enumScope) {
|
||||
removeLastIndent();
|
||||
}
|
||||
continue;
|
||||
if (globals) {
|
||||
removeLastIndent();
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
if (getScope().enumScope) {
|
||||
print(", ");
|
||||
} else {
|
||||
print(";").println().println();
|
||||
}
|
||||
} else {
|
||||
println().println();
|
||||
}
|
||||
}
|
||||
|
||||
// generate missing abstract methods if abstract class
|
||||
if (!getScope().interfaceScope && classdecl.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
|
||||
List<MethodSymbol> methods = new ArrayList<>();
|
||||
for (Type t : implementedInterfaces) {
|
||||
context.grabMethodsToBeImplemented(methods, t.tsym);
|
||||
for (JCTree def : classdecl.defs) {
|
||||
if (def instanceof JCClassDecl) {
|
||||
getScope().hasInnerClass = true;
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
JCVariableDecl var = (JCVariableDecl) def;
|
||||
if (!var.sym.isStatic() && var.init != null) {
|
||||
getScope().fieldsWithInitializers.add((JCVariableDecl) def);
|
||||
}
|
||||
}
|
||||
}
|
||||
methods.sort((m1, m2) -> m1.getSimpleName().compareTo(m2.getSimpleName()));
|
||||
Map<Name, String> signatures = new HashMap<>();
|
||||
for (MethodSymbol meth : methods) {
|
||||
if (meth.type instanceof MethodType && !context.hasAnnotationType(meth, JSweetConfig.ANNOTATION_ERASED)
|
||||
&& !isMappedOrErasedType(meth.owner)) {
|
||||
// do not generate default abstract method for already
|
||||
// generated methods
|
||||
if (getScope().generatedMethodNames.contains(meth.name.toString())) {
|
||||
|
||||
if (!globals && !getScope().enumScope && !context.isInterface(classdecl.sym)
|
||||
&& context.getStaticInitializerCount(classdecl.sym) > 0) {
|
||||
printIndent().print("static __static_initialized : boolean = false;").println();
|
||||
int liCount = context.getStaticInitializerCount(classdecl.sym);
|
||||
String prefix = getClassName(classdecl.sym) + ".";
|
||||
printIndent().print("static __static_initialize() { ");
|
||||
print("if(!" + prefix + "__static_initialized) { ");
|
||||
print(prefix + "__static_initialized = true; ");
|
||||
for (int i = 0; i < liCount; i++) {
|
||||
print(prefix + "__static_initializer_" + i + "(); ");
|
||||
}
|
||||
print("} }").println().println();
|
||||
String qualifiedClassName = getQualifiedTypeName(classdecl.sym, globals, true);
|
||||
context.addTopFooterStatement(
|
||||
(isBlank(qualifiedClassName) ? "" : qualifiedClassName + ".__static_initialize();"));
|
||||
}
|
||||
|
||||
boolean hasUninitializedFields = false;
|
||||
|
||||
for (JCTree def : classdecl.defs) {
|
||||
if (getScope().interfaceScope && ((def instanceof JCMethodDecl && ((JCMethodDecl) def).sym.isStatic())
|
||||
|| (def instanceof JCVariableDecl && ((JCVariableDecl) def).sym.isStatic()))) {
|
||||
// static interface members are printed in a namespace
|
||||
continue;
|
||||
}
|
||||
if (getScope().interfaceScope && def instanceof JCMethodDecl) {
|
||||
// object method should not be defined otherwise they will
|
||||
// have
|
||||
// to be implemented
|
||||
if (Util.isOverridingBuiltInJavaObjectMethod(((JCMethodDecl) def).sym)) {
|
||||
continue;
|
||||
}
|
||||
MethodSymbol s = Util.findMethodDeclarationInType(getContext().types, classdecl.sym,
|
||||
meth.getSimpleName().toString(), (MethodType) meth.type, true);
|
||||
if (Object.class.getName().equals(s.getEnclosingElement().toString())) {
|
||||
s = null;
|
||||
}
|
||||
if (def instanceof JCClassDecl) {
|
||||
// inner types are be printed in a namespace
|
||||
continue;
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
if (getScope().enumScope && ((JCVariableDecl) def).sym.getKind() != ElementKind.ENUM_CONSTANT) {
|
||||
getScope().isComplexEnum = true;
|
||||
continue;
|
||||
}
|
||||
boolean printAbstractDeclaration = false;
|
||||
if (s != null) {
|
||||
if (!s.getEnclosingElement().equals(classdecl.sym)) {
|
||||
if (!(s.isDefault() || (!context.isInterface((TypeSymbol) s.getEnclosingElement())
|
||||
&& !s.getModifiers().contains(Modifier.ABSTRACT)))) {
|
||||
printAbstractDeclaration = true;
|
||||
}
|
||||
}
|
||||
if (!((JCVariableDecl) def).getModifiers().getFlags().contains(Modifier.STATIC)
|
||||
&& ((JCVariableDecl) def).init == null) {
|
||||
hasUninitializedFields = true;
|
||||
}
|
||||
}
|
||||
if (def instanceof JCBlock && !((JCBlock) def).isStatic()) {
|
||||
hasUninitializedFields = true;
|
||||
}
|
||||
if (!getScope().enumScope) {
|
||||
printIndent();
|
||||
}
|
||||
int pos = getCurrentPosition();
|
||||
print(def);
|
||||
if (getCurrentPosition() == pos) {
|
||||
if (!getScope().enumScope) {
|
||||
removeLastIndent();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (def instanceof JCVariableDecl) {
|
||||
if (getScope().enumScope) {
|
||||
print(", ");
|
||||
} else {
|
||||
print(";").println().println();
|
||||
}
|
||||
} else {
|
||||
println().println();
|
||||
}
|
||||
}
|
||||
|
||||
if (printAbstractDeclaration) {
|
||||
Overload o = context.getOverload(classdecl.sym, meth);
|
||||
if (o != null && o.methods.size() > 1 && !o.isValid) {
|
||||
if (!meth.type.equals(o.coreMethod.type)) {
|
||||
printAbstractDeclaration = false;
|
||||
// generate missing abstract methods if abstract class
|
||||
if (!getScope().interfaceScope && classdecl.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
|
||||
List<MethodSymbol> methods = new ArrayList<>();
|
||||
for (Type t : implementedInterfaces) {
|
||||
context.grabMethodsToBeImplemented(methods, t.tsym);
|
||||
}
|
||||
methods.sort((m1, m2) -> m1.getSimpleName().compareTo(m2.getSimpleName()));
|
||||
Map<Name, String> signatures = new HashMap<>();
|
||||
for (MethodSymbol meth : methods) {
|
||||
if (meth.type instanceof MethodType
|
||||
&& !context.hasAnnotationType(meth, JSweetConfig.ANNOTATION_ERASED)
|
||||
&& !isMappedOrErasedType(meth.owner)) {
|
||||
// do not generate default abstract method for already
|
||||
// generated methods
|
||||
if (getScope().generatedMethodNames.contains(meth.name.toString())) {
|
||||
continue;
|
||||
}
|
||||
MethodSymbol s = Util.findMethodDeclarationInType(getContext().types, classdecl.sym,
|
||||
meth.getSimpleName().toString(), (MethodType) meth.type, true);
|
||||
if (Object.class.getName().equals(s.getEnclosingElement().toString())) {
|
||||
s = null;
|
||||
}
|
||||
boolean printAbstractDeclaration = false;
|
||||
if (s != null) {
|
||||
if (!s.getEnclosingElement().equals(classdecl.sym)) {
|
||||
if (!(s.isDefault() || (!context.isInterface((TypeSymbol) s.getEnclosingElement())
|
||||
&& !s.getModifiers().contains(Modifier.ABSTRACT)))) {
|
||||
printAbstractDeclaration = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s == null || printAbstractDeclaration) {
|
||||
String signature = getContext().types.erasure(meth.type).toString();
|
||||
if (!(signatures.containsKey(meth.name) && signatures.get(meth.name).equals(signature))) {
|
||||
printAbstractMethodDeclaration(meth);
|
||||
signatures.put(meth.name, signature);
|
||||
|
||||
if (printAbstractDeclaration) {
|
||||
Overload o = context.getOverload(classdecl.sym, meth);
|
||||
if (o != null && o.methods.size() > 1 && !o.isValid) {
|
||||
if (!meth.type.equals(o.coreMethod.type)) {
|
||||
printAbstractDeclaration = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s == null || printAbstractDeclaration) {
|
||||
String signature = getContext().types.erasure(meth.type).toString();
|
||||
if (!(signatures.containsKey(meth.name) && signatures.get(meth.name).equals(signature))) {
|
||||
printAbstractMethodDeclaration(meth);
|
||||
signatures.put(meth.name, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!getScope().hasDeclaredConstructor
|
||||
&& !(getScope().interfaceScope || getScope().enumScope || getScope().declareClassScope)) {
|
||||
Set<String> interfaces = new HashSet<>();
|
||||
context.grabSupportedInterfaceNames(interfaces, classdecl.sym);
|
||||
if (!interfaces.isEmpty() || getScope().innerClass || getScope().innerClassNotStatic
|
||||
|| hasUninitializedFields) {
|
||||
printIndent().print("constructor(");
|
||||
boolean hasArgs = false;
|
||||
if (getScope().innerClassNotStatic) {
|
||||
print(PARENT_CLASS_FIELD_NAME + ": any");
|
||||
hasArgs = true;
|
||||
}
|
||||
int anonymousClassIndex = scope.size() > 1 ? getScope(1).anonymousClasses.indexOf(classdecl) : -1;
|
||||
if (anonymousClassIndex != -1) {
|
||||
for (int i = 0; i < getScope(1).anonymousClassesConstructors.get(anonymousClassIndex).args
|
||||
.length(); i++) {
|
||||
if (!hasArgs) {
|
||||
hasArgs = true;
|
||||
} else {
|
||||
print(", ");
|
||||
}
|
||||
print("__arg" + i + ": any");
|
||||
}
|
||||
for (VarSymbol v : getScope(1).finalVariables.get(anonymousClassIndex)) {
|
||||
if (!hasArgs) {
|
||||
hasArgs = true;
|
||||
} else {
|
||||
print(", ");
|
||||
}
|
||||
print("private " + v.getSimpleName() + ": any");
|
||||
}
|
||||
}
|
||||
|
||||
print(") {").startIndent().println();
|
||||
if (classdecl.extending != null && !getScope().removedSuperclass
|
||||
&& !context.isInterface(classdecl.extending.type.tsym)) {
|
||||
printIndent().print("super(");
|
||||
boolean hasArg = false;
|
||||
if (!getScope().hasDeclaredConstructor
|
||||
&& !(getScope().interfaceScope || getScope().enumScope || getScope().declareClassScope)) {
|
||||
Set<String> interfaces = new HashSet<>();
|
||||
context.grabSupportedInterfaceNames(interfaces, classdecl.sym);
|
||||
if (!interfaces.isEmpty() || getScope().innerClass || getScope().innerClassNotStatic
|
||||
|| hasUninitializedFields) {
|
||||
printIndent().print("constructor(");
|
||||
boolean hasArgs = false;
|
||||
if (getScope().innerClassNotStatic) {
|
||||
TypeSymbol s = classdecl.extending.type.tsym;
|
||||
if (s.getEnclosingElement() instanceof ClassSymbol && !s.isStatic()) {
|
||||
print(PARENT_CLASS_FIELD_NAME);
|
||||
hasArg = true;
|
||||
}
|
||||
print(PARENT_CLASS_FIELD_NAME + ": any");
|
||||
hasArgs = true;
|
||||
}
|
||||
int anonymousClassIndex = scope.size() > 1 ? getScope(1).anonymousClasses.indexOf(classdecl) : -1;
|
||||
if (anonymousClassIndex != -1) {
|
||||
for (int i = 0; i < getScope(1).anonymousClassesConstructors.get(anonymousClassIndex).args
|
||||
.length(); i++) {
|
||||
if (hasArg) {
|
||||
print(", ");
|
||||
if (!hasArgs) {
|
||||
hasArgs = true;
|
||||
} else {
|
||||
hasArg = true;
|
||||
print(", ");
|
||||
}
|
||||
print("__arg" + i);
|
||||
print("__arg" + i + ": any");
|
||||
}
|
||||
for (VarSymbol v : getScope(1).finalVariables.get(anonymousClassIndex)) {
|
||||
if (!hasArgs) {
|
||||
hasArgs = true;
|
||||
} else {
|
||||
print(", ");
|
||||
}
|
||||
print("private " + v.getSimpleName() + ": any");
|
||||
}
|
||||
}
|
||||
print(");").println();
|
||||
}
|
||||
printInstanceInitialization(classdecl, null);
|
||||
endIndent().printIndent().print("}").println().println();
|
||||
}
|
||||
}
|
||||
|
||||
removeLastChar();
|
||||
|
||||
if (getScope().enumWrapperClassScope && !getScope(1).anonymousClasses.contains(classdecl)) {
|
||||
printIndent().print("public name() : string { return this." + ENUM_WRAPPER_CLASS_NAME + "; }").println();
|
||||
printIndent().print("public ordinal() : number { return this." + ENUM_WRAPPER_CLASS_ORDINAL + "; }")
|
||||
.println();
|
||||
printIndent().print("public compareTo(other : any) : number { return this." + ENUM_WRAPPER_CLASS_ORDINAL
|
||||
+ " - (isNaN(other)?other." + ENUM_WRAPPER_CLASS_ORDINAL + ":other); }").println();
|
||||
}
|
||||
|
||||
if (getScope().enumScope) {
|
||||
removeLastChar().println();
|
||||
}
|
||||
|
||||
if (!globals) {
|
||||
endIndent().printIndent().print("}");
|
||||
if (!getScope().interfaceScope && !getScope().declareClassScope && !getScope().enumScope
|
||||
&& !(getScope().enumWrapperClassScope && classdecl.sym.isAnonymous())) {
|
||||
if (!classdecl.sym.isAnonymous()) {
|
||||
println().printIndent()
|
||||
.print(getScope().enumWrapperClassScope ? classdecl.sym.getSimpleName().toString() : name)
|
||||
.print("[\"" + CLASS_NAME_IN_CONSTRUCTOR + "\"] = ")
|
||||
.print("\"" + classdecl.sym.getQualifiedName().toString() + "\";");
|
||||
}
|
||||
Set<String> interfaces = new HashSet<>();
|
||||
context.grabSupportedInterfaceNames(interfaces, classdecl.sym);
|
||||
if (!interfaces.isEmpty()) {
|
||||
println().printIndent()
|
||||
.print(getScope().enumWrapperClassScope ? classdecl.sym.getSimpleName().toString() : name)
|
||||
.print("[\"" + INTERFACES_FIELD_NAME + "\"] = ");
|
||||
print("[");
|
||||
for (String itf : interfaces) {
|
||||
print("\"").print(itf).print("\",");
|
||||
print(") {").startIndent().println();
|
||||
if (classdecl.extending != null && !getScope().removedSuperclass
|
||||
&& !context.isInterface(classdecl.extending.type.tsym)) {
|
||||
printIndent().print("super(");
|
||||
boolean hasArg = false;
|
||||
if (getScope().innerClassNotStatic) {
|
||||
TypeSymbol s = classdecl.extending.type.tsym;
|
||||
if (s.getEnclosingElement() instanceof ClassSymbol && !s.isStatic()) {
|
||||
print(PARENT_CLASS_FIELD_NAME);
|
||||
hasArg = true;
|
||||
}
|
||||
}
|
||||
if (anonymousClassIndex != -1) {
|
||||
for (int i = 0; i < getScope(1).anonymousClassesConstructors.get(anonymousClassIndex).args
|
||||
.length(); i++) {
|
||||
if (hasArg) {
|
||||
print(", ");
|
||||
} else {
|
||||
hasArg = true;
|
||||
}
|
||||
print("__arg" + i);
|
||||
}
|
||||
}
|
||||
print(");").println();
|
||||
}
|
||||
removeLastChar();
|
||||
print("];").println();
|
||||
}
|
||||
if (!getScope().enumWrapperClassScope) {
|
||||
println();
|
||||
printInstanceInitialization(classdecl, null);
|
||||
endIndent().printIndent().print("}").println().println();
|
||||
}
|
||||
}
|
||||
|
||||
removeLastChar();
|
||||
|
||||
if (getScope().enumWrapperClassScope && !getScope(1).anonymousClasses.contains(classdecl)) {
|
||||
printIndent().print("public name() : string { return this." + ENUM_WRAPPER_CLASS_NAME + "; }")
|
||||
.println();
|
||||
printIndent().print("public ordinal() : number { return this." + ENUM_WRAPPER_CLASS_ORDINAL + "; }")
|
||||
.println();
|
||||
printIndent().print("public compareTo(other : any) : number { return this." + ENUM_WRAPPER_CLASS_ORDINAL
|
||||
+ " - (isNaN(other)?other." + ENUM_WRAPPER_CLASS_ORDINAL + ":other); }").println();
|
||||
}
|
||||
|
||||
if (getScope().enumScope) {
|
||||
removeLastChar().println();
|
||||
}
|
||||
|
||||
if (!globals) {
|
||||
endIndent().printIndent().print("}");
|
||||
if (!getScope().interfaceScope && !getScope().declareClassScope && !getScope().enumScope
|
||||
&& !(getScope().enumWrapperClassScope && classdecl.sym.isAnonymous())
|
||||
&& !getScope().mixinScope) {
|
||||
if (!classdecl.sym.isAnonymous()) {
|
||||
println().printIndent()
|
||||
.print(getScope().enumWrapperClassScope ? classdecl.sym.getSimpleName().toString()
|
||||
: name)
|
||||
.print("[\"" + CLASS_NAME_IN_CONSTRUCTOR + "\"] = ")
|
||||
.print("\"" + classdecl.sym.getQualifiedName().toString() + "\";");
|
||||
}
|
||||
Set<String> interfaces = new HashSet<>();
|
||||
context.grabSupportedInterfaceNames(interfaces, classdecl.sym);
|
||||
if (!interfaces.isEmpty()) {
|
||||
println()
|
||||
.printIndent().print(getScope().enumWrapperClassScope
|
||||
? classdecl.sym.getSimpleName().toString() : name)
|
||||
.print("[\"" + INTERFACES_FIELD_NAME + "\"] = ");
|
||||
print("[");
|
||||
for (String itf : interfaces) {
|
||||
print("\"").print(itf).print("\",");
|
||||
}
|
||||
removeLastChar();
|
||||
print("];").println();
|
||||
}
|
||||
if (!getScope().enumWrapperClassScope) {
|
||||
println();
|
||||
}
|
||||
}
|
||||
List<ClassSymbol> mixins = new ArrayList<>();
|
||||
for (Type t : implementedInterfaces) {
|
||||
if (context.isInterfaceWithDefaultMethods(t.tsym.getQualifiedName().toString())) {
|
||||
mixins.add((ClassSymbol) t.tsym);
|
||||
}
|
||||
}
|
||||
List<ClassSymbol> allMixins = new ArrayList<>();
|
||||
Util.findInterfacesWithDefaultMethods(allMixins, context, mixins);
|
||||
if (!mixins.isEmpty() && !getScope().interfaceScope) {
|
||||
getScope().mixinTargetClass = true;
|
||||
println().printIndent().print("// class mixins (coming from Java interfaces with default methods)");
|
||||
println().printIndent();
|
||||
visitClassDef(classdecl);
|
||||
// println().printIndent().print("// class mixins (coming
|
||||
// from
|
||||
// Java interfaces with default methods)");
|
||||
// println().printIndent().print("export interface " + name
|
||||
// + "
|
||||
// extends "
|
||||
// + mixins.stream().map(t ->
|
||||
// getMixinName(t)).collect(Collectors.joining(",")) + "
|
||||
// {}");
|
||||
for (ClassSymbol mixin : allMixins) {
|
||||
useModule(getAdapter().getModuleImportDescriptor(
|
||||
new CompilationUnitElementSupport(compilationUnit), getMixinName(mixin), mixin));
|
||||
}
|
||||
context.addFooterStatement("// apply mixins (i.e. interfaces with default methods) to class");
|
||||
String targetName = null;
|
||||
if (classdecl.name.toString().isEmpty()) {
|
||||
// anonymous class case
|
||||
Symbol owner = classdecl.sym.owner;
|
||||
while (!(owner instanceof TypeSymbol)) {
|
||||
owner = owner.owner;
|
||||
}
|
||||
targetName = getRootRelativeName(owner) + "." + name;
|
||||
} else {
|
||||
targetName = getRootRelativeName(classdecl.sym);
|
||||
}
|
||||
// t = target class; ml = mixin classes list
|
||||
context.addFooterStatement(
|
||||
"((t: any, ml: any[]) => { ml.forEach(m => { Object.getOwnPropertyNames(m.prototype).forEach(name => { if(!Object.getOwnPropertyDescriptor(t.prototype, name)) Object.defineProperty(t.prototype, name, Object.getOwnPropertyDescriptor(m.prototype, name)); }); }); })"
|
||||
+ "(" + targetName + ", ["
|
||||
+ allMixins.stream().map(t -> getMixinName(t)).collect(Collectors.joining(","))
|
||||
+ "]);");
|
||||
context.addFooterStatement("// end apply mixins");
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
// end of getScope().interfaceForMixinTargetScope
|
||||
endIndent().printIndent().print("}");
|
||||
exitScope();
|
||||
return;
|
||||
}
|
||||
|
||||
// enum class for complex enum
|
||||
@ -1899,6 +1993,12 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
visitClassDef(classdecl);
|
||||
}
|
||||
|
||||
// mixin class for interfaces with default methods
|
||||
if (getScope().isInterfaceWithDefaultMethods) {
|
||||
println().println().printIndent();
|
||||
visitClassDef(classdecl);
|
||||
}
|
||||
|
||||
boolean nameSpace = false;
|
||||
|
||||
if (getScope().interfaceScope) {
|
||||
@ -2042,7 +2142,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
mainMethodQualifier = mainClassName + ".";
|
||||
}
|
||||
context.entryFiles.add(new File(compilationUnit.sourcefile.getName()));
|
||||
context.addFooterStatement(mainMethodQualifier + JSweetConfig.MAIN_FUNCTION_NAME + "("
|
||||
context.addBottomFooterStatement(mainMethodQualifier + JSweetConfig.MAIN_FUNCTION_NAME + "("
|
||||
+ (getScope().mainMethod.getParameters().isEmpty() ? "" : "null") + ");");
|
||||
}
|
||||
|
||||
@ -2112,6 +2212,16 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getScope().mixinScope && (methodDecl.body == null || methodDecl.sym.isStatic())) {
|
||||
// non-default methods are not required in mixins and static methods
|
||||
// should be in namespaces
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getScope().mixinScope && !getScope().defaultMethodScope && methodDecl.sym.isDefault()) {
|
||||
getScope().isInterfaceWithDefaultMethods = true;
|
||||
}
|
||||
|
||||
JCClassDecl parent = (JCClassDecl) getParent();
|
||||
|
||||
if (parent != null && methodDecl.pos == parent.pos && !getScope().enumWrapperClassScope) {
|
||||
@ -2163,7 +2273,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
if (!printCoreMethodDelegate) {
|
||||
if (overload.coreMethod.equals(methodDecl)) {
|
||||
inCoreWrongOverload = true;
|
||||
if (!isInterfaceMethod(parent, methodDecl) && !methodDecl.sym.isConstructor()
|
||||
if ((!(isInterfaceMethod(parent, methodDecl) && !getScope().mixinScope))
|
||||
&& !methodDecl.sym.isConstructor()
|
||||
&& parent.sym.equals(overload.coreMethod.sym.getEnclosingElement())) {
|
||||
printCoreMethodDelegate = true;
|
||||
visitMethodDef(overload.coreMethod);
|
||||
@ -2193,7 +2304,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
println().println().printIndent();
|
||||
}
|
||||
}
|
||||
if (isInterfaceMethod(parent, methodDecl)) {
|
||||
if (isInterfaceMethod(parent, methodDecl) && !getScope().mixinScope) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2389,12 +2500,12 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
printMethodArgs(methodDecl, overload, inOverload, inCoreWrongOverload, getScope());
|
||||
print(")");
|
||||
printMethodReturnDeclaration(methodDecl, inCoreWrongOverload);
|
||||
if (inCoreWrongOverload && isInterfaceMethod(parent, methodDecl)) {
|
||||
if (inCoreWrongOverload && isInterfaceMethod(parent, methodDecl) && !getScope().mixinScope) {
|
||||
print(";");
|
||||
return;
|
||||
}
|
||||
if (methodDecl.getBody() == null && !(inCoreWrongOverload && !getScope().declareClassScope)
|
||||
|| (methodDecl.mods.getFlags().contains(Modifier.DEFAULT) && !getScope().defaultMethodScope)) {
|
||||
|| (methodDecl.sym.isDefault() && !getScope().defaultMethodScope && !getScope().mixinScope)) {
|
||||
if (!getScope().interfaceScope && methodDecl.getModifiers().getFlags().contains(Modifier.ABSTRACT)
|
||||
&& inOverload && !overload.isValid) {
|
||||
print(" {");
|
||||
@ -2487,6 +2598,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
if (!Util.isParent(parent.sym, (ClassSymbol) method.sym.getEnclosingElement())) {
|
||||
continue;
|
||||
}
|
||||
if (getScope().mixinScope && parent.sym != method.sym.getEnclosingElement() && context
|
||||
.getOverload((ClassSymbol) method.sym.getEnclosingElement(), method.sym).coreMethod == method) {
|
||||
continue;
|
||||
}
|
||||
if (wasPrinted) {
|
||||
print(" else ");
|
||||
}
|
||||
@ -2495,7 +2610,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
printMethodParamsTest(overload, method);
|
||||
print(") ");
|
||||
if (method.sym.isConstructor()
|
||||
|| (method.sym.getModifiers().contains(Modifier.DEFAULT) && method.equals(overload.coreMethod))) {
|
||||
/*
|
||||
* || (method.sym.getModifiers().contains(Modifier.DEFAULT) &&
|
||||
* method.equals(overload.coreMethod))
|
||||
*/) {
|
||||
printInlinedMethod(overload, method, methodDecl.getParameters());
|
||||
} else {
|
||||
if (parent.sym != method.sym.getEnclosingElement() && context
|
||||
@ -3124,6 +3242,11 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getScope().mixinScope && varDecl.sym.isStatic()) {
|
||||
// static fields are defined in namespace
|
||||
return;
|
||||
}
|
||||
|
||||
if (getScope().enumScope) {
|
||||
// we print the doc comment for information, but
|
||||
// TypeScript-generated cannot be recognized by JSDoc... so this
|
||||
@ -3729,8 +3852,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
if (parent != null) {
|
||||
while (getScope(level++).innerClass) {
|
||||
parent = getParent(JCClassDecl.class, parent);
|
||||
if ((method = Util.findMethodDeclarationInType(context.types, parent.sym, methName,
|
||||
type)) != null) {
|
||||
if (parent == null || (method = Util.findMethodDeclarationInType(context.types,
|
||||
parent.sym, methName, type)) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -4494,7 +4617,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
Symbol s = newClass.constructor;
|
||||
if (!(s instanceof MethodSymbol)) {
|
||||
// not in source path
|
||||
print("null/*cannot resolve "+newClass.clazz+"*/");
|
||||
print("null/*cannot resolve " + newClass.clazz + "*/");
|
||||
return;
|
||||
}
|
||||
MethodSymbol methSym = (MethodSymbol) newClass.constructor;
|
||||
@ -4543,7 +4666,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
|
||||
print("(").printConstructorArgList(newClass, false).print(")");
|
||||
} else {
|
||||
if (newClass.constructorType instanceof ErrorType) {
|
||||
print("null/*cannot resolve constructor type "+newClass.clazz+"*/");
|
||||
print("null/*cannot resolve constructor type " + newClass.clazz + "*/");
|
||||
return;
|
||||
} else {
|
||||
print("new ");
|
||||
|
||||
@ -806,16 +806,18 @@ public class PrinterAdapter {
|
||||
while (importedClass.getEnclosingElement() instanceof ClassSymbol) {
|
||||
importedClass = (ClassSymbol) importedClass.getEnclosingElement();
|
||||
}
|
||||
|
||||
|
||||
if (parent != null && !hasAnnotationType(importedClass, JSweetConfig.ANNOTATION_ERASED)) {
|
||||
// '@' represents a common root in case there is no common
|
||||
// root
|
||||
// package => pathToImportedClass cannot be null because of
|
||||
// the
|
||||
// common '@' root
|
||||
String importedModuleName = importedModule.substring(0, importedModule.length() - 5);
|
||||
importedModuleName = importedModuleName.substring(importedModule.lastIndexOf("/"));
|
||||
String pathToImportedClass = util().getRelativePath(
|
||||
"@/" + currentCompilationUnit.getPackage().toString().replace('.', '/'),
|
||||
"@/" + importedClass.toString().replace('.', '/'));
|
||||
"@/" + (parent.toString()+"."+importedModuleName).replace('.', '/'));
|
||||
if (!pathToImportedClass.startsWith(".")) {
|
||||
pathToImportedClass = "./" + pathToImportedClass;
|
||||
}
|
||||
|
||||
@ -160,8 +160,10 @@ public class Util {
|
||||
* Gets the tree that corresponds to the given element (this is a slow
|
||||
* implementation - do not use intensively).
|
||||
*
|
||||
* @param context the transpiler's context
|
||||
* @param element the element to lookup
|
||||
* @param context
|
||||
* the transpiler's context
|
||||
* @param element
|
||||
* the element to lookup
|
||||
* @return the javac AST that corresponds to that element
|
||||
*/
|
||||
public static JCTree lookupTree(JSweetContext context, Element element) {
|
||||
@ -224,9 +226,12 @@ public class Util {
|
||||
/**
|
||||
* Recursively adds files to the given list.
|
||||
*
|
||||
* @param extension the extension to filter with
|
||||
* @param file the root file/directory to look into recursively
|
||||
* @param files the list to add the files matching the extension
|
||||
* @param extension
|
||||
* the extension to filter with
|
||||
* @param file
|
||||
* the root file/directory to look into recursively
|
||||
* @param files
|
||||
* the list to add the files matching the extension
|
||||
*/
|
||||
public static void addFiles(String extension, File file, Collection<File> files) {
|
||||
addFiles(f -> f.getName().endsWith(extension), file, files);
|
||||
@ -235,10 +240,13 @@ public class Util {
|
||||
/**
|
||||
* Recursively adds files to the given list.
|
||||
*
|
||||
* @param filter the filter predicate to apply (only files matching the
|
||||
* predicate will be added)
|
||||
* @param file the root file/directory to look into recursively
|
||||
* @param files the list to add the files matching the extension
|
||||
* @param filter
|
||||
* the filter predicate to apply (only files matching the
|
||||
* predicate will be added)
|
||||
* @param file
|
||||
* the root file/directory to look into recursively
|
||||
* @param files
|
||||
* the list to add the files matching the extension
|
||||
*/
|
||||
public static void addFiles(Predicate<File> filter, File file, Collection<File> files) {
|
||||
if (file.isDirectory()) {
|
||||
@ -371,8 +379,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the given map with all the variables beeing accessed within the given
|
||||
* code tree.
|
||||
* Fills the given map with all the variables beeing accessed within the
|
||||
* given code tree.
|
||||
*/
|
||||
public static void fillAllVariableAccesses(final Map<String, VarSymbol> vars, final JCTree tree) {
|
||||
new TreeScanner() {
|
||||
@ -393,7 +401,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the method declaration within the given type, for the given invocation.
|
||||
* Finds the method declaration within the given type, for the given
|
||||
* invocation.
|
||||
*/
|
||||
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol,
|
||||
JCMethodInvocation invocation) {
|
||||
@ -403,7 +412,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the method in the given type that matches the given name and signature.
|
||||
* Finds the method in the given type that matches the given name and
|
||||
* signature.
|
||||
*/
|
||||
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, String methodName,
|
||||
MethodType methodType) {
|
||||
@ -411,7 +421,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the method in the given type that matches the given name and signature.
|
||||
* Finds the method in the given type that matches the given name and
|
||||
* signature.
|
||||
*/
|
||||
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, String methodName,
|
||||
MethodType methodType, boolean overrides) {
|
||||
@ -471,8 +482,8 @@ public class Util {
|
||||
if (typeSymbol.getEnclosedElements() != null) {
|
||||
for (Element element : typeSymbol.getEnclosedElements()) {
|
||||
if ((element instanceof MethodSymbol) && (methodName.equals(element.getSimpleName().toString())
|
||||
|| ((MethodSymbol) element).getKind() == ElementKind.CONSTRUCTOR
|
||||
&& ("this".equals(methodName) /* || "super".equals(methodName) */))) {
|
||||
|| ((MethodSymbol) element).getKind() == ElementKind.CONSTRUCTOR && ("this".equals(
|
||||
methodName) /* || "super".equals(methodName) */))) {
|
||||
MethodSymbol methodSymbol = (MethodSymbol) element;
|
||||
if (methodType == null) {
|
||||
collector.add(methodSymbol);
|
||||
@ -575,8 +586,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first declaration (of any kind) matching the given name (and optionally
|
||||
* the given number of arguments for methods)
|
||||
* Find first declaration (of any kind) matching the given name (and
|
||||
* optionally the given number of arguments for methods)
|
||||
*/
|
||||
public static Symbol findFirstDeclarationInClassAndSuperClasses(TypeSymbol typeSymbol, String name,
|
||||
ElementKind kind, Integer methodArgsCount) {
|
||||
@ -586,7 +597,8 @@ public class Util {
|
||||
if (typeSymbol.getEnclosedElements() != null) {
|
||||
for (Element element : typeSymbol.getEnclosedElements()) {
|
||||
if (name.equals(element.getSimpleName().toString()) && element.getKind() == kind
|
||||
&& (methodArgsCount == null || methodArgsCount.equals(((ExecutableElement)element).getParameters().size()))) {
|
||||
&& (methodArgsCount == null
|
||||
|| methodArgsCount.equals(((ExecutableElement) element).getParameters().size()))) {
|
||||
return (Symbol) element;
|
||||
}
|
||||
}
|
||||
@ -658,10 +670,13 @@ public class Util {
|
||||
/**
|
||||
* Tells if a method can be invoked with some given parameter types.
|
||||
*
|
||||
* @param types a reference to the types in the compilation scope
|
||||
* @param from the caller method signature to test (contains the parameter
|
||||
* types)
|
||||
* @param target the callee method signature
|
||||
* @param types
|
||||
* a reference to the types in the compilation scope
|
||||
* @param from
|
||||
* the caller method signature to test (contains the parameter
|
||||
* types)
|
||||
* @param target
|
||||
* the callee method signature
|
||||
* @return true if the callee can be invoked by the caller
|
||||
*/
|
||||
public static boolean isInvocable(Types types, MethodType from, MethodType target) {
|
||||
@ -697,8 +712,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the given set with all the default methods found in the current type
|
||||
* and super interfaces.
|
||||
* Fills the given set with all the default methods found in the current
|
||||
* type and super interfaces.
|
||||
*/
|
||||
public static void findDefaultMethodsInType(Set<Entry<JCClassDecl, JCMethodDecl>> defaultMethods,
|
||||
JSweetContext context, ClassSymbol classSymbol) {
|
||||
@ -710,6 +725,25 @@ public class Util {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the given list with all the interfaces containing default methods
|
||||
* (including super interfaces).
|
||||
*/
|
||||
public static void findInterfacesWithDefaultMethods(List<ClassSymbol> interfacesWithDefaultMethods,
|
||||
JSweetContext context, List<ClassSymbol> initInterfaces) {
|
||||
for (ClassSymbol itf : initInterfaces) {
|
||||
if (context.isInterfaceWithDefaultMethods(itf)) {
|
||||
interfacesWithDefaultMethods.add(itf);
|
||||
}
|
||||
}
|
||||
for (ClassSymbol itf : initInterfaces) {
|
||||
if (context.isInterfaceWithDefaultMethods(itf)) {
|
||||
findInterfacesWithDefaultMethods(interfacesWithDefaultMethods, context,
|
||||
itf.getInterfaces().stream().map(i -> (ClassSymbol) i.tsym).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the field in the given type that matches the given name.
|
||||
*/
|
||||
@ -752,7 +786,7 @@ public class Util {
|
||||
public static boolean isVarargs(VarSymbol varSym) {
|
||||
return (varSym.flags_field & Flags.VARARGS) == Flags.VARARGS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the file from a Java file object.
|
||||
*/
|
||||
@ -794,12 +828,14 @@ public class Util {
|
||||
private final static Pattern REGEX_CHARS = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
|
||||
|
||||
/**
|
||||
* This function will escape special characters within a string to ensure that
|
||||
* the string will not be parsed as a regular expression. This is helpful with
|
||||
* accepting using input that needs to be used in functions that take a regular
|
||||
* expression as an argument (such as String.replaceAll(), or String.split()).
|
||||
* This function will escape special characters within a string to ensure
|
||||
* that the string will not be parsed as a regular expression. This is
|
||||
* helpful with accepting using input that needs to be used in functions
|
||||
* that take a regular expression as an argument (such as
|
||||
* String.replaceAll(), or String.split()).
|
||||
*
|
||||
* @param regex - argument which we wish to escape.
|
||||
* @param regex
|
||||
* - argument which we wish to escape.
|
||||
* @return - Resulting string with the following characters escaped:
|
||||
* [](){}+*^?$.\
|
||||
*/
|
||||
@ -846,8 +882,10 @@ public class Util {
|
||||
/**
|
||||
* Get the relative path to reach a symbol from another one.
|
||||
*
|
||||
* @param fromSymbol the start path
|
||||
* @param toSymbol the end path
|
||||
* @param fromSymbol
|
||||
* the start path
|
||||
* @param toSymbol
|
||||
* the end path
|
||||
* @return the '/'-separated path
|
||||
* @see #getRelativePath(String, String)
|
||||
*/
|
||||
@ -878,8 +916,10 @@ public class Util {
|
||||
* <p>
|
||||
* Bug fix: Renaud Pawlak
|
||||
*
|
||||
* @param fromPath the path to start from
|
||||
* @param toPath the path to reach
|
||||
* @param fromPath
|
||||
* the path to start from
|
||||
* @param toPath
|
||||
* the path to reach
|
||||
*/
|
||||
public static String getRelativePath(String fromPath, String toPath) {
|
||||
StringBuilder relativePath = null;
|
||||
@ -934,7 +974,8 @@ public class Util {
|
||||
/**
|
||||
* Removes the extensions of the given file name.
|
||||
*
|
||||
* @param fileName the given file name (can contain path)
|
||||
* @param fileName
|
||||
* the given file name (can contain path)
|
||||
* @return the file name without the extension
|
||||
*/
|
||||
public static String removeExtension(String fileName) {
|
||||
@ -947,11 +988,13 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given directory or any of its sub-directory contains one of the
|
||||
* given files.
|
||||
* Tells if the given directory or any of its sub-directory contains one of
|
||||
* the given files.
|
||||
*
|
||||
* @param dir the directory to look into
|
||||
* @param files the files to be found
|
||||
* @param dir
|
||||
* the directory to look into
|
||||
* @param files
|
||||
* the files to be found
|
||||
* @return true if one of the given files is found
|
||||
*/
|
||||
public static boolean containsFile(File dir, File[] files) {
|
||||
@ -1121,8 +1164,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively looks up one of the given types in the type hierachy of the given
|
||||
* class.
|
||||
* Recursively looks up one of the given types in the type hierachy of the
|
||||
* given class.
|
||||
*
|
||||
* @return true if one of the given names is found as a superclass or a
|
||||
* superinterface
|
||||
@ -1277,8 +1320,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if that variable is a non-static final field initialized with a literal
|
||||
* value.
|
||||
* Tells if that variable is a non-static final field initialized with a
|
||||
* literal value.
|
||||
*/
|
||||
public static boolean isConstantOrNullField(JCVariableDecl var) {
|
||||
return !var.getModifiers().getFlags().contains(Modifier.STATIC) && (var.init == null
|
||||
@ -1343,10 +1386,10 @@ public class Util {
|
||||
*
|
||||
* <p>
|
||||
* This method aims at overcoming TypeScrit limitation that forces a parent
|
||||
* class to be declared before its child class (it is not the case in Java). So
|
||||
* far this is a partial implementation that should cover most cases... for a
|
||||
* 100% coverage we would need a much more complicated implementation that is
|
||||
* probably not worth it.
|
||||
* class to be declared before its child class (it is not the case in Java).
|
||||
* So far this is a partial implementation that should cover most cases...
|
||||
* for a 100% coverage we would need a much more complicated implementation
|
||||
* that is probably not worth it.
|
||||
*/
|
||||
public static List<JCClassDecl> getSortedClassDeclarations(List<JCTree> decls) {
|
||||
// return (List<JCClassDecl>)(Object)decls;
|
||||
@ -1380,8 +1423,8 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first inner class declaration of the given name in the given class
|
||||
* hierarchy.
|
||||
* Finds the first inner class declaration of the given name in the given
|
||||
* class hierarchy.
|
||||
*/
|
||||
public static ClassSymbol findInnerClassDeclaration(ClassSymbol clazz, String name) {
|
||||
if (clazz == null) {
|
||||
|
||||
@ -127,7 +127,7 @@ public class ModuleTests extends AbstractTest {
|
||||
|
||||
@Test
|
||||
public void testRequireFromDifferentRootPackages() {
|
||||
transpile(logHandler -> {
|
||||
transpile(ModuleKind.commonjs, logHandler -> {
|
||||
logHandler.assertNoProblems();
|
||||
}, getSourceFile(2, "t.b.C1"), getSourceFile(3, "u.T1"));
|
||||
}
|
||||
|
||||
@ -71,6 +71,12 @@ import source.structural.TwoClassesInSameFile;
|
||||
import source.structural.WrappedParametersOwner;
|
||||
import source.structural.WrongConstructsInInterfaces;
|
||||
import source.structural.WrongThisAccessOnStatic;
|
||||
import source.structural.defaultMethods.AClass;
|
||||
import source.structural.defaultMethods.I;
|
||||
import source.structural.defaultMethods.J;
|
||||
import source.structural.defaultMethods.K;
|
||||
import source.structural.defaultMethodsWithAnonymousClasses.AnonymousClassWithDefaultMethod;
|
||||
import source.structural.defaultMethodsWithInnerInterfaces.MyPrimitiveIterator;
|
||||
import source.structural.fieldmethodclash.Person;
|
||||
import source.structural.fieldmethodclash.User;
|
||||
import source.structural.globalclasses.Globals;
|
||||
@ -140,7 +146,7 @@ public class StructuralTests extends AbstractTest {
|
||||
}, getSourceFile(source.structural.publicfieldmethodclash.Person2.class),
|
||||
getSourceFile(source.structural.publicfieldmethodclash.User2.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTwoClassesInSameFile() {
|
||||
transpile(logHandler -> {
|
||||
@ -429,7 +435,7 @@ public class StructuralTests extends AbstractTest {
|
||||
// TODO: make it work with modules
|
||||
// actually we need to completely change the implementation of default
|
||||
// method because they require the source code
|
||||
eval(ModuleKind.none, (logHandler, r) -> {
|
||||
eval((logHandler, r) -> {
|
||||
logHandler.assertNoProblems();
|
||||
assertEquals("m,m1,m2-overriden,FromAbstract_overload_called5;p2,FromAbstract_overload_called15;kako",
|
||||
r.get("FromAbstract_trace"));
|
||||
@ -441,6 +447,27 @@ public class StructuralTests extends AbstractTest {
|
||||
getSourceFile(DefaultMethodsConsumer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleDefaultMethods() {
|
||||
eval((logHandler, r) -> {
|
||||
logHandler.assertNoProblems();
|
||||
}, getSourceFile(J.class), getSourceFile(K.class), getSourceFile(I.class), getSourceFile(AClass.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInnerInterfaceDefaultMethods() {
|
||||
eval(ModuleKind.commonjs, (logHandler, r) -> {
|
||||
logHandler.assertNoProblems();
|
||||
}, getSourceFile(MyPrimitiveIterator.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousClassWithDefaultMethods() {
|
||||
eval((logHandler, r) -> {
|
||||
logHandler.assertNoProblems();
|
||||
}, getSourceFile(AnonymousClassWithDefaultMethod.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterfaceStaticMethods() {
|
||||
eval((logHandler, r) -> {
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package source.structural.defaultMethods;
|
||||
|
||||
public class AClass implements I {
|
||||
|
||||
@Override
|
||||
public String m1() {
|
||||
return "m1" + m2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String m3() {
|
||||
return "m3";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
assert "m1m2m3".equals(new AClass().m1());
|
||||
assert "m4".equals(new AClass().m4());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package source.structural.defaultMethods;
|
||||
|
||||
public interface I extends J {
|
||||
|
||||
String m1();
|
||||
|
||||
default String m2() {
|
||||
return "m2" + m3();
|
||||
}
|
||||
|
||||
String m3();
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package source.structural.defaultMethods;
|
||||
|
||||
public interface J {
|
||||
|
||||
default String m4() {
|
||||
return "m4";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package source.structural.defaultMethods;
|
||||
|
||||
public interface K {
|
||||
|
||||
default String m5() {
|
||||
return "m5";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package source.structural.defaultMethodsWithAnonymousClasses;
|
||||
|
||||
interface MyIterator<K> {
|
||||
default boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default K next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void remove() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface MyEntry<K,V> {
|
||||
default K getKey() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class AnonymousClassWithDefaultMethod<K, V> {
|
||||
|
||||
public MyIterator<K> iterator() {
|
||||
final MyIterator<MyEntry<K, V>> entryIterator = null;
|
||||
return new MyIterator<K>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return entryIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K next() {
|
||||
MyEntry<K, V> entry = entryIterator.next();
|
||||
return entry.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
entryIterator.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package source.structural.defaultMethodsWithInnerInterfaces;
|
||||
|
||||
import static source.structural.defaultMethodsWithInnerInterfaces.Util.checkCriticalNotNull;
|
||||
import static source.structural.defaultMethodsWithInnerInterfaces.Util.checkNotNull;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.DoubleConsumer;
|
||||
|
||||
class Util {
|
||||
static void checkCriticalNotNull(Object o) {}
|
||||
static void checkNotNull(Object o) {}
|
||||
}
|
||||
|
||||
interface MyIterator<T> {
|
||||
T next();
|
||||
boolean hasNext();
|
||||
default void forEachRemaining(Consumer<? super Double> consumer) {
|
||||
}
|
||||
}
|
||||
|
||||
public interface MyPrimitiveIterator<T, C> extends MyIterator<T> {
|
||||
|
||||
void forEachRemaining(C consumer);
|
||||
|
||||
interface OfDouble extends MyPrimitiveIterator<Double, DoubleConsumer> {
|
||||
double nextDouble();
|
||||
|
||||
@Override
|
||||
default Double next() {
|
||||
return nextDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void forEachRemaining(DoubleConsumer consumer) {
|
||||
checkNotNull(consumer);
|
||||
while (hasNext()) {
|
||||
//consumer.accept(nextDouble());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Double> consumer) {
|
||||
if (consumer instanceof DoubleConsumer) {
|
||||
forEachRemaining((DoubleConsumer) consumer);
|
||||
} else {
|
||||
checkCriticalNotNull(consumer);
|
||||
forEachRemaining((DoubleConsumer) null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user