From 196b484cd7f29a595cd7dbe05108ea2621fb9811 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Sun, 21 Feb 2016 00:01:27 +0300 Subject: [PATCH] [RESTORED] Spring Support: Inspection for final Spring-annotated classes/functions #KT-11098 Fixed --- ChangeLog.md | 1 + .../kotlin/generators/tests/GenerateTests.kt | 6 ++ idea/idea-ultimate/idea-ultimate.iml | 1 + .../KotlinFinalClassOrFunSpring.html | 5 + .../src/META-INF/kotlin-spring.xml | 8 +- .../KotlinFinalClassOrFunSpringInspection.kt | 92 ++++++++++++++++++ .../kotlin/idea/spring/springUtils.kt | 30 ++++++ .../UltimateInspectionTestGenerated.java | 43 ++++++++ .../UltimateQuickFixTestGenerated.java | 97 +++++++++++++++++++ .../tests/SpringTestFixtureExtension.kt | 9 +- .../inspectionData/expected.xml | 74 ++++++++++++++ .../inspectionData/inspections.test | 2 + .../finalSpringAnnotatedDeclaration/test.kt | 65 +++++++++++++ .../.inspection | 1 + .../classWithComponentRuntime.kt | 7 ++ .../classWithComponentRuntime.kt.after | 7 ++ .../classWithConfigurationRuntime.kt | 7 ++ .../classWithConfigurationRuntime.kt.after | 7 ++ .../classWithCustomConfigurationRuntime.kt | 10 ++ ...assWithCustomConfigurationRuntime.kt.after | 10 ++ .../funWithBeanFinalClassRuntime.kt | 9 ++ .../funWithBeanFinalClassRuntime.kt.after | 9 ++ .../funWithBeanOpenClassRuntime.kt | 9 ++ .../funWithBeanOpenClassRuntime.kt.after | 9 ++ .../funWithCustomBeanFinalClassRuntime.kt | 12 +++ ...unWithCustomBeanFinalClassRuntime.kt.after | 12 +++ .../funWithCustomBeanOpenClassRuntime.kt | 12 +++ ...funWithCustomBeanOpenClassRuntime.kt.after | 12 +++ .../codeInsight/AbstractInspectionTest.kt | 16 +-- .../idea/quickfix/AbstractQuickFixTest.java | 12 +++ 30 files changed, 582 insertions(+), 12 deletions(-) create mode 100644 idea/idea-ultimate/resources/inspectionDescriptions/KotlinFinalClassOrFunSpring.html create mode 100644 idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/inspections/KotlinFinalClassOrFunSpringInspection.kt create mode 100644 idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/springUtils.kt create mode 100644 idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/codeInsight/UltimateInspectionTestGenerated.java create mode 100644 idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/quickfix/UltimateQuickFixTestGenerated.java create mode 100644 idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/expected.xml create mode 100644 idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test create mode 100644 idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/test.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/.inspection create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt.after create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt create mode 100644 idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt.after diff --git a/ChangeLog.md b/ChangeLog.md index fbee7d64bfe..1283bc28291 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -124,6 +124,7 @@ New features: - [KT-11404](https://youtrack.jetbrains.com/issue/KT-11404) Quick fix to let type implement missing interface - [KT-6785](https://youtrack.jetbrains.com/issue/KT-6785), [KT-10013](https://youtrack.jetbrains.com/issue/KT-10013), [KT-9996](https://youtrack.jetbrains.com/issue/KT-9996), [KT-11675](https://youtrack.jetbrains.com/issue/KT-11675) Support Smart Enter for trailing lambda argument, try/catch/finally, property setter, init block - Add `kotlinClassName()` and `kotlinFunctionName()` macros for use in live templates +- [KT-11098](https://youtrack.jetbrains.com/issue/KT-11098) Inspection on final classes/functions annotated with Spring @Configuration/@Component/@Bean Issues fixed: diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 61f11003fc2..3d781a33373 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -792,7 +792,13 @@ fun main(args: Array) { } testGroup("idea/idea-ultimate/tests", "idea/testData") { + testClass("UltimateInspectionTestGenerated") { + model("ultimateInspections", pattern = "^(inspections\\.test)$", singleClass = true) + } + testClass("UltimateQuickFixTestGenerated") { + model("ultimateQuickFixes", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true) + } } testGroup("idea/tests", "compiler/testData") { diff --git a/idea/idea-ultimate/idea-ultimate.iml b/idea/idea-ultimate/idea-ultimate.iml index 1239656565e..9626bf90871 100644 --- a/idea/idea-ultimate/idea-ultimate.iml +++ b/idea/idea-ultimate/idea-ultimate.iml @@ -5,6 +5,7 @@ + diff --git a/idea/idea-ultimate/resources/inspectionDescriptions/KotlinFinalClassOrFunSpring.html b/idea/idea-ultimate/resources/inspectionDescriptions/KotlinFinalClassOrFunSpring.html new file mode 100644 index 00000000000..78265005eb0 --- /dev/null +++ b/idea/idea-ultimate/resources/inspectionDescriptions/KotlinFinalClassOrFunSpring.html @@ -0,0 +1,5 @@ + + +This inspection reports final Kotlin classes and functions annotated with Spring @Component, @Configuration or @Bean annotations + + diff --git a/idea/idea-ultimate/src/META-INF/kotlin-spring.xml b/idea/idea-ultimate/src/META-INF/kotlin-spring.xml index 42836638cd3..8999970dab2 100644 --- a/idea/idea-ultimate/src/META-INF/kotlin-spring.xml +++ b/idea/idea-ultimate/src/META-INF/kotlin-spring.xml @@ -1,5 +1,11 @@ - + \ No newline at end of file diff --git a/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/inspections/KotlinFinalClassOrFunSpringInspection.kt b/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/inspections/KotlinFinalClassOrFunSpringInspection.kt new file mode 100644 index 00000000000..e2778817373 --- /dev/null +++ b/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/inspections/KotlinFinalClassOrFunSpringInspection.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.spring.inspections + +import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation +import com.intellij.codeInspection.LocalQuickFix +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import com.intellij.psi.ElementDescriptionUtil +import com.intellij.psi.PsiElementVisitor +import com.intellij.spring.constants.SpringAnnotationsConstants +import com.intellij.spring.model.jam.stereotype.SpringComponent +import com.intellij.spring.model.jam.stereotype.SpringConfiguration +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.asJava.toLightMethods +import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection +import org.jetbrains.kotlin.idea.spring.isAnnotatedWith +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.isInheritable +import org.jetbrains.kotlin.psi.psiUtil.isOverridable + +class KotlinFinalClassOrFunSpringInspection : AbstractKotlinInspection() { + class QuickFix(private val element: T) : LocalQuickFix { + override fun getName(): String { + return "Make ${ElementDescriptionUtil.getElementDescription(element, HighlightUsagesDescriptionLocation.INSTANCE)} open" + } + + override fun getFamilyName() = "Make declaration open" + + override fun applyFix(project: Project, problemDescriptor: ProblemDescriptor) { + (element as? KtNamedDeclaration)?.containingClassOrObject?.addModifier(KtTokens.OPEN_KEYWORD) + element.addModifier(KtTokens.OPEN_KEYWORD) + } + } + + private fun getMessage(declaration: KtNamedDeclaration): String? { + when (declaration) { + is KtClass -> { + val lightClass = declaration.toLightClass() ?: return null + when { + SpringConfiguration.META.getJamElement(lightClass) != null -> return "@Configuration class should be declared open" + SpringComponent.META.getJamElement(lightClass) != null -> return "@Component class should be declared open" + } + } + + is KtNamedFunction -> { + val lightMethod = declaration.toLightMethods().firstOrNull() ?: return null + if (lightMethod.isAnnotatedWith(SpringAnnotationsConstants.JAVA_SPRING_BEAN)) return "@Bean function should be declared open" + } + } + return null + } + + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object: KtVisitorVoid() { + override fun visitNamedDeclaration(declaration: KtNamedDeclaration) { + when (declaration) { + is KtClass -> if (declaration.isInheritable()) return + is KtNamedFunction -> if (declaration.isOverridable()) return + else -> return + } + + val message = getMessage(declaration) ?: return + + holder.registerProblem( + declaration.nameIdentifier ?: declaration, + message, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + QuickFix(declaration) + ) + } + } + } +} \ No newline at end of file diff --git a/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/springUtils.kt b/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/springUtils.kt new file mode 100644 index 00000000000..3596a30bdc6 --- /dev/null +++ b/idea/idea-ultimate/src/org/jetbrains/kotlin/idea/spring/springUtils.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.spring + +import com.intellij.codeInsight.AnnotationUtil +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.psi.PsiModifierListOwner +import com.intellij.spring.model.jam.utils.JamAnnotationTypeUtil + +internal fun PsiModifierListOwner.isAnnotatedWith(annotationFqName: String): Boolean { + val module = ModuleUtilCore.findModuleForPsiElement(this) ?: return false + return JamAnnotationTypeUtil.getInstance(module) + .getAnnotationTypesWithChildren(annotationFqName) + .mapNotNull { it.qualifiedName } + .any { AnnotationUtil.isAnnotated(this, it, true) } +} diff --git a/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/codeInsight/UltimateInspectionTestGenerated.java b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/codeInsight/UltimateInspectionTestGenerated.java new file mode 100644 index 00000000000..0f3f21ecd0b --- /dev/null +++ b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/codeInsight/UltimateInspectionTestGenerated.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.codeInsight; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/ultimateInspections") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class UltimateInspectionTestGenerated extends AbstractInspectionTest { + public void testAllFilesPresentInUltimateInspections() throws Exception { + KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/ultimateInspections"), Pattern.compile("^(inspections\\.test)$")); + } + + @TestMetadata("spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test") + public void testSpring_finalSpringAnnotatedDeclaration_inspectionData_Inspections_test() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test"); + doTest(fileName); + } +} diff --git a/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/quickfix/UltimateQuickFixTestGenerated.java b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/quickfix/UltimateQuickFixTestGenerated.java new file mode 100644 index 00000000000..bd81441132e --- /dev/null +++ b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/quickfix/UltimateQuickFixTestGenerated.java @@ -0,0 +1,97 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.quickfix; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/ultimateQuickFixes") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class UltimateQuickFixTestGenerated extends AbstractQuickFixTest { + public void testAllFilesPresentInUltimateQuickFixes() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/ultimateQuickFixes"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("idea/testData/ultimateQuickFixes/spring") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Spring extends AbstractQuickFixTest { + public void testAllFilesPresentInSpring() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/ultimateQuickFixes/spring"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class FinalSpringAnnotatedDeclaration extends AbstractQuickFixTest { + public void testAllFilesPresentInFinalSpringAnnotatedDeclaration() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("classWithComponentRuntime.kt") + public void testClassWithComponentRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("classWithConfigurationRuntime.kt") + public void testClassWithConfigurationRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("classWithCustomConfigurationRuntime.kt") + public void testClassWithCustomConfigurationRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("funWithBeanFinalClassRuntime.kt") + public void testFunWithBeanFinalClassRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("funWithBeanOpenClassRuntime.kt") + public void testFunWithBeanOpenClassRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("funWithCustomBeanFinalClassRuntime.kt") + public void testFunWithCustomBeanFinalClassRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("funWithCustomBeanOpenClassRuntime.kt") + public void testFunWithCustomBeanOpenClassRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt"); + doTest(fileName); + } + } + } +} diff --git a/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/SpringTestFixtureExtension.kt b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/SpringTestFixtureExtension.kt index 80e0db4799f..97aed6f6d15 100644 --- a/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/SpringTestFixtureExtension.kt +++ b/idea/idea-ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/SpringTestFixtureExtension.kt @@ -53,9 +53,12 @@ class SpringTestFixtureExtension() : TestFixtureExtension { override fun tearDown() { try { // clear existing SpringFacet configuration before running next test - module?.let { SpringFacet.getInstance(it) }?.let { - it.removeFileSets() - FacetUtil.deleteFacet(it) + module?.let { module -> + SpringFacet.getInstance(module)?.let { facet -> + facet.removeFileSets() + FacetUtil.deleteFacet(facet) + } + ConfigLibraryUtil.removeLibrary(module, "spring" + SpringFramework.FRAMEWORK_4_2_0.version) } } finally { diff --git a/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/expected.xml b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/expected.xml new file mode 100644 index 00000000000..b8aa7b0bd5b --- /dev/null +++ b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/expected.xml @@ -0,0 +1,74 @@ + + + test.kt + 18 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Configuration class should be declared open + + + test.kt + 21 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Configuration class should be declared open + + + test.kt + 32 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Component class should be declared open + + + test.kt + 41 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + + test.kt + 44 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + + test.kt + 47 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + + test.kt + 50 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + + test.kt + 55 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + + test.kt + 58 + light_idea_test_case + + Final Kotlin class or function with Spring annotation + @Bean function should be declared open + + diff --git a/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test new file mode 100644 index 00000000000..f9437be0350 --- /dev/null +++ b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test @@ -0,0 +1,2 @@ +// INSPECTION_CLASS: org.jetbrains.kotlin.idea.spring.inspections.KotlinFinalClassOrFunSpringInspection +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension \ No newline at end of file diff --git a/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/test.kt b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/test.kt new file mode 100644 index 00000000000..c2d12b07e27 --- /dev/null +++ b/idea/testData/ultimateInspections/spring/finalSpringAnnotatedDeclaration/test.kt @@ -0,0 +1,65 @@ + +// WITH_RUNTIME + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration +import org.springframework.stereotype.Component + +@Configuration +annotation class MyConfiguration + +@Bean +annotation class MyBean + +// @Configuration + +@Configuration +class Application1 + +@MyConfiguration +class Application2 + +@Configuration +open class Application3 + +@MyConfiguration +open class Application4 + +// @Component + +@Component +class Component1 + +@Component +open class Component2 + +// @Bean + +class Utils1 { + @Bean + fun foo1() = Component1() + + @MyBean + fun foo2() = Component2() + + @Bean + open fun foo3() = Component3() + + @MyBean + open fun foo4() = Component4() +} + +open class Utils2 { + @Bean + fun foo1() = Component1() + + @MyBean + fun foo2() = Component2() + + @Bean + open fun foo3() = Component3() + + @MyBean + open fun foo4() = Component4() +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/.inspection b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/.inspection new file mode 100644 index 00000000000..4e681838d1b --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.spring.inspections.KotlinFinalClassOrFunSpringInspection \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt new file mode 100644 index 00000000000..bd1f35511a7 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt @@ -0,0 +1,7 @@ +// "Make class Bean open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.stereotype.Component + +@Component +class Bean \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt.after new file mode 100644 index 00000000000..cd8c986adac --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt.after @@ -0,0 +1,7 @@ +// "Make class Bean open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.stereotype.Component + +@Component +open class Bean \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt new file mode 100644 index 00000000000..2207fdfa6cb --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt @@ -0,0 +1,7 @@ +// "Make class Application open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Configuration + +@Configuration +class Application \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt.after new file mode 100644 index 00000000000..57b7e3216f8 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt.after @@ -0,0 +1,7 @@ +// "Make class Application open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Configuration + +@Configuration +open class Application \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt new file mode 100644 index 00000000000..b162e021593 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt @@ -0,0 +1,10 @@ +// "Make class Application open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Configuration + +@Configuration +annotation class MyConfiguration + +@MyConfiguration +class Application \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt.after new file mode 100644 index 00000000000..67167424348 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt.after @@ -0,0 +1,10 @@ +// "Make class Application open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Configuration + +@Configuration +annotation class MyConfiguration + +@MyConfiguration +open class Application \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt new file mode 100644 index 00000000000..61ac1ddd46b --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt @@ -0,0 +1,9 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +class Foo { + @Bean + fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt.after new file mode 100644 index 00000000000..4dcbfeef188 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt.after @@ -0,0 +1,9 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +open class Foo { + @Bean + open fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt new file mode 100644 index 00000000000..b5bd87e370b --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt @@ -0,0 +1,9 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +open class Foo { + @Bean + fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt.after new file mode 100644 index 00000000000..4dcbfeef188 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt.after @@ -0,0 +1,9 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +open class Foo { + @Bean + open fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt new file mode 100644 index 00000000000..4f88a0b5a16 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt @@ -0,0 +1,12 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +@Bean +annotation class MyBean + +class Foo { + @MyBean + fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt.after new file mode 100644 index 00000000000..777c72f8120 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt.after @@ -0,0 +1,12 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +@Bean +annotation class MyBean + +open class Foo { + @MyBean + open fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt new file mode 100644 index 00000000000..d12f89144e2 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt @@ -0,0 +1,12 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +@Bean +annotation class MyBean + +open class Foo { + @MyBean + fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt.after b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt.after new file mode 100644 index 00000000000..777c72f8120 --- /dev/null +++ b/idea/testData/ultimateQuickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt.after @@ -0,0 +1,12 @@ +// "Make function foo open" "true" +// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension +// DISABLE-ERRORS +import org.springframework.context.annotation.Bean + +@Bean +annotation class MyBean + +open class Foo { + @MyBean + open fun foo() = "" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt index e99d625c39e..8445928af99 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt @@ -24,21 +24,15 @@ import com.intellij.codeInspection.ex.InspectionManagerEx import com.intellij.codeInspection.ex.LocalInspectionToolWrapper import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.util.io.FileUtil -import com.intellij.psi.PsiFile import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.InspectionTestUtil import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl -import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil -import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor -import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.idea.test.* import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File -import kotlin.test.assertFalse -import java.util.* abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() { companion object { @@ -64,6 +58,8 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() val inspectionClass = Class.forName(InTextDirectivesUtils.findStringWithPrefixes(options, "// INSPECTION_CLASS: ")!!) val toolWrapper = LocalInspectionToolWrapper(inspectionClass.newInstance() as LocalInspectionTool) + val fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(options, "// FIXTURE_CLASS: ") + val inspectionsTestDir = optionsFile.parentFile!! val srcDir = inspectionsTestDir.parentFile!! @@ -74,7 +70,7 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() val psiFiles = srcDir.walkTopDown().onEnter { it.name != "inspectionData" }.mapNotNull { file -> if (file.isDirectory) { - null + null } else if (file.extension != "kt") { val filePath = file.relativeTo(srcDir).invariantSeparatorsPath @@ -112,6 +108,8 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() ) } + fixtureClasses.forEach { TestFixtureExtension.loadFixture(it, myFixture.module) } + val scope = AnalysisScope(project, psiFiles.map { it.virtualFile!! }) scope.invalidate() @@ -139,6 +137,8 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() } finally { + fixtureClasses.forEach { TestFixtureExtension.unloadFixture(it) } + if (isWithRuntime) { ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(myFixture.module, IdeaTestUtil.getMockJdk17()) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.java index 25187c4b4d5..ccab3d7560c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.java @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.idea.quickfix.utils.QuickfixTestUtilsKt; import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil; import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; +import org.jetbrains.kotlin.idea.test.TestFixtureExtension; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.KotlinTestUtils; @@ -57,6 +58,7 @@ import org.junit.Assert; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -132,8 +134,15 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase { public void run() { String fileText = ""; String expectedErrorMessage = ""; + List fixtureClasses = Collections.emptyList(); try { fileText = FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET); + + fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(fileText, "// FIXTURE_CLASS: "); + for (String fixtureClass : fixtureClasses) { + TestFixtureExtension.Companion.loadFixture(fixtureClass, getModule()); + } + expectedErrorMessage = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// SHOULD_FAIL_WITH: "); String contents = StringUtil.convertLineSeparators(fileText); quickFixTestCase.configureFromFileText(testFile.getName(), contents); @@ -157,6 +166,9 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase { fail(testName); } } finally { + for (String fixtureClass : fixtureClasses) { + TestFixtureExtension.Companion.unloadFixture(fixtureClass); + } ConfigLibraryUtil.unconfigureLibrariesByDirective(getModule(), fileText); } }