Support JvmPackageName annotation in binary format

The main changes are in jvm_package_table.proto and ModuleMapping.kt.
With JvmPackageName, package parts can now have a JVM package name that
differs from their Kotlin name. So, in addition to the old package parts
which were stored as short names + short name of multifile facade (we
can't change this because of compatibility with old compilers), we now
store separately those package parts, which have a different JVM package
name. The format is optimized to avoid storing any package name more
than once as a string.

Another notable change is in KotlinCliJavaFileManagerImpl, where we now
load .kotlin_module files when determining whether or not a package
exists. Before this change, no PsiPackage (and thus, no JavaPackage and
eventually, no LazyJavaPackageFragment) was created unless there was at
least one file in the corresponding directory. Now we also create
packages if they are "mapped" to other JVM packages, i.e. if all package
parts in them have been annotated with JvmPackageName.

Most of the other changes are refactorings to allow internal names of
package parts/multifile classes where previously there were only short
names.
This commit is contained in:
Alexander Udalov
2017-09-06 15:14:47 +03:00
parent d07b628e0c
commit 70ae1596fb
44 changed files with 2614 additions and 657 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.fileClasses
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
@@ -39,10 +38,9 @@ object JvmFileClassUtil {
private const val MULTIFILE_PART_NAME_DELIMITER = "__"
fun getPartFqNameForDeserialized(descriptor: DeserializedMemberDescriptor): FqName {
val implClassName = descriptor.getImplClassNameForDeserialized() ?: error("No implClassName for $descriptor")
return (descriptor.containingDeclaration as PackageFragmentDescriptor).fqName.child(implClassName)
}
fun getPartFqNameForDeserialized(descriptor: DeserializedMemberDescriptor): FqName =
descriptor.getImplClassNameForDeserialized()?.fqNameForTopLevelClassMaybeWithDollars
?: error("No implClassName for $descriptor")
@JvmStatic
fun getFileClassInternalName(file: KtFile): String =
@@ -64,36 +64,33 @@ class IncrementalPackageFragmentProvider(
get() = this@IncrementalPackageFragmentProvider.target
fun getPackageFragmentForMultifileClass(multifileClassFqName: FqName): IncrementalMultifileClassPackageFragment? {
val facadeInternalName = JvmClassName.byFqNameWithoutInnerClasses(multifileClassFqName).internalName
val partsNames = incrementalCache.getStableMultifileFacadeParts(facadeInternalName) ?: return null
return IncrementalMultifileClassPackageFragment(multifileClassFqName, partsNames)
val facadeName = JvmClassName.byFqNameWithoutInnerClasses(multifileClassFqName)
val partsNames = incrementalCache.getStableMultifileFacadeParts(facadeName.internalName) ?: return null
return IncrementalMultifileClassPackageFragment(facadeName, partsNames, multifileClassFqName.parent())
}
override fun getMemberScope(): MemberScope = MemberScope.Empty
}
inner class IncrementalMultifileClassPackageFragment(
private val multifileClassFqName: FqName,
val partsInternalNames: Collection<String>
) : PackageFragmentDescriptorImpl(moduleDescriptor, multifileClassFqName.parent()) {
val facadeName: JvmClassName,
val partsInternalNames: Collection<String>,
packageFqName: FqName
) : PackageFragmentDescriptorImpl(moduleDescriptor, packageFqName) {
private val memberScope = storageManager.createLazyValue {
ChainedMemberScope.create(
"Member scope for incremental compilation: union of multifile class parts data for $multifileClassFqName",
"Member scope for incremental compilation: union of multifile class parts data for $facadeName",
partsInternalNames.mapNotNull { internalName ->
incrementalCache.getPackagePartData(internalName)?.let { (data, strings) ->
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(data, strings)
val jvmBinaryClass = kotlinClassFinder.findKotlinClass(
ClassId.topLevel(FqName(internalName.replace('/', '.')))
)
val partName = JvmClassName.byInternalName(internalName)
val jvmBinaryClass =
kotlinClassFinder.findKotlinClass(ClassId.topLevel(partName.fqNameForTopLevelClassMaybeWithDollars))
DeserializedPackageMemberScope(
this, packageProto, nameResolver,
JvmPackagePartSource(
JvmClassName.byInternalName(internalName),
JvmClassName.byFqNameWithoutInnerClasses(multifileClassFqName.asString()),
knownJvmBinaryClass = jvmBinaryClass
),
JvmPackagePartSource(partName, facadeName, knownJvmBinaryClass = jvmBinaryClass),
deserializationComponents, classNames = { emptyList() }
)
}
@@ -101,9 +98,6 @@ class IncrementalPackageFragmentProvider(
)
}
val multifileClassName: Name
get() = multifileClassFqName.shortName()
override fun getMemberScope() = memberScope()
}
}
@@ -18,9 +18,7 @@ package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorNonRoot
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.OverloadFilter
@@ -42,14 +40,8 @@ object JvmOverloadFilter : OverloadFilter {
if (overload is ConstructorDescriptor) continue
if (overload !is DeserializedCallableMemberDescriptor) continue
val containingDeclaration = overload.containingDeclaration
if (containingDeclaration !is PackageFragmentDescriptor) {
throw AssertionError("Package member expected; got $overload with containing declaration $containingDeclaration")
}
val implClassName = overload.getImplClassNameForDeserialized() ?: throw AssertionError("No implClassName: $overload")
val implClassFQN = containingDeclaration.fqName.child(implClassName)
if (!sourceClassesFQNs.contains(implClassFQN)) {
val implClassFQN = JvmFileClassUtil.getPartFqNameForDeserialized(overload)
if (implClassFQN !in sourceClassesFQNs) {
result.add(overload)
}
}