diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index 09f771e130c..5b3b7612f87 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.jvm.JavaLazyAnalyzerPostConstruct import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory +import org.jetbrains.kotlin.synthetic.AdditionalScopesWithSyntheticExtensions public fun StorageComponentContainer.configureJavaTopDownAnalysis(moduleContentScope: GlobalSearchScope, project: Project) { useInstance(moduleContentScope) @@ -65,6 +66,7 @@ public fun StorageComponentContainer.configureJavaTopDownAnalysis(moduleContentS useImpl() useImpl() useImpl() + useImpl() } public fun createContainerForLazyResolveWithJava( diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt new file mode 100644 index 00000000000..a0a8791600b --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt @@ -0,0 +1,156 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.synthetic + +import com.intellij.util.SmartList +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.JetType + +interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor { + val getMethod: FunctionDescriptor + val setMethod: FunctionDescriptor? +} + +class AdditionalScopesWithSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes() { + private val scope = SyntheticExtensionsScope(storageManager) + + override fun scopes(file: JetFile) = listOf(scope) +} + +class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by JetScope.Empty { + private val syntheticPropertyInClass = storageManager.createMemoizedFunctionWithNullableValues, PropertyDescriptor> { triple -> + syntheticPropertyInClass(triple.first, triple.second, triple.third) + } + + private fun syntheticPropertyInClass(javaClass: JavaClassDescriptor, type: JetType, name: Name): PropertyDescriptor? { + val memberScope = javaClass.getMemberScope(type.getArguments()) + val getMethod = memberScope.getFunctions(name.toGetMethodName()).singleOrNull { + it.getValueParameters().isEmpty() && it.getTypeParameters().isEmpty() && it.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local? + } ?: return null + + val propertyType = getMethod.getReturnType() ?: return null + val setMethod = memberScope.getFunctions(name.toSetMethodName()).singleOrNull { + it.getValueParameters().singleOrNull()?.getType() == propertyType + && it.getTypeParameters().isEmpty() + && it.getReturnType()?.let { KotlinBuiltIns.isUnit(it) } ?: false + && it.getVisibility() == Visibilities.PUBLIC + } + + return MyPropertyDescriptor(javaClass, getMethod, setMethod, name, propertyType, type) + } + + override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection { + if (name.isSpecial()) return emptyList() + if (name.getIdentifier()[0].isUpperCase()) return emptyList() + return collectSyntheticProperties(null, receiverType, name) ?: emptyList() + } + + private fun collectSyntheticProperties(result: SmartList?, type: JetType, name: Name): SmartList? { + @suppress("NAME_SHADOWING") + var result = result + + val typeConstructor = type.getConstructor() + val classifier = typeConstructor.getDeclarationDescriptor() + if (classifier is JavaClassDescriptor) { + result = result.add(syntheticPropertyInClass(Triple(classifier, type, name))) + } + + typeConstructor.getSupertypes().forEach { result = collectSyntheticProperties(result, it, name) } + + return result + } + + private fun SmartList?.add(property: PropertyDescriptor?): SmartList? { + if (property == null) return this + val list = if (this != null) this else SmartList() + list.add(property) + return list + } + + //TODO: "is"? + //TODO: methods like "getURL"? + //TODO: reuse code with generation? + private fun Name.toGetMethodName(): Name { + return Name.identifier("get" + getIdentifier().capitalize()) + } + + private fun Name.toSetMethodName(): Name { + return Name.identifier("set" + getIdentifier().capitalize()) + } + + private class MyPropertyDescriptor( + javaClass: JavaClassDescriptor, + override val getMethod: FunctionDescriptor, + override val setMethod: FunctionDescriptor?, + name: Name, + type: JetType, + receiverType: JetType + ) : SyntheticExtensionPropertyDescriptor, PropertyDescriptorImpl( + DescriptorUtils.getContainingModule(javaClass)/* TODO:is it ok? */, + null, + Annotations.EMPTY, + Modality.FINAL, + Visibilities.PUBLIC, + setMethod != null, + name, + CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE/*TODO?*/ + ) { + init { + setType(type, emptyList(), null, receiverType) + + val getter = PropertyGetterDescriptorImpl(this, + Annotations.EMPTY, + Modality.FINAL, + Visibilities.PUBLIC, + false, + false, + CallableMemberDescriptor.Kind.SYNTHESIZED, + null, + SourceElement.NO_SOURCE/*TODO*/) + getter.initialize(null) + + val setter = if (setMethod != null) + PropertySetterDescriptorImpl(this, + Annotations.EMPTY, + Modality.FINAL, + Visibilities.PUBLIC, + false, + false, + CallableMemberDescriptor.Kind.SYNTHESIZED, + null, + SourceElement.NO_SOURCE/*TODO*/) + else + null + setter?.initializeDefault() + + initialize(getter, setter) + } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt index ce0d4a0f67a..32555451aa8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -39,7 +39,7 @@ public trait CallableDescriptorCollector { public fun getStaticMembersByName(receiver: JetType, name: Name, bindingTrace: BindingTrace): Collection - public fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection + public fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection } private fun CallableDescriptorCollector.withDefaultFilter() = filtered { !LibrarySourceHacks.shouldSkip(it) } @@ -97,7 +97,7 @@ private object FunctionCollector : CallableDescriptorCollector { + override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { val functions = scope.getFunctions(name) val (extensions, nonExtensions) = functions.partition { it.getExtensionReceiverParameter() != null } @@ -151,9 +151,9 @@ private object VariableCollector : CallableDescriptorCollector { + override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { // property may have an extension function type, we check the applicability later to avoid an early computing of deferred types - return (listOf(scope.getLocalVariable(name)) + scope.getProperties(name)).filterNotNull() + return (listOf(scope.getLocalVariable(name)) + scope.getProperties(name) + scope.getSyntheticExtensionProperties(receiver, name)).filterNotNull() } override fun toString() = "VARIABLES" @@ -175,8 +175,8 @@ private object PropertyCollector : CallableDescriptorCollector { - return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, bindingTrace)) + override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { + return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, receiver, bindingTrace)) } override fun toString() = "PROPERTIES" @@ -197,8 +197,8 @@ private fun CallableDescriptorCollector.filtered(fil return delegate.getStaticMembersByName(receiver, name, bindingTrace).filter(filter) } - override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { - return delegate.getExtensionsByName(scope, name, bindingTrace).filter(filter) + override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { + return delegate.getExtensionsByName(scope, name, receiver, bindingTrace).filter(filter) } override fun toString(): String { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index 1c7ae65a94e..e6b8ead5a3c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -164,7 +164,7 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { convertWithImpliedThis( c.scope, explicitReceiver, - callableDescriptorCollector.getExtensionsByName(c.scope, c.name, c.context.trace), + callableDescriptorCollector.getExtensionsByName(c.scope, c.name, explicitReceiver.getType(), c.context.trace), createKind(EXTENSION_RECEIVER, isExplicit), c.context.call ) @@ -237,7 +237,7 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { ) { c.result.addCandidates { val memberExtensions = - callableDescriptorCollector.getExtensionsByName(dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace) + callableDescriptorCollector.getExtensionsByName(dispatchReceiver.getType().getMemberScope(), c.name, receiverParameter.getType(), c.context.trace) convertWithReceivers(memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt index 0142950ccc8..eb376226710 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt @@ -223,8 +223,8 @@ public fun DeclarationDescriptor.isDynamic(): Boolean { } class CollectorForDynamicReceivers(val delegate: CallableDescriptorCollector) : CallableDescriptorCollector by delegate { - override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { - return delegate.getExtensionsByName(scope, name, bindingTrace).filter { + override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { + return delegate.getExtensionsByName(scope, name, receiver, bindingTrace).filter { it.getExtensionReceiverParameter()?.getType()?.isDynamic() ?: false } } diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.kt new file mode 100644 index 00000000000..1b924922c87 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.kt @@ -0,0 +1,31 @@ +// FILE: KotlinFile.kt +open class KotlinClass1 : JavaClass1() { + fun getSomethingKotlin1(): Int = 1 +} + +class KotlinClass2 : JavaClass2() { + fun getSomethingKotlin2(): Int = 1 +} + +fun foo(k: KotlinClass2) { + useInt(k.getSomething1()) + useInt(k.something1) + useInt(k.getSomething2()) + useInt(k.something2) + useInt(k.getSomethingKotlin1()) + useInt(k.getSomethingKotlin2()) + k.somethingKotlin1 + k.somethingKotlin2 +} + +fun useInt(i: Int) {} + +// FILE: JavaClass1.java +public class JavaClass1 { + public int getSomething1() { return 1; } +} + +// FILE: JavaClass2.java +public class JavaClass2 extends KotlinClass1 { + public int getSomething2() { return 1; } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.txt new file mode 100644 index 00000000000..51a80c0f2d6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/Bases.txt @@ -0,0 +1,42 @@ +package + +internal fun foo(/*0*/ k: KotlinClass2): kotlin.Unit +internal fun useInt(/*0*/ i: kotlin.Int): kotlin.Unit + +public open class JavaClass1 { + public constructor JavaClass1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class JavaClass2 : KotlinClass1 { + public constructor JavaClass2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getSomething1(): kotlin.Int + public open fun getSomething2(): kotlin.Int + internal final override /*1*/ /*fake_override*/ fun getSomethingKotlin1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal open class KotlinClass1 : JavaClass1 { + public constructor KotlinClass1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getSomething1(): kotlin.Int + internal final fun getSomethingKotlin1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class KotlinClass2 : JavaClass2 { + public constructor KotlinClass2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getSomething1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun getSomething2(): kotlin.Int + internal final override /*1*/ /*fake_override*/ fun getSomethingKotlin1(): kotlin.Int + internal final fun getSomethingKotlin2(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.kt new file mode 100644 index 00000000000..07e822a3ee7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.kt @@ -0,0 +1,6 @@ +// FILE: KotlinFile.kt +import java.io.File + +fun foo(file: File) { + file.absolutePath.length() +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.txt new file mode 100644 index 00000000000..736b22b85f4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ file: java.io.File): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.kt new file mode 100644 index 00000000000..c822e42778b --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.kt @@ -0,0 +1,14 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.something1 + javaClass.something2 + javaClass.somethingStatic +} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething1(int p) { return p; } + public T getSomething2() { return null; } + + public static int getSomethingStatic() { return 1; } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.txt new file mode 100644 index 00000000000..e4ef1a33e60 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.txt @@ -0,0 +1,15 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething1(/*0*/ p: kotlin.Int): kotlin.Int + public open fun getSomething2(): T! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun getSomethingStatic(): kotlin.Int +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.kt new file mode 100644 index 00000000000..d82f34ef121 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.kt @@ -0,0 +1,26 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.something1++ + javaClass.something2++ + javaClass.something3++ + javaClass.something4++ + javaClass.something5++ +} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething1() { return 1; } + public void setSomething1(int value, char c) { } + + public int getSomething2() { return 1; } + public void setSomething2(String value) { } + + public int getSomething3() { return 1; } + public int setSomething3(int value) { return value; } + + public int getSomething4() { return 1; } + public void setSomething4(int value) { return value; } + + public int getSomething5() { return 1; } + public static void setSomething5(int value) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.txt new file mode 100644 index 00000000000..8b6a8a97784 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.txt @@ -0,0 +1,22 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething1(): kotlin.Int + public open fun getSomething2(): kotlin.Int + public open fun getSomething3(): kotlin.Int + public open fun getSomething4(): kotlin.Int + public open fun getSomething5(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething1(/*0*/ value: kotlin.Int, /*1*/ c: kotlin.Char): kotlin.Unit + public open fun setSomething2(/*0*/ value: kotlin.String!): kotlin.Unit + public open fun setSomething3(/*0*/ value: kotlin.Int): kotlin.Int + public open fun setSomething4(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun setSomething5(/*0*/ value: kotlin.Int): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.kt new file mode 100644 index 00000000000..71a600c59a2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.kt @@ -0,0 +1,10 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.something += "x" +} + +// FILE: JavaClass.java +public class JavaClass { + public T getSomething() { return null; } + public void setSomething(T value) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.txt new file mode 100644 index 00000000000..7f43ca97e8a --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.txt @@ -0,0 +1,12 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): T! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: T!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.kt new file mode 100644 index 00000000000..27eb7ad4cb2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.kt @@ -0,0 +1,20 @@ +// FILE: KotlinFile.kt +class KotlinClass { + fun getSomething(): Int = 1 +} + +fun foo(javaClass: JavaClass, kotlinClass: KotlinClass) { + useInt(javaClass.getSomething()) + useInt(javaClass.something) + javaClass.something = 1 + javaClass.Something + useInt(kotlinClass.getSomething()) + kotlinClass.something +} + +fun useInt(i: Int) {} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething() { return 1; } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.txt new file mode 100644 index 00000000000..73feaeb7466 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/Getter.txt @@ -0,0 +1,20 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass, /*1*/ kotlinClass: KotlinClass): kotlin.Unit +internal fun useInt(/*0*/ i: kotlin.Int): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class KotlinClass { + public constructor KotlinClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun getSomething(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.kt new file mode 100644 index 00000000000..c26c6947cd1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.kt @@ -0,0 +1,10 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.something++ +} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething() { return 1; } + public void setSomething(int value) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.txt new file mode 100644 index 00000000000..b45913cb221 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.txt @@ -0,0 +1,12 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.kt new file mode 100644 index 00000000000..f8aa9d9af1c --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.kt @@ -0,0 +1,12 @@ +// FILE: KotlinFile.kt +fun JavaClass.foo() { + useInt(getSomething()) + useInt(something) +} + +fun useInt(i: Int) {} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething() { return 1; } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.txt new file mode 100644 index 00000000000..31708c4748a --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.txt @@ -0,0 +1,12 @@ +package + +internal fun useInt(/*0*/ i: kotlin.Int): kotlin.Unit +internal fun JavaClass.foo(): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt new file mode 100644 index 00000000000..9bcc925eb27 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt @@ -0,0 +1,18 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.somethingPublic + javaClass.somethingProtected + javaClass.somethingPrivate + javaClass.somethingPackage + javaClass.somethingPublic = 1 +} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomethingPublic() { return 1; } + protected int getSomethingProtected() { return 1; } + private int getSomethingPrivate() { return 1; } + int getSomethingPackage() { return 1; } + + protected void setSomethingPublic(int value) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.txt new file mode 100644 index 00000000000..cbb81bad348 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.txt @@ -0,0 +1,15 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getSomethingPackage(): kotlin.Int + private open fun getSomethingPrivate(): kotlin.Int + protected/*protected and package*/ open fun getSomethingProtected(): kotlin.Int + public open fun getSomethingPublic(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open fun setSomethingPublic(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt new file mode 100644 index 00000000000..9d3bef5eabe --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt @@ -0,0 +1,9 @@ +// FILE: KotlinFile.kt +fun foo(javaClass: JavaClass) { + javaClass.something = 1 +} + +// FILE: JavaClass.java +public class JavaClass { + public void setSomething(int value) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.txt new file mode 100644 index 00000000000..f22704ef214 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.txt @@ -0,0 +1,11 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 1fc9afd337e..7b4f1987491 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -14002,6 +14002,75 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/syntheticExtensions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SyntheticExtensions extends AbstractJetDiagnosticsTest { + public void testAllFilesPresentInSyntheticExtensions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/syntheticExtensions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("Bases.kt") + public void testBases() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/Bases.kt"); + doTest(fileName); + } + + @TestMetadata("CompiledClass.kt") + public void testCompiledClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/CompiledClass.kt"); + doTest(fileName); + } + + @TestMetadata("FalseGetters.kt") + public void testFalseGetters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/FalseGetters.kt"); + doTest(fileName); + } + + @TestMetadata("FalseSetters.kt") + public void testFalseSetters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/FalseSetters.kt"); + doTest(fileName); + } + + @TestMetadata("GenericClass.kt") + public void testGenericClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/GenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("Getter.kt") + public void testGetter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/Getter.kt"); + doTest(fileName); + } + + @TestMetadata("GetterAndSetter.kt") + public void testGetterAndSetter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/GetterAndSetter.kt"); + doTest(fileName); + } + + @TestMetadata("ImplicitReceiver.kt") + public void testImplicitReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/ImplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("OnlyPublic.kt") + public void testOnlyPublic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt"); + doTest(fileName); + } + + @TestMetadata("SetterOnly.kt") + public void testSetterOnly() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/thisAndSuper") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)