Fix infinity deferred element unfolding in J2K
#KT-13146 fixed
This commit is contained in:
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.core.setVisibility
|
import org.jetbrains.kotlin.idea.core.setVisibility
|
||||||
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||||
import org.jetbrains.kotlin.idea.intentions.*
|
import org.jetbrains.kotlin.idea.intentions.*
|
||||||
@@ -36,6 +37,9 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
|||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
@@ -66,6 +70,8 @@ object J2KPostProcessingRegistrar {
|
|||||||
_processings.add(FixObjectStringConcatenationProcessing())
|
_processings.add(FixObjectStringConcatenationProcessing())
|
||||||
_processings.add(ConvertToStringTemplateProcessing())
|
_processings.add(ConvertToStringTemplateProcessing())
|
||||||
_processings.add(UsePropertyAccessSyntaxProcessing())
|
_processings.add(UsePropertyAccessSyntaxProcessing())
|
||||||
|
_processings.add(UninitializedVariableReferenceFromInitializerToThisReferenceProcessing())
|
||||||
|
_processings.add(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing())
|
||||||
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
||||||
_processings.add(RemoveRedundantCastToNullableProcessing())
|
_processings.add(RemoveRedundantCastToNullableProcessing())
|
||||||
|
|
||||||
@@ -278,4 +284,39 @@ object J2KPostProcessingRegistrar {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing : J2kPostProcessing {
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
|
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNINITIALIZED_VARIABLE }) return null
|
||||||
|
|
||||||
|
val resolved = element.mainReference.resolve() ?: return null
|
||||||
|
if (resolved.isAncestor(element, strict = true)) {
|
||||||
|
if (resolved is KtVariableDeclaration && resolved.hasInitializer()) {
|
||||||
|
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
|
||||||
|
if (resolved.initializer!!.getChildOfType<KtClassOrObject>() == anonymousObject) {
|
||||||
|
return { element.replaced(KtPsiFactory(element).createThisExpression()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing : J2kPostProcessing {
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
|
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNRESOLVED_REFERENCE }) return null
|
||||||
|
|
||||||
|
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
|
||||||
|
|
||||||
|
val variable = anonymousObject.getParentOfType<KtVariableDeclaration>(true) ?: return null
|
||||||
|
|
||||||
|
if (variable.nameAsName == element.getReferencedNameAsName() &&
|
||||||
|
variable.initializer?.getChildOfType<KtClassOrObject>() == anonymousObject) {
|
||||||
|
return { element.replaced(KtPsiFactory(element).createThisExpression()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -150,30 +150,32 @@ class CodeConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type {
|
fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type {
|
||||||
val convertedExpression = convertExpression(expression)
|
with(converter.codeConverterForType) {
|
||||||
val actualType = expression.type ?: return ErrorType()
|
val convertedExpression = convertExpression(expression)
|
||||||
var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull)
|
val actualType = expression.type ?: return ErrorType()
|
||||||
|
var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull)
|
||||||
|
|
||||||
if (actualType is PsiPrimitiveType && resultType.isNullable ||
|
if (actualType is PsiPrimitiveType && resultType.isNullable ||
|
||||||
expectedType is PsiPrimitiveType && actualType is PsiClassType) {
|
expectedType is PsiPrimitiveType && actualType is PsiClassType) {
|
||||||
resultType = resultType.toNotNullType()
|
resultType = resultType.toNotNullType()
|
||||||
}
|
|
||||||
|
|
||||||
if (needConversion(actualType, expectedType)) {
|
|
||||||
val expectedTypeStr = expectedType.canonicalText
|
|
||||||
|
|
||||||
val willConvert = if (convertedExpression is LiteralExpression
|
|
||||||
|| expression is PsiPrefixExpression && expression.isLiteralWithSign() )
|
|
||||||
expectedTypeStr == "float" || expectedTypeStr == "double"
|
|
||||||
else
|
|
||||||
PRIMITIVE_TYPE_CONVERSIONS[expectedTypeStr] != null
|
|
||||||
|
|
||||||
if (willConvert) {
|
|
||||||
resultType = typeConverter.convertType(expectedType, Nullability.NotNull)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return resultType
|
if (needConversion(actualType, expectedType)) {
|
||||||
|
val expectedTypeStr = expectedType.canonicalText
|
||||||
|
|
||||||
|
val willConvert = if (convertedExpression is LiteralExpression
|
||||||
|
|| expression is PsiPrefixExpression && expression.isLiteralWithSign())
|
||||||
|
expectedTypeStr == "float" || expectedTypeStr == "double"
|
||||||
|
else
|
||||||
|
PRIMITIVE_TYPE_CONVERSIONS[expectedTypeStr] != null
|
||||||
|
|
||||||
|
if (willConvert) {
|
||||||
|
resultType = typeConverter.convertType(expectedType, Nullability.NotNull)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiPrefixExpression.isLiteralWithSign()
|
private fun PsiPrefixExpression.isLiteralWithSign()
|
||||||
|
|||||||
@@ -66,8 +66,13 @@ class Converter private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun withCommonState(state: CommonState) = Converter(elementToConvert, settings, inConversionScope, services, state)
|
||||||
|
|
||||||
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
|
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
|
||||||
|
|
||||||
|
/* special code converter for type, based on this with detached deferred elements list, to prevent recursive deferred elements */
|
||||||
|
val codeConverterForType by lazy { withCommonState(CommonState {}).createDefaultCodeConverter() }
|
||||||
|
|
||||||
data class IntermediateResult(
|
data class IntermediateResult(
|
||||||
val codeGenerator: (Map<PsiElement, Collection<UsageProcessing>>) -> Result,
|
val codeGenerator: (Map<PsiElement, Collection<UsageProcessing>>) -> Result,
|
||||||
val parseContext: ParseContext
|
val parseContext: ParseContext
|
||||||
@@ -489,15 +494,16 @@ class Converter private constructor(
|
|||||||
fun shouldDeclareVariableType(variable: PsiVariable, type: Type, canChangeType: Boolean): Boolean {
|
fun shouldDeclareVariableType(variable: PsiVariable, type: Type, canChangeType: Boolean): Boolean {
|
||||||
assert(inConversionScope(variable))
|
assert(inConversionScope(variable))
|
||||||
|
|
||||||
|
val codeConverter = codeConverterForType
|
||||||
val initializer = variable.initializer
|
val initializer = variable.initializer
|
||||||
if (initializer == null || initializer.isNullLiteral()) return true
|
if (initializer == null || initializer.isNullLiteral()) return true
|
||||||
if (initializer.type is PsiPrimitiveType && type is PrimitiveType) {
|
if (initializer.type is PsiPrimitiveType && type is PrimitiveType) {
|
||||||
if (createDefaultCodeConverter().convertedExpressionType(initializer, variable.type) != type) {
|
if (codeConverter.convertedExpressionType(initializer, variable.type) != type) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val initializerType = createDefaultCodeConverter().convertedExpressionType(initializer, variable.type)
|
val initializerType = codeConverter.convertedExpressionType(initializer, variable.type)
|
||||||
// do not add explicit type when initializer is not resolved, let user add it if really needed
|
// do not add explicit type when initializer is not resolved, let user add it if really needed
|
||||||
if (initializerType is ErrorType) return false
|
if (initializerType is ErrorType) return false
|
||||||
|
|
||||||
|
|||||||
@@ -566,15 +566,6 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
|||||||
val qualifier = expression.qualifierExpression
|
val qualifier = expression.qualifierExpression
|
||||||
|
|
||||||
var identifier = Identifier.withNoPrototype(referenceName, isNullable)
|
var identifier = Identifier.withNoPrototype(referenceName, isNullable)
|
||||||
|
|
||||||
|
|
||||||
expression.getContainingClass()?.getParentOfType<PsiVariable>(false)?.let {
|
|
||||||
if (it == expression.qualifierExpression?.reference?.resolve()) {
|
|
||||||
result = QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier, null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qualifier != null && qualifier.type is PsiArrayType && referenceName == "length") {
|
if (qualifier != null && qualifier.type is PsiArrayType && referenceName == "length") {
|
||||||
identifier = Identifier.withNoPrototype("size", isNullable)
|
identifier = Identifier.withNoPrototype("size", isNullable)
|
||||||
}
|
}
|
||||||
@@ -639,7 +630,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
|||||||
if (converter.shouldDeclareVariableType(target, converter.typeConverter.convertVariableType(target), canChangeType)) return false
|
if (converter.shouldDeclareVariableType(target, converter.typeConverter.convertVariableType(target), canChangeType)) return false
|
||||||
|
|
||||||
// if variable type won't be specified then check nullability of the initializer
|
// if variable type won't be specified then check nullability of the initializer
|
||||||
return codeConverter.convertExpression(target.initializer).isNullable
|
return converter.codeConverterForType.convertExpression(target.initializer).isNullable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSuperExpression(expression: PsiSuperExpression) {
|
override fun visitSuperExpression(expression: PsiSuperExpression) {
|
||||||
|
|||||||
@@ -15,3 +15,18 @@ public class Test2 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Handler {
|
||||||
|
public void postDelayed(Runnable r, long time) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test3 {
|
||||||
|
private Handler handler = new Handler();
|
||||||
|
|
||||||
|
private Runnable someRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
handler.postDelayed(someRunnable, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -13,3 +13,17 @@ class Test2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Handler {
|
||||||
|
fun postDelayed(r: Runnable, time: Long) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test3 {
|
||||||
|
private val handler = Handler()
|
||||||
|
|
||||||
|
private val someRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
handler.postDelayed(this, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user