From 8740b4c2a1380d0dc8c03e6ba9cc58d7220d32ec Mon Sep 17 00:00:00 2001 From: Eric Pabst Date: Sat, 29 Sep 2018 14:43:58 -0600 Subject: [PATCH] Fix overriding of equals, hashCode, and toString to always compile --- .../kotlin/ts2kt/TypeScriptToKotlinBase.kt | 22 ++++++++++++++++++- src/main/kotlin/ts2kt/translate.kt | 16 -------------- src/main/kotlin/ts2kt/typeScriptAstUtils.kt | 1 + testData/class/override/anyMembers.d.kt | 7 +++--- testData/class/override/anyMembers.d.ts | 1 + testData/interface/override/anyMembers.d.kt | 6 ++--- 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/ts2kt/TypeScriptToKotlinBase.kt b/src/main/kotlin/ts2kt/TypeScriptToKotlinBase.kt index 164a2d4..cc686d0 100644 --- a/src/main/kotlin/ts2kt/TypeScriptToKotlinBase.kt +++ b/src/main/kotlin/ts2kt/TypeScriptToKotlinBase.kt @@ -20,7 +20,27 @@ abstract class TypeScriptToKotlinBase( open fun addFunction(symbol: Symbol?, name: String, callSignature: KtCallSignature, extendsType: KtType? = null, needsNoImpl: Boolean = true, additionalAnnotations: List = listOf(), isOverride: Boolean = false, isOperator: Boolean = false) { val annotations = defaultAnnotations + additionalAnnotations - addDeclaration(symbol, KtFunction(KtName(name), callSignature, extendsType?.let { KtHeritageType(it) }, annotations, needsNoImpl = needsNoImpl, isOverride = isOverride, hasOpenModifier = hasMembersOpenModifier, isOperator = isOperator)) + var actualIsOverride = isOverride + val overrideCallSignature = if ("hashCode" == name && callSignature.params.isEmpty()) { + actualIsOverride = true + //force hashCode to return an Int so it will compile + callSignature.copy(returnType = callSignature.returnType.copy(type = KtType(INT))) + } else if ("toString" == name && callSignature.params.isEmpty()) { + actualIsOverride = true + //force toString to return a String so it will compile + callSignature.copy(returnType = callSignature.returnType.copy(type = KtType(STRING))) + } else if ("equals" == name && callSignature.params.size == 1 && callSignature.params[0].type.type.qualifiedName == ANY) { + actualIsOverride = true + callSignature.copy( + //force equals to take Any? (instead of Any) so that it overrides + params = callSignature.params.map { it.copy(type = it.type.copy(type = KtType(ANY, isNullable = true))) }, + //force equals to return a Boolean so it will compile + returnType = callSignature.returnType.copy(type = KtType(BOOLEAN))) + } else { + callSignature + } + val heritageType = extendsType?.let { KtHeritageType(it) } + addDeclaration(symbol, KtFunction(KtName(name), overrideCallSignature, heritageType, annotations, needsNoImpl, actualIsOverride, hasMembersOpenModifier, isOperator)) } protected fun addDeclaration(symbol: Symbol?, declaration: KtMember) { diff --git a/src/main/kotlin/ts2kt/translate.kt b/src/main/kotlin/ts2kt/translate.kt index 0b2a741..9a1d397 100644 --- a/src/main/kotlin/ts2kt/translate.kt +++ b/src/main/kotlin/ts2kt/translate.kt @@ -86,20 +86,6 @@ fun translate(srcPath: String, basePackageName: String, declareModifierIsOptiona // val fileNode = languageService.getSourceFile(normalizeSrcPath) val fileNode = languageService.getProgram().getSourceFile(normalizeSrcPath) - inline fun isAnyMember(node: MethodDeclaration): Boolean { - val params = node.parameters.arr - - return when (node.propertyName?.text) { - "equals" -> - params.size == 1 && params[0].type?.let { it.kind === SyntaxKind.AnyKeyword } ?: true - // TODO check return type ??? - "hashCode", "toString" -> - params.size == 0 - else -> - false - } - } - /*inline*/ fun isOverrideHelper( node: Declaration, /*crossinline*/ f: (TypeChecker, Type, String) -> Boolean @@ -172,8 +158,6 @@ fun translate(srcPath: String, basePackageName: String, declareModifierIsOptiona } fun isOverride(node: MethodDeclaration): Boolean { - if (isAnyMember(node)) return true - var nodeSignature: Signature? = null return isOverrideHelper(node) { typechecker, type, nodeName -> diff --git a/src/main/kotlin/ts2kt/typeScriptAstUtils.kt b/src/main/kotlin/ts2kt/typeScriptAstUtils.kt index e2af129..e4820ef 100644 --- a/src/main/kotlin/ts2kt/typeScriptAstUtils.kt +++ b/src/main/kotlin/ts2kt/typeScriptAstUtils.kt @@ -25,6 +25,7 @@ import typescriptServices.ts.* val ANY = KtQualifiedName("Any") val NOTHING = KtQualifiedName("Nothing") val NUMBER = KtQualifiedName("Number") +val INT = KtQualifiedName("Int") val STRING = KtQualifiedName("String") val BOOLEAN = KtQualifiedName("Boolean") val UNIT = KtQualifiedName("Unit") diff --git a/testData/class/override/anyMembers.d.kt b/testData/class/override/anyMembers.d.kt index 3f930c3..27d2985 100644 --- a/testData/class/override/anyMembers.d.kt +++ b/testData/class/override/anyMembers.d.kt @@ -1,12 +1,13 @@ package anyMembers external open class ExpectedOverrides { - override fun equals(a: Any): Unit = definedExternally - override fun hashCode(): Number = definedExternally + override fun equals(a: Any?): Boolean = definedExternally + override fun hashCode(): Int = definedExternally override fun toString(): String = definedExternally } external open class ExpectedOverrides2 { - override fun equals(a: Any): Unit = definedExternally + override fun equals(a: Any?): Boolean = definedExternally + override fun toString(): String = definedExternally } external open class ExpectedNoOverrides { open fun equals(): Unit = definedExternally diff --git a/testData/class/override/anyMembers.d.ts b/testData/class/override/anyMembers.d.ts index dae74dd..2c39c8e 100644 --- a/testData/class/override/anyMembers.d.ts +++ b/testData/class/override/anyMembers.d.ts @@ -6,6 +6,7 @@ declare class ExpectedOverrides { declare class ExpectedOverrides2 { equals(a); + toString(); } declare class ExpectedNoOverrides { diff --git a/testData/interface/override/anyMembers.d.kt b/testData/interface/override/anyMembers.d.kt index 34661c5..2dd1b0e 100644 --- a/testData/interface/override/anyMembers.d.kt +++ b/testData/interface/override/anyMembers.d.kt @@ -1,12 +1,12 @@ package anyMembers external interface ExpectedOverrides { - override fun equals(a: Any) - override fun hashCode(): Number + override fun equals(a: Any?): Boolean + override fun hashCode(): Int override fun toString(): String } external interface ExpectedOverrides2 { - override fun equals(a: Any) + override fun equals(a: Any?): Boolean } external interface ExpectedNoOverrides { fun equals()