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