Refactor light classes: Delegate LightClassDataHolder construction to LightClassGenerationSupport

This commit is contained in:
Pavel V. Talanov
2017-02-16 16:11:06 +03:00
parent 00e84fb483
commit d01aaeb65c
4 changed files with 70 additions and 48 deletions
@@ -26,7 +26,7 @@ import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
@@ -75,10 +75,18 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
trace.setKotlinCodeAnalyzer(codeAnalyzer)
}
override fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
override fun createLightClassDataHolderForClassOrObject(classOrObject: KtClassOrObject, builder: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
//force resolve companion for light class generation
bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
return LightClassConstructionContext(bindingContext, module)
val (stub, bindingContext, diagnostics) = builder(getContext())
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
return LightClassDataHolderImpl(
stub,
diagnostics
)
}
private fun getContext(): LightClassConstructionContext {
@@ -163,8 +171,9 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
}
}
override fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext {
return getContext()
override fun createLightClassDataHolderForFacade(files: Collection<KtFile>, build: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
val (stub, _, diagnostics) = build(getContext())
return LightClassDataHolderImpl(stub, diagnostics)
}
override fun createTrace(): BindingTraceContext {
@@ -20,7 +20,9 @@ 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.classes.KtLightClass
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.FqName
@@ -32,7 +34,13 @@ import org.jetbrains.kotlin.resolve.BindingContext
abstract class LightClassGenerationSupport {
abstract fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext
abstract fun createLightClassDataHolderForClassOrObject(
classOrObject: KtClassOrObject, builder: (LightClassConstructionContext) -> LightClassBuilderResult
): LightClassDataHolder
abstract fun createLightClassDataHolderForFacade(
files: Collection<KtFile>, build: (LightClassConstructionContext) -> LightClassBuilderResult
): LightClassDataHolder
abstract fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject>
@@ -71,8 +79,6 @@ abstract class LightClassGenerationSupport {
abstract fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile>
abstract fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext
companion object {
@JvmStatic fun getInstance(project: Project): LightClassGenerationSupport {
return ServiceManager.getService(project, LightClassGenerationSupport::class.java)
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext
abstract class LightClassDataProvider<T : LightClassDataHolder>(
private val project: Project
@@ -116,24 +115,17 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
}
}
val classConstructionContext = LightClassGenerationSupport.getInstance(classOrObject.project).getContextForClassOrObject(classOrObject)
val (stub, bindingContext, diagnostics) = buildLightClass(classOrObject.project, packageFqName, listOf(file), generateClassFilter, classConstructionContext) {
state, files ->
val packageCodegen = state.factory.forPackage(packageFqName, files)
val packagePartType = state.fileClassesProvider.getFileClassType(file)
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
packageCodegen.generateClassOrObject(getOutermostClassOrObject(classOrObject), context)
state.factory.asList()
return LightClassGenerationSupport.getInstance(classOrObject.project).createLightClassDataHolderForClassOrObject(classOrObject) {
constructionContext ->
buildLightClass(classOrObject.project, packageFqName, listOf(file), generateClassFilter, constructionContext) {
state, files ->
val packageCodegen = state.factory.forPackage(packageFqName, files)
val packagePartType = state.fileClassesProvider.getFileClassType(file)
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
packageCodegen.generateClassOrObject(getOutermostClassOrObject(classOrObject), context)
state.factory.asList()
}
}
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
return LightClassDataHolderImpl(
stub,
diagnostics
)
}
override fun toString(): String {
@@ -143,14 +135,14 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
sealed class LightClassDataProviderForFileFacade constructor(
protected val project: Project, protected val facadeFqName: FqName
) : LightClassDataProvider<LightClassDataHolderImpl>(project) {
) : LightClassDataProvider<LightClassDataHolder>(project) {
override val isLocal: Boolean get() = false
abstract val files: Collection<KtFile>
override val valueAbsent: Boolean
get() = files.isEmpty()
override fun computeLightClassData(): LightClassDataHolderImpl {
override fun computeLightClassData(): LightClassDataHolder {
val generateClassFilter = object : GenerationState.GenerateClassFilter() {
override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean {
return shouldGenerateClass(processingClassOrObject)
@@ -171,25 +163,26 @@ sealed class LightClassDataProviderForFileFacade constructor(
val packageFqName = facadeFqName.parent()
val (stub, _, diagnostics) = buildLightClass(project, packageFqName, files, generateClassFilter, LightClassGenerationSupport.getInstance(project).getContextForFacade(files)) generate@ {
state, files ->
if (!files.isEmpty()) {
val representativeFile = files.iterator().next()
val fileClassInfo = NoResolveFileClassesProvider.getFileClassInfo(representativeFile)
if (!fileClassInfo.withJvmMultifileClass) {
val codegen = state.factory.forPackage(representativeFile.packageFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
return@generate
return LightClassGenerationSupport.getInstance(project).createLightClassDataHolderForFacade(files) {
constructionContext ->
buildLightClass(project, packageFqName, files, generateClassFilter, constructionContext) generate@ {
state, files ->
if (!files.isEmpty()) {
val representativeFile = files.iterator().next()
val fileClassInfo = NoResolveFileClassesProvider.getFileClassInfo(representativeFile)
if (!fileClassInfo.withJvmMultifileClass) {
val codegen = state.factory.forPackage(representativeFile.packageFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
return@generate
}
}
val codegen = state.factory.forMultifileClass(facadeFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
}
val codegen = state.factory.forMultifileClass(facadeFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
}
return LightClassDataHolderImpl(stub, diagnostics)
}
override fun toString(): String {
@@ -28,8 +28,7 @@ import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
@@ -65,7 +64,17 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
private val psiManager: PsiManager = PsiManager.getInstance(project)
override fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
override fun createLightClassDataHolderForClassOrObject(classOrObject: KtClassOrObject, build: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
val (stub, bindingContext, diagnostics) = build(getContextForClassOrObject(classOrObject))
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
return LightClassDataHolderImpl(
stub,
diagnostics
)
}
fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
if (classOrObject.isLocal) {
return getContextForLocalClassOrObject(classOrObject)
}
@@ -108,7 +117,12 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
}
override fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext {
override fun createLightClassDataHolderForFacade(files: Collection<KtFile>, build: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
val (stub, _, diagnostics) = build(getContextForFacade(files))
return LightClassDataHolderImpl(stub, diagnostics)
}
fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext {
assert(!files.isEmpty()) { "No files in facade" }
val sortedFiles = files.sortedWith(scopeFileComparator)