From aa5599f6ca83ed14cc0fa3fb0d71a3411c2dbec6 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 4 Mar 2015 16:00:04 +0300 Subject: [PATCH] Improve positioning strategy for delegation calls --- .../jetbrains/kotlin/diagnostics/Errors.java | 16 +++++++++--- .../diagnostics/PositioningStrategies.kt | 25 +++++++++++++++++++ .../kotlin/psi/JetSecondaryConstructor.java | 6 +++++ .../cyclicDelegationCalls.kt | 18 ++++++------- .../tests/secondaryConstructors/enums.kt | 4 +-- .../superSecondaryNonExisting.kt | 2 +- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index a3b836767be..beb160d421b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -155,12 +155,19 @@ public interface Errors { // Secondary constructors - DiagnosticFactory0 CYCLIC_CONSTRUCTOR_DELEGATION_CALL = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 CYCLIC_CONSTRUCTOR_DELEGATION_CALL = + DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL); + DiagnosticFactory0 SECONDARY_CONSTRUCTOR_IN_OBJECT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED = DiagnosticFactory0.create(WARNING); - DiagnosticFactory0 DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR = DiagnosticFactory0.create(ERROR); + + DiagnosticFactory0 PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED = + DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL); + + DiagnosticFactory0 DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR = + DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL); + DiagnosticFactory0 PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS = DiagnosticFactory0.create(ERROR); // Trait-specific @@ -392,7 +399,8 @@ public interface Errors { DiagnosticFactory0 NOT_A_CLASS = DiagnosticFactory0.create(ERROR); DiagnosticFactory1>> OVERLOAD_RESOLUTION_AMBIGUITY = DiagnosticFactory1.create(ERROR); - DiagnosticFactory1>> NONE_APPLICABLE = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1>> NONE_APPLICABLE = + DiagnosticFactory1.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL_OR_DEFAULT); DiagnosticFactory1>> CANNOT_COMPLETE_RESOLVE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> UNRESOLVED_REFERENCE_WRONG_RECEIVER = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 79e4ac441d2..41c31a2312f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.lexer.JetKeywordToken import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.utils.sure import kotlin.platform.platformStatic +import org.jetbrains.kotlin.psi.psiUtil.* public object PositioningStrategies { private open class DeclarationHeader : PositioningStrategy() { @@ -373,4 +374,28 @@ public object PositioningStrategies { return DEFAULT.mark(element) } } + + public val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy = + object : PositioningStrategy() { + override fun mark(element: JetConstructorDelegationCall): List { + if (element.getCalleeExpression()?.isEmpty() ?: false) { + val constructor = element.getStrictParentOfType()!! + return markElement(constructor.getConstructorKeyword()) + } + return markElement(element.getCalleeExpression() ?: element) + } + } + + public val SECONDARY_CONSTRUCTOR_DELEGATION_CALL_OR_DEFAULT: PositioningStrategy = + object : PositioningStrategy() { + override fun mark(element: PsiElement): List { + val parent = element.getParent() + if (parent is JetConstructorDelegationCall) { + return SECONDARY_CONSTRUCTOR_DELEGATION_CALL.mark(parent) + } + else { + return DEFAULT.mark(element) + } + } + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java index ef4b04f660e..bf0a8f4b140 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub; @@ -180,4 +181,9 @@ public class JetSecondaryConstructor extends JetDeclarationStubthis() {} + constructor(): this() {} } class A2(x: Byte) { - constructor(x1: Int): this(x1, 1) {} - constructor(x1: Int, x2: Int): this(x1, x2, 2) {} - constructor(x1: Int, x2: Int, x3: Int): this(x1) {} + constructor(x1: Int): this(x1, 1) {} + constructor(x1: Int, x2: Int): this(x1, x2, 2) {} + constructor(x1: Int, x2: Int, x3: Int): this(x1) {} // delegating to previously declared cycle constructor(x1: Double): this(1) {} @@ -15,9 +15,9 @@ class A2(x: Byte) { // delegating to cycle declared after constructor(x1: String): this(1L) {} - constructor(x1: Long): this(x1, 1L) {} - constructor(x1: Long, x2: Long): this(x1, x2, 2L) {} - constructor(x1: Long, x2: Long, x3: Long): this(x1) {} + constructor(x1: Long): this(x1, 1L) {} + constructor(x1: Long, x2: Long): this(x1, x2, 2L) {} + constructor(x1: Long, x2: Long, x3: Long): this(x1) {} // no cycle, just call to primary constuctor constructor(x1: Double, x2: Double): this(x1, x2, 1.0) {} @@ -26,8 +26,8 @@ class A2(x: Byte) { constructor(): this("x", "y") {} - constructor(x1: String, x2: String): this(x1, x2, "") {} - constructor(x1: String, x2: String, x3: String): this(x1, x2) {} + constructor(x1: String, x2: String): this(x1, x2, "") {} + constructor(x1: String, x2: String, x3: String): this(x1, x2) {} } open class B(x: Byte) diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/enums.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/enums.kt index 3a18ab057f7..18457a93555 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/enums.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/enums.kt @@ -6,7 +6,7 @@ enum class A { constructor(x: Int) {} constructor(x: Int, y: Int): this(x+y) {} constructor(x: Double): this(x.toInt(), 1) {} - constructor(x: String): super(x, 1) {} + constructor(x: String): super(x, 1) {} } enum class B(x: Int) { @@ -14,7 +14,7 @@ enum class B(x: Int) { constructor(x: Int, y: Int): this(x+y) {} constructor(x: Double): this(x.toInt(), 1) {} - constructor(x: String): super(x, 1) {} + constructor(x: String): super(x, 1) {} } enum class C { diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/superSecondaryNonExisting.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/superSecondaryNonExisting.kt index 7c3b291450c..86b1bb8b989 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/superSecondaryNonExisting.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/superSecondaryNonExisting.kt @@ -6,5 +6,5 @@ open class B(x: Double) { trait C class A : B, C { constructor(): super(' ') { } - constructor(x: Int) { } + constructor(x: Int) { } }