diff --git a/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java b/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java index f4a62a6fb..cff9db20b 100644 --- a/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java +++ b/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java @@ -132,6 +132,7 @@ public boolean enterPythonClass(@NotNull AnnotatedPythonClass pythonClass) { new ArrayList<>(pythonClass.getDecorators()), new ArrayList<>(pythonClass.getSuperclasses()), new ArrayList<>(), + new ArrayList<>(), pythonClass.getDescription(), pythonClass.getFullDocstring(), annotations, diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.kt b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.kt index 4ed48ddb0..51889c1df 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.kt @@ -52,6 +52,16 @@ class RenameAnnotationProcessor : AbstractPackageDataTransformer() { return super.createNewClassOnLeave(oldClass, newAttributes, newMethods) } + override fun createNewAttribute(oldAttribute: AnnotatedPythonAttribute): AnnotatedPythonAttribute { + return oldAttribute.rename { newName -> + oldAttribute.fullCopy( + name = newName, + qualifiedName = qualifiedName(newName), + originalDeclaration = oldAttribute.originalDeclaration ?: oldAttribute + ) + } + } + override fun createNewFunctionOnEnter(oldFunction: AnnotatedPythonFunction): AnnotatedPythonFunction { val result = oldFunction.rename { newName -> oldFunction.fullCopy( @@ -88,10 +98,11 @@ class RenameAnnotationProcessor : AbstractPackageDataTransformer() { private fun T.rename(creator: (String) -> T): T { val renameAnnotations = this.annotations.filterIsInstance() - return when { - renameAnnotations.isEmpty() -> this - else -> creator(renameAnnotations[0].newName) + val newName = when { + renameAnnotations.isEmpty() -> this.name + else -> renameAnnotations[0].newName } + return creator(newName) } private fun qualifiedName(vararg additionalSegments: String): String { diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt b/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt index b91c0c7fd..5b75773ca 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt @@ -1,5 +1,6 @@ package com.larsreimann.api_editor.util +import com.larsreimann.api_editor.model.AnnotatedPythonAttribute import com.larsreimann.api_editor.model.AnnotatedPythonClass import com.larsreimann.api_editor.model.AnnotatedPythonFunction import com.larsreimann.api_editor.model.AnnotatedPythonModule @@ -55,6 +56,7 @@ fun createPythonClass( qualifiedName: String = name, decorators: List = emptyList(), superclasses: List = emptyList(), + attributes: List = mutableListOf(), methods: List = mutableListOf(), description: String = "", fullDocstring: String = "", @@ -71,10 +73,35 @@ fun createPythonClass( fullDocstring, annotations ) + newPythonClass.attributes += attributes newPythonClass.originalDeclaration = originalDeclaration return newPythonClass } +@JvmOverloads +fun createPythonAttribute( + name: String, + qualifiedName: String = name, + defaultValue: String = "", + isPublic: Boolean = true, + typeInDocs: String = "", + description: String = "", + annotations: MutableList = mutableListOf(), + originalDeclaration: AnnotatedPythonAttribute? = null, +): AnnotatedPythonAttribute { + val result = AnnotatedPythonAttribute( + name, + qualifiedName, + defaultValue, + isPublic, + typeInDocs, + description, + annotations + ) + result.originalDeclaration = originalDeclaration + return result +} + @JvmOverloads fun createPythonFunction( name: String, diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.kt index 4418ef69a..b95f769c1 100644 --- a/server/src/test/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.kt +++ b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.kt @@ -6,6 +6,7 @@ import com.larsreimann.api_editor.model.AnnotatedPythonFunction import com.larsreimann.api_editor.model.AnnotatedPythonPackage import com.larsreimann.api_editor.model.AnnotatedPythonParameter import com.larsreimann.api_editor.model.RenameAnnotation +import com.larsreimann.api_editor.util.createPythonAttribute import com.larsreimann.api_editor.util.createPythonClass import com.larsreimann.api_editor.util.createPythonFunction import com.larsreimann.api_editor.util.createPythonModule @@ -33,6 +34,12 @@ internal class RenameAnnotationProcessorTest { createPythonClass( name = "testClass", qualifiedName = "testModule.testClass", + attributes = listOf( + createPythonAttribute( + name = "testAttribute", + qualifiedName = "testModule.testClass.testAttribute" + ) + ), methods = listOf( createPythonFunction( name = "testMethod", @@ -54,7 +61,7 @@ internal class RenameAnnotationProcessorTest { parameters = listOf( createPythonParameter( name = "testParameter", - qualifiedName = "testModule.testClass.testMethod.testParameter", + qualifiedName = "testModule.testFunction.testParameter", ) ) ) @@ -83,6 +90,26 @@ internal class RenameAnnotationProcessorTest { qualifiedName shouldBe "testModule.renamedTestClass" } + @Test + fun `should rename method`() { + // given + val testMethod = testPackage.findUniqueDescendantOrFail("testMethod") + testMethod.annotations += RenameAnnotation("renamedTestMethod") + + // when + val modifiedPackage = testPackage.accept(RenameAnnotationProcessor()) + + // then + modifiedPackage.shouldNotBeNull() + modifiedPackage.modules.shouldHaveSize(1) + modifiedPackage.modules[0].classes.shouldHaveSize(1) + modifiedPackage.modules[0].classes[0].methods.shouldHaveSize(1) + + val (name, qualifiedName) = modifiedPackage.modules[0].classes[0].methods[0] + name shouldBe "renamedTestMethod" + qualifiedName shouldBe "testModule.testClass.renamedTestMethod" + } + @Test fun `should rename global function`() { // given @@ -103,10 +130,11 @@ internal class RenameAnnotationProcessorTest { } @Test - fun `should rename method`() { + fun `should rename parameter`() { // given val testMethod = testPackage.findUniqueDescendantOrFail("testMethod") - testMethod.annotations += RenameAnnotation("renamedTestMethod") + val testParameter = testMethod.findUniqueDescendantOrFail("testParameter") + testParameter.annotations += RenameAnnotation("renamedTestParameter") // when val modifiedPackage = testPackage.accept(RenameAnnotationProcessor()) @@ -116,21 +144,19 @@ internal class RenameAnnotationProcessorTest { modifiedPackage.modules.shouldHaveSize(1) modifiedPackage.modules[0].classes.shouldHaveSize(1) modifiedPackage.modules[0].classes[0].methods.shouldHaveSize(1) + modifiedPackage.modules[0].classes[0].methods[0].parameters.shouldHaveSize(1) - val (name, qualifiedName) = modifiedPackage.modules[0].classes[0].methods[0] - name shouldBe "renamedTestMethod" - qualifiedName shouldBe "testModule.testClass.renamedTestMethod" + val (parameterName, parameterQualifiedName) = modifiedPackage.modules[0].classes[0].methods[0].parameters[0] + parameterName shouldBe "renamedTestParameter" + parameterQualifiedName shouldBe "testModule.testClass.testMethod.renamedTestParameter" } @Test - fun `should rename class and its method`() { + fun `should change qualified names of descendants when renaming class`() { // given val testClass = testPackage.findUniqueDescendantOrFail("testClass") testClass.annotations += RenameAnnotation("renamedTestClass") - val testMethod = testClass.findUniqueDescendantOrFail("testMethod") - testMethod.annotations += RenameAnnotation("renamedTestMethod") - // when val modifiedPackage = testPackage.accept(RenameAnnotationProcessor()) @@ -138,29 +164,33 @@ internal class RenameAnnotationProcessorTest { modifiedPackage.shouldNotBeNull() modifiedPackage.modules.shouldHaveSize(1) modifiedPackage.modules[0].classes.shouldHaveSize(1) + modifiedPackage.modules[0].classes[0].attributes.shouldHaveSize(1) modifiedPackage.modules[0].classes[0].methods.shouldHaveSize(1) + modifiedPackage.modules[0].classes[0].methods[0].parameters.shouldHaveSize(1) val (className, classQualifiedName) = modifiedPackage.modules[0].classes[0] className shouldBe "renamedTestClass" classQualifiedName shouldBe "testModule.renamedTestClass" + val (attributeName, attributeQualifiedName) = modifiedPackage.modules[0].classes[0].attributes[0] + attributeName shouldBe "testAttribute" + attributeQualifiedName shouldBe "testModule.renamedTestClass.testAttribute" + val (methodName, methodQualifiedName) = modifiedPackage.modules[0].classes[0].methods[0] - methodName shouldBe "renamedTestMethod" - methodQualifiedName shouldBe "testModule.renamedTestClass.renamedTestMethod" + methodName shouldBe "testMethod" + methodQualifiedName shouldBe "testModule.renamedTestClass.testMethod" + + val (parameterName, parameterQualifiedName) = modifiedPackage.modules[0].classes[0].methods[0].parameters[0] + parameterName shouldBe "testParameter" + parameterQualifiedName shouldBe "testModule.renamedTestClass.testMethod.testParameter" } @Test - fun `should rename class, method, and parameter`() { + fun `should change qualified names of descendants when renaming method`() { // given - val testClass = testPackage.findUniqueDescendantOrFail("testClass") - testClass.annotations += RenameAnnotation("renamedTestClass") - - val testMethod = testClass.findUniqueDescendantOrFail("testMethod") + val testMethod = testPackage.findUniqueDescendantOrFail("testMethod") testMethod.annotations += RenameAnnotation("renamedTestMethod") - val testParameter = testMethod.findUniqueDescendantOrFail("testParameter") - testParameter.annotations += RenameAnnotation("renamedTestParameter") - // when val modifiedPackage = testPackage.accept(RenameAnnotationProcessor()) @@ -171,28 +201,21 @@ internal class RenameAnnotationProcessorTest { modifiedPackage.modules[0].classes[0].methods.shouldHaveSize(1) modifiedPackage.modules[0].classes[0].methods[0].parameters.shouldHaveSize(1) - val (className, classQualifiedName) = modifiedPackage.modules[0].classes[0] - className shouldBe "renamedTestClass" - classQualifiedName shouldBe "testModule.renamedTestClass" - val (methodName, methodQualifiedName) = modifiedPackage.modules[0].classes[0].methods[0] methodName shouldBe "renamedTestMethod" - methodQualifiedName shouldBe "testModule.renamedTestClass.renamedTestMethod" + methodQualifiedName shouldBe "testModule.testClass.renamedTestMethod" val (parameterName, parameterQualifiedName) = modifiedPackage.modules[0].classes[0].methods[0].parameters[0] - parameterName shouldBe "renamedTestParameter" - parameterQualifiedName shouldBe "testModule.renamedTestClass.renamedTestMethod.renamedTestParameter" + parameterName shouldBe "testParameter" + parameterQualifiedName shouldBe "testModule.testClass.renamedTestMethod.testParameter" } @Test - fun `should rename global function and parameter`() { + fun `should change qualified names of descendants when renaming global function`() { // given val testFunction = testPackage.findUniqueDescendantOrFail("testFunction") testFunction.annotations += RenameAnnotation("renamedTestFunction") - val testParameter = testFunction.findUniqueDescendantOrFail("testParameter") - testParameter.annotations += RenameAnnotation("renamedTestParameter") - // when val modifiedPackage = testPackage.accept(RenameAnnotationProcessor()) @@ -207,8 +230,8 @@ internal class RenameAnnotationProcessorTest { functionQualifiedName shouldBe "testModule.renamedTestFunction" val (parameterName, parameterQualifiedName) = modifiedPackage.modules[0].functions[0].parameters[0] - parameterName shouldBe "renamedTestParameter" - parameterQualifiedName shouldBe "testModule.renamedTestFunction.renamedTestParameter" + parameterName shouldBe "testParameter" + parameterQualifiedName shouldBe "testModule.renamedTestFunction.testParameter" } @Test