Add "expectedBy" to module descriptor and use it in checker

Now ExpectActualDeclarationChecker in IDE context
uses common module descriptors for relevant checks.
Compiler still uses own module instead (see comment in checker)
So #KT-21771 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-12-12 17:22:35 +03:00
parent 78136fbb07
commit 3f500a1655
16 changed files with 93 additions and 11 deletions
@@ -227,10 +227,10 @@ object TopDownAnalyzerFacadeForJVM {
}
// TODO: remove dependencyModule from friends
module.setDependencies(ModuleDependenciesImpl(
module.setDependencies(
listOfNotNull(module, dependencyModule, optionalBuiltInsModule),
if (dependencyModule != null) setOf(dependencyModule) else emptySet()
))
)
module.initialize(CompositePackageFragmentProvider(
listOf(container.get<KotlinCodeAnalyzer>().packageFragmentProvider) +
additionalProviders
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import java.util.*
import kotlin.coroutines.experimental.buildSequence
@@ -307,6 +308,10 @@ class LazyModuleDependencies<M : ModuleInfo>(
override val allDependencies: List<ModuleDescriptorImpl> get() = dependencies()
override val expectedByDependency by storageManager.createNullableLazyValue {
module.expectedBy?.let { resolverForProject.descriptorForModule(it as M) }
}
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
get() =
module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) {
@@ -110,10 +110,12 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
private fun checkActualDeclarationHasExpected(
reportOn: KtNamedDeclaration, descriptor: MemberDescriptor, trace: BindingTrace, checkActual: Boolean
) {
// Using the platform module instead of the common module is sort of fine here because the former always depends on the latter.
// However, it would be clearer to find the common module this platform module implements and look for expected there instead.
// TODO: use common module here
val compatibility = ExpectedActualResolver.findExpectedForActual(descriptor, descriptor.module) ?: return
// TODO: ideally, we should always use common module here
// However, in compiler context platform & common modules are joined into one module,
// so there is yet no "common module" in this situation.
// So yet we are using own module in compiler context and common module in IDE context.
val commonOrOwnModule = descriptor.module.expectedByModule ?: descriptor.module
val compatibility = ExpectedActualResolver.findExpectedForActual(descriptor, commonOrOwnModule) ?: return
val hasActualModifier = descriptor.isActual && reportOn.hasActualModifier()
if (!hasActualModifier) {
@@ -40,6 +40,8 @@ interface ModuleDescriptor : DeclarationDescriptor {
*/
val allDependencyModules: List<ModuleDescriptor>
val expectedByModule: ModuleDescriptor?
fun <T> getCapability(capability: Capability<T>): T?
class Capability<T>(val name: String) {
@@ -66,6 +66,9 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
override val allDependencyModules: List<ModuleDescriptor>
get() = this.dependencies.sure { "Dependencies of module $id were not set" }.allDependencies.filter { it != this }
override val expectedByModule: ModuleDescriptor?
get() = this.dependencies.sure { "Dependencies of module $id were not set" }.expectedByDependency
override fun getPackage(fqName: FqName): PackageViewDescriptor {
assertValid()
return packages(fqName)
@@ -104,11 +107,11 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
}
fun setDependencies(descriptors: List<ModuleDescriptorImpl>) {
setDependencies(ModuleDependenciesImpl(descriptors, emptySet()))
setDependencies(descriptors, emptySet())
}
fun setDependencies(descriptors: List<ModuleDescriptorImpl>, friends: Set<ModuleDescriptorImpl>) {
setDependencies(ModuleDependenciesImpl(descriptors, friends))
setDependencies(ModuleDependenciesImpl(descriptors, friends, null))
}
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
@@ -147,9 +150,11 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
interface ModuleDependencies {
val allDependencies: List<ModuleDescriptorImpl>
val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
val expectedByDependency: ModuleDescriptorImpl?
}
class ModuleDependenciesImpl(
override val allDependencies: List<ModuleDescriptorImpl>,
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
override val allDependencies: List<ModuleDescriptorImpl>,
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>,
override val expectedByDependency: ModuleDescriptorImpl?
) : ModuleDependencies
@@ -85,6 +85,12 @@ public class ErrorUtils {
return emptyList();
}
@Nullable
@Override
public ModuleDescriptor getExpectedByModule() {
return null;
}
@Override
public <R, D> R accept(@NotNull DeclarationDescriptorVisitor<R, D> visitor, D data) {
return null;
@@ -10,6 +10,6 @@ expect class Their {
}
actual class Their {
actual class <error descr="[ACTUAL_WITHOUT_EXPECT] Actual class 'Their' has no corresponding expected declaration">Their</error> {
}
@@ -0,0 +1 @@
expect class My
@@ -0,0 +1 @@
class <error descr="[ACTUAL_MISSING] Declaration must be marked with 'actual'">My</error>
@@ -0,0 +1 @@
expect class My
@@ -0,0 +1 @@
expect fun foo(my: Any)
@@ -0,0 +1,3 @@
class My
actual fun foo(my: Any) {}
@@ -0,0 +1 @@
expect class My
@@ -0,0 +1 @@
expect fun foo(my: My)
@@ -0,0 +1,3 @@
class <error descr="[ACTUAL_MISSING] Declaration must be marked with 'actual'">My</error>
actual fun foo(my: My) {}
@@ -33,6 +33,20 @@ class MultiPlatformHighlightingTest : AbstractMultiModuleHighlightingTest() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
fun testDepends() {
val commonModule = module("common", TestJdkKind.MOCK_JDK)
commonModule.createFacet(TargetPlatformKind.Common)
commonModule.enableMultiPlatform()
val jvmPlatform = TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
val jvmModule = module("jvm", TestJdkKind.MOCK_JDK)
jvmModule.createFacet(jvmPlatform)
jvmModule.enableMultiPlatform()
jvmModule.addDependency(commonModule)
checkHighlightingInAllFiles()
}
fun testHeaderClass() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
@@ -106,4 +120,40 @@ class MultiPlatformHighlightingTest : AbstractMultiModuleHighlightingTest() {
checkHighlightingInAllFiles()
}
fun testTriangle() {
val commonModule = module("common_base", TestJdkKind.MOCK_JDK)
commonModule.createFacet(TargetPlatformKind.Common, false)
val derivedModule = module("common_derived", TestJdkKind.MOCK_JDK)
derivedModule.createFacet(TargetPlatformKind.Common)
derivedModule.enableMultiPlatform()
val jvmPlatform = TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
val jvmModule = module("jvm_derived", TestJdkKind.MOCK_JDK)
jvmModule.createFacet(jvmPlatform, implementedModuleName = "common_derived")
jvmModule.enableMultiPlatform()
jvmModule.addDependency(commonModule)
jvmModule.addDependency(derivedModule)
checkHighlightingInAllFiles()
}
fun testTriangleWithDependency() {
val commonModule = module("common_base", TestJdkKind.MOCK_JDK)
commonModule.createFacet(TargetPlatformKind.Common, false)
val derivedModule = module("common_derived", TestJdkKind.MOCK_JDK)
derivedModule.createFacet(TargetPlatformKind.Common)
derivedModule.enableMultiPlatform()
derivedModule.addDependency(commonModule)
val jvmPlatform = TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
val jvmModule = module("jvm_derived", TestJdkKind.MOCK_JDK)
jvmModule.createFacet(jvmPlatform, implementedModuleName = "common_derived")
jvmModule.enableMultiPlatform()
jvmModule.addDependency(commonModule)
jvmModule.addDependency(derivedModule)
checkHighlightingInAllFiles()
}
}