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