diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java index 385bdaf6991..9ac556522a4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java @@ -407,7 +407,15 @@ public class ResolveSession implements KotlinCodeAnalyzer { return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter); } } - return super.visitParameter(parameter, data); + else if (grandFather instanceof JetNamedFunction) { + FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((JetNamedFunction) grandFather, data); + function.getValueParameters(); + return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter); + } + else { + //TODO: support parameters in accessors and other places(?) + return super.visitParameter(parameter, data); + } } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.kt b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.kt index 52016a5a8aa..1934f2d273b 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.kt +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.kt @@ -38,6 +38,7 @@ import org.jetbrains.jet.plugin.j2k.J2kPostProcessor import com.intellij.openapi.vfs.CharsetToolkit import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.utils.addIfNotNull +import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession public class JavaToKotlinAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { @@ -110,7 +111,7 @@ public class JavaToKotlinAction : AnAction() { } private fun convertFiles(javaFiles: List, project: Project): List { - val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(javaFiles), IdeaReferenceSearcher) + val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(javaFiles), IdeaReferenceSearcher, { it.getLazyResolveSession() }) val convertedTexts = converter.elementsToKotlin(javaFiles.map { it to J2kPostProcessor(it) }) diff --git a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index 4efcf5e9318..b31cb28ac13 100644 --- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -34,6 +34,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.lang.java.JavaLanguage import org.jetbrains.jet.plugin.j2k.J2kPostProcessor +import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor() { @@ -89,7 +90,8 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor KotlinCodeAnalyzer)?, private val postProcessor: PostProcessor?, private val commonState: Converter.CommonState, private val personalState: Converter.PersonalState) { @@ -59,15 +62,15 @@ class Converter private(private val elementToConvert: PsiElement, class object { public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope, - referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter { - return Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, CommonState(), PersonalState(null)) + referenceSearcher: ReferenceSearcher, lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?, postProcessor: PostProcessor?): Converter { + return Converter(elementToConvert, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, CommonState(), PersonalState(null)) } } public fun withSpecialContext(context: PsiElement): Converter = withState(PersonalState(context)) private fun withState(state: PersonalState): Converter - = Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, commonState, state) + = Converter(elementToConvert, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, commonState, state) private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null) diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt index 5994ef4b143..bd15c3b3843 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt @@ -26,6 +26,8 @@ import org.jetbrains.jet.lang.resolve.BindingContext import com.intellij.openapi.diagnostic.Logger import java.util.ArrayList import org.jetbrains.jet.j2k.usageProcessing.UsageProcessing +import org.jetbrains.jet.lang.psi.JetElement +import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer public trait ConversionScope { public fun contains(element: PsiElement): Boolean @@ -44,7 +46,8 @@ public trait PostProcessor { public class JavaToKotlinConverter(private val project: Project, private val settings: ConverterSettings, private val conversionScope: ConversionScope /*TODO: drop this parameter*/, - private val referenceSearcher: ReferenceSearcher) { + private val referenceSearcher: ReferenceSearcher, + private val lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?) { private val LOG = Logger.getInstance("#org.jetbrains.jet.j2k.JavaToKotlinConverter") public fun elementsToKotlin(psiElementsAndProcessors: List>): List { @@ -52,7 +55,7 @@ public class JavaToKotlinConverter(private val project: Project, val intermediateResults = ArrayList(psiElementsAndProcessors.size) val usageProcessings = ArrayList() for ((psiElement, postProcessor) in psiElementsAndProcessors) { - val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, postProcessor) + val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor) val result = converter.convert() intermediateResults.add(result) result?.usageProcessings?.let { usageProcessings.addAll(it) } diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index a2a67a71f8a..b1dd23094d0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -90,7 +90,7 @@ public object JavaToKotlinTranslator { fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { - val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), EmptyReferenceSearcher) + val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), EmptyReferenceSearcher, null) return prettify(converter.elementsToKotlin(listOf(file to null))[0]) } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index de01722c675..f24f28ad2d4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -31,6 +31,11 @@ import org.jetbrains.jet.j2k.ast.Identifier import java.util.HashMap import org.jetbrains.jet.j2k.ast.Mutability import java.util.HashSet +import org.jetbrains.jet.asJava.KotlinLightElement +import org.jetbrains.jet.lang.psi.JetCallableDeclaration +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.types.TypeUtils +import org.jetbrains.jet.lang.resolve.DescriptorUtils class TypeConverter(val converter: Converter) { public fun convertType(type: PsiType?, nullability: Nullability = Nullability.Default, mutability: Mutability = Mutability.Default): Type { @@ -363,6 +368,20 @@ class TypeConverter(val converter: Converter) { } override fun fromAnnotations(owner: PsiModifierListOwner): Mutability { + if (owner is KotlinLightElement<*, *>) { + val jetDeclaration = owner.origin as? JetCallableDeclaration ?: return Mutability.Default + val codeAnalyzer = converter.lazyResolveSessionGetter?.invoke(jetDeclaration) + val descriptor = codeAnalyzer?.resolveToDescriptor(jetDeclaration) + as? CallableDescriptor ?: return Mutability.Default + val type = descriptor.getReturnType() ?: return Mutability.Default + val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default + return if (DescriptorUtils.getFqName(classDescriptor).asString() in mutableKotlinClasses) + Mutability.Mutable + else + Mutability.NonMutable + } + //TODO: Kotlin compiled elements + return super.fromAnnotations(owner) //TODO: ReadOnly annotation } @@ -408,5 +427,7 @@ class TypeConverter(val converter: Converter) { private val modificationMethodNames = setOf( "add", "remove", "set", "addAll", "removeAll", "retainAll", "clear", "put", "putAll" ) + + private val mutableKotlinClasses = TypeVisitor.toKotlinMutableTypesMap.values().toSet() } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterMultiFileTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterMultiFileTest.kt index f6db205df5e..48a8d662dd8 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterMultiFileTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterMultiFileTest.kt @@ -32,6 +32,7 @@ import com.intellij.psi.PsiManager import java.util.ArrayList import org.jetbrains.jet.j2k.ConverterSettings import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession public abstract class AbstractJavaToKotlinConverterMultiFileTest() : AbstractJavaToKotlinConverterTest() { public fun doTest(dirPath: String) { @@ -46,7 +47,7 @@ public abstract class AbstractJavaToKotlinConverterMultiFileTest() : AbstractJav psiFiles.add(psiFile) } - val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(psiFiles), IdeaReferenceSearcher) + val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, FilesConversionScope(psiFiles), IdeaReferenceSearcher, { it.getLazyResolveSession() }) val results: List = converter.elementsToKotlin(psiFiles.map { it to J2kPostProcessor(it) }) .map { reformat(it, project) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterSingleFileTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterSingleFileTest.kt index fc8d1e186d5..f20535d4e77 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterSingleFileTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterSingleFileTest.kt @@ -33,9 +33,7 @@ import com.intellij.psi.PsiJavaFile import org.jetbrains.jet.j2k.IdeaReferenceSearcher import org.jetbrains.jet.j2k.JavaToKotlinConverter import org.jetbrains.jet.lang.psi.JetFile -import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults -import org.jetbrains.jet.lang.diagnostics.Severity -import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages +import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession public abstract class AbstractJavaToKotlinConverterSingleFileTest() : AbstractJavaToKotlinConverterTest() { val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n") @@ -113,14 +111,14 @@ public abstract class AbstractJavaToKotlinConverterSingleFileTest() : AbstractJa private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { val fileWithText = createJavaFile(text) - val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(fileWithText)), IdeaReferenceSearcher) + val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(fileWithText)), IdeaReferenceSearcher, { it.getLazyResolveSession() }) val element = fileWithText.getFirstChild()!! return converter.elementsToKotlin(listOf(element to J2kPostProcessor(fileWithText)))[0] } private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { val file = createJavaFile(text) - val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(file)), IdeaReferenceSearcher) + val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(file)), IdeaReferenceSearcher, { it.getLazyResolveSession() }) return converter.elementsToKotlin(listOf(file to J2kPostProcessor(file)))[0] } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java index 5ddd6b41a84..4a4329ccf8f 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -2799,6 +2799,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("Overrides.java") + public void testOverrides() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/mutableCollections/Overrides.java"); + doTest(fileName); + } + @TestMetadata("Recursion.java") public void testRecursion() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/mutableCollections/Recursion.java"); diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java index 124405df099..0fe9628b615 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java @@ -2799,6 +2799,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("Overrides.java") + public void testOverrides() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/mutableCollections/Overrides.java"); + doTest(fileName); + } + @TestMetadata("Recursion.java") public void testRecursion() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/mutableCollections/Recursion.java"); diff --git a/j2k/tests/testData/KotlinApi.kt b/j2k/tests/testData/KotlinApi.kt index 4a200f9bbe9..c83b1815deb 100644 --- a/j2k/tests/testData/KotlinApi.kt +++ b/j2k/tests/testData/KotlinApi.kt @@ -4,6 +4,8 @@ public open class KotlinClass(public var field: Int) { public var property: String = "" public var nullableProperty: String? = "" + public open fun foo(mutableCollection: MutableCollection, nullableCollection: Collection?): MutableList = arrayListOf() + class object { public fun staticFun(p: Int): Int = p public var staticVar: Int = 1 diff --git a/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.java b/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.java new file mode 100644 index 00000000000..5d73af7104b --- /dev/null +++ b/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.java @@ -0,0 +1,16 @@ +package javaApi; + +import kotlinApi.KotlinClass; + +import java.util.Collection; +import java.util.List; + +public abstract class C extends KotlinClass { + public C(int field) { + super(field); + } + + public List foo(Collection mutableCollection, Collection nullableCollection) { + return super.foo(mutableCollection, nullableCollection); + } +} diff --git a/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.kt b/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.kt new file mode 100644 index 00000000000..695936d66d6 --- /dev/null +++ b/j2k/tests/testData/fileOrElement/mutableCollections/Overrides.kt @@ -0,0 +1,10 @@ +package javaApi + +import kotlinApi.KotlinClass + +public abstract class C(field: Int) : KotlinClass(field) { + + override fun foo(mutableCollection: MutableCollection, nullableCollection: Collection?): MutableList { + return super.foo(mutableCollection, nullableCollection) + } +}