Fixed KT-5383 J2K: preserve annotations from primary constructor + never drop constructors with annotations

#KT-5383 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-07-11 14:25:42 +04:00
parent 3527b186bf
commit bcc36c4e48
6 changed files with 65 additions and 7 deletions
@@ -121,12 +121,10 @@ class ConstructorConverter(private val psiClass: PsiClass, private val converter
}
private fun dropConstructorsForDefaultValues(primary: PsiMethod, toTargetConstructorMap: Map<PsiMethod, TargetConstructorInfo>) {
//TODO: should we drop when annotations exist?
val dropCandidates = toTargetConstructorMap
.filter { it.value.parameterDefaults != null }
.map { it.key }
.filter { it.accessModifier() == primary.accessModifier() }
.filter { it.accessModifier() == primary.accessModifier() && it.getModifierList().getAnnotations().isEmpty() /* do not drop constructors with annotations */ }
.sortBy { -it.getParameterList().getParametersCount() } // we will try to drop them starting from ones with more parameters
val primaryParamCount = primary.getParameterList().getParametersCount()
@DropCandidatesLoop
@@ -340,7 +338,7 @@ class ConstructorConverter(private val psiClass: PsiClass, private val converter
//TODO: we can generate it private when secondary constructors are supported by Kotlin
//val modifiers = Modifiers(listOf(Modifier.PRIVATE)).assignNoPrototype()
val parameterList = ParameterList(parameters).assignNoPrototype()
val constructorSignature = PrimaryConstructorSignature(modifiers, parameterList).assignNoPrototype()
val constructorSignature = PrimaryConstructorSignature(Annotations.Empty, modifiers, parameterList).assignNoPrototype()
val updatedMembers = classBody.members.filter { !fieldsToInitialize.contains(it) }
return ClassBody(constructorSignature, updatedMembers, classBody.classObjectMembers, updatedFactoryFunctions, classBody.lBrace, classBody.rBrace)
}
@@ -66,3 +66,6 @@ class Annotations(val annotations: List<Annotation>, val newLines: Boolean) : El
val Empty = Annotations(listOf(), false)
}
}
fun Annotations.withBrackets(): Annotations
= Annotations(annotations.map { Annotation(it.name, it.arguments, true).assignPrototypesFrom(it) }, newLines).assignPrototypesFrom(this)
@@ -37,17 +37,23 @@ class PrimaryConstructor(annotations: Annotations,
public fun signature(): PrimaryConstructorSignature {
val noBody = block.isEmpty
val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = noBody, commentsInside = noBody)
return PrimaryConstructorSignature(modifiers, parameterList).assignPrototypesFrom(this, inheritance)
return PrimaryConstructorSignature(annotations, modifiers, parameterList).assignPrototypesFrom(this, inheritance)
}
}
class PrimaryConstructorSignature(val modifiers: Modifiers, val parameterList: ParameterList) : Element() {
class PrimaryConstructorSignature(val annotations: Annotations, val modifiers: Modifiers, val parameterList: ParameterList) : Element() {
override fun generateCode(builder: CodeBuilder) {
val accessModifier = modifiers.filter { it in ACCESS_MODIFIERS && it != Modifier.PUBLIC }
if (accessModifier.isEmpty && parameterList.parameters.isEmpty()) return
if (accessModifier.isEmpty && annotations.isEmpty && parameterList.parameters.isEmpty()) return
if (!annotations.isEmpty) {
builder append " " append annotations.withBrackets()
}
if (!accessModifier.isEmpty) {
builder append " " append accessModifier
}
builder append "(" append parameterList append ")"
}
}
@@ -821,6 +821,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
doTest("j2k/tests/testData/ast/constructors/chain.java");
}
@TestMetadata("constructorAnnotations.java")
public void testConstructorAnnotations() throws Exception {
doTest("j2k/tests/testData/ast/constructors/constructorAnnotations.java");
}
@TestMetadata("customerBuilder.java")
public void testCustomerBuilder() throws Exception {
doTest("j2k/tests/testData/ast/constructors/customerBuilder.java");
@@ -0,0 +1,29 @@
import javaApi.Anon5;
class A {
private final int a;
private final int b;
@Anon5(10)
public A(int a, int b) {
this.a = a;
this.b = b;
}
@Deprecated // this constructor will not be replaced by default parameter value in primary because of this annotation
public A(int a) {
this(a, 1);
}
}
class B {
@Anon5(11)
public B() {
}
}
class C {
@Anon5(12)
private C() {
}
}
@@ -0,0 +1,17 @@
import javaApi.Anon5
deprecated("") // this constructor will not be replaced by default parameter value in primary because of this annotation
fun A(a: Int): A {
return A(a, 1)
}
class A
[Anon5(10)]
(private val a: Int, private val b: Int)
class B [Anon5(11)]
()
class C [Anon5(12)]
private()