diff --git a/mps-model-adapters-plugin/src/test/kotlin/org/modelix/model/mpsadapters/MPSAreaTest.kt b/mps-model-adapters-plugin/src/test/kotlin/org/modelix/model/mpsadapters/MPSAreaTest.kt new file mode 100644 index 0000000000..e79955be63 --- /dev/null +++ b/mps-model-adapters-plugin/src/test/kotlin/org/modelix/model/mpsadapters/MPSAreaTest.kt @@ -0,0 +1,38 @@ +package org.modelix.model.mpsadapters + +import org.modelix.model.api.BuiltinLanguages +import org.modelix.model.api.INode + +/* + * Copyright (c) 2023. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class MPSAreaTest : MpsAdaptersTestBase("SimpleProject") { + + fun testResolveModuleInNonExistingProject() { + val repositoryNode: INode = MPSRepositoryAsNode(mpsProject.repository) + val area = repositoryNode.getArea() + readAction { + val nonExistingProject = MPSProjectReference("nonExistingProject") + val module = repositoryNode.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Repository.modules) + .single { it.getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name) == "Solution1" } + val projectModuleReference = MPSProjectModuleReference((module.reference as MPSModuleReference).moduleReference, nonExistingProject) + + val resolutionResult = area.resolveNode(projectModuleReference) + + assertNull(resolutionResult) + } + } +} diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/MPSArea.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/MPSArea.kt index cace44d610..1b20cee0be 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/MPSArea.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/MPSArea.kt @@ -306,13 +306,24 @@ data class MPSArea(val repository: SRepository) : IArea, IAreaReference { val projectRef = if (ref is MPSProjectModuleReference) { ref.projectRef } else { + // XXX Prefix of `projectRef` is not checked. + // `projectRef` might actually be a ref to anything. + // This might trigger unexpected resolution results and undefined behavior. + // Similar missing checks exist for other references in `MPSArea`. + // See https://issues.modelix.org/issue/MODELIX-923 val projectRef = serialized.substringAfter(MPSProjectModuleReference.SEPARATOR) NodeReference(projectRef) } + val resolvedNodeForProject = resolveNode(projectRef) ?: return null + check(resolvedNodeForProject is MPSProjectAsNode) { + "Resolved node `$resolvedNodeForProject` does not represent a project." + } + val resolvedProject = resolvedNodeForProject.project + return moduleRef.resolve(repository)?.let { MPSProjectModuleAsNode( - project = (resolveNode(projectRef) as MPSProjectAsNode).project, + project = resolvedProject, module = it, ) }