Fix CCE in constructNestedClassReferenceIdentifier J2K

#KT-17712 fixed
This commit is contained in:
Simon Ogorodnik
2017-05-19 20:02:55 +03:00
parent d0991fffd2
commit 6a8bb8b33d
7 changed files with 19 additions and 36 deletions
@@ -123,15 +123,14 @@ class ConstructorConverter(
val body = primaryConstructor.body
val parameterUsageReplacementMap = HashMap<String, String>()
val correctedTypeConverter = converter.withSpecialContext(psiClass).typeConverter /* to correct nested class references */
val bodyGenerator: (CodeConverter) -> Block = if (body != null) {
val statementsToRemove = HashSet<PsiStatement>()
for (parameter in params) {
val (field, initializationStatement) = findBackingFieldForConstructorParameter(parameter, primaryConstructor) ?: continue
val fieldType = correctedTypeConverter.convertVariableType(field)
val parameterType = correctedTypeConverter.convertVariableType(parameter)
val fieldType = converter.typeConverter.convertVariableType(field)
val parameterType = converter.typeConverter.convertVariableType(parameter)
// types can be different only in nullability
val type = if (fieldType == parameterType) {
fieldType
@@ -175,27 +174,25 @@ class ConstructorConverter(
// we need to replace renamed parameter usages in base class constructor arguments and in default values
val correctedConverter = converter.withSpecialContext(psiClass) /* to correct nested class references */
fun CodeConverter.correct() = withSpecialExpressionConverter(ReplacingExpressionConverter(parameterUsageReplacementMap))
val statement = primaryConstructor.body?.statements?.firstOrNull()
val methodCall = (statement as? PsiExpressionStatement)?.expression as? PsiMethodCallExpression
if (methodCall != null && methodCall.isSuperConstructorCall()) {
baseClassParams = methodCall.argumentList.expressions.map {
correctedConverter.deferredElement { codeConverter -> codeConverter.correct().convertExpression(it) }
converter.deferredElement { codeConverter -> codeConverter.correct().convertExpression(it) }
}
}
else {
baseClassParams = emptyList()
}
val parameterList = correctedConverter.convertParameterList(
val parameterList = converter.convertParameterList(
primaryConstructor,
overloadReducer,
{ parameter, default ->
if (!parameterToField.containsKey(parameter)) {
correctedConverter.convertParameter(parameter, defaultValue = default)
converter.convertParameter(parameter, defaultValue = default)
}
else {
val (field, type) = parameterToField[parameter]!!
+6 -17
View File
@@ -41,8 +41,7 @@ class Converter private constructor(
val settings: ConverterSettings,
val inConversionScope: (PsiElement) -> Boolean,
val services: JavaToKotlinConverterServices,
private val commonState: Converter.CommonState,
private val personalState: Converter.PersonalState
private val commonState: Converter.CommonState
) {
// state which is shared between all converter's based on this one
@@ -51,15 +50,10 @@ class Converter private constructor(
val postUnfoldActions = ArrayList<() -> Unit>()
}
// state which may differ in different converter's
class PersonalState(val specialContext: PsiElement?)
val project: Project = elementToConvert.project
val typeConverter: TypeConverter = TypeConverter(this)
val annotationConverter: AnnotationConverter = AnnotationConverter(this)
val specialContext: PsiElement? = personalState.specialContext
val referenceSearcher: ReferenceSearcher = CachingReferenceSearcher(services.referenceSearcher)
val propertyDetectionCache = PropertyDetectionCache(this)
@@ -68,15 +62,10 @@ class Converter private constructor(
fun create(elementToConvert: PsiElement, settings: ConverterSettings, services: JavaToKotlinConverterServices,
inConversionScope: (PsiElement) -> Boolean, usageProcessingsCollector: (UsageProcessing) -> Unit): Converter {
return Converter(elementToConvert, settings, inConversionScope,
services, CommonState(usageProcessingsCollector), PersonalState(null))
services, CommonState(usageProcessingsCollector))
}
}
fun withSpecialContext(context: PsiElement): Converter = withState(PersonalState(context))
private fun withState(state: PersonalState): Converter
= Converter(elementToConvert, settings, inConversionScope, services, commonState, state)
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
data class IntermediateResult(
@@ -134,14 +123,14 @@ class Converter private constructor(
var i = 0
while (i < commonState.deferredElements.size) {
val deferredElement = commonState.deferredElements[i++]
deferredElement.unfold(codeConverter.withConverter(this.withState(deferredElement.converterState)))
deferredElement.unfold(codeConverter)
}
commonState.postUnfoldActions.forEach { it() }
}
fun <TResult : Element> deferredElement(generator: (CodeConverter) -> TResult): DeferredElement<TResult> {
val element = DeferredElement(generator, personalState)
val element = DeferredElement(generator)
commonState.deferredElements.add(element)
return element
}
@@ -686,7 +675,7 @@ class Converter private constructor(
if (!hasExternalQualifier) {
// references to nested classes may need correction
if (targetClass != null) {
val identifier = constructNestedClassReferenceIdentifier(targetClass, specialContext ?: element)
val identifier = constructNestedClassReferenceIdentifier(targetClass, element)
if (identifier != null) {
return ReferenceElement(identifier, typeArgs).assignPrototype(element, CommentsAndSpacesInheritance.NO_SPACES)
}
@@ -701,7 +690,7 @@ class Converter private constructor(
val outerClass = psiClass.containingClass
if (outerClass != null
&& !PsiTreeUtil.isAncestor(outerClass, context, true)
&& !psiClass.isImported(context.containingFile as PsiJavaFile)) {
&& !psiClass.isImported(elementToConvert.containingFile as PsiJavaFile)) {
val qualifier = constructNestedClassReferenceIdentifier(outerClass, context)?.name ?: outerClass.name!!
return Identifier.withNoPrototype(Identifier.toKotlin(qualifier) + "." + Identifier.toKotlin(psiClass.name!!))
}
@@ -593,12 +593,11 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
// add qualification for static members from base classes and also this works for enum constants in switch
val context = converter.specialContext ?: expression
if (target is PsiMember
&& target.hasModifierProperty(PsiModifier.STATIC)
&& target.containingClass != null
&& !PsiTreeUtil.isAncestor(target.containingClass, context, true)
&& !target.isImported(context.containingFile as PsiJavaFile)) {
&& target.hasModifierProperty(PsiModifier.STATIC)
&& target.containingClass != null
&& !PsiTreeUtil.isAncestor(target.containingClass, expression, true)
&& !target.isImported(expression.containingFile as PsiJavaFile)) {
var member: PsiMember = target
var code = Identifier.toKotlin(referenceName)
while (true) {
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.j2k.ast
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.j2k.CodeBuilder
import org.jetbrains.kotlin.j2k.CodeConverter
import org.jetbrains.kotlin.j2k.Converter
import org.jetbrains.kotlin.j2k.EmptyDocCommentConverter
fun <TElement: Element> TElement.assignPrototype(prototype: PsiElement?, inheritance: CommentsAndSpacesInheritance = CommentsAndSpacesInheritance()): TElement {
@@ -109,8 +108,7 @@ abstract class Element {
// this class should never be created directly - Converter.deferredElement() should be used!
class DeferredElement<TResult : Element>(
private val generator: (CodeConverter) -> TResult,
val converterState: Converter.PersonalState
private val generator: (CodeConverter) -> TResult
) : Element() {
private var result: TResult? = null
@@ -1,4 +1,4 @@
internal class A @JvmOverloads constructor(nested: A.Nested = A.Nested(A.Nested.FIELD)) {
internal class A @JvmOverloads constructor(nested: Nested = Nested(Nested.FIELD)) {
internal class Nested(p: Int) {
companion object {
@@ -1,4 +1,4 @@
internal open class Base(nested: Base.Nested) {
internal open class Base(nested: Nested) {
internal class Nested(p: Int) {
companion object {
+1 -1
View File
@@ -1,4 +1,4 @@
internal class X(private val list: List<X.Y>) {
internal class X(private val list: List<Y>) {
internal inner class Y
}