diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt index de66e6f240c..58620699393 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt @@ -26,17 +26,11 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.collectionUtils.concat import org.jetbrains.kotlin.utils.Printer -@Deprecated("We probably don't need it at all") -public fun LexicalScope.getImportingScopeChain(): ImportingScope { - var currentScope = this - while(currentScope.parent != null) { - currentScope = currentScope.parent!! - } - assert(currentScope is ImportingScope) { - "Not FileScope without parent: $currentScope" // todo improve debug message - } - return currentScope as ImportingScope -} +public val LexicalScope.parentsWithSelf: Sequence + get() = sequence(this) { it.parent } + +public val LexicalScope.parents: Sequence + get() = parentsWithSelf.drop(1) /** * Adds receivers to the list in order of locality, so that the closest (the most local) receiver goes first @@ -84,25 +78,21 @@ public fun LexicalScope.getDescriptorsFiltered( @Deprecated("Use getOwnProperties instead") public fun LexicalScope.getLocalVariable(name: Name): VariableDescriptor? { - processForMeAndParent { - if (it is LexicalScopeWrapper) { - it.delegate.getLocalVariable(name)?.let { return it } - } - else if (it is MemberScopeToImportingScopeAdapter) { // todo remove hack - it.memberScope.getLocalVariable(name)?.let { return it } - } - else if (it !is ImportingScope && it !is LexicalChainedScope) { // todo check this - it.getDeclaredVariables(name, NoLookupLocation.UNSORTED).singleOrNull()?.let { return it } + return findFirstFromMeAndParent { + when { + it is LexicalScopeWrapper -> it.delegate.getLocalVariable(name) + + it is MemberScopeToImportingScopeAdapter -> it.memberScope.getLocalVariable(name) /* todo remove hack*/ + + it !is ImportingScope && it !is LexicalChainedScope -> it.getDeclaredVariables(name, NoLookupLocation.UNSORTED).singleOrNull() /* todo check this*/ + + else -> null } } - return null } public fun LexicalScope.getClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { - processForMeAndParent { - it.getDeclaredClassifier(name, location)?.let { return it } - } - return null + return findFirstFromMeAndParent { it.getDeclaredClassifier(name, location) } } public fun LexicalScope.takeSnapshot(): LexicalScope = if (this is LexicalWritableScope) takeSnapshot() else this @@ -131,10 +121,7 @@ private class LexicalToKtScopeAdapter(lexicalScope: LexicalScope): KtScope { override fun getClassifier(name: Name, location: LookupLocation) = lexicalScope.getClassifier(name, location) override fun getPackage(name: Name): PackageViewDescriptor? { - lexicalScope.processForMeAndParent { - (it as? ImportingScope)?.getPackage(name)?.let { return it } - } - return null + return lexicalScope.findFirstFromMeAndParent { (it as? ImportingScope)?.getPackage(name) } } override fun getProperties(name: Name, location: LookupLocation): Collection { @@ -245,7 +232,7 @@ private class MemberScopeToImportingScopeAdapter(override val parent: ImportingS } } -private inline fun LexicalScope.processForMeAndParent(process: (LexicalScope) -> Unit) { +inline fun LexicalScope.processForMeAndParent(process: (LexicalScope) -> Unit) { var currentScope = this process(currentScope) @@ -271,7 +258,7 @@ private inline fun LexicalScope.collectFromMeAndParent( return result ?: emptyList() } -internal inline fun LexicalScope.collectAllFromMeAndParent( +inline fun LexicalScope.collectAllFromMeAndParent( collect: (LexicalScope) -> Collection ): Collection { var result: Collection? = null @@ -279,32 +266,40 @@ internal inline fun LexicalScope.collectAllFromMeAndParent( return result ?: emptySet() } -public fun LexicalScope.addImportScope(importScope: KtScope): LexicalScope { - val fileScope = getImportingScopeChain() - val scopeWithAdditionImport = - LexicalChainedScope(fileScope, fileScope.ownerDescriptor, false, null, "Scope with addition import", importScope) - return replaceFileScope(scopeWithAdditionImport) +inline fun LexicalScope.findFirstFromMeAndParent(fetch: (LexicalScope) -> T?): T? { + processForMeAndParent { fetch(it)?.let { return it } } + return null } -//TODO!!! -public fun LexicalScope.replaceFileScope(fileScopeReplace: LexicalScope): LexicalScope { - if (this is ImportingScope) return fileScopeReplace - - return LexicalScopeWrapper(this, fileScopeReplace) +fun LexicalScope.addImportScope(importScope: KtScope): LexicalScope { + if (this is ImportingScope) { + return importScope.memberScopeAsImportingScope(this) + } + else { + val lastNonImporting = parentsWithSelf.last { it !is ImportingScope } + val firstImporting = lastNonImporting.parent as ImportingScope? + val newImportingScope = importScope.memberScopeAsImportingScope(firstImporting) + return LexicalScopeWrapper(this, newImportingScope) + } } -public fun LexicalScope.withNoFileScope(): LexicalScope = replaceFileScope(MemberScopeToImportingScopeAdapter(null, KtScope.Empty)) +fun LexicalScope.replaceImportingScopes(importingScopeChain: ImportingScope?): LexicalScope { + return if (this is ImportingScope) + importingScopeChain!! + else + LexicalScopeWrapper(this, importingScopeChain) +} -private class LexicalScopeWrapper(val delegate: LexicalScope, val fileScopeReplace: LexicalScope): LexicalScope by delegate { +private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingScopeChain: ImportingScope?): LexicalScope by delegate { override val parent: LexicalScope? by lazy(LazyThreadSafetyMode.NONE) { - assert(delegate !is ImportingScope) { "We should replace FileScope($delegate) to $fileScopeReplace" } - val parent = delegate.parent!! + assert(delegate !is ImportingScope) - if (parent is ImportingScope) { - fileScopeReplace + val parent = delegate.parent + if (parent == null || parent is ImportingScope) { + newImportingScopeChain } else { - LexicalScopeWrapper(parent, fileScopeReplace) + LexicalScopeWrapper(parent, newImportingScopeChain) } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt index fe1051792f5..956efe98672 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt @@ -40,9 +40,10 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import org.jetbrains.kotlin.resolve.scopes.utils.findFirstFromMeAndParent import org.jetbrains.kotlin.resolve.scopes.utils.getClassifier -import org.jetbrains.kotlin.resolve.scopes.utils.getImportingScopeChain import java.util.* public class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT }) { @@ -280,7 +281,7 @@ public class ShortenReferences(val options: (KtElement) -> Options = { Options.D val targetByName = if (target is ClassifierDescriptor) scope.getClassifier(name, NoLookupLocation.FROM_IDE) else - scope.getImportingScopeChain().getPackage(name) + scope.findFirstFromMeAndParent { (it as? ImportingScope)?.getPackage(name) } val canShortenNow = targetByName?.asString() == target.asString() processQualifiedElement(type, target, canShortenNow) diff --git a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt index a10db124e01..387ebaadcc6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt @@ -40,10 +40,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor import org.jetbrains.kotlin.resolve.scopes.KtScope -import org.jetbrains.kotlin.resolve.scopes.utils.asKtScope -import org.jetbrains.kotlin.resolve.scopes.utils.getClassifier -import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy -import org.jetbrains.kotlin.resolve.scopes.utils.withNoFileScope +import org.jetbrains.kotlin.resolve.scopes.utils.* import java.util.* public class KotlinImportOptimizer() : ImportOptimizer { @@ -137,7 +134,7 @@ public class KotlinImportOptimizer() : ImportOptimizer { } val resolutionScope = place.getResolutionScope(bindingContext, place.getResolutionFacade()) - val noImportsScope = resolutionScope.withNoFileScope() + val noImportsScope = resolutionScope.replaceImportingScopes(null) return isInScope(noImportsScope.asKtScope()) || resolutionScope.getImplicitReceiversHierarchy().any { isInScope(it.type.memberScope) } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt index bb0b122ec99..5231ea31630 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden import org.jetbrains.kotlin.resolve.scopes.ImportingScope +import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull @@ -89,8 +90,12 @@ public class ConflictingExtensionPropertyInspection : AbstractKotlinInspection() private fun conflictingSyntheticExtension(descriptor: PropertyDescriptor, importingScope: ImportingScope): SyntheticJavaPropertyDescriptor? { val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null return importingScope - .getSyntheticExtensionProperties(listOf(extensionReceiverType), descriptor.name, NoLookupLocation.FROM_IDE) - .firstIsInstanceOrNull() + .collectAllFromMeAndParent { + (it as? ImportingScope) + ?.getSyntheticExtensionProperties(listOf(extensionReceiverType), descriptor.name, NoLookupLocation.FROM_IDE) + ?: emptyList() + } + .firstIsInstanceOrNull() } private fun isSameAsSynthetic(declaration: KtProperty, syntheticProperty: SyntheticJavaPropertyDescriptor): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt index 4e9284e26e6..ef9dcdf097b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt @@ -41,7 +41,8 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.resolve.scopes.utils.getImportingScopeChain +import org.jetbrains.kotlin.resolve.scopes.ImportingScope +import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.utils.addToStdlib.check @@ -178,12 +179,14 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() { } // SAM adapters for member functions - val resolutionScope = functionCall.getResolutionScope(bindingContext, functionCall.getResolutionFacade()).getImportingScopeChain() - val syntheticExtensions = resolutionScope.getSyntheticExtensionFunctions( - containingClass.defaultType.singletonList(), - functionResolvedCall.resultingDescriptor.name, - NoLookupLocation.FROM_IDE - ) + val resolutionScope = functionCall.getResolutionScope(bindingContext, functionCall.getResolutionFacade()) + val syntheticExtensions = resolutionScope.collectAllFromMeAndParent { + (it as? ImportingScope)?.getSyntheticExtensionFunctions( + containingClass.defaultType.singletonList(), + functionResolvedCall.resultingDescriptor.name, + NoLookupLocation.FROM_IDE + ) ?: emptyList() + } for (syntheticExtension in syntheticExtensions) { val samAdapter = syntheticExtension as? SamAdapterExtensionFunctionDescriptor ?: continue if (isSamAdapterSuitableForCall(samAdapter, originalFunctionDescriptor, samConstructorCalls.size())) {