Got rid of conversionScope parameter for JavaToKotlinConverter

This commit is contained in:
Valentin Kipyatkov
2015-04-02 20:14:21 +03:00
parent 751f952536
commit 0ed7d228f6
8 changed files with 70 additions and 58 deletions
@@ -36,7 +36,6 @@ import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.FilesConversionScope
import org.jetbrains.kotlin.j2k.IdeaReferenceSearcher import org.jetbrains.kotlin.j2k.IdeaReferenceSearcher
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetFile
@@ -51,7 +50,7 @@ public class JavaToKotlinAction : AnAction() {
var convertedTexts: List<String>? = null var convertedTexts: List<String>? = null
fun convert() { fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(javaFiles), IdeaReferenceSearcher, IdeaResolverForConverter) val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaReferenceSearcher, IdeaResolverForConverter)
convertedTexts = converter.elementsToKotlin(javaFiles.map { it to J2kPostProcessor(it, formatCode = true) }, convertedTexts = converter.elementsToKotlin(javaFiles.map { it to J2kPostProcessor(it, formatCode = true) },
ProgressManager.getInstance().getProgressIndicator()) ProgressManager.getInstance().getProgressIndicator())
} }
@@ -18,25 +18,28 @@ package org.jetbrains.kotlin.idea.conversion.copy
import com.intellij.codeInsight.editorActions.CopyPastePostProcessor import com.intellij.codeInsight.editorActions.CopyPastePostProcessor
import com.intellij.codeInsight.editorActions.TextBlockTransferableData import com.intellij.codeInsight.editorActions.TextBlockTransferableData
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.idea.editor.JetEditorOptions
import java.awt.datatransfer.Transferable
import com.intellij.openapi.util.TextRange
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.lang.java.JavaLanguage import org.jetbrains.kotlin.idea.editor.JetEditorOptions
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter
import com.intellij.openapi.project.DumbService import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.IdeaReferenceSearcher
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import java.awt.datatransfer.Transferable
import java.util.ArrayList
public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBlockTransferableData>() { public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBlockTransferableData>() {
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.conversion.copy.ConvertJavaCopyPastePostProcessor") private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.conversion.copy.ConvertJavaCopyPastePostProcessor")
@@ -90,34 +93,55 @@ public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBloc
} }
private fun convertCopiedCodeToKotlin(code: CopiedCode, sourceFile: PsiJavaFile, sourceFileText: String, targetFile: JetFile): String { private fun convertCopiedCodeToKotlin(code: CopiedCode, sourceFile: PsiJavaFile, sourceFileText: String, targetFile: JetFile): String {
assert(code.startOffsets.size() == code.endOffsets.size(), "Must have the same size")
val list = ArrayList<Any>()
for (i in code.startOffsets.indices) {
list.collectElementsToConvert(sourceFile, sourceFileText, TextRange(code.startOffsets[i], code.endOffsets[i]))
}
val converter = JavaToKotlinConverter( val converter = JavaToKotlinConverter(
sourceFile.getProject(), sourceFile.getProject(),
ConverterSettings.defaultSettings, ConverterSettings.defaultSettings,
FilesConversionScope(listOf(sourceFile)),
IdeaReferenceSearcher, IdeaReferenceSearcher,
IdeaResolverForConverter IdeaResolverForConverter
) )
assert(code.startOffsets.size() == code.endOffsets.size(), "Must have the same size")
val builder = StringBuilder() val results = converter.elementsToKotlin(list.filterIsInstance<PsiElement>().map { it to J2kPostProcessor(targetFile, formatCode = false) })
for (i in code.startOffsets.indices) {
val textRange = TextRange(code.startOffsets[i], code.endOffsets[i]) var resultIndex = 0
builder.append(convertRangeToKotlin(sourceFile, sourceFileText, targetFile, textRange, converter)) val text = StringBuilder {
} for (o in list) {
return StringUtil.convertLineSeparators(builder.toString()) if (o is PsiElement) {
val result = results[resultIndex++]
if (!result.isEmpty()) {
append(result)
}
else { // failed to convert element to Kotlin, insert "as is"
append(o.getText())
}
}
else {
append(o as String)
}
}
}.toString()
return StringUtil.convertLineSeparators(text)
} }
private fun convertRangeToKotlin(file: PsiJavaFile, // builds list consisting of PsiElement's to convert and plain String's
fileText: String, private fun MutableList<Any>.collectElementsToConvert(
targetFile: JetFile, file: PsiJavaFile,
range: TextRange, fileText: String,
converter: JavaToKotlinConverter): String { range: TextRange
val builder = StringBuilder() ) {
var currentRange = range var currentRange = range
while (!currentRange.isEmpty()) { while (!currentRange.isEmpty()) {
val leaf = findFirstLeafWhollyInRange(file, currentRange) val leaf = findFirstLeafWhollyInRange(file, currentRange)
if (leaf == null) { if (leaf == null) {
val unconvertedSuffix = fileText.substring(currentRange.start, currentRange.end) val unconvertedSuffix = fileText.substring(currentRange.start, currentRange.end)
builder.append(unconvertedSuffix) add(unconvertedSuffix)
break break
} }
@@ -130,19 +154,12 @@ public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBloc
val elementToConvertRange = elementToConvert.range val elementToConvertRange = elementToConvert.range
val unconvertedPrefix = fileText.substring(currentRange.start, elementToConvertRange.start) val unconvertedPrefix = fileText.substring(currentRange.start, elementToConvertRange.start)
builder.append(unconvertedPrefix) add(unconvertedPrefix)
val converted = converter.elementsToKotlin(listOf(elementToConvert to J2kPostProcessor(targetFile, formatCode = false))).single() add(elementToConvert)
if (!converted.isEmpty()) {
builder.append(converted)
}
else {
builder.append(fileText.substring(elementToConvertRange.start, elementToConvertRange.end))
}
currentRange = TextRange(elementToConvertRange.end, currentRange.end) currentRange = TextRange(elementToConvertRange.end, currentRange.end)
} }
return builder.toString()
} }
private fun findFirstLeafWhollyInRange(file: PsiJavaFile, range: TextRange): PsiElement? { private fun findFirstLeafWhollyInRange(file: PsiJavaFile, range: TextRange): PsiElement? {
@@ -35,7 +35,7 @@ import java.util.ArrayList
class Converter private( class Converter private(
private val elementToConvert: PsiElement, private val elementToConvert: PsiElement,
val settings: ConverterSettings, val settings: ConverterSettings,
val conversionScope: ConversionScope, val inConversionScope: (PsiElement) -> Boolean,
val referenceSearcher: ReferenceSearcher, val referenceSearcher: ReferenceSearcher,
val resolverForConverter: ResolverForConverter, val resolverForConverter: ResolverForConverter,
private val postProcessor: PostProcessor?, private val postProcessor: PostProcessor?,
@@ -59,17 +59,17 @@ class Converter private(
public val specialContext: PsiElement? = personalState.specialContext public val specialContext: PsiElement? = personalState.specialContext
companion object { companion object {
public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope, public fun create(elementToConvert: PsiElement, settings: ConverterSettings, inConversionScope: (PsiElement) -> Boolean,
referenceSearcher: ReferenceSearcher, resolverForConverter: ResolverForConverter, postProcessor: PostProcessor?, referenceSearcher: ReferenceSearcher, resolverForConverter: ResolverForConverter, postProcessor: PostProcessor?,
usageProcessingsCollector: (UsageProcessing) -> Unit): Converter { usageProcessingsCollector: (UsageProcessing) -> Unit): Converter {
return Converter(elementToConvert, settings, conversionScope, referenceSearcher, resolverForConverter, postProcessor, CommonState(usageProcessingsCollector), PersonalState(null)) return Converter(elementToConvert, settings, inConversionScope, referenceSearcher, resolverForConverter, postProcessor, CommonState(usageProcessingsCollector), PersonalState(null))
} }
} }
public fun withSpecialContext(context: PsiElement): Converter = withState(PersonalState(context)) public fun withSpecialContext(context: PsiElement): Converter = withState(PersonalState(context))
private fun withState(state: PersonalState): Converter private fun withState(state: PersonalState): Converter
= Converter(elementToConvert, settings, conversionScope, referenceSearcher, resolverForConverter, postProcessor, commonState, state) = Converter(elementToConvert, settings, inConversionScope, referenceSearcher, resolverForConverter, postProcessor, commonState, state)
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null) private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
@@ -227,7 +227,7 @@ class Converter private(
val parameters = annotationMethods val parameters = annotationMethods
.map { method -> .map { method ->
val returnType = method.getReturnType() val returnType = method.getReturnType()
val typeConverted = if (method == annotationMethods.last && returnType is PsiArrayType) val typeConverted = if (method == annotationMethods.last() && returnType is PsiArrayType)
VarArgType(typeConverter.convertType(returnType.getComponentType(), Nullability.NotNull)) VarArgType(typeConverter.convertType(returnType.getComponentType(), Nullability.NotNull))
else else
typeConverter.convertType(returnType, Nullability.NotNull) typeConverter.convertType(returnType, Nullability.NotNull)
@@ -377,7 +377,7 @@ class Converter private(
var params = convertParameterList(method.getParameterList()) var params = convertParameterList(method.getParameterList())
val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
var body = deferredElement { (codeConverter: CodeConverter) -> var body = deferredElement { codeConverter: CodeConverter ->
val body = codeConverter.withMethodReturnType(method.getReturnType()).convertBlock(method.getBody()) val body = codeConverter.withMethodReturnType(method.getReturnType()).convertBlock(method.getBody())
postProcessBody(body) postProcessBody(body)
} }
@@ -410,8 +410,8 @@ class Converter private(
if (containing != null) { if (containing != null) {
val hasOtherJavaSuperclasses = containing.getSuperTypes().any { val hasOtherJavaSuperclasses = containing.getSuperTypes().any {
//TODO: correctly check for kotlin class //TODO: correctly check for kotlin class
val `class` = it.resolve() val klass = it.resolve()
`class` != null && `class`.getQualifiedName() != JAVA_LANG_OBJECT && !conversionScope.contains(`class`) klass != null && klass.getQualifiedName() != JAVA_LANG_OBJECT && !inConversionScope(klass)
} }
if (hasOtherJavaSuperclasses) return true if (hasOtherJavaSuperclasses) return true
} }
@@ -30,18 +30,11 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.j2k.ast.Element import org.jetbrains.kotlin.j2k.ast.Element
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import java.util.ArrayList import java.util.ArrayList
import java.util.HashMap import java.util.HashMap
public trait ConversionScope {
public fun contains(element: PsiElement): Boolean
}
public class FilesConversionScope(val files: Collection<PsiJavaFile>) : ConversionScope {
override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it }
}
public trait PostProcessor { public trait PostProcessor {
public val contextToAnalyzeIn: PsiElement public val contextToAnalyzeIn: PsiElement
public fun analyzeFile(file: JetFile): BindingContext public fun analyzeFile(file: JetFile): BindingContext
@@ -72,7 +65,6 @@ public trait PostProcessor {
public class JavaToKotlinConverter(private val project: Project, public class JavaToKotlinConverter(private val project: Project,
private val settings: ConverterSettings, private val settings: ConverterSettings,
private val conversionScope: ConversionScope /*TODO: drop this parameter*/,
private val referenceSearcher: ReferenceSearcher, private val referenceSearcher: ReferenceSearcher,
private val resolverForConverter: ResolverForConverter) { private val resolverForConverter: ResolverForConverter) {
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter") private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter")
@@ -124,7 +116,11 @@ public class JavaToKotlinConverter(private val project: Project,
processFilesWithProgress(0.25) { i -> processFilesWithProgress(0.25) { i ->
val psiElement = psiElementsAndProcessors[i].first val psiElement = psiElementsAndProcessors[i].first
val postProcessor = psiElementsAndProcessors[i].second val postProcessor = psiElementsAndProcessors[i].second
val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, resolverForConverter, postProcessor, usageProcessingCollector)
fun inConversionScope(element: PsiElement)
= psiElementsAndProcessors.any { it.first.isAncestor(element, strict = false) }
val converter = Converter.create(psiElement, settings, ::inConversionScope, referenceSearcher, resolverForConverter, postProcessor, usageProcessingCollector)
val result = converter.convert() val result = converter.convert()
intermediateResults.add(result) intermediateResults.add(result)
} }
@@ -134,7 +134,7 @@ public object JavaToKotlinTranslator {
fun generateKotlinCode(javaCode: String): String { fun generateKotlinCode(javaCode: String): String {
val file = createFile(javaCode) val file = createFile(javaCode)
if (file is PsiJavaFile) { if (file is PsiJavaFile) {
val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), EmptyReferenceSearcher, EmptyResolverForConverter) val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, EmptyReferenceSearcher, EmptyResolverForConverter)
return prettify(converter.elementsToKotlin(listOf(file to null))[0]) return prettify(converter.elementsToKotlin(listOf(file to null))[0])
} }
return "" return ""
@@ -151,7 +151,7 @@ class TypeConverter(val converter: Converter) {
value = fromTypeHeuristics(variableType) value = fromTypeHeuristics(variableType)
if (value != default) return value if (value != default) return value
if (!converter.conversionScope.contains(variable)) return default // do not analyze usages of variables not in our conversion scope if (!converter.inConversionScope(variable)) return default // do not analyze usages of variables not in our conversion scope
val scope = searchScope(variable) val scope = searchScope(variable)
if (scope != null) { if (scope != null) {
@@ -189,7 +189,7 @@ class TypeConverter(val converter: Converter) {
value = fromTypeHeuristics(returnType) value = fromTypeHeuristics(returnType)
if (value != default) return value if (value != default) return value
if (!converter.conversionScope.contains(method)) return default // do not analyze body and usages of methods out of our conversion scope if (!converter.inConversionScope(method)) return default // do not analyze body and usages of methods out of our conversion scope
val body = method.getBody() val body = method.getBody()
if (body != null) { if (body != null) {
@@ -262,7 +262,7 @@ class TypeConverter(val converter: Converter) {
if (variable is PsiField if (variable is PsiField
&& variable.hasModifierProperty(PsiModifier.PRIVATE) && variable.hasModifierProperty(PsiModifier.PRIVATE)
&& converter.conversionScope.contains(variable) && converter.inConversionScope(variable)
&& shouldGenerateDefaultInitializer(converter.referenceSearcher, variable)) { && shouldGenerateDefaultInitializer(converter.referenceSearcher, variable)) {
return Nullability.Nullable return Nullability.Nullable
} }
@@ -43,7 +43,7 @@ public abstract class AbstractJavaToKotlinConverterMultiFileTest : AbstractJavaT
psiFiles.add(psiFile) psiFiles.add(psiFile)
} }
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(psiFiles), IdeaReferenceSearcher, IdeaResolverForConverter) val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaReferenceSearcher, IdeaResolverForConverter)
val results: List<String> = converter.elementsToKotlin(psiFiles.map { it to J2kPostProcessor(it, formatCode = true) }) val results: List<String> = converter.elementsToKotlin(psiFiles.map { it to J2kPostProcessor(it, formatCode = true) })
fun expectedFile(i: Int) = File(javaFiles[i].getPath().replace(".java", ".kt")) fun expectedFile(i: Int) = File(javaFiles[i].getPath().replace(".java", ".kt"))
@@ -106,7 +106,7 @@ public abstract class AbstractJavaToKotlinConverterSingleFileTest : AbstractJava
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val file = createJavaFile(text) val file = createJavaFile(text)
val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(file)), IdeaReferenceSearcher, IdeaResolverForConverter) val converter = JavaToKotlinConverter(project, settings, IdeaReferenceSearcher, IdeaResolverForConverter)
return converter.elementsToKotlin(listOf(file to J2kPostProcessor(file, formatCode = false)))[0] return converter.elementsToKotlin(listOf(file to J2kPostProcessor(file, formatCode = false)))[0]
} }