mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-15941 Workspace Model: report codegen problems instead of throwing exceptions
GitOrigin-RevId: e22ecff8580e73951d1672e709e2a004258f6e04
This commit is contained in:
committed by
intellij-monorepo-bot
parent
498dd67191
commit
3b5c542ff5
+1
-1
@@ -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
|
||||
|
||||
+3
-2
@@ -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) }
|
||||
|
||||
+4
-2
@@ -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) =
|
||||
|
||||
+36
-21
@@ -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 ->
|
||||
|
||||
+24
-6
@@ -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")
|
||||
|
||||
+48
-23
@@ -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?)
|
||||
|
||||
+1
-1
@@ -11,5 +11,5 @@ interface WorkspaceMetaModelProvider {
|
||||
module: Module,
|
||||
processAbstractTypes: Boolean,
|
||||
isTestSourceFolder: Boolean,
|
||||
): List<CompiledObjModule>
|
||||
): Pair<List<CompiledObjModule>, List<MetaProblem>>
|
||||
}
|
||||
|
||||
+3
-3
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user