From 6c678351286c163ec22969c95246a9c0fc3453c9 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Mon, 13 Nov 2023 18:56:06 +0100 Subject: [PATCH] [LL] Add PSI resilience tests for `LLFirDeclarationModificationService` - The cause of KT-63130 is that `LLFirDeclarationModificationService` tries to analyze inconsistent PSI. These new tests replicate the inconsistent PSI by deleting different children and then call the declaration modification service with it, making sure that the service doesn't throw any exceptions. Both exceptions mentioned in the issue are reproduced by the added tests, specifically, the receiver and selector resilience tests for dot-qualified expressions. - A few of the tests need to be marked with `IGNORE_FIR` until the error has been fixed in the subsequent commit. ^KT-63130 --- .../callExpression/contractCall.kt | 10 ++ .../callExpression/printlnFirstStatement.kt | 3 + .../callExpression/printlnSecondStatement.kt | 4 + .../dotQualifiedExpression/contractCall.kt | 11 +++ .../stringLengthFirstStatement.kt | 5 + .../stringLengthSecondStatement.kt | 4 + .../propertyDeclaration/simpleProperty.kt | 1 + ...ionModificationServicePsiResilienceTest.kt | 96 +++++++++++++++++++ ...pressionCalleeResilienceTestGenerated.java | 44 +++++++++ ...essionReceiverResilienceTestGenerated.java | 44 +++++++++ ...essionSelectorResilienceTestGenerated.java | 44 +++++++++ ...ionInitializerResilienceTestGenerated.java | 32 +++++++ .../tests/analysis/api/firLowLevel.kt | 32 +++++++ 13 files changed, 330 insertions(+) create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/contractCall.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnFirstStatement.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnSecondStatement.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt create mode 100644 analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration/simpleProperty.kt create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractDeclarationModificationServicePsiResilienceTest.kt create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceCallExpressionCalleeResilienceTestGenerated.java create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTestGenerated.java create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTestGenerated.java create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServicePropertyDeclarationInitializerResilienceTestGenerated.java diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/contractCall.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/contractCall.kt new file mode 100644 index 00000000000..bdbe38a6ba2 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/contractCall.kt @@ -0,0 +1,10 @@ +import kotlin.contracts.contract +import kotlin.contracts.InvocationKind + +inline fun foo(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + + block() +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnFirstStatement.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnFirstStatement.kt new file mode 100644 index 00000000000..66ac2bb0804 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnFirstStatement.kt @@ -0,0 +1,3 @@ +fun foo(string: String) { + println("Hello world, $string!") +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnSecondStatement.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnSecondStatement.kt new file mode 100644 index 00000000000..ad31f7e65ef --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnSecondStatement.kt @@ -0,0 +1,4 @@ +fun foo(string: String) { + val a = 7 + println("Hello world, $string!") +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt new file mode 100644 index 00000000000..4386803e7a7 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt @@ -0,0 +1,11 @@ +// IGNORE_FIR + +import kotlin.contracts.InvocationKind + +inline fun foo(block: () -> Unit) { + kotlin.contracts.contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + + block() +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt new file mode 100644 index 00000000000..71da7975268 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt @@ -0,0 +1,5 @@ +// IGNORE_FIR + +fun foo(string: String) { + string.length +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt new file mode 100644 index 00000000000..2d9879e4b29 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt @@ -0,0 +1,4 @@ +fun foo(string: String) { + println() + string.length +} diff --git a/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration/simpleProperty.kt b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration/simpleProperty.kt new file mode 100644 index 00000000000..338606be592 --- /dev/null +++ b/analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration/simpleProperty.kt @@ -0,0 +1 @@ +val property: Int = 5 diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractDeclarationModificationServicePsiResilienceTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractDeclarationModificationServicePsiResilienceTest.kt new file mode 100644 index 00000000000..60b3d2c18ac --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractDeclarationModificationServicePsiResilienceTest.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiModifiablePsiSingleFileTest +import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.test.services.TestModuleStructure +import org.jetbrains.kotlin.test.services.TestServices +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +/** + * In the IDE, [LLFirDeclarationModificationService] might be called with PSI elements received via PSI tree change events. Because such + * elements may currently be in the process of modification, they may be inconsistent. This test ensures that the declaration modification + * service can handle such inconsistent PSI, without throwing exceptions. + */ +abstract class AbstractDeclarationModificationServicePsiResilienceTest : AbstractLowLevelApiModifiablePsiSingleFileTest() { + protected abstract fun modifySelectedElement(element: PsiElement) + + override fun doTestWithPsiModification(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) { + val selectedElement = testServices.expressionMarkerProvider.getSelectedElement(ktFile) + modifySelectedElement(selectedElement) + + // The test passes when `LLFirDeclarationModificationService` throws no exceptions. + LLFirDeclarationModificationService.getInstance(ktFile.project).elementModified(selectedElement) + } +} + +@OptIn(ExperimentalContracts::class) +private inline fun assertSelectedElementType(selectedElement: PsiElement) { + contract { returns() implies (selectedElement is E) } + if (selectedElement !is E) { + error("Expected the selected element to be a ${E::class.simpleName}. Selected element: $selectedElement") + } +} + +abstract class AbstractDeclarationModificationServiceCallExpressionCalleeResilienceTest : + AbstractDeclarationModificationServicePsiResilienceTest() { + override fun modifySelectedElement(element: PsiElement) { + assertSelectedElementType(element) + + val calleeExpression = element.calleeExpression + require(calleeExpression != null) { + "A consistent call expression should have a callee expression. Expression: $this" + } + calleeExpression.delete() + } +} + +abstract class AbstractDeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTest : + AbstractDeclarationModificationServicePsiResilienceTest() { + override fun modifySelectedElement(element: PsiElement) { + assertSelectedElementType(element) + element.checkConsistency() + + element.firstChild.delete() + } +} + +abstract class AbstractDeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTest : + AbstractDeclarationModificationServicePsiResilienceTest() { + override fun modifySelectedElement(element: PsiElement) { + assertSelectedElementType(element) + element.checkConsistency() + + element.firstChild.delete() + element.operationTokenNode.psi.delete() + } +} + +private fun KtDotQualifiedExpression.checkConsistency() { + require(children.size == 2) { + "A consistent dot-qualified expression should have two children. Expression: $this" + } +} + +abstract class AbstractDeclarationModificationServicePropertyDeclarationInitializerResilienceTest : + AbstractDeclarationModificationServicePsiResilienceTest() { + override fun modifySelectedElement(element: PsiElement) { + assertSelectedElementType(element) + + val initializer = element.initializer + require(initializer != null) { + "The property declaration is expected to have an initializer. Property declaration: $this" + } + initializer.delete() + } +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceCallExpressionCalleeResilienceTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceCallExpressionCalleeResilienceTestGenerated.java new file mode 100644 index 00000000000..2f121443baf --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceCallExpressionCalleeResilienceTestGenerated.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression") +@TestDataPath("$PROJECT_ROOT") +public class DeclarationModificationServiceCallExpressionCalleeResilienceTestGenerated extends AbstractDeclarationModificationServiceCallExpressionCalleeResilienceTest { + @Test + public void testAllFilesPresentInCallExpression() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression"), Pattern.compile("^([^.]+)\\.kt$"), null, false); + } + + @Test + @TestMetadata("contractCall.kt") + public void testContractCall() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/contractCall.kt"); + } + + @Test + @TestMetadata("printlnFirstStatement.kt") + public void testPrintlnFirstStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnFirstStatement.kt"); + } + + @Test + @TestMetadata("printlnSecondStatement.kt") + public void testPrintlnSecondStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/callExpression/printlnSecondStatement.kt"); + } +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTestGenerated.java new file mode 100644 index 00000000000..3394f1c157c --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTestGenerated.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression") +@TestDataPath("$PROJECT_ROOT") +public class DeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTestGenerated extends AbstractDeclarationModificationServiceDotQualifiedExpressionReceiverResilienceTest { + @Test + public void testAllFilesPresentInDotQualifiedExpression() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression"), Pattern.compile("^([^.]+)\\.kt$"), null, false); + } + + @Test + @TestMetadata("contractCall.kt") + public void testContractCall() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt"); + } + + @Test + @TestMetadata("stringLengthFirstStatement.kt") + public void testStringLengthFirstStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt"); + } + + @Test + @TestMetadata("stringLengthSecondStatement.kt") + public void testStringLengthSecondStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt"); + } +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTestGenerated.java new file mode 100644 index 00000000000..e5ba03b3fe5 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTestGenerated.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression") +@TestDataPath("$PROJECT_ROOT") +public class DeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTestGenerated extends AbstractDeclarationModificationServiceDotQualifiedExpressionSelectorResilienceTest { + @Test + public void testAllFilesPresentInDotQualifiedExpression() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression"), Pattern.compile("^([^.]+)\\.kt$"), null, false); + } + + @Test + @TestMetadata("contractCall.kt") + public void testContractCall() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/contractCall.kt"); + } + + @Test + @TestMetadata("stringLengthFirstStatement.kt") + public void testStringLengthFirstStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthFirstStatement.kt"); + } + + @Test + @TestMetadata("stringLengthSecondStatement.kt") + public void testStringLengthSecondStatement() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/dotQualifiedExpression/stringLengthSecondStatement.kt"); + } +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServicePropertyDeclarationInitializerResilienceTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServicePropertyDeclarationInitializerResilienceTestGenerated.java new file mode 100644 index 00000000000..2d675d86d74 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/DeclarationModificationServicePropertyDeclarationInitializerResilienceTestGenerated.java @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration") +@TestDataPath("$PROJECT_ROOT") +public class DeclarationModificationServicePropertyDeclarationInitializerResilienceTestGenerated extends AbstractDeclarationModificationServicePropertyDeclarationInitializerResilienceTest { + @Test + public void testAllFilesPresentInPropertyDeclaration() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration"), Pattern.compile("^([^.]+)\\.kt$"), null, false); + } + + @Test + @TestMetadata("simpleProperty.kt") + public void testSimpleProperty() throws Exception { + runTest("analysis/low-level-api-fir/testData/declarationModificationService/psiResilience/propertyDeclaration/simpleProperty.kt"); + } +} diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt index 50cf80850a6..401f7d82e11 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt @@ -82,6 +82,38 @@ internal fun TestGroupSuite.generateFirLowLevelApiTests() { model("inBlockModification/codeFragments", recursive = false, pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME) } + testClass { + model( + "declarationModificationService/psiResilience/callExpression", + recursive = false, + pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME, + ) + } + + testClass { + model( + "declarationModificationService/psiResilience/dotQualifiedExpression", + recursive = false, + pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME, + ) + } + + testClass { + model( + "declarationModificationService/psiResilience/dotQualifiedExpression", + recursive = false, + pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME, + ) + } + + testClass { + model( + "declarationModificationService/psiResilience/propertyDeclaration", + recursive = false, + pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME, + ) + } + testClass { model("fileStructure", pattern = TestGeneratorUtil.KT) }