diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplCodeAnalyzer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplCodeAnalyzer.kt index 60f4ffa4ac1..98048a4adbd 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplCodeAnalyzer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplCodeAnalyzer.kt @@ -222,7 +222,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) { val lastLineImports = lexicalScopeAfterLastLine.parentsWithSelf.first { it is ImportingScope } as ImportingScope val scopesForThisLine = fileScopeFactory.createScopesForFile(lineInfo.linePsi, lastLineImports) val combinedLexicalScopes = lexicalScopeAfterLastLine.replaceImportingScopes(scopesForThisLine.importingScope) - return FileScopes(combinedLexicalScopes, scopesForThisLine.importingScope, scopesForThisLine.importResolver) + return FileScopes(combinedLexicalScopes, scopesForThisLine.importingScope, scopesForThisLine.importForceResolver) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index b5dab79fffc..ac114c27574 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -247,7 +247,7 @@ class LazyTopDownAnalyzer( } fun resolveImportsInFile(file: KtFile) { - fileScopeProvider.getImportResolver(file).forceResolveAllImports() + fileScopeProvider.getImportResolver(file).forceResolveNonDefaultImports() } private fun createTypeAliasDescriptors( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt index ac3fd1255c9..5c309e50d0b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportInfo import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.scopes.* @@ -33,7 +34,7 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.utils.Printer -data class FileScopes(val lexicalScope: LexicalScope, val importingScope: ImportingScope, val importResolver: ImportResolver) +data class FileScopes(val lexicalScope: LexicalScope, val importingScope: ImportingScope, val importForceResolver: ImportForceResolver) class FileScopeFactory( private val topLevelDescriptorProvider: TopLevelDescriptorProvider, @@ -69,13 +70,13 @@ class FileScopeFactory( } private data class DefaultImportResolvers( - val explicit: LazyImportResolver, - val allUnder: LazyImportResolver, - val lowPriority: LazyImportResolver + val explicit: LazyImportResolver, + val allUnder: LazyImportResolver, + val lowPriority: LazyImportResolver ) private fun createDefaultImportResolvers( - extraImports: Collection, + extraImports: Collection, aliasImportNames: Collection ): DefaultImportResolvers { val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve", false) @@ -87,20 +88,20 @@ class FileScopeFactory( allImplicitImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames } } - val explicit = createImportResolver( + val explicit = createDefaultImportResolver( ExplicitImportsIndexed(defaultImportsFiltered), tempTrace, packageFragment = null, aliasImportNames = aliasImportNames ) - val allUnder = createImportResolver( + val allUnder = createDefaultImportResolver( AllUnderImportsIndexed(defaultImportsFiltered), tempTrace, packageFragment = null, aliasImportNames = aliasImportNames, excludedImports = targetPlatform.excludedImports ) - val lowPriority = createImportResolver( + val lowPriority = createDefaultImportResolver( AllUnderImportsIndexed(defaultLowPriorityImports.also { imports -> assert(imports.all { it.isAllUnder }) { "All low priority imports must be all-under: $imports" } }), @@ -116,8 +117,8 @@ class FileScopeFactory( createDefaultImportResolvers(emptyList(), emptyList()) } - private fun createImportResolver( - indexedImports: IndexedImports, + private fun createDefaultImportResolver( + indexedImports: IndexedImports, trace: BindingTrace, aliasImportNames: Collection, packageFragment: PackageFragmentDescriptor?, @@ -128,6 +129,17 @@ class FileScopeFactory( deprecationResolver ) + private fun createImportResolver( + indexedImports: IndexedImports, + trace: BindingTrace, + aliasImportNames: Collection, + packageFragment: PackageFragmentDescriptor?, + excludedImports: List? = null + ) = LazyImportResolverForKtImportDirective( + storageManager, qualifiedExpressionResolver, moduleDescriptor, platformToKotlinClassMap, languageVersionSettings, + indexedImports, aliasImportNames concat excludedImports, trace, packageFragment, + deprecationResolver + ) private inner class FilesScopesBuilder( private val file: KtFile, @@ -156,13 +168,13 @@ class FileScopeFactory( val lexicalScope = LexicalScope.Base(lazyImportingScope, topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(file.packageFqName, file)) - val importResolver = object : ImportResolver { - override fun forceResolveAllImports() { - explicitImportResolver.forceResolveAllImports() - allUnderImportResolver.forceResolveAllImports() + val importResolver = object : ImportForceResolver { + override fun forceResolveNonDefaultImports() { + explicitImportResolver.forceResolveNonDefaultImports() + allUnderImportResolver.forceResolveNonDefaultImports() } - override fun forceResolveImport(importDirective: KtImportInfo) { + override fun forceResolveImport(importDirective: KtImportDirective) { if (importDirective.isAllUnder) { allUnderImportResolver.forceResolveImport(importDirective) } else { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProvider.kt index 58f06f9e99b..939cbceaa4b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProvider.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.storage.StorageManager @DefaultImplementation(FileScopeProviderImpl::class) interface FileScopeProvider { fun getFileResolutionScope(file: KtFile): LexicalScope = getFileScopes(file).lexicalScope - fun getImportResolver(file: KtFile): ImportResolver = getFileScopes(file).importResolver + fun getImportResolver(file: KtFile): ImportForceResolver = getFileScopes(file).importForceResolver fun getFileScopes(file: KtFile): FileScopes @@ -57,4 +57,4 @@ interface FileScopesCustomizer { fun createFileScopes(fileScopeFactory: FileScopeFactory): FileScopes } -var KtFile.fileScopesCustomizer: FileScopesCustomizer? by UserDataProperty(Key.create("FILE_SCOPES_CUSTOMIZER")) \ No newline at end of file +var KtFile.fileScopesCustomizer: FileScopesCustomizer? by UserDataProperty(Key.create("FILE_SCOPES_CUSTOMIZER")) 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 877fded684c..36bc608d8a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.incremental.components.LookupLocation -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtImportDirective @@ -42,21 +41,21 @@ import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable import org.jetbrains.kotlin.utils.ifEmpty -interface IndexedImports { - val imports: List - fun importsForName(name: Name): Collection +interface IndexedImports { + val imports: List + fun importsForName(name: Name): Collection } -class AllUnderImportsIndexed(allImports: Collection) : IndexedImports { +class AllUnderImportsIndexed(allImports: Collection) : IndexedImports { override val imports = allImports.filter { it.isAllUnder } override fun importsForName(name: Name) = imports } -class ExplicitImportsIndexed(allImports: Collection) : IndexedImports { +class ExplicitImportsIndexed(allImports: Collection) : IndexedImports { override val imports = allImports.filter { !it.isAllUnder } - private val nameToDirectives: ListMultimap by lazy { - val builder = ImmutableListMultimap.builder() + private val nameToDirectives: ListMultimap by lazy { + val builder = ImmutableListMultimap.builder() for (directive in imports) { val importedName = directive.importedName ?: continue // parse error @@ -69,100 +68,29 @@ class ExplicitImportsIndexed(allImports: Collection) : IndexedImpo override fun importsForName(name: Name) = nameToDirectives.get(name) } -interface ImportResolver { - fun forceResolveAllImports() - fun forceResolveImport(importDirective: KtImportInfo) +interface ImportForceResolver { + fun forceResolveNonDefaultImports() + fun forceResolveImport(importDirective: KtImportDirective) } -class LazyImportResolver( +open class LazyImportResolver( val storageManager: StorageManager, private val qualifiedExpressionResolver: QualifiedExpressionResolver, val moduleDescriptor: ModuleDescriptor, private val platformToKotlinClassMap: PlatformToKotlinClassMap, val languageVersionSettings: LanguageVersionSettings, - val indexedImports: IndexedImports, + val indexedImports: IndexedImports, excludedImportNames: Collection, - private val traceForImportResolve: BindingTrace, + protected val traceForImportResolve: BindingTrace, private val packageFragment: PackageFragmentDescriptor?, val deprecationResolver: DeprecationResolver -) : ImportResolver { +) { private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues { directive: KtImportInfo -> - qualifiedExpressionResolver.processImportReference( directive, moduleDescriptor, traceForImportResolve, excludedImportNames, packageFragment ) } - private val forceResolveImportDirective = storageManager.createMemoizedFunction { directive: KtImportInfo -> - val scope = importedScopesProvider(directive) - if (scope is LazyExplicitImportScope) { - val allDescriptors = scope.storeReferencesToDescriptors() - if (directive is KtImportDirective) { - PlatformClassesMappedToKotlinChecker.checkPlatformClassesMappedToKotlin( - platformToKotlinClassMap, traceForImportResolve, directive, allDescriptors - ) - } - } - - Unit - } - - private val forceResolveAllImportsTask: NotNullLazyValue = storageManager.createLazyValue { - val explicitClassImports = HashMultimap.create() - for (importDirective in indexedImports.imports) { - forceResolveImport(importDirective) - val scope = importedScopesProvider(importDirective) - - val alias = importDirective.importedName - if (scope != null && alias != null) { - val lookupLocation = when (importDirective) { - is KtImportDirective -> KotlinLookupLocation(importDirective) - else -> NoLookupLocation.FOR_DEFAULT_IMPORTS - } - if (scope.getContributedClassifier(alias, lookupLocation) != null) { - explicitClassImports.put(alias.asString(), importDirective) - } - } - - checkResolvedImportDirective(importDirective) - } - for ((alias, import) in explicitClassImports.entries()) { - if (import !is KtImportDirective) continue - if (alias.all { it == '_' }) { - traceForImportResolve.report(Errors.UNDERSCORE_IS_RESERVED.on(import)) - } - } - for (alias in explicitClassImports.keySet()) { - val imports = explicitClassImports.get(alias) - if (imports.size > 1) { - imports.filterIsInstance().forEach { - traceForImportResolve.report(Errors.CONFLICTING_IMPORT.on(it, alias)) - } - } - } - } - - override fun forceResolveAllImports() { - forceResolveAllImportsTask() - } - - private fun checkResolvedImportDirective(importDirective: KtImportInfo) { - if (importDirective !is KtImportDirective) return - val importedReference = KtPsiUtil.getLastReference(importDirective.importedReference ?: return) ?: return - val importedDescriptor = traceForImportResolve.bindingContext.get(BindingContext.REFERENCE_TARGET, importedReference) ?: return - - val aliasName = importDirective.aliasName - - if (importedDescriptor is FunctionDescriptor && importedDescriptor.isOperator && - aliasName != null && OperatorConventions.isConventionName(Name.identifier(aliasName))) { - traceForImportResolve.report(Errors.OPERATOR_RENAMED_ON_IMPORT.on(importedReference)) - } - } - - override fun forceResolveImport(importDirective: KtImportInfo) { - forceResolveImportDirective(importDirective) - } - fun selectSingleFromImports( name: Name, descriptorSelector: (ImportingScope, Name) -> D? @@ -214,10 +142,100 @@ class LazyImportResolver( } } +class LazyImportResolverForKtImportDirective( + storageManager: StorageManager, + qualifiedExpressionResolver: QualifiedExpressionResolver, + moduleDescriptor: ModuleDescriptor, + platformToKotlinClassMap: PlatformToKotlinClassMap, + languageVersionSettings: LanguageVersionSettings, + indexedImports: IndexedImports, + excludedImportNames: Collection, + traceForImportResolve: BindingTrace, + packageFragment: PackageFragmentDescriptor?, + deprecationResolver: DeprecationResolver +) : LazyImportResolver( + storageManager, + qualifiedExpressionResolver, + moduleDescriptor, + platformToKotlinClassMap, + languageVersionSettings, + indexedImports, + excludedImportNames, + traceForImportResolve, + packageFragment, + deprecationResolver +), ImportForceResolver { + + private val forceResolveImportDirective = storageManager.createMemoizedFunction { directive: KtImportDirective -> + val scope = getImportScope(directive) + if (scope is LazyExplicitImportScope) { + val allDescriptors = scope.storeReferencesToDescriptors() + PlatformClassesMappedToKotlinChecker.checkPlatformClassesMappedToKotlin( + platformToKotlinClassMap, traceForImportResolve, directive, allDescriptors + ) + } + + Unit + } + + private val forceResolveNonDefaultImportsTask: NotNullLazyValue = storageManager.createLazyValue { + val explicitClassImports = HashMultimap.create() + for (importInfo in indexedImports.imports) { + forceResolveImport(importInfo) + + val scope = getImportScope(importInfo) + + val alias = importInfo.importedName + if (alias != null) { + val lookupLocation = KotlinLookupLocation(importInfo) + if (scope.getContributedClassifier(alias, lookupLocation) != null) { + explicitClassImports.put(alias.asString(), importInfo) + } + } + + checkResolvedImportDirective(importInfo) + } + for ((alias, import) in explicitClassImports.entries()) { + if (alias.all { it == '_' }) { + traceForImportResolve.report(Errors.UNDERSCORE_IS_RESERVED.on(import)) + } + } + for (alias in explicitClassImports.keySet()) { + val imports = explicitClassImports.get(alias) + if (imports.size > 1) { + imports.forEach { + traceForImportResolve.report(Errors.CONFLICTING_IMPORT.on(it, alias)) + } + } + } + } + + override fun forceResolveNonDefaultImports() { + forceResolveNonDefaultImportsTask() + } + + private fun checkResolvedImportDirective(importDirective: KtImportInfo) { + if (importDirective !is KtImportDirective) return + val importedReference = KtPsiUtil.getLastReference(importDirective.importedReference ?: return) ?: return + val importedDescriptor = traceForImportResolve.bindingContext.get(BindingContext.REFERENCE_TARGET, importedReference) ?: return + + val aliasName = importDirective.aliasName + + if (importedDescriptor is FunctionDescriptor && importedDescriptor.isOperator && + aliasName != null && OperatorConventions.isConventionName(Name.identifier(aliasName))) { + traceForImportResolve.report(Errors.OPERATOR_RENAMED_ON_IMPORT.on(importedReference)) + } + } + + override fun forceResolveImport(importDirective: KtImportDirective) { + forceResolveImportDirective(importDirective) + } +} + class LazyImportScope( override val parent: ImportingScope?, - private val importResolver: LazyImportResolver, - private val secondaryImportResolver: LazyImportResolver?, + private val importResolver: LazyImportResolver<*>, + private val secondaryImportResolver: LazyImportResolver<*>?, private val filteringKind: LazyImportScope.FilteringKind, private val debugName: String ) : ImportingScope { @@ -228,7 +246,7 @@ class LazyImportScope( INVISIBLE_CLASSES } - private fun LazyImportResolver.isClassifierVisible(descriptor: ClassifierDescriptor): Boolean { + private fun LazyImportResolver<*>.isClassifierVisible(descriptor: ClassifierDescriptor): Boolean { if (filteringKind == FilteringKind.ALL) return true if (deprecationResolver.isHiddenInResolution(descriptor)) return false @@ -243,7 +261,7 @@ class LazyImportScope( return importResolver.getClassifier(name, location) ?: secondaryImportResolver?.getClassifier(name, location) } - private fun LazyImportResolver.getClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { + private fun LazyImportResolver<*>.getClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { return selectSingleFromImports(name) { scope, _ -> val descriptor = scope.getContributedClassifier(name, location) if ((descriptor is ClassDescriptor || descriptor is TypeAliasDescriptor) && isClassifierVisible(descriptor)) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/repl/ReplState.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/repl/ReplState.kt index aac6e9453f7..fc6b2315b03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/repl/ReplState.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/repl/ReplState.kt @@ -77,6 +77,6 @@ class ReplState { val lastLineImports = lexicalScopeAfterLastLine.parentsWithSelf.firstIsInstance() val scopesForThisLine = fileScopeFactory.createScopesForFile(lineInfo.linePsi, lastLineImports) val combinedLexicalScopes = lexicalScopeAfterLastLine.replaceImportingScopes(scopesForThisLine.importingScope) - return FileScopes(combinedLexicalScopes, scopesForThisLine.importingScope, scopesForThisLine.importResolver) + return FileScopes(combinedLexicalScopes, scopesForThisLine.importingScope, scopesForThisLine.importForceResolver) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 6f134a15053..f60d653c581 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -371,7 +371,7 @@ class ResolveElementCache( is KtImportList -> { val resolver = resolveSession.fileScopeProvider.getImportResolver(resolveElement.getContainingKtFile()) - resolver.forceResolveAllImports() + resolver.forceResolveNonDefaultImports() resolveSession.trace }