diff --git a/compiler/fir/java/build.gradle.kts b/compiler/fir/java/build.gradle.kts index 98069f67cfd..e4331785db1 100644 --- a/compiler/fir/java/build.gradle.kts +++ b/compiler/fir/java/build.gradle.kts @@ -7,6 +7,7 @@ plugins { jvmTarget = "1.6" dependencies { + compile(project(":compiler:frontend.common")) compile(project(":compiler:frontend.java")) compile(project(":compiler:fir:resolve")) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt index c2206c7b28d..e6497751955 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt @@ -6,21 +6,59 @@ package org.jetbrains.kotlin.fir.java import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.fir.FirModuleBasedSession +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider +import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl import org.jetbrains.kotlin.fir.resolve.impl.FirLibrarySymbolProviderImpl -import org.jetbrains.kotlin.fir.service -class FirJavaModuleBasedSession(moduleInfo: ModuleInfo, project: Project) : FirModuleBasedSession(moduleInfo) { +class FirJavaModuleBasedSession( + moduleInfo: ModuleInfo, + override val sessionProvider: FirProjectSessionProvider, + scope: GlobalSearchScope +) : FirModuleBasedSession(moduleInfo) { init { + sessionProvider.sessionCache[moduleInfo] = this registerComponent( FirSymbolProvider::class, FirCompositeSymbolProvider( - listOf(service(), JavaSymbolProvider(project), FirLibrarySymbolProviderImpl(this)) + listOf( + service(), + JavaSymbolProvider(sessionProvider.project, scope), + FirDependenciesSymbolProviderImpl(this) + ) ) ) } +} + +class FirLibrarySession( + moduleInfo: ModuleInfo, + override val sessionProvider: FirProjectSessionProvider, + scope: GlobalSearchScope +) : FirSessionBase() { + init { + sessionProvider.sessionCache[moduleInfo] = this + registerComponent( + FirSymbolProvider::class, + FirCompositeSymbolProvider( + listOf( + FirLibrarySymbolProviderImpl(this), + JavaSymbolProvider(sessionProvider.project, scope), + FirDependenciesSymbolProviderImpl(this) + ) + ) + ) + } +} + +class FirProjectSessionProvider(val project: Project) : FirSessionProvider { + override fun getSession(moduleInfo: ModuleInfo): FirSession? { + return sessionCache[moduleInfo] + } + + val sessionCache = mutableMapOf() } \ No newline at end of file diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 4c150746c93..2bff2916893 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -8,38 +8,22 @@ package org.jetbrains.kotlin.fir.java import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.fir.java.symbols.JavaClassSymbol -import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider import org.jetbrains.kotlin.fir.symbols.ConeSymbol import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade -class JavaSymbolProvider(val project: Project) : FirSymbolProvider { - - override val doesLookupInFir: Boolean - get() = false - - // TODO: Concrete scope here - private val allScope = GlobalSearchScope.allScope(project) - - private val classCache = mutableMapOf() - private val packageCache = mutableMapOf() - - private inline fun MutableMap.lookupCacheOrCalculate(key: K, l: (K) -> V): V? { - return if (key in this.keys) { - this[key] - } else { - val calculated = l(key) - this[key] = calculated - calculated - } - } +class JavaSymbolProvider( + val project: Project, + private val searchScope: GlobalSearchScope +) : AbstractFirSymbolProvider() { override fun getSymbolByFqName(classId: ClassId): ConeSymbol? { return classCache.lookupCacheOrCalculate(classId) { val facade = KotlinJavaPsiFacade.getInstance(project) - val foundClass = facade.findClass(JavaClassFinder.Request(classId), allScope) + val foundClass = facade.findClass(JavaClassFinder.Request(classId), searchScope) foundClass?.let { javaClass -> JavaClassSymbol(javaClass) } } } @@ -47,7 +31,7 @@ class JavaSymbolProvider(val project: Project) : FirSymbolProvider { override fun getPackage(fqName: FqName): FqName? { return packageCache.lookupCacheOrCalculate(fqName) { val facade = KotlinJavaPsiFacade.getInstance(project) - val javaPackage = facade.findPackage(fqName.asString(), allScope) ?: return@lookupCacheOrCalculate null + val javaPackage = facade.findPackage(fqName.asString(), searchScope) ?: return@lookupCacheOrCalculate null FqName(javaPackage.qualifiedName) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/AbstractFirSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/AbstractFirSymbolProvider.kt new file mode 100644 index 00000000000..8119e294ba8 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/AbstractFirSymbolProvider.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve + +import org.jetbrains.kotlin.fir.symbols.ConeSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName + +abstract class AbstractFirSymbolProvider : FirSymbolProvider { + protected val classCache = mutableMapOf() + protected val packageCache = mutableMapOf() + + protected inline fun MutableMap.lookupCacheOrCalculate(key: K, crossinline l: (K) -> V): V? { + return if (key in this.keys) { + this[key] + } else { + val calculated = l(key) + this[key] = calculated + calculated + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt index 5884c0e28bb..7c3984d06f4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt @@ -13,8 +13,6 @@ import org.jetbrains.kotlin.name.FqName interface FirSymbolProvider { - val doesLookupInFir: Boolean - fun getSymbolByFqName(classId: ClassId): ConeSymbol? fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt index c5cc52466f4..c1e12fe95fc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt @@ -13,9 +13,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult class FirCompositeSymbolProvider(val providers: List) : FirSymbolProvider { - override val doesLookupInFir: Boolean - get() = providers.any(FirSymbolProvider::doesLookupInFir) - override fun getPackage(fqName: FqName): FqName? { return providers.firstNotNullResult { it.getPackage(fqName) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt new file mode 100644 index 00000000000..15520d236dd --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.impl + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.dependenciesWithoutSelf +import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.service +import org.jetbrains.kotlin.fir.symbols.ConeSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName + +class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider() { + + private val dependencyProviders by lazy { + val moduleInfo = session.moduleInfo ?: return@lazy emptyList() + moduleInfo.dependenciesWithoutSelf().mapNotNull { + session.sessionProvider?.getSession(it)?.service() + }.toList() + } + + override fun getSymbolByFqName(classId: ClassId): ConeSymbol? { + return classCache.lookupCacheOrCalculate(classId) { + for (provider in dependencyProviders) { + provider.getSymbolByFqName(classId)?.let { + return@lookupCacheOrCalculate it + } + } + null + } + } + + override fun getPackage(fqName: FqName): FqName? { + return packageCache.lookupCacheOrCalculate(fqName) { + for (provider in dependencyProviders) { + provider.getPackage(fqName)?.let { + return@lookupCacheOrCalculate it + } + } + null + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt index a0114b39b1b..26255a2be23 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt @@ -28,13 +28,10 @@ import java.io.InputStream class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider { - override val doesLookupInFir: Boolean - get() = false - private class BuiltInsPackageFragment(stream: InputStream, val fqName: FqName) { lateinit var version: BuiltInsBinaryVersion - val packageProto = run { + val packageProto: ProtoBuf.PackageFragment = run { version = BuiltInsBinaryVersion.readFrom(stream) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt index 41ff4db2682..8d78591cf59 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt @@ -19,9 +19,6 @@ import org.jetbrains.kotlin.name.FqName class FirProviderImpl(val session: FirSession) : FirProvider { - override val doesLookupInFir: Boolean - get() = true - override fun getFirClassifierBySymbol(symbol: ConeSymbol): FirNamedDeclaration? { return when (symbol) { is FirBasedSymbol<*> -> symbol.fir as? FirNamedDeclaration diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractStarImportingScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractStarImportingScope.kt index 7a00eb227a5..a254d4664b2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractStarImportingScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractStarImportingScope.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirResolvedImport import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider +import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl import org.jetbrains.kotlin.fir.scopes.FirPosition import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.ConeSymbol @@ -21,7 +22,7 @@ abstract class FirAbstractStarImportingScope(val session: FirSession, lookupInFi val provider = FirSymbolProvider.getInstance(session).let { when { - it is FirCompositeSymbolProvider && !lookupInFir -> FirCompositeSymbolProvider(it.providers.filter { !it.doesLookupInFir }) + it is FirCompositeSymbolProvider && !lookupInFir -> it.providers.find { it is FirDependenciesSymbolProviderImpl }!! else -> it } } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt index 8446246e19a..ff809537aee 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt @@ -5,7 +5,9 @@ package org.jetbrains.kotlin.fir +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.declarations.FirFile @@ -21,13 +23,16 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas return createEnvironmentWithMockJdk(ConfigurationKind.JDK_NO_RUNTIME) } - fun doCreateAndProcessFir(ktFiles: List): List { - val session = createSession() + private fun doCreateAndProcessFir(ktFiles: List): List { + + val scope = GlobalSearchScope.filesScope(project, ktFiles.mapNotNull { it.virtualFile }) + .uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project)) + val session = createSession(scope) val builder = RawFirBuilder(session) val transformer = FirTotalResolveTransformer() - val firFiles = ktFiles.map { + return ktFiles.map { val firFile = builder.buildFirFile(it) (session.service() as FirProviderImpl).recordFile(firFile) firFile @@ -39,8 +44,6 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas throw e } } - - return firFiles } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveWithSessionTestCase.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveWithSessionTestCase.kt index a8ec3854a1d..6579b3630c7 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveWithSessionTestCase.kt +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveWithSessionTestCase.kt @@ -5,10 +5,27 @@ package org.jetbrains.kotlin.fir +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession +import org.jetbrains.kotlin.fir.java.FirLibrarySession +import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.test.KotlinTestWithEnvironment abstract class AbstractFirResolveWithSessionTestCase : KotlinTestWithEnvironment() { - open fun createSession(): FirSession = FirJavaModuleBasedSession(FirTestModuleInfo(), project) + open fun createSession(sourceScope: GlobalSearchScope): FirSession { + val moduleInfo = FirTestModuleInfo() + val provider = FirProjectSessionProvider(project) + return FirJavaModuleBasedSession(moduleInfo, provider, sourceScope).also { + createSessionForDependencies(provider, moduleInfo, sourceScope) + } + } + + private fun createSessionForDependencies( + provider: FirProjectSessionProvider, moduleInfo: FirTestModuleInfo, sourceScope: GlobalSearchScope + ) { + val dependenciesInfo = FirTestModuleInfo() + moduleInfo.dependencies.add(dependenciesInfo) + FirLibrarySession(dependenciesInfo, provider, GlobalSearchScope.notScope(sourceScope)) + } } \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt index 935adf82322..7085807cfe7 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt @@ -11,11 +11,17 @@ import kotlin.reflect.KClass interface FirSession { val moduleInfo: ModuleInfo? + val sessionProvider: FirSessionProvider? get() = null + val components: Map, Any> fun getService(kclass: KClass): T = components[kclass] as T } +interface FirSessionProvider { + fun getSession(moduleInfo: ModuleInfo): FirSession? +} + inline fun FirSession.service(): T = getService(T::class) \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt index 7cddf101611..423d343e4e9 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir +import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.visitors.FirTransformer fun MutableList.transformInplace(transformer: FirTransformer, data: D) { @@ -31,4 +32,6 @@ fun MutableList.transformInplace(transformer: FirTransfor fun T.transformSingle(transformer: FirTransformer, data: D): T { return this.transform(transformer, data).single -} \ No newline at end of file +} + +fun ModuleInfo.dependenciesWithoutSelf(): Sequence = dependencies().asSequence().filter { it != this } \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirTestModuleInfo.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirTestModuleInfo.kt index 3d745a58828..b763b1c88d8 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirTestModuleInfo.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirTestModuleInfo.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform class FirTestModuleInfo( override val name: Name = Name.identifier("TestModule"), - private val dependencies: List = emptyList(), + val dependencies: MutableList = mutableListOf(), override val platform: TargetPlatform = JvmPlatform ) : ModuleInfo { override fun dependencies(): List = dependencies diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 62a95f0d91f..bc4c235abc5 100755 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -91,6 +91,7 @@ import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest @@ -804,6 +805,10 @@ fun main(args: Array) { model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } + + testClass { + model("fir/multiModule", recursive = false, extension = null) + } } testGroup("idea/idea-maven/test", "idea/idea-maven/testData") { diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as31 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as31 index 6f8138ad07e..5a2b0960ff3 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as31 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as31 @@ -93,6 +93,7 @@ import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest @@ -786,6 +787,10 @@ fun main(args: Array) { model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } + + testClass { + model("fir/multiModule", recursive = false, extension = null) + } } /* diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as32 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as32 index 6f8138ad07e..5a2b0960ff3 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as32 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as32 @@ -93,6 +93,7 @@ import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest @@ -786,6 +787,10 @@ fun main(args: Array) { model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } + + testClass { + model("fir/multiModule", recursive = false, extension = null) + } } /* diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as33 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as33 index 9b688f96aa4..5d3c4482b19 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as33 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as33 @@ -85,6 +85,7 @@ import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest @@ -778,6 +779,10 @@ fun main(args: Array) { model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } + + testClass { + model("fir/multiModule", recursive = false, extension = null) + } } /* diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 index 9b688f96aa4..5d3c4482b19 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 @@ -85,6 +85,7 @@ import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest @@ -778,6 +779,10 @@ fun main(args: Array) { model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } + + testClass { + model("fir/multiModule", recursive = false, extension = null) + } } /* diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt index 0e26e2b9fd1..17c22a454f3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt @@ -374,7 +374,7 @@ private class SdkScope(project: Project, val sdk: Sdk) : override fun toString() = "SdkScope($sdk)" } -internal fun IdeaModuleInfo.isLibraryClasses() = this is SdkInfo || this is LibraryInfo +fun IdeaModuleInfo.isLibraryClasses() = this is SdkInfo || this is LibraryInfo val OriginCapability = ModuleDescriptor.Capability("MODULE_ORIGIN") diff --git a/idea/testData/fir/multiModule/basic/m1_java/base.kt b/idea/testData/fir/multiModule/basic/m1_java/base.kt new file mode 100644 index 00000000000..101af630af6 --- /dev/null +++ b/idea/testData/fir/multiModule/basic/m1_java/base.kt @@ -0,0 +1,5 @@ +package hello + +class Hello(val msg: String) + +class Test(val set: java.util.Set<*>) \ No newline at end of file diff --git a/idea/testData/fir/multiModule/basic/m1_java/base.txt b/idea/testData/fir/multiModule/basic/m1_java/base.txt new file mode 100644 index 00000000000..94415be0825 --- /dev/null +++ b/idea/testData/fir/multiModule/basic/m1_java/base.txt @@ -0,0 +1,15 @@ +FILE: base.kt + public final class Hello { + public constructor(msg: R|kotlin/String|): super() + + public final property msg(val): R|kotlin/String| + public get(): R|kotlin/String| + + } + public final class Test { + public constructor(set: R|java/util/Set<*>|): super() + + public final property set(val): R|java/util/Set<*>| + public get(): R|java/util/Set<*>| + + } diff --git a/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.kt b/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.kt new file mode 100644 index 00000000000..f8209c7ac1a --- /dev/null +++ b/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.kt @@ -0,0 +1,5 @@ +package test + +import hello.Hello + +fun foo(hello: Hello): String = hello.msg \ No newline at end of file diff --git a/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.txt b/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.txt new file mode 100644 index 00000000000..b3e5c25f76e --- /dev/null +++ b/idea/testData/fir/multiModule/basic/m2_java_dep(m1-java)/user.txt @@ -0,0 +1,4 @@ +FILE: user.kt + public final function foo(hello: R|hello/Hello|): R|kotlin/String| { + STUB + } diff --git a/idea/tests/org/jetbrains/kotlin/idea/fir/AbstractFirMultiModuleResolveTest.kt b/idea/tests/org/jetbrains/kotlin/idea/fir/AbstractFirMultiModuleResolveTest.kt new file mode 100644 index 00000000000..522b4e16424 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/fir/AbstractFirMultiModuleResolveTest.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.fir + +import com.intellij.openapi.module.Module +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.search.FileTypeIndex +import org.jetbrains.kotlin.fir.FirRenderer +import org.jetbrains.kotlin.fir.builder.RawFirBuilder +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.dependenciesWithoutSelf +import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession +import org.jetbrains.kotlin.fir.java.FirLibrarySession +import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider +import org.jetbrains.kotlin.fir.resolve.FirProvider +import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl +import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer +import org.jetbrains.kotlin.fir.service +import org.jetbrains.kotlin.idea.KotlinFileType +import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo +import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses +import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo +import org.jetbrains.kotlin.idea.multiplatform.setupMppProjectFromDirStructure +import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.idea.util.projectStructure.allModules +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestJdkKind +import org.jetbrains.kotlin.utils.addToStdlib.cast +import java.io.File + +abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() { + override fun getTestDataPath(): String { + return File(PluginTestCaseBase.getTestDataPathBase(), "/fir/multiModule").path + File.separator + } + + fun doTest(dirPath: String) { + setupMppProjectFromDirStructure(File(dirPath)) + for (module in project.allModules().drop(1)) { + ConfigLibraryUtil.configureSdk( + module, + PluginTestCaseBase.addJdk(testRootDisposable) { PluginTestCaseBase.jdk(TestJdkKind.MOCK_JDK) } + ) + } + doFirResolveTest(dirPath) + } + + private fun createSession(module: Module, provider: FirProjectSessionProvider): FirJavaModuleBasedSession { + val moduleInfo = module.productionSourceInfo()!! + return FirJavaModuleBasedSession(moduleInfo, provider, moduleInfo.contentScope()) + } + + private fun createLibrarySession(moduleInfo: IdeaModuleInfo, provider: FirProjectSessionProvider): FirLibrarySession { + val contentScope = moduleInfo.contentScope() + return FirLibrarySession(moduleInfo, provider, contentScope) + } + + private fun doFirResolveTest(dirPath: String) { + val firFiles = mutableListOf() + val provider = FirProjectSessionProvider(project) + for (module in project.allModules().drop(1)) { + val session = createSession(module, provider) + + val builder = RawFirBuilder(session) + val psiManager = PsiManager.getInstance(project) + + val ideaModuleInfo = session.moduleInfo.cast() + + ideaModuleInfo.dependenciesWithoutSelf().forEach { + if (it is IdeaModuleInfo && it.isLibraryClasses()) { + createLibrarySession(it, provider) + } + } + + val contentScope = ideaModuleInfo.contentScope() + + val files = FileTypeIndex.getFiles(KotlinFileType.INSTANCE, contentScope) + + println("Got vfiles: ${files.size}") + files.forEach { + val file = psiManager.findFile(it) as? KtFile ?: return@forEach + val firFile = builder.buildFirFile(file) + (session.service() as FirProviderImpl).recordFile(firFile) + firFiles += firFile + } + } + println("Raw fir up, files: ${firFiles.size}") + + fun expectedTxtPath(virtualFile: VirtualFile): String { + val virtualPath = virtualFile.path + var result: String? = null + val root = File(dirPath) + for (file in root.walkTopDown()) { + if (!file.isDirectory && file.name in virtualPath) { + result = file.absolutePath.replace(".kt", ".txt") + } + } + return result!! + } + + val transformer = FirTotalResolveTransformer() + for (file in firFiles) { + transformer.processFile(file) + val firFileDump = StringBuilder().also { file.accept(FirRenderer(it), null) }.toString() + val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile) + KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump) + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java new file mode 100644 index 00000000000..0caa5153b63 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.fir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/fir/multiModule") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleResolveTest { + public void testAllFilesPresentInMultiModule() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/fir/multiModule"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false); + } + + @TestMetadata("basic") + public void testBasic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/fir/multiModule/basic/"); + doTest(fileName); + } +}