Skip to content

Commit e6dae01

Browse files
committed
add deprecated inspection warning for service classes #375
1 parent 23c5b07 commit e6dae01

File tree

4 files changed

+168
-3
lines changed

4 files changed

+168
-3
lines changed

META-INF/plugin.xml

+4
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@
476476
language="yaml"
477477
implementationClass="fr.adrienbrault.idea.symfony2plugin.routing.inspection.YamlControllerMethodInspection"/>
478478

479+
<localInspection groupPath="Symfony2" shortName="YamlDeprecatedClasses" displayName="Deprecated Class"
480+
groupName="Service"
481+
enabledByDefault="true" level="WARNING"
482+
implementationClass="fr.adrienbrault.idea.symfony2plugin.codeInspection.service.ServiceDeprecatedClassesInspection"/>
479483

480484
<toolWindow id="Symfony2" anchor="left" secondary="false" icon="SymfonyIcons.SymfonyToolWindow"
481485
factoryClass="fr.adrienbrault.idea.symfony2plugin.toolwindow.Symfony2SearchToolWindowFactory"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package fr.adrienbrault.idea.symfony2plugin.codeInspection.service;
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.intellij.psi.PsiFile;
9+
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
10+
import com.intellij.psi.xml.XmlFile;
11+
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
12+
import com.jetbrains.php.lang.psi.PhpFile;
13+
import com.jetbrains.php.lang.psi.elements.MethodReference;
14+
import com.jetbrains.php.lang.psi.elements.PhpClass;
15+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
16+
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
17+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
18+
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
19+
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
20+
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
21+
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
22+
import org.apache.commons.lang.StringUtils;
23+
import org.jetbrains.annotations.NotNull;
24+
import org.jetbrains.yaml.YAMLTokenTypes;
25+
import org.jetbrains.yaml.psi.YAMLFile;
26+
27+
28+
public class ServiceDeprecatedClassesInspection extends LocalInspectionTool {
29+
30+
@NotNull
31+
@Override
32+
public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) {
33+
34+
final PsiFile psiFile = holder.getFile();
35+
if(!Symfony2ProjectComponent.isEnabled(psiFile.getProject())) {
36+
return super.buildVisitor(holder, isOnTheFly);
37+
}
38+
39+
40+
if(psiFile instanceof YAMLFile) {
41+
psiFile.acceptChildren(new YmlClassElementWalkingVisitor(holder));
42+
}
43+
44+
if(psiFile instanceof XmlFile) {
45+
psiFile.acceptChildren(new XmlClassElementWalkingVisitor(holder));
46+
}
47+
48+
if(psiFile instanceof PhpFile) {
49+
psiFile.acceptChildren(new PhpClassWalkingVisitor(holder));
50+
}
51+
52+
return super.buildVisitor(holder, isOnTheFly);
53+
}
54+
55+
private void attachDeprecatedProblem(PsiElement element, String text, ProblemsHolder holder) {
56+
57+
PhpClass phpClass = ServiceUtil.getResolvedClassDefinition(element.getProject(), text);
58+
if(phpClass == null) {
59+
return;
60+
}
61+
62+
PhpDocComment docComment = phpClass.getDocComment();
63+
if(docComment != null && docComment.getTagElementsByName("@deprecated").length > 0) {
64+
holder.registerProblem(element, String.format("Class '%s' is deprecated", phpClass.getName()), ProblemHighlightType.LIKE_DEPRECATED);
65+
}
66+
67+
}
68+
69+
70+
private class XmlClassElementWalkingVisitor extends PsiRecursiveElementWalkingVisitor {
71+
private final ProblemsHolder holder;
72+
73+
public XmlClassElementWalkingVisitor(ProblemsHolder holder) {
74+
this.holder = holder;
75+
}
76+
77+
@Override
78+
public void visitElement(PsiElement element) {
79+
if(XmlHelper.getServiceIdPattern().accepts(element) || XmlHelper.getArgumentServiceIdPattern().accepts(element)) {
80+
String text = PsiElementUtils.trimQuote(element.getText());
81+
PsiElement[] psiElements = element.getChildren();
82+
83+
// we need to attach to child because else strike out equal and quote char
84+
if(StringUtils.isNotBlank(text) && psiElements.length > 2) {
85+
attachDeprecatedProblem(psiElements[1], text, holder);
86+
}
87+
}
88+
89+
super.visitElement(element);
90+
}
91+
}
92+
93+
private class YmlClassElementWalkingVisitor extends PsiRecursiveElementWalkingVisitor {
94+
private final ProblemsHolder holder;
95+
96+
public YmlClassElementWalkingVisitor(ProblemsHolder holder) {
97+
this.holder = holder;
98+
}
99+
100+
@Override
101+
public void visitElement(PsiElement element) {
102+
103+
if(YamlElementPatternHelper.getSingleLineScalarKey("class").accepts(element)) {
104+
// class: '\Foo'
105+
String text = PsiElementUtils.trimQuote(element.getText());
106+
if(StringUtils.isNotBlank(text)) {
107+
attachDeprecatedProblem(element, text, holder);
108+
}
109+
} else if(element.getNode().getElementType() == YAMLTokenTypes.TEXT) {
110+
// @service
111+
String text = element.getText();
112+
if(text != null && StringUtils.isNotBlank(text) && text.startsWith("@")) {
113+
attachDeprecatedProblem(element, text.substring(1), holder);
114+
}
115+
}
116+
117+
super.visitElement(element);
118+
}
119+
}
120+
121+
private class PhpClassWalkingVisitor extends PsiRecursiveElementWalkingVisitor {
122+
123+
private final ProblemsHolder holder;
124+
Symfony2InterfacesUtil symfony2InterfacesUtil;
125+
126+
public PhpClassWalkingVisitor(ProblemsHolder holder) {
127+
this.holder = holder;
128+
symfony2InterfacesUtil = new Symfony2InterfacesUtil();
129+
}
130+
131+
@Override
132+
public void visitElement(PsiElement element) {
133+
134+
MethodReference methodReference = PsiElementUtils.getMethodReferenceWithFirstStringParameter(element);
135+
if (methodReference == null || !symfony2InterfacesUtil.isContainerGetCall(methodReference)) {
136+
super.visitElement(element);
137+
return;
138+
}
139+
140+
PsiElement psiElement = element.getParent();
141+
if(!(psiElement instanceof StringLiteralExpression)) {
142+
super.visitElement(element);
143+
return;
144+
}
145+
146+
String contents = ((StringLiteralExpression) psiElement).getContents();
147+
if(StringUtils.isNotBlank(contents)) {
148+
attachDeprecatedProblem(element, contents, holder);
149+
}
150+
151+
super.visitElement(element);
152+
}
153+
}
154+
}

src/fr/adrienbrault/idea/symfony2plugin/util/dict/ServiceUtil.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
2020
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
2121
import org.apache.commons.lang.StringUtils;
22+
import org.jetbrains.annotations.NotNull;
2223
import org.jetbrains.annotations.Nullable;
2324
import org.jetbrains.yaml.YAMLFileType;
2425

@@ -69,7 +70,7 @@ public class ServiceUtil {
6970
* %test%, service, \Class\Name to PhpClass
7071
*/
7172
@Nullable
72-
public static PhpClass getResolvedClassDefinition(Project project, String serviceClassParameterName) {
73+
public static PhpClass getResolvedClassDefinition(@NotNull Project project, @NotNull String serviceClassParameterName) {
7374

7475
// match parameter
7576
if(serviceClassParameterName.startsWith("%") && serviceClassParameterName.endsWith("%")) {
@@ -117,11 +118,11 @@ public static Collection<PsiElement> getParameterDefinition(Project project, Str
117118

118119
}
119120

120-
public static Collection<PsiElement> getServiceClassTargets(Project project, String value) {
121+
public static Collection<PsiElement> getServiceClassTargets(@NotNull Project project, @Nullable String value) {
121122

122123
List<PsiElement> resolveResults = new ArrayList<PsiElement>();
123124

124-
if(StringUtils.isBlank(value)) {
125+
if(value == null || StringUtils.isBlank(value)) {
125126
return resolveResults;
126127
}
127128

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<html>
2+
<body>
3+
Class is deprecated, you should replace this class
4+
<!-- tooltip end -->
5+
</body>
6+
</html>

0 commit comments

Comments
 (0)