From 3f500a1655f8142e621e07ef8a494563f4ce63cb Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 12 Dec 2017 17:22:35 +0300 Subject: [PATCH] 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 --- .../compiler/TopDownAnalyzerFacadeForJVM.kt | 4 +- .../kotlin/analyzer/AnalyzerFacade.kt | 5 ++ .../ExpectedActualDeclarationChecker.kt | 10 ++-- .../kotlin/descriptors/ModuleDescriptor.kt | 2 + .../descriptors/impl/ModuleDescriptorImpl.kt | 13 +++-- .../jetbrains/kotlin/types/ErrorUtils.java | 6 +++ .../multiplatform/basic/jvm/jvm.kt | 2 +- .../multiplatform/depends/common/common.kt | 1 + .../multiplatform/depends/jvm/jvm.kt | 1 + .../multiplatform/triangle/common_base/My.kt | 1 + .../triangle/common_derived/foo.kt | 1 + .../triangle/jvm_derived/impl.kt | 3 ++ .../triangleWithDependency/common_base/My.kt | 1 + .../common_derived/foo.kt | 1 + .../jvm_derived/impl.kt | 3 ++ .../resolve/MultiPlatformHighlightingTest.kt | 50 +++++++++++++++++++ 16 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/depends/common/common.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/depends/jvm/jvm.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangle/common_base/My.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangle/common_derived/foo.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangle/jvm_derived/impl.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_base/My.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_derived/foo.kt create mode 100644 idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/jvm_derived/impl.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt index 684b5d7907c..a8421b4a9e5 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt @@ -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().packageFragmentProvider) + additionalProviders diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt index 82178086c8b..3ef7d72b057 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt @@ -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( override val allDependencies: List get() = dependencies() + override val expectedByDependency by storageManager.createNullableLazyValue { + module.expectedBy?.let { resolverForProject.descriptorForModule(it as M) } + } + override val modulesWhoseInternalsAreVisible: Set get() = module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt index 72a6fa60419..9e8ab2ca4a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -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) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt index d5a2164a41a..7035dfabb8f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt @@ -40,6 +40,8 @@ interface ModuleDescriptor : DeclarationDescriptor { */ val allDependencyModules: List + val expectedByModule: ModuleDescriptor? + fun getCapability(capability: Capability): T? class Capability(val name: String) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt index e7c6862df9f..8c7dce58219 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt @@ -66,6 +66,9 @@ class ModuleDescriptorImpl @JvmOverloads constructor( override val allDependencyModules: List 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) { - setDependencies(ModuleDependenciesImpl(descriptors, emptySet())) + setDependencies(descriptors, emptySet()) } fun setDependencies(descriptors: List, friends: Set) { - 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 val modulesWhoseInternalsAreVisible: Set + val expectedByDependency: ModuleDescriptorImpl? } class ModuleDependenciesImpl( - override val allDependencies: List, - override val modulesWhoseInternalsAreVisible: Set + override val allDependencies: List, + override val modulesWhoseInternalsAreVisible: Set, + override val expectedByDependency: ModuleDescriptorImpl? ) : ModuleDependencies diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 9216637bc9a..ae2bd983b6a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -85,6 +85,12 @@ public class ErrorUtils { return emptyList(); } + @Nullable + @Override + public ModuleDescriptor getExpectedByModule() { + return null; + } + @Override public R accept(@NotNull DeclarationDescriptorVisitor visitor, D data) { return null; diff --git a/idea/testData/multiModuleHighlighting/multiplatform/basic/jvm/jvm.kt b/idea/testData/multiModuleHighlighting/multiplatform/basic/jvm/jvm.kt index 2634e8e96bf..d513b858280 100644 --- a/idea/testData/multiModuleHighlighting/multiplatform/basic/jvm/jvm.kt +++ b/idea/testData/multiModuleHighlighting/multiplatform/basic/jvm/jvm.kt @@ -10,6 +10,6 @@ expect class Their { } -actual class Their { +actual class Their { } diff --git a/idea/testData/multiModuleHighlighting/multiplatform/depends/common/common.kt b/idea/testData/multiModuleHighlighting/multiplatform/depends/common/common.kt new file mode 100644 index 00000000000..2b091d063d1 --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/depends/common/common.kt @@ -0,0 +1 @@ +expect class My diff --git a/idea/testData/multiModuleHighlighting/multiplatform/depends/jvm/jvm.kt b/idea/testData/multiModuleHighlighting/multiplatform/depends/jvm/jvm.kt new file mode 100644 index 00000000000..43ec49aaf7a --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/depends/jvm/jvm.kt @@ -0,0 +1 @@ +class My \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_base/My.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_base/My.kt new file mode 100644 index 00000000000..023d50bcba5 --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_base/My.kt @@ -0,0 +1 @@ +expect class My \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_derived/foo.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_derived/foo.kt new file mode 100644 index 00000000000..32ace5627a5 --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangle/common_derived/foo.kt @@ -0,0 +1 @@ +expect fun foo(my: Any) \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangle/jvm_derived/impl.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangle/jvm_derived/impl.kt new file mode 100644 index 00000000000..24e8106e93f --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangle/jvm_derived/impl.kt @@ -0,0 +1,3 @@ +class My + +actual fun foo(my: Any) {} \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_base/My.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_base/My.kt new file mode 100644 index 00000000000..023d50bcba5 --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_base/My.kt @@ -0,0 +1 @@ +expect class My \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_derived/foo.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_derived/foo.kt new file mode 100644 index 00000000000..a8508a1a779 --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/common_derived/foo.kt @@ -0,0 +1 @@ +expect fun foo(my: My) \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/jvm_derived/impl.kt b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/jvm_derived/impl.kt new file mode 100644 index 00000000000..c79e944e0ce --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/triangleWithDependency/jvm_derived/impl.kt @@ -0,0 +1,3 @@ +class My + +actual fun foo(my: My) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiPlatformHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiPlatformHighlightingTest.kt index f742dd3d10c..d71c7a943c5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiPlatformHighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiPlatformHighlightingTest.kt @@ -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() + } } \ No newline at end of file