Skip to content

Commit 4edf41c

Browse files
authored
Merge pull request #1964 from Haehnchen/feature/deprecated-controller
inspection for deprecated "controller" targets on route
2 parents 05ea895 + 3daa2ad commit 4edf41c

File tree

6 files changed

+196
-12
lines changed

6 files changed

+196
-12
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package fr.adrienbrault.idea.symfony2plugin.routing;
2+
3+
import com.intellij.codeInspection.LocalInspectionTool;
4+
import com.intellij.codeInspection.ProblemHighlightType;
5+
import com.intellij.codeInspection.ProblemsHolder;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.psi.PsiElementVisitor;
8+
import com.jetbrains.php.lang.psi.elements.Method;
9+
import com.jetbrains.php.lang.psi.elements.PhpClass;
10+
import com.jetbrains.php.lang.psi.elements.PhpClassMember;
11+
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
12+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
13+
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
14+
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
15+
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
16+
import org.apache.commons.lang.StringUtils;
17+
import org.jetbrains.annotations.NotNull;
18+
19+
/**
20+
* @author Daniel Espendiller <daniel@espendiller.net>
21+
*/
22+
public class RouteControllerDeprecatedInspection extends LocalInspectionTool {
23+
24+
@NotNull
25+
public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) {
26+
if(!Symfony2ProjectComponent.isEnabled(holder.getProject())) {
27+
return super.buildVisitor(holder, isOnTheFly);
28+
}
29+
30+
return new PsiElementVisitor() {
31+
@Override
32+
public void visitElement(@NotNull PsiElement element) {
33+
if (XmlHelper.getRouteControllerPattern().accepts(element)) {
34+
PsiElement parent = element.getParent();
35+
if (parent != null) {
36+
String text = RouteXmlReferenceContributor.getControllerText(parent);
37+
if(text != null) {
38+
extracted(element, text, holder);
39+
}
40+
}
41+
} else if(YamlElementPatternHelper.getSingleLineScalarKey("_controller", "controller").accepts(element)) {
42+
String text = PsiElementUtils.trimQuote(element.getText());
43+
if (StringUtils.isNotBlank(text)) {
44+
extracted(element, text, holder);
45+
}
46+
}
47+
48+
super.visitElement(element);
49+
}
50+
};
51+
}
52+
53+
private void extracted(@NotNull PsiElement element, String text, @NotNull ProblemsHolder holder) {
54+
for (PsiElement psiElement : RouteHelper.getMethodsOnControllerShortcut(element.getProject(), text)) {
55+
if (!(psiElement instanceof PhpNamedElement)) {
56+
continue;
57+
}
58+
59+
// action is deprecated
60+
if (((PhpNamedElement) psiElement).isDeprecated()) {
61+
holder.registerProblem(element, "Symfony: Controller action is deprecated", ProblemHighlightType.LIKE_DEPRECATED);
62+
break;
63+
}
64+
65+
// class is deprecated
66+
if (psiElement instanceof PhpClassMember) {
67+
PhpClass containingClass = ((Method) psiElement).getContainingClass();
68+
if (containingClass != null && containingClass.isDeprecated()) {
69+
holder.registerProblem(element, "Symfony: Controller action is deprecated", ProblemHighlightType.LIKE_DEPRECATED);
70+
break;
71+
}
72+
}
73+
}
74+
}
75+
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteXmlReferenceContributor.java

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import fr.adrienbrault.idea.symfony2plugin.util.controller.ControllerIndex;
1111
import org.apache.commons.lang.StringUtils;
1212
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
1314

1415
/**
1516
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -43,20 +44,14 @@ private RouteActionReference(PsiElement psiElement) {
4344

4445
@NotNull
4546
@Override
46-
public ResolveResult[] multiResolve(boolean b) {
47-
PsiElement element = getElement();
48-
PsiElement parent = element.getParent();
49-
50-
String text = null;
51-
if(parent instanceof XmlText) {
52-
// <route><default key="_controller">Fo<caret>o\Bar</default></route>
53-
text = parent.getText();
54-
} else if(parent instanceof XmlAttribute) {
55-
// <route controller=""/>
56-
text = ((XmlAttribute) parent).getValue();
47+
public ResolveResult @NotNull [] multiResolve(boolean b) {
48+
PsiElement parent = getElement().getParent();
49+
if (parent == null) {
50+
return new ResolveResult[0];
5751
}
5852

59-
if(text == null || StringUtils.isBlank(text)) {
53+
String text = getControllerText(parent);
54+
if(text == null) {
6055
return new ResolveResult[0];
6156
}
6257

@@ -71,4 +66,26 @@ public Object[] getVariants() {
7166
return ControllerIndex.getControllerLookupElements(getElement().getProject()).toArray();
7267
}
7368
}
69+
70+
/**
71+
* <default key="_controller">Fo<caret>o\Bar</default>
72+
* <route controller=""/>
73+
*/
74+
@Nullable
75+
public static String getControllerText(@NotNull PsiElement parent) {
76+
String text = null;
77+
if(parent instanceof XmlText) {
78+
// <route><default key="_controller">Fo<caret>o\Bar</default></route>
79+
text = parent.getText();
80+
} else if(parent instanceof XmlAttribute) {
81+
// <route controller=""/>
82+
text = ((XmlAttribute) parent).getValue();
83+
}
84+
85+
if (StringUtils.isBlank(text)) {
86+
return null;
87+
}
88+
89+
return text;
90+
}
7491
}

src/main/resources/META-INF/plugin.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,12 @@
495495
language="PHP"
496496
implementationClass="fr.adrienbrault.idea.symfony2plugin.templating.inspection.TemplateExistsAnnotationPhpAttributeLocalInspection"/>
497497

498+
<localInspection groupPath="Symfony" shortName="RouteControllerDeprecatedInspection" displayName="Deprecated Action"
499+
groupName="Route"
500+
enabledByDefault="true"
501+
level="WARNING"
502+
implementationClass="fr.adrienbrault.idea.symfony2plugin.routing.RouteControllerDeprecatedInspection"/>
503+
498504
<intentionAction>
499505
<className>fr.adrienbrault.idea.symfony2plugin.intentions.php.PhpServiceIntention</className>
500506
<category>PHP</category>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html>
2+
<body>
3+
<!-- tooltip end -->
4+
</body>
5+
</html>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.routing;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
4+
5+
/**
6+
* @author Daniel Espendiller <daniel@espendiller.net>
7+
*
8+
* @see fr.adrienbrault.idea.symfony2plugin.routing.RouteControllerDeprecatedInspection
9+
*/
10+
public class RouteControllerDeprecatedInspectionTest extends SymfonyLightCodeInsightFixtureTestCase {
11+
12+
public void setUp() throws Exception {
13+
super.setUp();
14+
15+
myFixture.copyFileToProject("RouteControllerDeprecatedInspection.php");
16+
}
17+
18+
protected String getTestDataPath() {
19+
return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures";
20+
}
21+
22+
public void testDeprecatedRouteActionForYml() {
23+
assertLocalInspectionContains("foobar.yml","" +
24+
"blog_list:\n" +
25+
" controller: App\\Controller\\BarController::foo<caret>bar",
26+
"Symfony: Controller action is deprecated"
27+
);
28+
29+
assertLocalInspectionContains("foobar.yml","" +
30+
"blog_list:\n" +
31+
" defaults: { _controller: App\\Controller\\BarController::foo<caret>bar }",
32+
"Symfony: Controller action is deprecated"
33+
);
34+
}
35+
36+
public void testDeprecatedRouteActionForXml() {
37+
assertLocalInspectionContains("foobar.xml",
38+
"<routes>\n" +
39+
" <route controller=\"App\\Controller\\BarController::foo<caret>bar\"/>\n" +
40+
"</routes>",
41+
"Symfony: Controller action is deprecated"
42+
);
43+
44+
assertLocalInspectionContains("foobar.xml",
45+
"<routes>\n" +
46+
" <route>\n" +
47+
" <default key=\"_controller\">App\\Controller\\BarController::foo<caret>bar</default>\n" +
48+
" </route>\n" +
49+
"</routes>",
50+
"Symfony: Controller action is deprecated"
51+
);
52+
}
53+
54+
public void testDeprecatedRouteActionForClassMember() {
55+
assertLocalInspectionContains("foobar.yml","" +
56+
"blog_list:\n" +
57+
" controller: App\\Controller\\CarController::foo<caret>bar",
58+
"Symfony: Controller action is deprecated"
59+
);
60+
}
61+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace App\Controller
4+
{
5+
class BarController
6+
{
7+
/**
8+
* @deprecated
9+
*/
10+
public function foobar() {}
11+
}
12+
13+
/**
14+
* @deprecated
15+
*/
16+
class CarController
17+
{
18+
public function foobar() {}
19+
}
20+
}

0 commit comments

Comments
 (0)