stable point in using mixins - but does not work yet for compiling J4TS

This commit is contained in:
Renaud Pawlak 2020-03-05 06:41:42 +01:00
parent eb3579a397
commit fc3b436a31
13 changed files with 712 additions and 331 deletions

View File

@ -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 {

View File

@ -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>();
/**

View File

@ -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 ");

View File

@ -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;
}

View File

@ -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) {

View File

@ -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"));
}

View File

@ -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) -> {

View File

@ -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());
}
}

View File

@ -0,0 +1,13 @@
package source.structural.defaultMethods;
public interface I extends J {
String m1();
default String m2() {
return "m2" + m3();
}
String m3();
}

View File

@ -0,0 +1,9 @@
package source.structural.defaultMethods;
public interface J {
default String m4() {
return "m4";
}
}

View File

@ -0,0 +1,9 @@
package source.structural.defaultMethods;
public interface K {
default String m5() {
return "m5";
}
}

View File

@ -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();
}
};
}
}

View File

@ -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);
}
}
}
}