LightClassDataHolder: refactor, extract subinterfaces

This commit is contained in:
Pavel V. Talanov
2017-03-15 14:36:16 +03:00
parent 6d595e30c2
commit 04591bb938
8 changed files with 56 additions and 43 deletions
@@ -76,7 +76,9 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
trace.setKotlinCodeAnalyzer(codeAnalyzer)
}
override fun createDataHolderForClassOrObject(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder {
override fun createDataHolderForClass(
classOrObject: KtClassOrObject, builder: LightClassBuilder
): LightClassDataHolder.ForClass {
//force resolve companion for light class generation
bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
@@ -172,7 +174,7 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
}
}
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder {
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade {
val (stub, _, diagnostics) = builder(getContext())
return LightClassDataHolderImpl(stub, diagnostics)
}
@@ -20,9 +20,7 @@ import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.asJava.builder.LightClassBuilderResult
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.FqName
@@ -36,9 +34,9 @@ typealias LightClassBuilder = (LightClassConstructionContext) -> LightClassBuild
abstract class LightClassGenerationSupport {
abstract fun createDataHolderForClassOrObject(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder
abstract fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass
abstract fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder
abstract fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade
abstract fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject>
@@ -42,13 +42,18 @@ interface LightClassDataHolder {
fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData
fun findDataForDefaultImpls(classOrObject: KtClassOrObject) = findData {
it.findDelegate(classOrObject).findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false)
?: throw IllegalStateException("Couldn't get delegate for $this\n in ${DebugUtil.stubTreeToString(it)}")
interface ForClass : LightClassDataHolder {
fun findDataForDefaultImpls(classOrObject: KtClassOrObject) = findData {
it.findDelegate(classOrObject).findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false)
?: throw IllegalStateException("Couldn't get delegate for $this\n in ${DebugUtil.stubTreeToString(it)}")
}
fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData = findData { it.findDelegate(classOrObject) }
}
fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData = findData { it.findDelegate(classOrObject) }
fun findDataForFacade(classFqName: FqName): LightClassData = findData { it.findDelegate(classFqName) }
interface ForFacade : LightClassDataHolder {
fun findDataForFacade(classFqName: FqName): LightClassData = findData { it.findDelegate(classFqName) }
}
}
interface LightClassData {
@@ -70,7 +75,7 @@ class LightClassDataImpl(override val clsDelegate: PsiClass) : LightClassData {
}
}
object InvalidLightClassDataHolder : LightClassDataHolder {
object InvalidLightClassDataHolder : LightClassDataHolder.ForClass {
override val javaFileStub: PsiJavaFileStub
get() = shouldNotBeCalled()
@@ -85,7 +90,7 @@ object InvalidLightClassDataHolder : LightClassDataHolder {
class LightClassDataHolderImpl(
override val javaFileStub: PsiJavaFileStub,
override val extraDiagnostics: Diagnostics
) : LightClassDataHolder {
) : LightClassDataHolder.ForClass, LightClassDataHolder.ForFacade {
override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass) = findDelegate(javaFileStub).let(::LightClassDataImpl)
}
@@ -36,12 +36,14 @@ import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassOrObject) : CachedValueProvider<LightClassDataHolder> {
class LightClassDataProviderForClassOrObject(
private val classOrObject: KtClassOrObject
) : CachedValueProvider<LightClassDataHolder.ForClass> {
private fun computeLightClassData(): LightClassDataHolder {
private fun computeLightClassData(): LightClassDataHolder.ForClass {
val file = classOrObject.containingKtFile
val packageFqName = file.packageFqName
return LightClassGenerationSupport.getInstance(classOrObject.project).createDataHolderForClassOrObject(classOrObject) {
return LightClassGenerationSupport.getInstance(classOrObject.project).createDataHolderForClass(classOrObject) {
constructionContext ->
buildLightClass(packageFqName, listOf(file), ClassFilterForClassOrObject(classOrObject), constructionContext) {
state, files ->
@@ -54,7 +56,7 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
}
}
override fun compute(): CachedValueProvider.Result<LightClassDataHolder>? {
override fun compute(): CachedValueProvider.Result<LightClassDataHolder.ForClass>? {
return CachedValueProvider.Result.create(
computeLightClassData(),
if (classOrObject.isLocal()) PsiModificationTracker.MODIFICATION_COUNT else PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
@@ -68,10 +70,10 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
sealed class LightClassDataProviderForFileFacade constructor(
protected val project: Project, protected val facadeFqName: FqName
) : CachedValueProvider<LightClassDataHolder> {
) : CachedValueProvider<LightClassDataHolder.ForFacade> {
abstract fun findFiles(): Collection<KtFile>
private fun computeLightClassData(files: Collection<KtFile>): LightClassDataHolder {
private fun computeLightClassData(files: Collection<KtFile>): LightClassDataHolder.ForFacade {
return LightClassGenerationSupport.getInstance(project).createDataHolderForFacade(files) {
constructionContext ->
buildLightClass(facadeFqName.parent(), files, ClassFilterForFacade, constructionContext) generate@ {
@@ -92,7 +94,7 @@ sealed class LightClassDataProviderForFileFacade constructor(
}
}
override fun compute(): CachedValueProvider.Result<LightClassDataHolder>? {
override fun compute(): CachedValueProvider.Result<LightClassDataHolder.ForFacade>? {
val files = findFiles()
if (files.isEmpty()) return null
@@ -32,7 +32,6 @@ import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.KotlinLanguage
@@ -50,17 +49,17 @@ import javax.swing.Icon
class KtLightClassForFacade private constructor(
manager: PsiManager,
private val facadeClassFqName: FqName,
private val lightClassDataCache: CachedValue<LightClassDataHolder>,
private val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
files: Collection<KtFile>
) : KtLazyLightClass(manager) {
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
class FacadeStubCache(private val project: Project) {
private inner class FacadeCacheData {
val cache = object : SLRUCache<StubCacheKey, CachedValue<LightClassDataHolder>>(20, 30) {
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder> {
val cache = object : SLRUCache<StubCacheKey, CachedValue<LightClassDataHolder.ForFacade>>(20, 30) {
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder.ForFacade> {
val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope)
return CachedValuesManager.getManager(project).createCachedValue<LightClassDataHolder>(stubProvider, /*trackValue = */false)
return CachedValuesManager.getManager(project).createCachedValue<LightClassDataHolder.ForFacade>(stubProvider, /*trackValue = */false)
}
}
}
@@ -69,7 +68,7 @@ class KtLightClassForFacade private constructor(
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
/*trackValue = */ false)
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder> {
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder.ForFacade> {
synchronized (cachedValue) {
return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope))
}
@@ -273,7 +272,7 @@ class KtLightClassForFacade private constructor(
): KtLightClassForFacade {
// TODO: refactor, using cached value doesn't make sense for this case
val cachedValue = CachedValuesManager.getManager(manager.project).
createCachedValue<LightClassDataHolder>(
createCachedValue<LightClassDataHolder.ForFacade>(
LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false
)
return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file))
@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.asJava.elements.KtLightModifierListWithExplicitModifiers
import org.jetbrains.kotlin.asJava.elements.KtLightPsiReferenceList
import org.jetbrains.kotlin.asJava.hasInterfaceDefaultImpls
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
@@ -91,7 +90,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
return LightClassGenerationSupport.getInstance(project).resolveToDescriptor(classOrObject) as? ClassDescriptor
}
protected fun getLightClassDataHolder(): LightClassDataHolder {
protected fun getLightClassDataHolder(): LightClassDataHolder.ForClass {
val lightClassData = getLightClassDataHolder(classOrObject)
if (lightClassData is InvalidLightClassDataHolder) {
LOG.error("Invalid light class data for existing light class:\n$lightClassData\n${classOrObject.getElementTextWithContext()}")
@@ -324,7 +323,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
override fun getImplementsList() = _implementsList
companion object {
private val JAVA_API_STUB = Key.create<CachedValue<LightClassDataHolder>>("JAVA_API_STUB")
private val JAVA_API_STUB = Key.create<CachedValue<LightClassDataHolder.ForClass>>("JAVA_API_STUB")
private val jetTokenToPsiModifier = listOf(
PUBLIC_KEYWORD to PsiModifier.PUBLIC,
@@ -365,11 +364,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
return classOrObject.getBody()?.declarations?.isEmpty() ?: true
}
fun getLightClassDataHolder(classOrObject: KtClassOrObject): LightClassDataHolder {
fun getLightClassDataHolder(classOrObject: KtClassOrObject): LightClassDataHolder.ForClass {
return getLightClassCachedValue(classOrObject).value
}
fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue<LightClassDataHolder> {
fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue<LightClassDataHolder.ForClass> {
var value =
getOutermostClassOrObject(classOrObject).getUserData(JAVA_API_STUB) // stub computed for outer class can be used for inner/nested
?: classOrObject.getUserData(JAVA_API_STUB)
@@ -60,16 +60,16 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
private val psiManager: PsiManager = PsiManager.getInstance(project)
override fun createDataHolderForClassOrObject(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder {
override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass {
return if (classOrObject.isLocal) {
LazyLightClassDataHolder(
LazyLightClassDataHolder.ForClass(
builder,
exactContextProvider = { IDELightClassContexts.contextForLocalClassOrObject(classOrObject) },
dummyContextProvider = null
)
}
else {
LazyLightClassDataHolder(
LazyLightClassDataHolder.ForClass(
builder,
exactContextProvider = { IDELightClassContexts.contextForNonLocalClassOrObject(classOrObject) },
dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
@@ -78,12 +78,12 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
}
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder {
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade {
assert(!files.isEmpty()) { "No files in facade" }
val sortedFiles = files.sortedWith(scopeFileComparator)
return LazyLightClassDataHolder(
return LazyLightClassDataHolder.ForFacade(
builder,
exactContextProvider = { IDELightClassContexts.contextForFacade(sortedFiles) },
dummyContextProvider = { IDELightClassContexts.lightContextForFacade(sortedFiles) }
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
typealias LightClassContextProvider = () -> LightClassConstructionContext
class LazyLightClassDataHolder(
sealed class LazyLightClassDataHolder(
builder: LightClassBuilder,
exactContextProvider: LightClassContextProvider,
dummyContextProvider: LightClassContextProvider?
@@ -57,10 +57,18 @@ class LazyLightClassDataHolder(
findDelegate(lightClassBuilderResult.stub)
}
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
lightClassBuilderResult.stub.findDelegate(classOrObject)
}
class ForClass(
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
lightClassBuilderResult.stub.findDelegate(classOrObject)
}
}
class ForFacade(
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
private inner class LazyLightClassData(
private val relyOnDummySupertypes: Boolean,