From 3daa2ad93cacfa7441f63db9d8d5fba5b06f8e2e Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Thu, 16 Jun 2022 10:06:29 +0200 Subject: [PATCH] inspection for deprecated "controller" targets on route --- .../RouteControllerDeprecatedInspection.java | 75 +++++++++++++++++++ .../routing/RouteXmlReferenceContributor.java | 41 +++++++--- src/main/resources/META-INF/plugin.xml | 6 ++ .../RouteControllerDeprecatedInspection.html | 5 ++ ...uteControllerDeprecatedInspectionTest.java | 61 +++++++++++++++ .../RouteControllerDeprecatedInspection.php | 20 +++++ 6 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteControllerDeprecatedInspection.java create mode 100644 src/main/resources/inspectionDescriptions/RouteControllerDeprecatedInspection.html create mode 100644 src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/RouteControllerDeprecatedInspectionTest.java create mode 100644 src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures/RouteControllerDeprecatedInspection.php diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteControllerDeprecatedInspection.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteControllerDeprecatedInspection.java new file mode 100644 index 000000000..74ed797f5 --- /dev/null +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteControllerDeprecatedInspection.java @@ -0,0 +1,75 @@ +package fr.adrienbrault.idea.symfony2plugin.routing; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.jetbrains.php.lang.psi.elements.PhpClassMember; +import com.jetbrains.php.lang.psi.elements.PhpNamedElement; +import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; +import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper; +import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper; +import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils; +import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; + +/** + * @author Daniel Espendiller + */ +public class RouteControllerDeprecatedInspection extends LocalInspectionTool { + + @NotNull + public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) { + if(!Symfony2ProjectComponent.isEnabled(holder.getProject())) { + return super.buildVisitor(holder, isOnTheFly); + } + + return new PsiElementVisitor() { + @Override + public void visitElement(@NotNull PsiElement element) { + if (XmlHelper.getRouteControllerPattern().accepts(element)) { + PsiElement parent = element.getParent(); + if (parent != null) { + String text = RouteXmlReferenceContributor.getControllerText(parent); + if(text != null) { + extracted(element, text, holder); + } + } + } else if(YamlElementPatternHelper.getSingleLineScalarKey("_controller", "controller").accepts(element)) { + String text = PsiElementUtils.trimQuote(element.getText()); + if (StringUtils.isNotBlank(text)) { + extracted(element, text, holder); + } + } + + super.visitElement(element); + } + }; + } + + private void extracted(@NotNull PsiElement element, String text, @NotNull ProblemsHolder holder) { + for (PsiElement psiElement : RouteHelper.getMethodsOnControllerShortcut(element.getProject(), text)) { + if (!(psiElement instanceof PhpNamedElement)) { + continue; + } + + // action is deprecated + if (((PhpNamedElement) psiElement).isDeprecated()) { + holder.registerProblem(element, "Symfony: Controller action is deprecated", ProblemHighlightType.LIKE_DEPRECATED); + break; + } + + // class is deprecated + if (psiElement instanceof PhpClassMember) { + PhpClass containingClass = ((Method) psiElement).getContainingClass(); + if (containingClass != null && containingClass.isDeprecated()) { + holder.registerProblem(element, "Symfony: Controller action is deprecated", ProblemHighlightType.LIKE_DEPRECATED); + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteXmlReferenceContributor.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteXmlReferenceContributor.java index 17e9df2ff..2ee94f2a5 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteXmlReferenceContributor.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteXmlReferenceContributor.java @@ -10,6 +10,7 @@ import fr.adrienbrault.idea.symfony2plugin.util.controller.ControllerIndex; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Daniel Espendiller @@ -43,20 +44,14 @@ private RouteActionReference(PsiElement psiElement) { @NotNull @Override - public ResolveResult[] multiResolve(boolean b) { - PsiElement element = getElement(); - PsiElement parent = element.getParent(); - - String text = null; - if(parent instanceof XmlText) { - // Foo\Bar - text = parent.getText(); - } else if(parent instanceof XmlAttribute) { - // - text = ((XmlAttribute) parent).getValue(); + public ResolveResult @NotNull [] multiResolve(boolean b) { + PsiElement parent = getElement().getParent(); + if (parent == null) { + return new ResolveResult[0]; } - if(text == null || StringUtils.isBlank(text)) { + String text = getControllerText(parent); + if(text == null) { return new ResolveResult[0]; } @@ -71,4 +66,26 @@ public Object[] getVariants() { return ControllerIndex.getControllerLookupElements(getElement().getProject()).toArray(); } } + + /** + * Foo\Bar + * + */ + @Nullable + public static String getControllerText(@NotNull PsiElement parent) { + String text = null; + if(parent instanceof XmlText) { + // Foo\Bar + text = parent.getText(); + } else if(parent instanceof XmlAttribute) { + // + text = ((XmlAttribute) parent).getValue(); + } + + if (StringUtils.isBlank(text)) { + return null; + } + + return text; + } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 4d4cb8db2..48b537210 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -495,6 +495,12 @@ language="PHP" implementationClass="fr.adrienbrault.idea.symfony2plugin.templating.inspection.TemplateExistsAnnotationPhpAttributeLocalInspection"/> + + fr.adrienbrault.idea.symfony2plugin.intentions.php.PhpServiceIntention PHP diff --git a/src/main/resources/inspectionDescriptions/RouteControllerDeprecatedInspection.html b/src/main/resources/inspectionDescriptions/RouteControllerDeprecatedInspection.html new file mode 100644 index 000000000..c09576e0f --- /dev/null +++ b/src/main/resources/inspectionDescriptions/RouteControllerDeprecatedInspection.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/RouteControllerDeprecatedInspectionTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/RouteControllerDeprecatedInspectionTest.java new file mode 100644 index 000000000..c7c6f7123 --- /dev/null +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/RouteControllerDeprecatedInspectionTest.java @@ -0,0 +1,61 @@ +package fr.adrienbrault.idea.symfony2plugin.tests.routing; + +import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase; + +/** + * @author Daniel Espendiller + * + * @see fr.adrienbrault.idea.symfony2plugin.routing.RouteControllerDeprecatedInspection + */ +public class RouteControllerDeprecatedInspectionTest extends SymfonyLightCodeInsightFixtureTestCase { + + public void setUp() throws Exception { + super.setUp(); + + myFixture.copyFileToProject("RouteControllerDeprecatedInspection.php"); + } + + protected String getTestDataPath() { + return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures"; + } + + public void testDeprecatedRouteActionForYml() { + assertLocalInspectionContains("foobar.yml","" + + "blog_list:\n" + + " controller: App\\Controller\\BarController::foobar", + "Symfony: Controller action is deprecated" + ); + + assertLocalInspectionContains("foobar.yml","" + + "blog_list:\n" + + " defaults: { _controller: App\\Controller\\BarController::foobar }", + "Symfony: Controller action is deprecated" + ); + } + + public void testDeprecatedRouteActionForXml() { + assertLocalInspectionContains("foobar.xml", + "\n" + + " bar\"/>\n" + + "", + "Symfony: Controller action is deprecated" + ); + + assertLocalInspectionContains("foobar.xml", + "\n" + + " \n" + + " App\\Controller\\BarController::foobar\n" + + " \n" + + "", + "Symfony: Controller action is deprecated" + ); + } + + public void testDeprecatedRouteActionForClassMember() { + assertLocalInspectionContains("foobar.yml","" + + "blog_list:\n" + + " controller: App\\Controller\\CarController::foobar", + "Symfony: Controller action is deprecated" + ); + } +} \ No newline at end of file diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures/RouteControllerDeprecatedInspection.php b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures/RouteControllerDeprecatedInspection.php new file mode 100644 index 000000000..818faee95 --- /dev/null +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures/RouteControllerDeprecatedInspection.php @@ -0,0 +1,20 @@ +