FIR: add symbol provider for IDE #KT-24097 Fixed

Functions & properties aren't yet supported
This commit is contained in:
Simon Ogorodnik
2018-04-10 14:04:14 +03:00
committed by Mikhail Glukhikh
parent 12ee81358c
commit 5cef869d36
5 changed files with 120 additions and 12 deletions
@@ -18,8 +18,10 @@ import org.jetbrains.kotlin.fir.resolve.impl.FirLibrarySymbolProviderImpl
class FirJavaModuleBasedSession(
moduleInfo: ModuleInfo,
override val sessionProvider: FirProjectSessionProvider,
scope: GlobalSearchScope
scope: GlobalSearchScope,
dependenciesProvider: FirSymbolProvider? = null
) : FirModuleBasedSession(moduleInfo) {
init {
sessionProvider.sessionCache[moduleInfo] = this
registerComponent(
@@ -28,7 +30,8 @@ class FirJavaModuleBasedSession(
listOf(
service<FirProvider>(),
JavaSymbolProvider(this, sessionProvider.project, scope),
FirDependenciesSymbolProviderImpl(this)
FirLibrarySymbolProviderImpl(this),
dependenciesProvider ?: FirDependenciesSymbolProviderImpl(this)
)
)
)
+2
View File
@@ -36,6 +36,8 @@ dependencies {
compile(project(":j2k"))
compile(project(":idea:formatter"))
compile(project(":idea:fir-view"))
compile(project(":compiler:fir:resolve"))
compile(project(":compiler:fir:java"))
compile(project(":idea:idea-core"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
@@ -0,0 +1,108 @@
/*
* 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.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelTypeAliasFqNameIndex
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTypeAlias
class IdeFirDependenciesSymbolProvider(
val moduleInfo: ModuleSourceInfo,
val project: Project,
private val sessionProvider: FirProjectSessionProvider
) : AbstractFirSymbolProvider() {
// TODO: Our special scope here?
private val depScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(moduleInfo.module)
private val javaSymbolProvider by lazy { JavaSymbolProvider(sessionProvider.getSession(moduleInfo)!!, project, depScope) }
private fun buildKotlinClassOnRequest(file: KtFile, classId: ClassId, session: FirSession): ConeClassLikeSymbol? {
val impl = FirProvider.getInstance(session) as FirProviderImpl
val classifier = impl.getClassLikeSymbolByFqName(classId)
if (classifier != null) {
return classifier
}
val builder = RawFirBuilder(session, stubMode = true)
impl.recordFile(builder.buildFirFile(file))
return impl.getClassLikeSymbolByFqName(classId)
}
private fun selectNearest(classesPsi: Collection<KtDeclaration>, typeAliasesPsi: Collection<KtTypeAlias>): KtDeclaration? {
return when {
typeAliasesPsi.isEmpty() -> classesPsi.firstOrNull()
classesPsi.isEmpty() -> typeAliasesPsi.firstOrNull()
else -> (classesPsi.asSequence() + typeAliasesPsi.asSequence()).minWith(Comparator { o1, o2 ->
depScope.compare(o1.containingFile.virtualFile, o2.containingFile.virtualFile)
})
}
}
private fun tryKotlin(classId: ClassId): ConeClassLikeSymbol? {
return classCache.lookupCacheOrCalculate(classId) {
val index = KotlinFullClassNameIndex.getInstance()
val fqNameString = classId.packageFqName.asString() + "." + classId.relativeClassName.asString()
val classesPsi = index[fqNameString, project, depScope]
val typeAliasesPsi = KotlinTopLevelTypeAliasFqNameIndex.getInstance()[fqNameString, project, depScope]
val psi = selectNearest(classesPsi, typeAliasesPsi) ?: return@lookupCacheOrCalculate null
val module = psi.getModuleInfo()
if (psi.containingKtFile.isCompiled) {
// TODO: WTF? Resolving libraries in current session
val session = sessionProvider.getSession(moduleInfo) ?: return@lookupCacheOrCalculate null
return@lookupCacheOrCalculate buildKotlinClassOnRequest(psi.containingKtFile, classId, session)
}
val session = sessionProvider.getSession(module) ?: return@lookupCacheOrCalculate null
session.service<FirProvider>().getClassLikeSymbolByFqName(classId)
}
}
private fun tryJava(classId: ClassId): ConeClassLikeSymbol? {
return javaSymbolProvider.getClassLikeSymbolByFqName(classId)
}
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? {
return tryKotlin(classId) ?: tryJava(classId)
}
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
// TODO
return emptyList()
}
override fun getPackage(fqName: FqName): FqName? {
if (PackageIndexUtil.packageExists(fqName, depScope, project)) {
return fqName
}
return javaSymbolProvider.getPackage(fqName)
}
}
@@ -14,18 +14,14 @@ import com.intellij.testFramework.ModuleTestCase
import org.jetbrains.kotlin.fir.FirSession
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.doFirResolveTestBench
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.psi.KtFile
import java.io.File
@@ -60,13 +56,11 @@ class FirTotalKotlinResolveInIdeTest : ModuleTestCase() {
private fun createSession(): FirSession {
val moduleInfo = module.productionSourceInfo()!!
val sessionProvider = FirProjectSessionProvider(project)
moduleInfo.dependenciesWithoutSelf().forEach {
if (it is IdeaModuleInfo && it.isLibraryClasses()) {
FirLibrarySession(it, sessionProvider, it.contentScope())
}
}
return FirJavaModuleBasedSession(moduleInfo, sessionProvider, moduleInfo.contentScope())
return FirJavaModuleBasedSession(
moduleInfo, sessionProvider, moduleInfo.contentScope(),
IdeFirDependenciesSymbolProvider(moduleInfo, project, sessionProvider)
)
}
fun testTotalKotlin() {
+1
View File
@@ -35,6 +35,7 @@ val projectsToShadow by extra(listOf(
":compiler:fir:cones",
":compiler:fir:resolve",
":compiler:fir:tree",
":compiler:fir:java",
":compiler:fir:psi2fir",
":idea:fir-view"
)