New J2K: make post-processing aware of other files which are being converted

Before post-processing was able to handle only one converting file at once
So, some conversions (like (field, getter, setter) to Kotlin property)
was not able to work when converting class hierarchy was split into
multiple files.
Also, inferring nullability for a set of files was broken

#KT-19569 fixed
#KT-34266 fixed
#KT-32518 fixed
This commit is contained in:
Ilya Kirillov
2019-10-11 00:33:10 +03:00
parent 999918d499
commit b350515237
29 changed files with 498 additions and 165 deletions
@@ -32,8 +32,7 @@ import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.ConverterContext import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.PostProcessor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -61,11 +60,15 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
} }
override fun doAdditionalProcessing( override fun doAdditionalProcessing(
file: KtFile, target: JKPostProcessingTarget,
converterContext: ConverterContext?, converterContext: ConverterContext?,
rangeMarker: RangeMarker?,
onPhaseChanged: ((Int, String) -> Unit)? onPhaseChanged: ((Int, String) -> Unit)?
) = ) {
val (file, rangeMarker) = when (target) {
is JKPieceOfCodePostProcessingTarget -> target.file to target.rangeMarker
is JKMultipleFilesPostProcessingTarget -> target.files.single() to null
}
runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) {
do { do {
var modificationStamp: Long? = file.modificationStamp var modificationStamp: Long? = file.modificationStamp
@@ -109,7 +112,7 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
} }
} }
} }
}
private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean) private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean)
@@ -57,7 +57,6 @@ import org.jetbrains.kotlin.idea.util.isRunningInCidrIde
import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.UserDataProperty import org.jetbrains.kotlin.psi.UserDataProperty
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.util.* import java.util.*
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.j2k package org.jetbrains.kotlin.j2k
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
@@ -29,14 +30,19 @@ class AfterConversionPass(val project: Project, val postProcessor: PostProcessor
range: TextRange?, range: TextRange?,
onPhaseChanged: ((Int, String) -> Unit)? = null onPhaseChanged: ((Int, String) -> Unit)? = null
) { ) {
val rangeMarker = if (range != null) { postProcessor.doAdditionalProcessing(
val document = kotlinFile.viewProvider.document!! when {
val marker = runReadAction { document.createRangeMarker(range.startOffset, range.endOffset) } range != null -> JKPieceOfCodePostProcessingTarget(kotlinFile, range.toRangeMarker(kotlinFile))
marker.isGreedyToLeft = true else -> JKMultipleFilesPostProcessingTarget(listOf(kotlinFile))
marker.isGreedyToRight = true },
marker converterContext,
} else null onPhaseChanged
)
postProcessor.doAdditionalProcessing(kotlinFile, converterContext, rangeMarker, onPhaseChanged)
} }
} }
fun TextRange.toRangeMarker(file: KtFile): RangeMarker =
runReadAction { file.viewProvider.document!!.createRangeMarker(startOffset, endOffset) }.apply {
isGreedyToLeft = true
isGreedyToRight = true
}
@@ -26,12 +26,15 @@ import com.intellij.openapi.util.Computable
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.source.DummyHolder import com.intellij.psi.impl.source.DummyHolder
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ast.Element import org.jetbrains.kotlin.j2k.ast.Element
import org.jetbrains.kotlin.j2k.usageProcessing.ExternalCodeProcessor import org.jetbrains.kotlin.j2k.usageProcessing.ExternalCodeProcessor
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import java.util.* import java.util.*
@@ -43,13 +46,37 @@ interface PostProcessor {
val phasesCount: Int val phasesCount: Int
fun doAdditionalProcessing( fun doAdditionalProcessing(
file: KtFile, target: JKPostProcessingTarget,
converterContext: ConverterContext?, converterContext: ConverterContext?,
rangeMarker: RangeMarker?,
onPhaseChanged: ((Int, String) -> Unit)? onPhaseChanged: ((Int, String) -> Unit)?
) )
} }
sealed class JKPostProcessingTarget
data class JKPieceOfCodePostProcessingTarget(
val file: KtFile,
val rangeMarker: RangeMarker
) : JKPostProcessingTarget()
data class JKMultipleFilesPostProcessingTarget(
val files: List<KtFile>
) : JKPostProcessingTarget()
fun JKPostProcessingTarget.elements() = when (this) {
is JKPieceOfCodePostProcessingTarget -> runReadAction {
val range = rangeMarker.range ?: return@runReadAction emptyList()
file.elementsInRange(range)
}
is JKMultipleFilesPostProcessingTarget -> files
}
fun JKPostProcessingTarget.files() = when (this) {
is JKPieceOfCodePostProcessingTarget -> listOf(file)
is JKMultipleFilesPostProcessingTarget -> files
}
enum class ParseContext { enum class ParseContext {
TOP_LEVEL, TOP_LEVEL,
CODE_BLOCK CODE_BLOCK
@@ -270,7 +297,7 @@ interface WithProgressProcessor {
processItem: (TInputItem) -> TOutputItem processItem: (TInputItem) -> TOutputItem
): List<TOutputItem> ): List<TOutputItem>
fun updateState(fileIndex: Int, phase: Int, description: String) fun updateState(fileIndex: Int?, phase: Int, description: String)
fun <T> process(action: () -> T): T fun <T> process(action: () -> T): T
} }
@@ -318,7 +345,7 @@ class OldWithProgressProcessor(private val progress: ProgressIndicator?, private
throw AbstractMethodError("Should not be called for old J2K") throw AbstractMethodError("Should not be called for old J2K")
} }
override fun updateState(fileIndex: Int, phase: Int, description: String) { override fun updateState(fileIndex: Int?, phase: Int, description: String) {
throw AbstractMethodError("Should not be called for old J2K") throw AbstractMethodError("Should not be called for old J2K")
} }
} }
@@ -22,7 +22,9 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialSta
import org.jetbrains.kotlin.idea.quickfix.* import org.jetbrains.kotlin.idea.quickfix.*
import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.j2k.ConverterContext import org.jetbrains.kotlin.j2k.ConverterContext
import org.jetbrains.kotlin.j2k.JKPostProcessingTarget
import org.jetbrains.kotlin.j2k.PostProcessor import org.jetbrains.kotlin.j2k.PostProcessor
import org.jetbrains.kotlin.j2k.files
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
@@ -42,23 +44,23 @@ class NewJ2kPostProcessor : PostProcessor {
override val phasesCount = processings.size override val phasesCount = processings.size
override fun doAdditionalProcessing( override fun doAdditionalProcessing(
file: KtFile, target: JKPostProcessingTarget,
converterContext: ConverterContext?, converterContext: ConverterContext?,
rangeMarker: RangeMarker?,
onPhaseChanged: ((Int, String) -> Unit)? onPhaseChanged: ((Int, String) -> Unit)?
) { ) {
for ((i, group) in processings.withIndex()) { for ((i, group) in processings.withIndex()) {
onPhaseChanged?.invoke(i + 1, group.description) onPhaseChanged?.invoke(i + 1, group.description)
for (processing in group.processings) { for (processing in group.processings) {
try { try {
processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) processing.runProcessing(target, converterContext as NewJ2kConverterContext)
} catch (e: ProcessCanceledException) { } catch (e: ProcessCanceledException) {
throw e throw e
} catch (t: Throwable) { } catch (t: Throwable) {
LOG.error(t) LOG.error(t)
} finally { } finally {
commitFile(file) target.files().forEach(::commitFile)
} }
} }
} }
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.psi.KtElement
internal abstract class JKInMemoryFilesSearcher {
abstract fun search(element: KtElement): Iterable<PsiReference>
companion object {
fun create(files: List<PsiElement>) = when {
files.size == 1 -> JKSingleFileInMemoryFilesSearcher(files.single())
else -> JKMultipleFilesInMemoryFilesSearcher(files)
}
}
}
internal class JKSingleFileInMemoryFilesSearcher(private val scopeElement: PsiElement) : JKInMemoryFilesSearcher() {
override fun search(element: KtElement): Iterable<PsiReference> =
ReferencesSearch.search(element, LocalSearchScope(scopeElement))
}
// it does not cover all cases e.g, just-changed reference
// maybe the solution is to do searching manually
// firstly by-text and then resolving
internal class JKMultipleFilesInMemoryFilesSearcher(private val scopeElements: List<PsiElement>) : JKInMemoryFilesSearcher() {
override fun search(element: KtElement): Iterable<PsiReference> {
val result = mutableListOf<PsiReference>()
for (scopeElement in scopeElements) {
result += ReferencesSearch.search(element, LocalSearchScope(scopeElement))
}
return result
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
@@ -15,6 +16,7 @@ import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -23,7 +25,7 @@ import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<DiagnosticBasedProcessing>) : ProcessingGroup { class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<DiagnosticBasedProcessing>) : FileBasedPostProcessing() {
constructor(vararg diagnosticBasedProcessings: DiagnosticBasedProcessing) : this(diagnosticBasedProcessings.toList()) constructor(vararg diagnosticBasedProcessings: DiagnosticBasedProcessing) : this(diagnosticBasedProcessings.toList())
private val diagnosticToFix = private val diagnosticToFix =
@@ -33,8 +35,9 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<Diagno
list.map { it.second } list.map { it.second }
} }
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val diagnostics = runReadAction { analyzeFileRange(file, rangeMarker).all() } val resolutionFacade = runReadAction { KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(allFiles) }
val diagnostics = runReadAction { analyzeFileRange(file, rangeMarker, resolutionFacade).all() }
runUndoTransparentActionInEdt(inWriteAction = true) { runUndoTransparentActionInEdt(inWriteAction = true) {
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
val range = rangeMarker?.range ?: file.textRange val range = rangeMarker?.range ?: file.textRange
@@ -49,7 +52,7 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<Diagno
} }
} }
private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?): Diagnostics { private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?, resolutionFacade: ResolutionFacade): Diagnostics {
val elements = when { val elements = when {
rangeMarker == null -> listOf(file) rangeMarker == null -> listOf(file)
rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!).filterIsInstance<KtElement>() rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!).filterIsInstance<KtElement>()
@@ -57,7 +60,7 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<Diagno
} }
return if (elements.isNotEmpty()) return if (elements.isNotEmpty())
file.getResolutionFacade().analyzeWithAllCompilerChecks(elements).bindingContext.diagnostics resolutionFacade.analyzeWithAllCompilerChecks(elements).bindingContext.diagnostics
else Diagnostics.EMPTY else Diagnostics.EMPTY
} }
} }
@@ -18,15 +18,13 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.mapToIndex import org.jetbrains.kotlin.utils.mapToIndex
import java.util.* import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf
class InspectionLikeProcessingGroup( class InspectionLikeProcessingGroup(
private val runSingleTime: Boolean = false, private val runSingleTime: Boolean = false,
private val acceptNonKtElements: Boolean = false, private val acceptNonKtElements: Boolean = false,
private val processings: List<InspectionLikeProcessing> private val processings: List<InspectionLikeProcessing>
) : ProcessingGroup { ) : FileBasedPostProcessing() {
constructor(vararg processings: InspectionLikeProcessing) : this( constructor(vararg processings: InspectionLikeProcessing) : this(
runSingleTime = false, runSingleTime = false,
acceptNonKtElements = false, acceptNonKtElements = false,
@@ -35,8 +33,7 @@ class InspectionLikeProcessingGroup(
private val processingsToPriorityMap = processings.mapToIndex() private val processingsToPriorityMap = processings.mapToIndex()
fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing) fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing)
override fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
do { do {
var modificationStamp: Long? = file.modificationStamp var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction { val elementToActions = runReadAction {
@@ -7,27 +7,35 @@ package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.j2k.JKMultipleFilesPostProcessingTarget
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.j2k.JKPieceOfCodePostProcessingTarget
import org.jetbrains.kotlin.j2k.JKPostProcessingTarget
import org.jetbrains.kotlin.j2k.elements
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
interface GeneralPostProcessing { interface GeneralPostProcessing {
fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext)
} }
abstract class FileBasedPostProcessing : GeneralPostProcessing {
final override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) = when (target) {
is JKPieceOfCodePostProcessingTarget ->
runProcessing(target.file, listOf(target.file), target.rangeMarker, converterContext)
is JKMultipleFilesPostProcessingTarget ->
target.files.forEach { file ->
runProcessing(file, target.files, rangeMarker = null, converterContext = converterContext)
}
}
abstract fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext)
}
abstract class ElementsBasedPostProcessing : GeneralPostProcessing { abstract class ElementsBasedPostProcessing : GeneralPostProcessing {
final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { final override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) {
val elements = runReadAction { runProcessing(target.elements(), converterContext)
rangeMarker?.let { marker ->
val range = marker.range ?: return@let emptyList()
file.elementsInRange(range)
} ?: listOf(file)
}
runProcessing(elements, converterContext)
} }
abstract fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) abstract fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext)
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.OverridingMethodsSearch import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.rename.RenamePsiElementProcessor import com.intellij.refactoring.rename.RenamePsiElementProcessor
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -22,17 +22,21 @@ import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.readWriteAccess import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.nj2k.* import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asGetterName
import org.jetbrains.kotlin.nj2k.asSetterName
import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFakeFieldData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFakeFieldData
import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFieldData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFieldData
import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKMethodData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKMethodData
import org.jetbrains.kotlin.nj2k.externalCodeProcessing.NewExternalCodeProcessing import org.jetbrains.kotlin.nj2k.externalCodeProcessing.NewExternalCodeProcessing
import org.jetbrains.kotlin.nj2k.fqNameWithoutCompanions
import org.jetbrains.kotlin.nj2k.postProcessing.* import org.jetbrains.kotlin.nj2k.postProcessing.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
@@ -51,16 +55,59 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.mapToIndex import org.jetbrains.kotlin.utils.mapToIndex
class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing() { class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing() {
override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) {
val ktElements = elements.filterIsInstance<KtElement>()
val resolutionFacade = runReadAction {
KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(ktElements)
}
ConvertGettersAndSettersToPropertyStatefulProcessing(
resolutionFacade,
ktElements,
converterContext.externalCodeProcessor
).runProcessing()
}
}
private class ConvertGettersAndSettersToPropertyStatefulProcessing(
private val resolutionFacade: ResolutionFacade,
private val elements: List<KtElement>,
private val externalCodeUpdater: NewExternalCodeProcessing
) {
private val searcher = JKInMemoryFilesSearcher.create(elements)
fun runProcessing() {
val collectingState = CollectingState()
val classesWithPropertiesData = runReadAction {
elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
.map { klass ->
klass to klass.collectPropertiesData(collectingState)
}
}
if (classesWithPropertiesData.isEmpty()) return
runUndoTransparentActionInEdt(inWriteAction = true) {
for ((klass, propertiesData) in classesWithPropertiesData) {
convertClass(klass, propertiesData)
}
}
}
private fun KtNamedFunction.hasOverrides(): Boolean = private fun KtNamedFunction.hasOverrides(): Boolean =
toLightMethods().singleOrNull()?.let { lightMethod -> toLightMethods().singleOrNull()?.let { lightMethod ->
OverridingMethodsSearch.search(lightMethod).findFirst() if (OverridingMethodsSearch.search(lightMethod).findFirst() != null) return@let true
} != null if (elements.size == 1) return@let false
elements.any { element ->
OverridingMethodsSearch.search(lightMethod, LocalSearchScope(element), true).findFirst() != null
}
} == true
private fun KtNamedFunction.hasSuperFunction(): Boolean = private fun KtNamedFunction.hasSuperFunction(): Boolean =
resolveToDescriptorIfAny()?.original?.overriddenDescriptors?.isNotEmpty() == true resolveToDescriptorIfAny(resolutionFacade)?.original?.overriddenDescriptors?.isNotEmpty() == true
private fun KtNamedFunction.hasInvalidSuperDescriptors(): Boolean = private fun KtNamedFunction.hasInvalidSuperDescriptors(): Boolean =
resolveToDescriptorIfAny() resolveToDescriptorIfAny(resolutionFacade)
?.original ?.original
?.overriddenDescriptors ?.overriddenDescriptors
?.any { it.isJavaDescriptor || it is FunctionDescriptor } == true ?.any { it.isJavaDescriptor || it is FunctionDescriptor } == true
@@ -216,7 +263,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
} }
private fun KtElement.usages() = private fun KtElement.usages() =
ReferencesSearch.search(this, LocalSearchScope(containingKtFile)) searcher.search(this)
private fun <T : KtExpression> T.withReplacedExpressionInBody( private fun <T : KtExpression> T.withReplacedExpressionInBody(
from: KtElement, from: KtElement,
@@ -249,7 +296,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
val sorted = mutableListOf<KtClassOrObject>() val sorted = mutableListOf<KtClassOrObject>()
val visited = Array(size) { false } val visited = Array(size) { false }
val descriptors = map { it.resolveToDescriptorIfAny()!! } val descriptors = map { it.resolveToDescriptorIfAny(resolutionFacade)!! }
val descriptorToIndex = descriptors.mapToIndex() val descriptorToIndex = descriptors.mapToIndex()
val outers = descriptors.map { descriptor -> val outers = descriptors.map { descriptor ->
descriptor.superClassAndSuperInterfaces().mapNotNull { descriptorToIndex[it] } descriptor.superClassAndSuperInterfaces().mapNotNull { descriptorToIndex[it] }
@@ -273,25 +320,6 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
return sorted return sorted
} }
override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) {
val collectingState = CollectingState()
val classesWithPropertiesData = runReadAction {
elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
.map { klass ->
klass to klass.collectPropertiesData(collectingState)
}
}
if (classesWithPropertiesData.isEmpty()) return
runUndoTransparentActionInEdt(inWriteAction = true) {
for ((klass, propertiesData) in classesWithPropertiesData) {
convertClass(klass, propertiesData, converterContext.externalCodeProcessor)
}
}
}
private fun causesNameConflictInCurrentDeclarationAndItsParents(name: String, declaration: DeclarationDescriptor?): Boolean = private fun causesNameConflictInCurrentDeclarationAndItsParents(name: String, declaration: DeclarationDescriptor?): Boolean =
when (declaration) { when (declaration) {
is ClassDescriptor -> { is ClassDescriptor -> {
@@ -310,27 +338,11 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
} }
private fun calculatePropertyType(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? { private fun calculatePropertyType(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? {
val getterType = getter?.resolveToDescriptorIfAny()?.returnType val getterType = getter?.resolveToDescriptorIfAny(resolutionFacade)?.returnType
val setterType = setter?.resolveToDescriptorIfAny()?.valueParameters?.singleOrNull()?.type val setterType = setter?.resolveToDescriptorIfAny(resolutionFacade)?.valueParameters?.singleOrNull()?.type
return calculatePropertyType(getterType, setterType) return calculatePropertyType(getterType, setterType)
} }
private fun calculatePropertyTypeBasedOnSuperDescriptors(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? {
val superGetterType = getter
?.resolveToDescriptorIfAny()
?.overriddenDescriptors
?.firstOrNull()
?.returnType
val superSetterType = setter
?.resolveToDescriptorIfAny()
?.overriddenDescriptors
?.firstOrNull()
?.valueParameters
?.singleOrNull()
?.type
return calculatePropertyType(superGetterType, superSetterType)
}
private fun KtClassOrObject.collectPropertiesData(collectingState: CollectingState): List<PropertyData> { private fun KtClassOrObject.collectPropertiesData(collectingState: CollectingState): List<PropertyData> {
return declarations return declarations
.asSequence() .asSequence()
@@ -356,7 +368,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
val name = realGetter?.name ?: realSetter?.name!! val name = realGetter?.name ?: realSetter?.name!!
val superDeclarationOwner = (realGetter?.function ?: realSetter?.function) val superDeclarationOwner = (realGetter?.function ?: realSetter?.function)
?.resolveToDescriptorIfAny() ?.resolveToDescriptorIfAny(resolutionFacade)
?.overriddenDescriptors ?.overriddenDescriptors
?.firstOrNull() ?.firstOrNull()
?.findPsi() ?.findPsi()
@@ -378,7 +390,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
klass: KtClassOrObject, klass: KtClassOrObject,
factory: KtPsiFactory factory: KtPsiFactory
): List<PropertyWithAccessors> { ): List<PropertyWithAccessors> {
val classDescriptor = klass.resolveToDescriptorIfAny() ?: return emptyList() val classDescriptor = klass.resolveToDescriptorIfAny(resolutionFacade) ?: return emptyList()
val variablesDescriptorsMap = val variablesDescriptorsMap =
(listOfNotNull(classDescriptor.getSuperClassNotAny()) + classDescriptor.getSuperInterfaces()) (listOfNotNull(classDescriptor.getSuperClassNotAny()) + classDescriptor.getSuperInterfaces())
@@ -462,7 +474,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
val getter = realGetter ?: when { val getter = realGetter ?: when {
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any { realProperty?.property?.resolveToDescriptorIfAny(resolutionFacade)?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true it.safeAs<VariableDescriptor>()?.isVar == true
} == true -> FakeGetter(name, null, "") } == true -> FakeGetter(name, null, "")
@@ -487,7 +499,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
realProperty?.property?.isVar == true -> realProperty?.property?.isVar == true ->
FakeSetter(name, null, "") FakeSetter(name, null, "")
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any { realProperty?.property?.resolveToDescriptorIfAny(resolutionFacade)?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true it.safeAs<VariableDescriptor>()?.isVar == true
} == true } == true
|| variablesDescriptorsMap[name]?.isVar == true -> || variablesDescriptorsMap[name]?.isVar == true ->
@@ -523,7 +535,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
} }
private fun KtProperty.renameTo(newName: String, factory: KtPsiFactory) { private fun KtProperty.renameTo(newName: String, factory: KtPsiFactory) {
for (usage in usages().toList()) { for (usage in usages()) {
val element = usage.element val element = usage.element
val isBackingField = element is KtNameReferenceExpression val isBackingField = element is KtNameReferenceExpression
&& element.text == KtTokens.FIELD_KEYWORD.value && element.text == KtTokens.FIELD_KEYWORD.value
@@ -540,8 +552,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
private fun convertClass( private fun convertClass(
klass: KtClassOrObject, klass: KtClassOrObject,
propertiesData: List<PropertyData>, propertiesData: List<PropertyData>
externalCodeUpdater: NewExternalCodeProcessing
) { ) {
val factory = KtPsiFactory(klass) val factory = KtPsiFactory(klass)
val accessors = propertiesData.filterGettersAndSetters(klass, factory) val accessors = propertiesData.filterGettersAndSetters(klass, factory)
@@ -5,9 +5,8 @@
package org.jetbrains.kotlin.nj2k.postProcessing.processings package org.jetbrains.kotlin.nj2k.postProcessing.processings
import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
@@ -20,19 +19,16 @@ import org.jetbrains.kotlin.nj2k.inference.common.collectors.CommonConstraintsCo
import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector
import org.jetbrains.kotlin.nj2k.inference.mutability.* import org.jetbrains.kotlin.nj2k.inference.mutability.*
import org.jetbrains.kotlin.nj2k.inference.nullability.* import org.jetbrains.kotlin.nj2k.inference.nullability.*
import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.ElementsBasedPostProcessing
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
abstract class InferenceProcessing : GeneralPostProcessing { abstract class InferenceProcessing : ElementsBasedPostProcessing() {
final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) {
val elements = if (rangeMarker != null) { val kotlinElements = elements.filterIsInstance<KtElement>()
val range = rangeMarker.range ?: return val resolutionFacade = runReadAction {
runReadAction { file.elementsInRange(range) }.filterIsInstance<KtElement>() KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(kotlinElements)
} else listOf(file) }
val resolutionFacade = runReadAction { file.getResolutionFacade() } createInferenceFacade(resolutionFacade, converterContext).runOn(kotlinElements)
createInferenceFacade(resolutionFacade, converterContext).runOn(elements)
} }
abstract fun createInferenceFacade( abstract fun createInferenceFacade(
@@ -10,12 +10,13 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.nj2k.JKImportStorage import org.jetbrains.kotlin.nj2k.JKImportStorage
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.postProcessing.FileBasedPostProcessing
import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing
import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtQualifiedExpression import org.jetbrains.kotlin.psi.KtQualifiedExpression
class ShortenReferenceProcessing : GeneralPostProcessing { class ShortenReferenceProcessing : FileBasedPostProcessing() {
private val filter = filter@{ element: PsiElement -> private val filter = filter@{ element: PsiElement ->
when (element) { when (element) {
is KtQualifiedExpression -> when { is KtQualifiedExpression -> when {
@@ -26,7 +27,7 @@ class ShortenReferenceProcessing : GeneralPostProcessing {
} }
} }
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
runUndoTransparentActionInEdt(inWriteAction = false) { runUndoTransparentActionInEdt(inWriteAction = false) {
if (rangeMarker != null) { if (rangeMarker != null) {
if (rangeMarker.isValid) { if (rangeMarker.isValid) {
@@ -13,16 +13,19 @@ import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.JKPostProcessingTarget
import org.jetbrains.kotlin.j2k.elements
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asLabel import org.jetbrains.kotlin.nj2k.asLabel
import org.jetbrains.kotlin.nj2k.postProcessing.FileBasedPostProcessing
import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing
import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
class FormatCodeProcessing : GeneralPostProcessing { class FormatCodeProcessing : FileBasedPostProcessing() {
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val codeStyleManager = CodeStyleManager.getInstance(file.project) val codeStyleManager = CodeStyleManager.getInstance(file.project)
runUndoTransparentActionInEdt(inWriteAction = true) { runUndoTransparentActionInEdt(inWriteAction = true) {
if (rangeMarker != null) { if (rangeMarker != null) {
@@ -38,28 +41,30 @@ class FormatCodeProcessing : GeneralPostProcessing {
class ClearUnknownLabelsProcessing : GeneralPostProcessing { class ClearUnknownLabelsProcessing : GeneralPostProcessing {
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) {
val comments = mutableListOf<PsiComment>() val comments = mutableListOf<PsiComment>()
runUndoTransparentActionInEdt(inWriteAction = true) { runUndoTransparentActionInEdt(inWriteAction = true) {
file.accept(object : PsiElementVisitor() { target.elements().forEach { element ->
override fun visitElement(element: PsiElement) { element.accept(object : PsiElementVisitor() {
element.acceptChildren(this) override fun visitElement(element: PsiElement) {
} element.acceptChildren(this)
override fun visitComment(comment: PsiComment) {
if (comment.text.asLabel() != null) {
comments += comment
} }
}
}) override fun visitComment(comment: PsiComment) {
if (comment.text.asLabel() != null) {
comments += comment
}
}
})
}
comments.forEach { it.delete() } comments.forEach { it.delete() }
} }
} }
} }
class OptimizeImportsProcessing : GeneralPostProcessing { class OptimizeImportsProcessing : FileBasedPostProcessing() {
override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, allFiles: List<KtFile>, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val elements = runReadAction { val elements = runReadAction {
when { when {
rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!) rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!)
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.nj2k package org.jetbrains.kotlin.nj2k
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@@ -28,7 +26,6 @@ import com.intellij.openapi.util.Computable
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.nj2k.conversions.JKResolver import org.jetbrains.kotlin.nj2k.conversions.JKResolver
@@ -68,36 +65,27 @@ class NewJavaToKotlinConverter(
elementsToKotlin(files, withProgressProcessor) elementsToKotlin(files, withProgressProcessor)
}) })
val texts = results.mapIndexed { i, result -> val kotlinFiles = results.mapIndexed { i, result ->
try { runUndoTransparentActionInEdt(inWriteAction = true) {
val kotlinFile = ApplicationManager.getApplication().runReadAction(Computable { val javaFile = files[i]
KtPsiFactory(project).createFileWithLightClassSupport("dummy.kt", result!!.text, files[i]) KtPsiFactory(project).createFileWithLightClassSupport(
}) javaFile.name.replace(".java", ".kt"),
result!!.text,
ApplicationManager.getApplication().invokeAndWait { files[i]
CommandProcessor.getInstance().runUndoTransparentAction { ).apply {
runWriteAction { addImports(result.importsToAdd)
kotlinFile.addImports(result!!.importsToAdd)
}
}
} }
AfterConversionPass(project, postProcessor).run(
kotlinFile,
context,
range = null,
onPhaseChanged = { phase, description ->
withProgressProcessor.updateState(i, phase + 1, description)
}
)
kotlinFile.text
} catch (e: ProcessCanceledException) {
throw e
} catch (t: Throwable) {
LOG.error(t)
result!!.text
} }
} }
FilesResult(texts, externalCodeProcessing)
postProcessor.doAdditionalProcessing(
JKMultipleFilesPostProcessingTarget(kotlinFiles),
context
) { phase, description ->
withProgressProcessor.updateState(fileIndex = null, phase = phase + 1, description = description)
}
FilesResult(kotlinFiles.map { it.text }, externalCodeProcessing)
} }
} }
@@ -217,12 +205,13 @@ class NewJ2kWithProgressProcessor(
val DEFAULT = NewJ2kWithProgressProcessor(null, null, 0) val DEFAULT = NewJ2kWithProgressProcessor(null, null, 0)
} }
override fun updateState(fileIndex: Int, phase: Int, description: String) { override fun updateState(fileIndex: Int?, phase: Int, description: String) {
progress?.checkCanceled() progress?.checkCanceled()
progress?.fraction = phase / phasesCount.toDouble() progress?.fraction = phase / phasesCount.toDouble()
progress?.text = "$description - phase $phase of $phasesCount" progress?.text = "$description - phase $phase of $phasesCount"
if (files != null && files.isNotEmpty()) { progress?.text2 = when {
progress?.text2 = files[fileIndex].virtualFile.presentableUrl files != null && files.isNotEmpty() && fileIndex != null -> files[fileIndex].virtualFile.presentableUrl
else -> ""
} }
} }
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.nj2k
import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature
import com.intellij.lang.jvm.JvmClassKind import com.intellij.lang.jvm.JvmClassKind
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.InheritanceUtil
import com.intellij.psi.util.MethodSignatureUtil import com.intellij.psi.util.MethodSignatureUtil
import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.ClassKind import org.jetbrains.kotlin.j2k.ClassKind
import org.jetbrains.kotlin.j2k.ReferenceSearcher import org.jetbrains.kotlin.j2k.ReferenceSearcher
import org.jetbrains.kotlin.j2k.isNullLiteral import org.jetbrains.kotlin.j2k.isNullLiteral
@@ -141,3 +144,16 @@ val KtDeclaration.fqNameWithoutCompanions
.filter { it.safeAs<KtObjectDeclaration>()?.isCompanion() != true && it.name != null } .filter { it.safeAs<KtObjectDeclaration>()?.isCompanion() != true && it.name != null }
.toList() .toList()
.foldRight(containingKtFile.packageFqName) { container, acc -> acc.child(Name.identifier(container.name!!)) } .foldRight(containingKtFile.packageFqName) { container, acc -> acc.child(Name.identifier(container.name!!)) }
internal fun <T> runUndoTransparentActionInEdt(inWriteAction: Boolean, action: () -> T): T {
var result: T? = null
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
result = when {
inWriteAction -> runWriteAction(action)
else -> action()
}
}
}
return result!!
}
@@ -0,0 +1,31 @@
package test;
public class B {
public String getFromB1() {
return "";
}
public String getFromB2() {
return "";
}
public void setFromB2(String value) {
}
public String getFromB3() {
return "";
}
public void setFromB3(String value) {
}
public String getFromB4() {
return "";
}
public void setFromB4(String value) {
}
public void setFromB5(String value) {
}
}
@@ -0,0 +1,20 @@
package test
open class B {
val fromB1: String
get() = ""
var fromB2: String?
get() = ""
set(value) {}
var fromB3: String?
get() = ""
set(value) {}
var fromB4: String?
get() = ""
set(value) {}
open fun setFromB5(value: String?) {}
}
@@ -0,0 +1,57 @@
package test;
public abstract class C extends B implements I {
private final int mySomething1;
private int mySomething6;
C(int something1) {
mySomething1 = something1;
}
@Override
public int getSomething1() {
return mySomething1;
}
@Override
public int getSomething2() {
return 0;
}
@Override
public int getSomething3() {
return 0;
}
@Override
public void setSomething3(int value) {
}
@Override
public int getSomething4() {
return 0;
}
@Override
public void setSomething5(int value) {
}
public int getSomething6() {
return mySomething6;
}
@Override
public void setSomething6(int value) {
mySomething6 = value;
}
public String getFromB5() {
return "";
}
@Override
public void setFromB5(String value) {
super.setFromB5(value);
}
}
@@ -0,0 +1,34 @@
package test
abstract class C internal constructor(override val something1: Int) : B(), I {
private var mySomething6 = 0
override val something2: Int
get() = 0
override var something3: Int
get() = 0
set(value) {}
override fun getSomething4(): Int {
return 0
}
override fun setSomething5(value: Int) {}
fun getSomething6(): Int {
return mySomething6
}
override fun setSomething6(value: Int) {
mySomething6 = value
}
fun getFromB5(): String {
return ""
}
override fun setFromB5(value: String?) {
super.setFromB5(value)
}
}
@@ -0,0 +1,21 @@
package test;
public interface I {
int getSomething1();
int getSomething2();
int getSomething3();
void setSomething3(int value);
int getSomething4();
void setSomething4(int value);
int getSomething5();
void setSomething5(int value);
void setSomething6(int value);
}
@@ -0,0 +1,13 @@
package test
interface I {
val something1: Int
val something2: Int
var something3: Int
fun getSomething4(): Int
fun setSomething4(value: Int)
fun getSomething5(): Int
fun setSomething5(value: Int)
fun setSomething6(value: Int)
}
@@ -0,0 +1,7 @@
package test;
public interface I1 extends I {
void setSomething1(int value);
int getSomething6();
}
@@ -0,0 +1,6 @@
package test
interface I1 : I {
fun setSomething1(value: Int)
val something6: Int
}
@@ -0,0 +1,5 @@
package test;
public interface IUser {
String getName();
}
@@ -0,0 +1,5 @@
package test
interface IUser {
val name: String
}
@@ -0,0 +1,14 @@
package test;
public class UserImpl implements IUser {
private final String name;
public UserImpl(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
@@ -0,0 +1,3 @@
package test
class UserImpl(override val name: String) : IUser
@@ -28,9 +28,11 @@ abstract class AbstractNewJavaToKotlinConverterMultiFileTest : AbstractJavaToKot
psiManager.findFile(virtualFile) as PsiJavaFile psiManager.findFile(virtualFile) as PsiJavaFile
} }
val externalFiles = File(dirPath + File.separator + "external").listFiles { _, name -> val externalFiles = File(dirPath + File.separator + "external")
name.endsWith(".java") || name.endsWith(".kt") .takeIf { it.exists() }
}!! ?.listFiles { _, name ->
name.endsWith(".java") || name.endsWith(".kt")
}.orEmpty()
val externalPsiFiles = externalFiles.map { file -> val externalPsiFiles = externalFiles.map { file ->
val virtualFile = addFile(file, "test") val virtualFile = addFile(file, "test")
@@ -34,6 +34,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ
runTest("nj2k/testData/multiFile/AnnotationWithArrayParameter/"); runTest("nj2k/testData/multiFile/AnnotationWithArrayParameter/");
} }
@TestMetadata("DetectPropertiesMultipleFiles")
public void testDetectPropertiesMultipleFiles() throws Exception {
runTest("nj2k/testData/multiFile/DetectPropertiesMultipleFiles/");
}
@TestMetadata("FieldToProperty") @TestMetadata("FieldToProperty")
public void testFieldToProperty() throws Exception { public void testFieldToProperty() throws Exception {
runTest("nj2k/testData/multiFile/FieldToProperty/"); runTest("nj2k/testData/multiFile/FieldToProperty/");
@@ -49,6 +54,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ
runTest("nj2k/testData/multiFile/GetterAndSetterUsages/"); runTest("nj2k/testData/multiFile/GetterAndSetterUsages/");
} }
@TestMetadata("InterfaceWithGetterInOtherFile")
public void testInterfaceWithGetterInOtherFile() throws Exception {
runTest("nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/");
}
@TestMetadata("KT11952") @TestMetadata("KT11952")
public void testKT11952() throws Exception { public void testKT11952() throws Exception {
runTest("nj2k/testData/multiFile/KT11952/"); runTest("nj2k/testData/multiFile/KT11952/");