IJPL-15941 Workspace Model: report codegen problems instead of throwing exceptions

GitOrigin-RevId: e22ecff8580e73951d1672e709e2a004258f6e04
This commit is contained in:
Kirill Bochkarev
2025-12-19 00:57:36 +00:00
committed by intellij-monorepo-bot
parent 498dd67191
commit 3b5c542ff5
12 changed files with 153 additions and 76 deletions
@@ -9,7 +9,7 @@ public object CodeGeneratorVersions {
/** these constants are accessed from WorkspaceImplObsoleteInspection */
private const val API_VERSION_INTERNAL = 3
private const val IMPL_MAJOR_VERSION_INTERNAL = 7
private const val IMPL_MINOR_VERSION_INTERNAL = 10
private const val IMPL_MINOR_VERSION_INTERNAL = 11
@set:TestOnly
public var API_VERSION: Int = API_VERSION_INTERNAL
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.IncorrectObjInterfaceException
import com.intellij.devkit.workspaceModel.metaModel.MetaModelBuilderException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceEntityInheritsEntitySourceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceEntityMultipleInheritanceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
@@ -12,6 +12,7 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.workspaceModel.codegen.deft.meta.*
import org.jetbrains.kotlin.backend.jvm.ir.psiElement
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.base.projectStructure.productionSourceInfo
@@ -259,7 +260,7 @@ internal class WorkspaceMetaModelBuilder(
}
classDescriptor.isAbstractClassOrInterface -> {
if (!processAbstractTypes) {
throw IncorrectObjInterfaceException("$javaClassFqn is abstract type. Abstract types are not supported in generator")
throw MetaModelBuilderException("$javaClassFqn is abstract type. Abstract types are not supported in generator", classDescriptor.psiElement)
}
val inheritors = classDescriptor.inheritors(javaPsiFacade, allScope)
.filter { !it.isEntitySource || ( it.packageName == compiledObjModule.name) } // && it.module == moduleDescriptor) }
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.MetaProblem
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.openapi.module.Module
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
@@ -13,13 +14,14 @@ internal class WorkspaceMetaModelProviderImpl : WorkspaceMetaModelProvider {
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule> {
): Pair<List<CompiledObjModule>, List<MetaProblem>> {
val packages = ktClasses.values.mapTo(LinkedHashSet()) { it.containingKtFile.packageFqName.asString() }
val metaModelProvider = WorkspaceMetaModelBuilder(
processAbstractTypes = processAbstractTypes,
module.project
)
return packages.filter { it != "" }.map { metaModelProvider.getObjModule(it, module, isTestSourceFolder) }
val compiledObjModules = packages.filter { it != "" }.map { metaModelProvider.getObjModule(it, module, isTestSourceFolder) }
return compiledObjModules to emptyList()
}
}
@@ -1,6 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.MetaModelBuilderException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.impl.CompiledObjModuleImpl
import com.intellij.devkit.workspaceModel.metaModel.impl.ObjAnnotationImpl
@@ -39,11 +40,10 @@ internal fun KaSession.inheritors(
// can be rewritten using org.jetbrains.kotlin.idea.searching.inheritors.KotlinSearchUtilKt.findAllInheritors
val psiClass = javaPsiFacade.findClass(classSymbol.javaClassFqn, scope) ?: return emptyList()
return ClassInheritorsSearch.search(psiClass, scope, true, true, false)
.asIterable()
.filterNot { it.isAnonymous }
.sortedBy { it.qualifiedName } // Sorting is needed for consistency in case of regeneration
.mapNotNull {
KotlinFullClassNameIndex[it.qualifiedName!!, it.project, scope].firstOrNull()
.mapNotNull { psiClass ->
psiClass.qualifiedName?.let { KotlinFullClassNameIndex[it, psiClass.project, scope].firstOrNull() }
}
}
@@ -88,7 +88,7 @@ internal val KaClassLikeSymbol.packageName: String
get() = packageOrDie.asString()
internal val KaClassLikeSymbol.packageOrDie: FqName
get() = classId?.packageFqName ?: error("$name has no package")
get() = classId?.packageFqName ?: throw MetaModelBuilderException("$name has no package", sourcePsiSafe())
internal fun KaSession.getPackageSymbol(classSymbol: KaClassSymbol): KaPackageSymbol? =
classSymbol.classId?.packageFqName?.let { findPackage(it) }
@@ -145,8 +145,10 @@ internal fun KaSession.createObjTypeStub(symbol: KaClassSymbol, module: Compiled
val propertyAnnotations = symbol.annotations
.mapNotNull { it.classId?.asSingleFqName() }
.map { ObjAnnotationImpl(it.asString(), it.pathSegments().map { segment -> segment.asString() }) }
val identifier = symbol.name?.identifier ?: throw MetaModelBuilderException("Could not get identifier of ${symbol.name}", symbol.sourcePsiSafe())
return ObjClassImpl(module, symbol.name?.identifier!!, openness, symbol.sourcePsi(), propertyAnnotations)
return ObjClassImpl(module, identifier, openness, symbol.sourcePsi(), propertyAnnotations)
}
internal fun KaSession.isParent(kaType: KaAnnotated) =
@@ -1,12 +1,8 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceEntityInheritsEntitySourceException
import com.intellij.devkit.workspaceModel.metaModel.IncorrectObjInterfaceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceEntityMultipleInheritanceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.*
import com.intellij.devkit.workspaceModel.metaModel.impl.*
import com.intellij.devkit.workspaceModel.metaModel.unsupportedType
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
@@ -36,8 +32,9 @@ internal class WorkspaceMetaModelBuilder(
kaModule: KaModule,
): CompiledObjModule = analyze(kaModule) {
val ktFile = KotlinExactPackagesIndex.get(packageName, project, kaModule.contentScope).firstOrNull()
?: error("Cannot find any files with package $packageName in module ${kaModule}")
val packageSymbol = findPackage(ktFile.packageFqName) ?: error("Could not find package $packageName in module ${kaModule}")
?: throw MetaModelBuilderException("Cannot find any files with package $packageName in module ${kaModule}", null)
val packageSymbol = findPackage(ktFile.packageFqName)
?: throw MetaModelBuilderException("Could not find package $packageName in module ${kaModule}", null)
getObjModule(packageName, packageSymbol, kaModule)
}
@@ -92,10 +89,17 @@ internal class WorkspaceMetaModelBuilder(
}
private fun KaSession.getObjClass(entityInterface: KaClassSymbol): ObjClass<*> {
val containingPackage = getPackageSymbol(entityInterface) ?: error("Cannot find package for ${entityInterface.name ?: entityInterface}")
val objModule = getObjModule(entityInterface.packageName, containingPackage, entityInterface.containingModule)
val entityInterfaceName = entityInterface.name?.identifier ?: error("Too many errors")
return objModule.types.find { it.name == entityInterfaceName } ?: error("Cannot find $entityInterfaceName in $objModule")
val packageSymbol = getPackageSymbol(entityInterface)
if (packageSymbol == null) {
throw MetaModelBuilderException("Cannot find package for ${entityInterface.name ?: entityInterface}", entityInterface.sourcePsiSafe())
}
val objModule = getObjModule(entityInterface.packageName, packageSymbol, entityInterface.containingModule)
val objClass = entityInterface.name?.identifier?.let { entityInterfaceName -> objModule.types.find { it.name == entityInterfaceName } }
if (objClass == null) {
throw MetaModelBuilderException("Cannot find class ${entityInterface.name ?: entityInterface} in module ${objModule.name}",
entityInterface.sourcePsiSafe())
}
return objClass
}
private inner class ObjModuleStub(
@@ -136,11 +140,11 @@ internal class WorkspaceMetaModelBuilder(
extendedAbstract.add(superClass.name)
}
if (isEntitySource(superSymbol)) {
throw WorkspaceEntityInheritsEntitySourceException(classSymbol.javaClassFqn)
throw MetaModelBuilderException("${classSymbol.javaClassFqn} should not extend WorkspaceEntity and EntitySource at the same time", classSymbol.sourcePsiSafe())
}
}
if (extendedAbstract.size > 1) {
throw WorkspaceEntityMultipleInheritanceException(classSymbol.javaClassFqn, extendedAbstract)
throw MetaModelBuilderException("${classSymbol.javaClassFqn} should not extend multiple @Abstract entities: ${extendedAbstract.joinToString(", ")}", classSymbol.sourcePsiSafe())
}
compiledObjModule.addType(objType)
@@ -207,9 +211,17 @@ internal class WorkspaceMetaModelBuilder(
}
} ?: emptyList()
return ExtPropertyImpl(findObjClass(receiverClass), extProperty.name.identifier, valueType, computeKind(extProperty),
extProperty.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.classId), !extProperty.isVal, false, compiledObjModule,
extPropertyId, propertyAnnotations, extProperty.sourcePsiSafe())
return ExtPropertyImpl(findObjClass(receiverClass),
extProperty.name.identifier,
valueType,
computeKind(extProperty),
extProperty.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.classId),
!extProperty.isVal,
false,
compiledObjModule,
extPropertyId,
propertyAnnotations,
extProperty.sourcePsiSafe())
}
private fun KaSession.convertType(
@@ -217,7 +229,8 @@ internal class WorkspaceMetaModelBuilder(
knownTypes: MutableMap<String, ValueType.Blob<*>>,
hasParentAnnotation: Boolean,
): ValueType<*> {
if (type !is KaClassType) error("$type is not a class in module ${compiledObjModule.name}")
if (type !is KaClassType) throw MetaModelBuilderException("$type is not a class in module ${compiledObjModule.name}",
type.expandedSymbol?.sourcePsiSafe())
if (type.isMarkedNullable) {
val nonNullableType = type.withNullability(false)
return ValueType.Optional(convertType(nonNullableType, knownTypes, hasParentAnnotation))
@@ -234,7 +247,7 @@ internal class WorkspaceMetaModelBuilder(
when {
type.isSubtypeOf(StandardClassIds.List) -> return ValueType.List(genericType)
type.isSubtypeOf(StandardClassIds.Set) -> return ValueType.Set(genericType)
else -> return unsupportedType(type.toString())
else -> return unsupportedType(type.toString(), type.expandedSymbol?.sourcePsiSafe())
}
}
@@ -252,13 +265,14 @@ internal class WorkspaceMetaModelBuilder(
return classSymbolToValueType(symbol, knownTypes, processAbstractTypes)
}
return unsupportedType(type.toString())
return unsupportedType(type.toString(), type.expandedSymbol?.sourcePsiSafe())
}
private fun KaSession.findObjClass(classSymbol: KaClassSymbol): ObjClass<*> {
if (classSymbol.packageOrDie.asString() == compiledObjModule.name) {
return entityTypes.find { it.first.classId == classSymbol.classId }?.second
?: error("Cannot find ${classSymbol.name} in $compiledObjModule")
?: throw MetaModelBuilderException("Cannot find ${classSymbol.name} in ${compiledObjModule.name}",
classSymbol.sourcePsiSafe())
}
return getObjClass(classSymbol)
}
@@ -294,7 +308,8 @@ internal class WorkspaceMetaModelBuilder(
}
classSymbol.classKind == KaClassKind.INTERFACE || classSymbol.modality != KaSymbolModality.FINAL -> {
if (!processAbstractTypes) {
throw IncorrectObjInterfaceException("$javaClassFqn is abstract type. Abstract types are not supported in generator")
throw MetaModelBuilderException("$javaClassFqn is abstract type. Abstract types are not supported in generator",
classSymbol.sourcePsiSafe())
}
val inheritors = inheritors(classSymbol, javaPsiFacade, allProjectScope)
.mapNotNull { ktClassOrObject ->
@@ -1,6 +1,8 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.MetaModelBuilderException
import com.intellij.devkit.workspaceModel.metaModel.MetaProblem
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.openapi.module.Module
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
@@ -8,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisFromWriteAct
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisFromWriteAction
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.projectStructure.KaSourceModule
import org.jetbrains.kotlin.idea.base.projectStructure.toKaSourceModuleForProduction
import org.jetbrains.kotlin.idea.base.projectStructure.toKaSourceModuleForTest
import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -20,7 +23,7 @@ internal class WorkspaceMetaModelProviderImpl : WorkspaceMetaModelProvider {
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule> {
): Pair<List<CompiledObjModule>, List<MetaProblem>> {
val packages = ktClasses.values.mapTo(LinkedHashSet()) { it.containingKtFile.packageFqName.asString() }
val metaModelProvider = WorkspaceMetaModelBuilder(
@@ -34,17 +37,32 @@ internal class WorkspaceMetaModelProviderImpl : WorkspaceMetaModelProvider {
module.toKaSourceModuleForTest()
}
if (kaModule == null) {
return emptyList()
return (emptyList<CompiledObjModule>() to emptyList())
}
val compiledObjModule = allowAnalysisOnEdt {
val problems: MutableList<MetaProblem> = mutableListOf()
val compiledObjModules = allowAnalysisOnEdt {
allowAnalysisFromWriteAction {
packages
.filter { it != "" }
.map { packageName ->
metaModelProvider.getObjModule(packageName, kaModule)
.mapNotNull { packageName ->
metaModelProvider.getObjModuleOrProblem(packageName, kaModule, problems)
}
}
}
return compiledObjModule
return compiledObjModules to problems
}
private fun WorkspaceMetaModelBuilder.getObjModuleOrProblem(
packageName: String,
kaModule: KaSourceModule,
problems: MutableList<MetaProblem>
): CompiledObjModule? {
try {
return getObjModule(packageName, kaModule)
}
catch (e: MetaModelBuilderException) {
problems.add(MetaProblem(e.message ?: "", e.psiToHighlight))
return null
}
}
}
@@ -98,7 +98,16 @@ object CodeWriter {
ApplicationManagerEx.getApplicationEx().runWriteActionWithCancellableProgressInDispatchThread(title, project, null) { indicator ->
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.collecting.classes.metadata")
val metaLoader: WorkspaceMetaModelProvider = service<WorkspaceMetaModelProvider>()
val objModules = metaLoader.loadObjModules(ktClasses, module, processAbstractTypes, isTestSourceFolder)
val (objModules, metaProblems) = metaLoader.loadObjModules(ktClasses, module, processAbstractTypes, isTestSourceFolder)
if (metaProblems.isNotEmpty()) {
WorkspaceCodegenProblemsProvider.getInstance(project).reportMetaProblem(metaProblems)
val genFolder = existingTargetFolder.invoke()
if (genFolder != null) {
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.removing.old.code")
removeGeneratedCode(genFolder)
}
return@runWriteActionWithCancellableProgressInDispatchThread
}
val results = generate(codeGenerator, objModules, explicitApiEnabled, isTestModule)
val generatedCode = results.flatMap { it.generatedCode }
@@ -106,7 +115,6 @@ object CodeWriter {
WorkspaceCodegenProblemsProvider.getInstance(project).reportProblems(problems)
if (generatedCode.isEmpty() || problems.any { it.level == GenerationProblem.Level.ERROR }) {
LOG.info("Not found types for generation")
val genFolder = existingTargetFolder.invoke()
if (genFolder != null) {
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.removing.old.code")
@@ -7,6 +7,7 @@ import com.intellij.analysis.problemsView.ProblemsCollector
import com.intellij.analysis.problemsView.ProblemsProvider
import com.intellij.analysis.problemsView.toolWindow.ProblemsViewToolWindowUtils.selectProjectErrorsTab
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.devkit.workspaceModel.metaModel.MetaProblem
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithPsi
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
@@ -14,6 +15,7 @@ import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.util.startOffset
import com.intellij.workspaceModel.codegen.engine.GenerationProblem
@@ -21,19 +23,36 @@ import com.intellij.workspaceModel.codegen.engine.ProblemLocation
import javax.swing.Icon
@Service(Service.Level.PROJECT)
class WorkspaceCodegenProblemsProvider(override val project: Project): ProblemsProvider {
class WorkspaceCodegenProblemsProvider(override val project: Project) : ProblemsProvider {
private var currentProblems = emptyList<WorkspaceModelCodeGenerationProblem>()
companion object {
fun getInstance(project: Project): WorkspaceCodegenProblemsProvider = project.service()
}
fun reportMetaProblem(metaProblems: List<MetaProblem>) {
if (ApplicationManager.getApplication().isUnitTestMode) {
val firstProblem = metaProblems.firstOrNull() ?: return
error("Failed to collect metadata: ${firstProblem.message}")
}
for (currentProblem in currentProblems) {
ProblemsCollector.getInstance(project).problemDisappeared(currentProblem)
}
val problems = metaProblems.map { it.toProblem() }
currentProblems = problems
for (currentProblem in problems) {
ProblemsCollector.getInstance(project).problemAppeared(currentProblem)
}
selectProjectErrorsTab(project)
}
fun reportProblems(generationProblems: List<GenerationProblem>) {
if (generationProblems.isNotEmpty() && ApplicationManager.getApplication().isUnitTestMode) {
val problem = generationProblems.first()
error("Failed to generate code for ${problem.location}: ${problem.message}")
}
val problems = generationProblems.map { it.toProblem() }
for (currentProblem in currentProblems) {
ProblemsCollector.getInstance(project).problemDisappeared(currentProblem)
@@ -46,39 +65,45 @@ class WorkspaceCodegenProblemsProvider(override val project: Project): ProblemsP
selectProjectErrorsTab(project)
}
}
private fun MetaProblem.toProblem(): WorkspaceModelCodeGenerationProblem {
if (psiToHighlight == null) return WorkspaceModelCodeGenerationProblem(message, HighlightDisplayLevel.ERROR.icon)
return problemWithPsi(psiToHighlight, message, HighlightDisplayLevel.ERROR.icon)
}
private fun GenerationProblem.toProblem(): WorkspaceModelCodeGenerationProblem {
val icon = when (level) {
GenerationProblem.Level.WARNING -> HighlightDisplayLevel.WARNING.icon
else -> HighlightDisplayLevel.ERROR.icon
}
val psiElement = when (val problemLocation = location) {
is ProblemLocation.Class -> (problemLocation.objClass as ObjMetaElementWithPsi).sourcePsi
is ProblemLocation.Property -> (problemLocation.property as ObjMetaElementWithPsi).sourcePsi
} ?: return WorkspaceModelCodeGenerationProblem(this)
is ProblemLocation.Class -> (problemLocation.objClass as ObjMetaElementWithPsi).sourcePsi
is ProblemLocation.Property -> (problemLocation.property as ObjMetaElementWithPsi).sourcePsi
} ?: return WorkspaceModelCodeGenerationProblem(message, icon)
return problemWithPsi(psiElement, message, icon)
}
private fun problemWithPsi(psiElement: PsiElement, text: String, icon: Icon): WorkspaceModelCodeGenerationProblem {
val psiToHighlight = (psiElement as? PsiNameIdentifierOwner)?.nameIdentifier ?: psiElement
val file = psiToHighlight.containingFile.virtualFile
val document = FileDocumentManager.getInstance().getDocument(file) ?: return WorkspaceModelCodeGenerationProblem(this)
val document = FileDocumentManager.getInstance().getDocument(file) ?: return WorkspaceModelCodeGenerationProblem(text, icon)
val offset = psiToHighlight.startOffset
val line = document.getLineNumber(offset)
val column = offset - document.getLineStartOffset(line)
return WorkspaceModelCodeGenerationProblemInFile(this, file, line, column)
return WorkspaceModelCodeGenerationProblemInFile(text, icon, file, line, column)
}
private open inner class WorkspaceModelCodeGenerationProblem(private val originalProblem: GenerationProblem) : Problem {
private open inner class WorkspaceModelCodeGenerationProblem(override val text: String, override val icon: Icon) : Problem {
override val provider: ProblemsProvider
get() = this@WorkspaceCodegenProblemsProvider
override val text: String
get() = originalProblem.message
override val icon: Icon
get() = when (originalProblem.level) {
GenerationProblem.Level.ERROR -> HighlightDisplayLevel.ERROR.icon
GenerationProblem.Level.WARNING -> HighlightDisplayLevel.WARNING.icon
}
}
private open inner class WorkspaceModelCodeGenerationProblemInFile(
originalProblem: GenerationProblem,
private inner class WorkspaceModelCodeGenerationProblemInFile(
text: String,
icon: Icon,
override val file: VirtualFile,
override val line: Int,
override val column: Int
) : WorkspaceModelCodeGenerationProblem(originalProblem), FileProblem
override val column: Int,
) : WorkspaceModelCodeGenerationProblem(text, icon), FileProblem
}
@@ -0,0 +1,12 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel
import com.intellij.psi.PsiElement
class MetaModelBuilderException(errorMessage: String, val psiToHighlight: PsiElement?) : RuntimeException(errorMessage)
class WorkspaceEntityInheritsEntitySourceException(entityFqn: String) :
IllegalStateException("$entityFqn extends WorkspaceEntity and EntitySource at the same time, which is prohibited.")
class WorkspaceEntityMultipleInheritanceException(entityFqn: String, supers: Set<String>) :
IllegalStateException("$entityFqn extends multiple @Abstract entities, which is prohibited: ${supers.joinToString(", ")}.")
@@ -4,18 +4,12 @@ package com.intellij.devkit.workspaceModel.metaModel
import com.intellij.psi.PsiElement
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
class IncorrectObjInterfaceException(errorMessage: String) : RuntimeException(errorMessage)
class WorkspaceEntityInheritsEntitySourceException(entityFqn: String) :
IllegalStateException("$entityFqn extends WorkspaceEntity and EntitySource at the same time, which is prohibited.")
class WorkspaceEntityMultipleInheritanceException(entityFqn: String, supers: Set<String>) :
IllegalStateException("$entityFqn extends multiple @Abstract entities, which is prohibited: ${supers.joinToString(", ")}.")
interface ObjMetaElementWithPsi {
val sourcePsi: PsiElement?
}
fun unsupportedType(type: String?): ValueType<*> {
throw IncorrectObjInterfaceException("Unsupported type '$type'")
fun unsupportedType(type: String?, psiToHighlight: PsiElement? = null): ValueType<*> {
throw MetaModelBuilderException("Unsupported type '$type'", psiToHighlight)
}
class MetaProblem(val message: String, val psiToHighlight: PsiElement?)
@@ -11,5 +11,5 @@ interface WorkspaceMetaModelProvider {
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule>
): Pair<List<CompiledObjModule>, List<MetaProblem>>
}
@@ -103,7 +103,7 @@ abstract class AbstractEntityCodeGenTest : CodeGenerationTestBase() {
}
fun testBothLinksAreChildren() {
doTestAndCheckErrorMessage("Both fields MainEntity#secondaryEntities and SecondaryEntity#mainEntity are marked as child. Probably @Parent annotation is missing from one of the properties.")
doTestAndCheckErrorMessage("Failed to generate code for secondaryEntities (MainEntity): Both fields MainEntity#secondaryEntities and SecondaryEntity#mainEntity are marked as child. Probably @Parent annotation is missing from one of the properties.")
}
fun testChildrenShouldBeNullable() {
@@ -119,11 +119,11 @@ abstract class AbstractEntityCodeGenTest : CodeGenerationTestBase() {
}
fun testInheritanceEntityAndSource() {
doTestAndCheckErrorMessage("com.intellij.workspaceModel.test.api.IllegalEntity extends WorkspaceEntity and EntitySource at the same time, which is prohibited.")
doTestAndCheckErrorMessage("Failed to collect metadata: com.intellij.workspaceModel.test.api.IllegalEntity should not extend WorkspaceEntity and EntitySource at the same time")
}
fun testInheritanceMultiple() {
doTestAndCheckErrorMessage("com.intellij.workspaceModel.test.api.MultipleInheritanceEntity extends multiple @Abstract entities, which is prohibited: AbstractEntity3, AnotherAbstractEntity.")
doTestAndCheckErrorMessage("Failed to collect metadata: com.intellij.workspaceModel.test.api.MultipleInheritanceEntity should not extend multiple @Abstract entities: AbstractEntity3, AnotherAbstractEntity")
}
fun testInheritanceNonAbstract() {