Allow to exclude specific types from packages imported by default.

This commit is contained in:
Ilya Gorbunov
2016-08-11 20:18:17 +03:00
parent 0f8bf310f2
commit afe1b7eab1
10 changed files with 41 additions and 25 deletions
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.utils.Printer
class AllUnderImportScope( class AllUnderImportScope(
descriptor: DeclarationDescriptor, descriptor: DeclarationDescriptor,
aliasImportNames: Collection<FqName> excludedImportNames: Collection<FqName>
) : BaseImportingScope(null) { ) : BaseImportingScope(null) {
private val scopes: List<ResolutionScope> = if (descriptor is ClassDescriptor) { private val scopes: List<ResolutionScope> = if (descriptor is ClassDescriptor) {
@@ -40,12 +40,13 @@ class AllUnderImportScope(
listOf((descriptor as PackageViewDescriptor).memberScope) listOf((descriptor as PackageViewDescriptor).memberScope)
} }
private val excludedNames = if (aliasImportNames.isEmpty()) { // optimization private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
emptyList<Name>() emptySet<Name>()
} }
else { else {
val fqName = DescriptorUtils.getFqNameSafe(descriptor) val fqName = DescriptorUtils.getFqNameSafe(descriptor)
aliasImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null } // toSet() is used here instead mapNotNullTo(hashSetOf()) because it results in not keeping empty sets as separate instances
excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
} }
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<DeclarationDescriptor> { override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<DeclarationDescriptor> {
@@ -158,7 +158,7 @@ class QualifiedExpressionResolver(val classifierUsageCheckers: Iterable<Classifi
importDirective: KtImportDirective, importDirective: KtImportDirective,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
trace: BindingTrace, trace: BindingTrace,
aliasImportNames: Collection<FqName>, excludedImportNames: Collection<FqName>,
packageFragmentForVisibilityCheck: PackageFragmentDescriptor? packageFragmentForVisibilityCheck: PackageFragmentDescriptor?
): ImportingScope? { // null if some error happened ): ImportingScope? { // null if some error happened
val importedReference = importDirective.importedReference ?: return null val importedReference = importDirective.importedReference ?: return null
@@ -182,7 +182,7 @@ class QualifiedExpressionResolver(val classifierUsageCheckers: Iterable<Classifi
return null return null
} }
return AllUnderImportScope(packageOrClassDescriptor, aliasImportNames) return AllUnderImportScope(packageOrClassDescriptor, excludedImportNames)
} }
else { else {
return processSingleImport(moduleDescriptor, trace, importDirective, path, lastPart, packageFragmentForCheck) return processSingleImport(moduleDescriptor, trace, importDirective, path, lastPart, packageFragmentForCheck)
@@ -58,26 +58,19 @@ class FileScopeFactory(
val debugName = "LazyFileScope for file " + file.name val debugName = "LazyFileScope for file " + file.name
val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve") val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve")
infix fun <T> Collection<T>.concat(other: Collection<T>?) =
if (other == null || other.isEmpty()) this else this + other
val imports = file.importDirectives val imports = file.importDirectives
val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null } val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null }
val packageView = moduleDescriptor.getPackage(file.packageFqName)
val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName)
?: error("Could not find fragment ${file.packageFqName} for file ${file.name}")
fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace)
= LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, aliasImportNames, trace, packageFragment)
val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace)
val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace)
val extraImports = file.originalFile.virtualFile?.let { vFile -> val extraImports = file.originalFile.virtualFile?.let { vFile ->
val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project) val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project)
ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map { ImportPath(it) }.orEmpty()) ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map { ImportPath(it) }.orEmpty())
} }
val allImplicitImports = defaultImports + extraImports.orEmpty() val allImplicitImports = defaultImports concat extraImports
val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization
allImplicitImports allImplicitImports
@@ -85,8 +78,19 @@ class FileScopeFactory(
else { else {
allImplicitImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames } allImplicitImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames }
} }
val packageView = moduleDescriptor.getPackage(file.packageFqName)
val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName)
?: error("Could not find fragment ${file.packageFqName} for file ${file.name}")
fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace, excludedImports: List<FqName>? = null)
= LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, aliasImportNames concat excludedImports, trace, packageFragment)
val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace)
val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace) // TODO: should we count excludedImports here also?
val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace) val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace)
val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace) val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace, moduleDescriptor.excludedImports)
val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment) val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment)
@@ -75,14 +75,14 @@ class LazyImportResolver(
val qualifiedExpressionResolver: QualifiedExpressionResolver, val qualifiedExpressionResolver: QualifiedExpressionResolver,
val moduleDescriptor: ModuleDescriptor, val moduleDescriptor: ModuleDescriptor,
val indexedImports: IndexedImports, val indexedImports: IndexedImports,
aliasImportNames: Collection<FqName>, excludedImportNames: Collection<FqName>,
private val traceForImportResolve: BindingTrace, private val traceForImportResolve: BindingTrace,
private val packageFragment: PackageFragmentDescriptor private val packageFragment: PackageFragmentDescriptor
) : ImportResolver { ) : ImportResolver {
private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues { private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues {
directive: KtImportDirective -> directive: KtImportDirective ->
val directiveImportScope = qualifiedExpressionResolver.processImportReference( val directiveImportScope = qualifiedExpressionResolver.processImportReference(
directive, moduleDescriptor, traceForImportResolve, aliasImportNames, packageFragment) ?: return@createMemoizedFunctionWithNullableValues null directive, moduleDescriptor, traceForImportResolve, excludedImportNames, packageFragment) ?: return@createMemoizedFunctionWithNullableValues null
if (!directive.isAllUnder) { if (!directive.isAllUnder) {
PlatformTypesMappedToKotlinChecker.checkPlatformTypesMappedToKotlin( PlatformTypesMappedToKotlinChecker.checkPlatformTypesMappedToKotlin(
@@ -49,7 +49,7 @@ class RuntimeModuleData private constructor(val deserialization: Deserialization
val storageManager = LockBasedStorageManager() val storageManager = LockBasedStorageManager()
val builtIns = JvmBuiltIns(storageManager) val builtIns = JvmBuiltIns(storageManager)
val module = ModuleDescriptorImpl(Name.special("<runtime module for $classLoader>"), storageManager, val module = ModuleDescriptorImpl(Name.special("<runtime module for $classLoader>"), storageManager,
ModuleParameters(listOf(), JavaToKotlinClassMap.INSTANCE), builtIns) ModuleParameters(emptyList(), emptyList(), JavaToKotlinClassMap.INSTANCE), builtIns)
val reflectKotlinClassFinder = ReflectKotlinClassFinder(classLoader) val reflectKotlinClassFinder = ReflectKotlinClassFinder(classLoader)
val deserializedDescriptorResolver = DeserializedDescriptorResolver(RuntimeErrorReporter) val deserializedDescriptorResolver = DeserializedDescriptorResolver(RuntimeErrorReporter)
@@ -49,6 +49,7 @@ interface ModuleDescriptor : DeclarationDescriptor, ModuleParameters {
interface ModuleParameters { interface ModuleParameters {
val defaultImports: List<ImportPath> val defaultImports: List<ImportPath>
val excludedImports: List<FqName> get() = emptyList()
val platformToKotlinClassMap: PlatformToKotlinClassMap val platformToKotlinClassMap: PlatformToKotlinClassMap
object Empty: ModuleParameters { object Empty: ModuleParameters {
@@ -57,8 +58,9 @@ interface ModuleParameters {
} }
} }
fun ModuleParameters(defaultImports: List<ImportPath>, platformToKotlinClassMap: PlatformToKotlinClassMap): ModuleParameters = fun ModuleParameters(defaultImports: List<ImportPath>, excludedImports: List<FqName>, platformToKotlinClassMap: PlatformToKotlinClassMap): ModuleParameters =
object : ModuleParameters { object : ModuleParameters {
override val defaultImports: List<ImportPath> = defaultImports override val defaultImports: List<ImportPath> = defaultImports
override val excludedImports: List<FqName> get() = excludedImports
override val platformToKotlinClassMap: PlatformToKotlinClassMap = platformToKotlinClassMap override val platformToKotlinClassMap: PlatformToKotlinClassMap = platformToKotlinClassMap
} }
@@ -69,6 +69,12 @@ public class ErrorUtils {
return emptyList(); return emptyList();
} }
@NotNull
@Override
public List<FqName> getExcludedImports() {
return emptyList();
}
@NotNull @NotNull
@Override @Override
public Annotations getAnnotations() { public Annotations getAnnotations() {
@@ -85,5 +85,5 @@ fun ResolutionFacade.resolveImportReference(
val importDirective = KtPsiFactory(project).createImportDirective(ImportPath(fqName, false)) val importDirective = KtPsiFactory(project).createImportDirective(ImportPath(fqName, false))
val qualifiedExpressionResolver = this.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java) val qualifiedExpressionResolver = this.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java)
return qualifiedExpressionResolver.processImportReference( return qualifiedExpressionResolver.processImportReference(
importDirective, moduleDescriptor, BindingTraceContext(), aliasImportNames = emptyList(), packageFragmentForVisibilityCheck = null)?.getContributedDescriptors() ?: emptyList() importDirective, moduleDescriptor, BindingTraceContext(), excludedImportNames = emptyList(), packageFragmentForVisibilityCheck = null)?.getContributedDescriptors() ?: emptyList()
} }
@@ -136,7 +136,7 @@ class CodeFragmentAnalyzer(
val importScopes = importList.imports.mapNotNull { val importScopes = importList.imports.mapNotNull {
qualifierResolver.processImportReference(it, resolveSession.moduleDescriptor, resolveSession.trace, qualifierResolver.processImportReference(it, resolveSession.moduleDescriptor, resolveSession.trace,
aliasImportNames = emptyList(), packageFragmentForVisibilityCheck = null) excludedImportNames = emptyList(), packageFragmentForVisibilityCheck = null)
} }
return scopeForContextElement.addImportingScopes(importScopes) to dataFlowInfo return scopeForContextElement.addImportingScopes(importScopes) to dataFlowInfo
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.context.ContextKt;
import org.jetbrains.kotlin.context.MutableModuleContext; import org.jetbrains.kotlin.context.MutableModuleContext;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ModuleDescriptorKt; import org.jetbrains.kotlin.descriptors.ModuleDescriptorKt;
import org.jetbrains.kotlin.descriptors.ModuleParameters;
import org.jetbrains.kotlin.frontend.di.InjectionKt; import org.jetbrains.kotlin.frontend.di.InjectionKt;
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex; import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex;
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope; import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope;
@@ -239,10 +240,12 @@ public class SourceNavigationHelper {
) { ) {
TargetPlatform platform = TargetPlatform.Default.INSTANCE; TargetPlatform platform = TargetPlatform.Default.INSTANCE;
ModuleParameters defaultJvmModuleParameters = JvmPlatform.INSTANCE.getDefaultModuleParameters();
MutableModuleContext newModuleContext = ContextKt.ContextForNewModule( MutableModuleContext newModuleContext = ContextKt.ContextForNewModule(
project, Name.special("<library module>"), project, Name.special("<library module>"),
ModuleDescriptorKt.ModuleParameters( ModuleDescriptorKt.ModuleParameters(
JvmPlatform.INSTANCE.getDefaultModuleParameters().getDefaultImports(), defaultJvmModuleParameters.getDefaultImports(),
defaultJvmModuleParameters.getExcludedImports(),
PlatformToKotlinClassMap.EMPTY PlatformToKotlinClassMap.EMPTY
), ),
DefaultBuiltIns.getInstance() DefaultBuiltIns.getInstance()