diff --git a/compiler/frontend.java/frontend.java.iml b/compiler/frontend.java/frontend.java.iml index 6f37b7eda52..57f41bf2a78 100644 --- a/compiler/frontend.java/frontend.java.iml +++ b/compiler/frontend.java/frontend.java.iml @@ -13,5 +13,6 @@ + \ No newline at end of file diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt index a0a8791600b..2a630a13a48 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SyntheticExtensionsScope.kt @@ -31,6 +31,8 @@ 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 +import org.jetbrains.kotlin.utils.addIfNotNull +import java.util.* interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor { val getMethod: FunctionDescriptor @@ -50,12 +52,12 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet private fun syntheticPropertyInClass(javaClass: JavaClassDescriptor, type: JetType, name: Name): PropertyDescriptor? { val memberScope = javaClass.getMemberScope(type.getArguments()) - val getMethod = memberScope.getFunctions(name.toGetMethodName()).singleOrNull { + val getMethod = memberScope.getFunctions(toGetMethodName(name)).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 { + val setMethod = memberScope.getFunctions(toSetMethodName(name)).singleOrNull { it.getValueParameters().singleOrNull()?.getType() == propertyType && it.getTypeParameters().isEmpty() && it.getReturnType()?.let { KotlinBuiltIns.isUnit(it) } ?: false @@ -68,10 +70,10 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet 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() + return collectSyntheticPropertiesByName(null, receiverType, name) ?: emptyList() } - private fun collectSyntheticProperties(result: SmartList?, type: JetType, name: Name): SmartList? { + private fun collectSyntheticPropertiesByName(result: SmartList?, type: JetType, name: Name): SmartList? { @suppress("NAME_SHADOWING") var result = result @@ -81,11 +83,32 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet result = result.add(syntheticPropertyInClass(Triple(classifier, type, name))) } - typeConstructor.getSupertypes().forEach { result = collectSyntheticProperties(result, it, name) } + typeConstructor.getSupertypes().forEach { result = collectSyntheticPropertiesByName(result, it, name) } return result } + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + val result = ArrayList() + result.collectSyntheticProperties(receiverType) + return result + } + + private fun MutableList.collectSyntheticProperties(type: JetType) { + val typeConstructor = type.getConstructor() + val classifier = typeConstructor.getDeclarationDescriptor() + if (classifier is JavaClassDescriptor) { + for (descriptor in classifier.getMemberScope(type.getArguments()).getAllDescriptors()) { + if (descriptor is FunctionDescriptor) { + val propertyName = fromGetMethodName(descriptor.getName()) ?: continue + addIfNotNull(syntheticPropertyInClass(classifier, type, propertyName)) + } + } + } + + typeConstructor.getSupertypes().forEach { collectSyntheticProperties(it) } + } + private fun SmartList?.add(property: PropertyDescriptor?): SmartList? { if (property == null) return this val list = if (this != null) this else SmartList() @@ -96,12 +119,19 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet //TODO: "is"? //TODO: methods like "getURL"? //TODO: reuse code with generation? - private fun Name.toGetMethodName(): Name { - return Name.identifier("get" + getIdentifier().capitalize()) + private fun toGetMethodName(propertyName: Name): Name { + return Name.identifier("get" + propertyName.getIdentifier().capitalize()) } - private fun Name.toSetMethodName(): Name { - return Name.identifier("set" + getIdentifier().capitalize()) + private fun toSetMethodName(propertyName: Name): Name { + return Name.identifier("set" + propertyName.getIdentifier().capitalize()) + } + + private fun fromGetMethodName(methodName: Name): Name? { + if (methodName.isSpecial()) return null + val identifier = methodName.getIdentifier() + if (!identifier.startsWith("get")) return null + return Name.identifier(identifier.removePrefix("get").decapitalize()) } private class MyPropertyDescriptor( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt index 3e653a4432a..94a9868fae2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt @@ -57,6 +57,10 @@ class AllUnderImportsScope : JetScope { return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType, name) } } + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType) } + } + override fun getPackage(name: Name): PackageViewDescriptor? = null // packages are not imported by all under imports override fun getLocalVariable(name: Name): VariableDescriptor? = null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/SingleImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/SingleImportScope.kt index 0dded31f58a..6b84617d723 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/SingleImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/SingleImportScope.kt @@ -19,11 +19,11 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.utils.Printer -class SingleImportScope(private val aliasName: Name, private val descriptors: Collection) : JetScope { +class SingleImportScope(private val aliasName: Name, private val descriptors: Collection) : JetScopeImpl() { override fun getClassifier(name: Name) = if (name == aliasName) descriptors.filterIsInstance().singleOrNull() else null @@ -36,20 +36,10 @@ class SingleImportScope(private val aliasName: Name, private val descriptors: Co override fun getFunctions(name: Name) = if (name == aliasName) descriptors.filterIsInstance() else emptyList() - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = emptyList() - - override fun getLocalVariable(name: Name): VariableDescriptor? = null - override fun getContainingDeclaration(): DeclarationDescriptor = throw UnsupportedOperationException() - override fun getDeclarationsByLabel(labelName: Name): Collection = emptyList() - override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = descriptors - override fun getImplicitReceiversHierarchy(): List = emptyList() - - override fun getOwnDeclaredDescriptors(): Collection = emptyList() - override fun printScopeStructure(p: Printer) { p.println(javaClass.getSimpleName(), ": ", aliasName) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index d3a9b7fdfa3..903d61c4e9e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -260,6 +260,17 @@ class LazyImportScope( return importResolver.collectFromImports(name, LookupMode.EVERYTHING) { scope, name -> scope.getSyntheticExtensionProperties(receiverType, name) } } + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + // we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() + + return importResolver.resolveSession.getStorageManager().compute { + importResolver.indexedImports.imports.flatMapTo(LinkedHashSet()) { import -> + importResolver.getImportScope(import, LookupMode.EVERYTHING).getSyntheticExtensionProperties(receiverType) + } + } + } + override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt index fd3e126ac8a..d6fe4b51cbf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.lazy.data.JetScriptInfo import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProvider import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.JetType @@ -41,7 +42,7 @@ protected constructor( protected val declarationProvider: DP, protected val thisDescriptor: D, protected val trace: BindingTrace -) : JetScope { +) : JetScopeImpl() { protected val storageManager: StorageManager = c.storageManager private val classDescriptors: MemoizedFunctionToNotNull> = storageManager.createMemoizedFunction { resolveClassDescriptor(it) } @@ -111,12 +112,6 @@ protected constructor( protected abstract fun getNonDeclaredProperties(name: Name, result: MutableSet) - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = listOf() - - override fun getLocalVariable(name: Name): VariableDescriptor? = null - - override fun getDeclarationsByLabel(labelName: Name) = setOf() - protected fun computeDescriptorsFromDeclaredElements(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List { val declarations = declarationProvider.getDeclarations(kindFilter, nameFilter) @@ -163,8 +158,6 @@ protected constructor( return result.toReadOnlyList() } - override fun getImplicitReceiversHierarchy() = listOf() - // Do not change this, override in concrete subclasses: // it is very easy to compromise laziness of this class, and fail all the debugging // a generic implementation can't do this properly diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaMemberScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaMemberScope.kt index e82897671a4..0628b88ac3f 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaMemberScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaMemberScope.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.jvm.PLATFORM_TYPES import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude.NonExtensions import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl import org.jetbrains.kotlin.storage.NotNullLazyValue import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils @@ -51,7 +52,7 @@ import java.util.LinkedHashSet public abstract class LazyJavaMemberScope( protected val c: LazyJavaResolverContext, private val containingDeclaration: DeclarationDescriptor -) : JetScope { +) : JetScopeImpl() { // this lazy value is not used at all in LazyPackageFragmentScopeForJavaPackage because we do not use caching there // but is placed in the base class to not duplicate code private val allDescriptors = c.storageManager.createRecursionTolerantLazyValue>( @@ -297,11 +298,6 @@ public abstract class LazyJavaMemberScope( override fun getProperties(name: Name): Collection = properties(name) - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = listOf() - - override fun getLocalVariable(name: Name): VariableDescriptor? = null - override fun getDeclarationsByLabel(labelName: Name) = listOf() - override fun getOwnDeclaredDescriptors() = getDescriptors() override fun getDescriptors(kindFilter: DescriptorKindFilter, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt index 98f4032841d..aee4d5f6423 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt @@ -51,6 +51,10 @@ public abstract class AbstractScopeAdapter : JetScope { return workerScope.getSyntheticExtensionProperties(receiverType, name) } + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + return workerScope.getSyntheticExtensionProperties(receiverType) + } + override fun getLocalVariable(name: Name): VariableDescriptor? { return workerScope.getLocalVariable(name) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt index 0a270366fdb..7d1319fbeb4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt @@ -68,6 +68,9 @@ public open class ChainedScope( override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = getFromAllScopes { it.getSyntheticExtensionProperties(receiverType, name) } + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection + = getFromAllScopes { it.getSyntheticExtensionProperties(receiverType) } + override fun getImplicitReceiversHierarchy(): List { if (implicitReceiverHierarchy == null) { val result = ArrayList() @@ -82,12 +85,8 @@ public open class ChainedScope( override fun getDeclarationsByLabel(labelName: Name) = scopeChain.flatMap { it.getDeclarationsByLabel(labelName) } - override fun getDescriptors(kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean): Collection { - val result = LinkedHashSet() - scopeChain.flatMapTo(result) { it.getDescriptors(kindFilter, nameFilter) } - return result - } + override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) + = getFromAllScopes { it.getDescriptors(kindFilter, nameFilter) } override fun getOwnDeclaredDescriptors(): Collection { throw UnsupportedOperationException() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ExplicitImportsScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ExplicitImportsScope.kt index b2e6067b031..55dadbd0179 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ExplicitImportsScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ExplicitImportsScope.kt @@ -22,29 +22,19 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -public class ExplicitImportsScope(private val descriptors: Collection) : JetScope { +public class ExplicitImportsScope(private val descriptors: Collection) : JetScopeImpl() { override fun getClassifier(name: Name) = descriptors.filter { it.getName() == name }.firstIsInstanceOrNull() override fun getPackage(name: Name)= descriptors.filter { it.getName() == name }.firstIsInstanceOrNull() override fun getProperties(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance() - override fun getLocalVariable(name: Name): VariableDescriptor? = null - override fun getFunctions(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance() - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = listOf() - override fun getContainingDeclaration() = throw UnsupportedOperationException() - override fun getDeclarationsByLabel(labelName: Name) = emptyList() - override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = descriptors - override fun getImplicitReceiversHierarchy() = emptyList() - - override fun getOwnDeclaredDescriptors() = emptyList() - override fun printScopeStructure(p: Printer) { p.println(javaClass.getName()) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt index 313181b5638..650c8ff0f8c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt @@ -38,6 +38,8 @@ public class FilteringScope(private val workerScope: JetScope, private val predi override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = workerScope.getSyntheticExtensionProperties(receiverType, name).filter(predicate) + override fun getSyntheticExtensionProperties(receiverType: JetType) = workerScope.getSyntheticExtensionProperties(receiverType).filter(predicate) + override fun getLocalVariable(name: Name) = filterDescriptor(workerScope.getLocalVariable(name)) override fun getDescriptors(kindFilter: DescriptorKindFilter, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt index a6ba0850059..d2ddc74eca1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt @@ -37,6 +37,8 @@ public trait JetScope { public fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection + public fun getSyntheticExtensionProperties(receiverType: JetType): Collection + public fun getContainingDeclaration(): DeclarationDescriptor public fun getDeclarationsByLabel(labelName: Name): Collection diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt index 3761435f6f0..011ed035050 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt @@ -34,6 +34,8 @@ public abstract class JetScopeImpl : JetScope { override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = listOf() + override fun getSyntheticExtensionProperties(receiverType: JetType): Collection = listOf() + override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() override fun getDescriptors(kindFilter: DescriptorKindFilter, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinClass.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinClass.kt index d53d46cf158..cfe0ea28415 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinClass.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinClass.kt @@ -27,7 +27,7 @@ import kotlin.properties.Delegates public class StaticScopeForKotlinClass( private val containingClass: ClassDescriptor -) : JetScope { +) : JetScopeImpl() { override fun getClassifier(name: Name) = null // TODO private val functions: List by Delegates.lazy { @@ -46,13 +46,7 @@ public class StaticScopeForKotlinClass( override fun getFunctions(name: Name) = functions.filterTo(ArrayList(2)) { it.getName() == name } - override fun getPackage(name: Name) = null - override fun getProperties(name: Name) = listOf() - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = listOf() - override fun getLocalVariable(name: Name) = null override fun getContainingDeclaration() = containingClass - override fun getDeclarationsByLabel(labelName: Name) = listOf() - override fun getImplicitReceiversHierarchy() = listOf() override fun printScopeStructure(p: Printer) { p.println("Static scope for $containingClass") diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt index 19bc67d6cb6..2d53c9f2ad9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt @@ -71,6 +71,8 @@ public class SubstitutingScope(private val workerScope: JetScope, private val su override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = substitute(workerScope.getSyntheticExtensionProperties(receiverType, name)) + override fun getSyntheticExtensionProperties(receiverType: JetType) = substitute(workerScope.getSyntheticExtensionProperties(receiverType)) + override fun getPackage(name: Name) = workerScope.getPackage(name) override fun getImplicitReceiversHierarchy(): List { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 320058f54b3..6c0716e61dc 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -99,6 +99,12 @@ public class ErrorUtils { return ERROR_PROPERTY_GROUP; } + @NotNull + @Override + public Collection getSyntheticExtensionProperties(@NotNull JetType receiverType) { + return ERROR_PROPERTY_GROUP; + } + @Override public VariableDescriptor getLocalVariable(@NotNull Name name) { return ERROR_PROPERTY; @@ -209,6 +215,12 @@ public class ErrorUtils { throw new IllegalStateException(); } + @NotNull + @Override + public Collection getSyntheticExtensionProperties(@NotNull JetType receiverType) { + throw new IllegalStateException(); + } + @NotNull @Override public DeclarationDescriptor getContainingDeclaration() { diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberScope.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberScope.kt index 7ead7345cf7..f2cc98fdb0c 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberScope.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberScope.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl import org.jetbrains.kotlin.serialization.Flags import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind @@ -34,7 +34,7 @@ import java.util.LinkedHashSet public abstract class DeserializedMemberScope protected constructor( protected val c: DeserializationContext, membersList: Collection -) : JetScope { +) : JetScopeImpl() { private data class ProtoKey(val name: Name, val kind: Kind, val isExtension: Boolean) private enum class Kind { FUNCTION, PROPERTY } @@ -112,16 +112,8 @@ public abstract class DeserializedMemberScope protected constructor( protected abstract fun addClassDescriptors(result: MutableCollection, nameFilter: (Name) -> Boolean) - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = listOf() - - override fun getPackage(name: Name): PackageViewDescriptor? = null - - override fun getLocalVariable(name: Name): VariableDescriptor? = null - override fun getContainingDeclaration() = c.containingDeclaration - override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() - protected fun computeDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { //NOTE: descriptors should be in the same order they were serialized in diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 83fbe3443b2..96032f7e66f 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -88,6 +88,8 @@ public class ReferenceVariantsHelper( val descriptors = LinkedHashSet() + val dataFlowInfo = context.getDataFlowInfo(expression) + val pair = getExplicitReceiverData(expression) if (pair != null) { val (receiverExpression, callType) = pair @@ -104,25 +106,17 @@ public class ReferenceVariantsHelper( context.getType(receiverExpression) if (expressionType != null && !expressionType.isError()) { val receiverValue = ExpressionReceiver(receiverExpression, expressionType) - val dataFlowInfo = context.getDataFlowInfo(expression) - - for (variant in SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)) { - descriptors.addMembersFromReceiver(variant, callType, kindFilter, nameFilter) - } + descriptors.addMembersFromReceiverAndSyntheticExtensions(receiverValue, callType, kindFilter, nameFilter, resolutionScope, dataFlowInfo) descriptors.addCallableExtensions(resolutionScope, receiverValue, dataFlowInfo, callType, kindFilter, nameFilter) } } else { - val dataFlowInfo = context.getDataFlowInfo(expression) - // process instance members that can be called via implicit receiver's instances val receivers = resolutionScope.getImplicitReceiversWithInstance() val receiverValues = receivers.map { it.getValue() } for (receiverValue in receiverValues) { - for (variant in SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)) { - descriptors.addMembersFromReceiver(variant, CallType.NORMAL, kindFilter, nameFilter) - } + descriptors.addMembersFromReceiverAndSyntheticExtensions(receiverValue, CallType.NORMAL, kindFilter, nameFilter, resolutionScope, dataFlowInfo) } // process extensions and non-instance members @@ -143,22 +137,36 @@ public class ReferenceVariantsHelper( return descriptors } - private fun MutableCollection.addMembersFromReceiver( - receiverType: JetType, + private fun MutableSet.addMembersFromReceiverAndSyntheticExtensions( + receiverValue: ReceiverValue, callType: CallType, kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean + nameFilter: (Name) -> Boolean, + resolutionScope: JetScope, + dataFlowInfo: DataFlowInfo ) { - var memberFilter = kindFilter exclude DescriptorKindExclude.Extensions - val members = receiverType.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors - for (member in members) { - if (member is ClassDescriptor) { - if (member.isInner()) { - member.getConstructors().filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) } + val memberFilter = kindFilter exclude DescriptorKindExclude.Extensions + val containingDeclaration = resolutionScope.getContainingDeclaration() + + for (receiverType in SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)) { + val members = receiverType.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors + for (member in members) { + if (member is ClassDescriptor) { + if (member.isInner()) { + member.getConstructors().filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) } + } + } + else if (callType.canCall(member) && memberFilter.accepts(member)) { + this.add(member) } } - else if (callType.canCall(member) && memberFilter.accepts(member)) { - this.add(member) + + if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) { + for (extension in resolutionScope.getSyntheticExtensionProperties(receiverType)) { + if (nameFilter(extension.getName()) && kindFilter.accepts(extension)) { + addAll(extension.substituteExtensionIfCallable(receiverValue, callType, context, dataFlowInfo, containingDeclaration)) + } + } } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 62e7260e9dd..7f2178a7dbb 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -217,16 +217,20 @@ public class LookupElementFactory( if (descriptor is CallableDescriptor) { if (descriptor.getExtensionReceiverParameter() != null) { - val container = descriptor.getContainingDeclaration() - val containerPresentation = if (container is ClassDescriptor) { - DescriptorUtils.getFqNameFromTopLevelClass(container).toString() - } - else { - DescriptorUtils.getFqName(container).toString() - } val originalReceiver = descriptor.getOriginal().getExtensionReceiverParameter()!! val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(originalReceiver.getType()) - element = element.appendTailText(" for $receiverPresentation in $containerPresentation", true) + element = element.appendTailText(" for $receiverPresentation", true) + + val container = descriptor.getContainingDeclaration() + val containerPresentation = if (container is ClassDescriptor) + DescriptorUtils.getFqNameFromTopLevelClass(container).toString() + else if (container is PackageFragmentDescriptor) + container.fqName.toString() + else + null + if (containerPresentation != null) { + element = element.appendTailText(" in $containerPresentation", true) + } } else { val container = descriptor.getContainingDeclaration() diff --git a/idea/idea-completion/testData/basic/common/extensions/Extensions.kt b/idea/idea-completion/testData/basic/common/extensions/Extensions.kt index 2da87f2994a..bc09d2cd9b9 100644 --- a/idea/idea-completion/testData/basic/common/extensions/Extensions.kt +++ b/idea/idea-completion/testData/basic/common/extensions/Extensions.kt @@ -3,6 +3,8 @@ package a.b class Some { inner class Inner { fun foo() { + fun String.localExtension() = 1 + "". } @@ -19,3 +21,4 @@ val String.extProp: Int get() = 1 // EXIST: { lookupString: "extProp", itemText: "extProp", tailText: " for String in a.b", typeText: "Int" } // EXIST: { lookupString: "memberExtFun", itemText: "memberExtFun", tailText: "() for String in Some.Inner", typeText: "Unit" } // EXIST: { lookupString: "memberExtProp", itemText: "memberExtProp", tailText: " for String in Some", typeText: "Int" } +// EXIST: { lookupString: "localExtension", itemText: "localExtension", tailText: "() for String", typeText: "Int" } diff --git a/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions1.kt b/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions1.kt new file mode 100644 index 00000000000..568ab2a2869 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions1.kt @@ -0,0 +1,7 @@ +import java.io.File + +fun foo(file: File) { + file. +} + +// EXIST_JAVA_ONLY: { lookupString: "absolutePath", itemText: "absolutePath", tailText: " for File", typeText: "String!" } diff --git a/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions2.kt b/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions2.kt new file mode 100644 index 00000000000..511ecc4b5bd --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions2.kt @@ -0,0 +1,7 @@ +import java.io.File + +fun File.foo() { + +} + +// EXIST_JAVA_ONLY: { lookupString: "absolutePath", itemText: "absolutePath", tailText: " for File", typeText: "String!" } diff --git a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt new file mode 100644 index 00000000000..a4f68a36f93 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt @@ -0,0 +1,7 @@ +import java.io.File + +fun foo(file: File) { + file.abs +} + +// ELEMENT: absolutePath diff --git a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after new file mode 100644 index 00000000000..69f9eb2d9b1 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after @@ -0,0 +1,7 @@ +import java.io.File + +fun foo(file: File) { + file.absolutePath +} + +// ELEMENT: absolutePath diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index f4c5eb64996..0b5a1a64a44 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1209,6 +1209,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("SyntheticExtensions1.kt") + public void testSyntheticExtensions1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions1.kt"); + doTest(fileName); + } + + @TestMetadata("SyntheticExtensions2.kt") + public void testSyntheticExtensions2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions2.kt"); + doTest(fileName); + } + @TestMetadata("WrongExplicitReceiver.kt") public void testWrongExplicitReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/WrongExplicitReceiver.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 3f3935b0f2b..c0771c4c166 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1209,6 +1209,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("SyntheticExtensions1.kt") + public void testSyntheticExtensions1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions1.kt"); + doTest(fileName); + } + + @TestMetadata("SyntheticExtensions2.kt") + public void testSyntheticExtensions2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/SyntheticExtensions2.kt"); + doTest(fileName); + } + @TestMetadata("WrongExplicitReceiver.kt") public void testWrongExplicitReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/WrongExplicitReceiver.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index e29bb1ea289..7f62698685d 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -119,6 +119,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion doTest(fileName); } + @TestMetadata("SyntheticExtension.kt") + public void testSyntheticExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt"); + doTest(fileName); + } + @TestMetadata("idea/idea-completion/testData/handlers/basic/exclChar") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)