Skip to content

Commit ba7904f

Browse files
authored
Merge pull request Haehnchen#1201 from cedricziel/service-class-inspection
Add inspection and quick fix for fuzzy service class names in YAML
2 parents 9614c4a + 6cdd169 commit ba7904f

File tree

5 files changed

+87
-22
lines changed

5 files changed

+87
-22
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package fr.adrienbrault.idea.symfony2plugin.action.quickfix;
2+
3+
import com.intellij.codeInspection.LocalQuickFix;
4+
import com.intellij.codeInspection.ProblemDescriptor;
5+
import com.intellij.openapi.project.Project;
6+
import com.intellij.psi.PsiElement;
7+
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlPsiElementFactory;
8+
import org.jetbrains.annotations.Nls;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.yaml.psi.YAMLKeyValue;
11+
12+
public class CorrectClassNameCasingYamlLocalQuickFix implements LocalQuickFix {
13+
14+
private final String replacementFQN;
15+
16+
public CorrectClassNameCasingYamlLocalQuickFix(String replacementFQN) {
17+
18+
this.replacementFQN = replacementFQN;
19+
}
20+
21+
@Nls(capitalization = Nls.Capitalization.Sentence)
22+
@NotNull
23+
@Override
24+
public String getFamilyName() {
25+
return "YAML";
26+
}
27+
28+
@Nls(capitalization = Nls.Capitalization.Sentence)
29+
@NotNull
30+
@Override
31+
public String getName() {
32+
return "Use " + replacementFQN;
33+
}
34+
35+
@Override
36+
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
37+
PsiElement psiElement1 = descriptor.getPsiElement();
38+
YAMLKeyValue replacement = YamlPsiElementFactory.createFromText(
39+
project,
40+
YAMLKeyValue.class,
41+
"class: " + replacementFQN
42+
);
43+
44+
if (replacement != null && replacement.getValue() != null) {
45+
psiElement1.replace(replacement.getValue());
46+
}
47+
}
48+
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInspection/service/ServiceDeprecatedClassesInspection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public void visitElement(PsiElement element) {
140140
} else if(element.getNode().getElementType() == YAMLTokenTypes.TEXT) {
141141
// @service
142142
String text = element.getText();
143-
if(text != null && StringUtils.isNotBlank(text) && text.startsWith("@")) {
143+
if(StringUtils.isNotBlank(text) && text.startsWith("@")) {
144144
this.problemRegistrar.attachDeprecatedProblem(element, text.substring(1), holder);
145145
this.problemRegistrar.attachServiceDeprecatedProblem(element, text.substring(1), holder);
146146
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/inspection/YamlClassInspection.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import com.intellij.psi.PsiElement;
77
import com.intellij.psi.PsiElementVisitor;
88
import com.jetbrains.php.PhpIndex;
9+
import com.jetbrains.php.lang.psi.elements.PhpClass;
910
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
11+
import fr.adrienbrault.idea.symfony2plugin.action.quickfix.CorrectClassNameCasingYamlLocalQuickFix;
1012
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
1113
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
1214
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
@@ -20,6 +22,10 @@
2022
* @author Daniel Espendiller <daniel@espendiller.net>
2123
*/
2224
public class YamlClassInspection extends LocalInspectionTool {
25+
26+
public static final String MESSAGE_WRONG_CASING = "Wrong class casing";
27+
public static final String MESSAGE_MISSING_CLASS = "Missing class";
28+
2329
@NotNull
2430
public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) {
2531
if (!Symfony2ProjectComponent.isEnabled(holder.getProject())) {
@@ -29,7 +35,7 @@ public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, bool
2935
return new PsiElementVisitor() {
3036
@Override
3137
public void visitElement(PsiElement psiElement) {
32-
if(!((YamlElementPatternHelper.getSingleLineScalarKey("class", "factory_class").accepts(psiElement) || YamlElementPatternHelper.getParameterClassPattern().accepts(psiElement)) && YamlElementPatternHelper.getInsideServiceKeyPattern().accepts(psiElement))) {
38+
if (!((YamlElementPatternHelper.getSingleLineScalarKey("class", "factory_class").accepts(psiElement) || YamlElementPatternHelper.getParameterClassPattern().accepts(psiElement)) && YamlElementPatternHelper.getInsideServiceKeyPattern().accepts(psiElement))) {
3339
super.visitElement(psiElement);
3440
return;
3541
}
@@ -44,15 +50,18 @@ public void visitElement(PsiElement psiElement) {
4450
private void invoke(@NotNull final PsiElement psiElement, @NotNull ProblemsHolder holder) {
4551
String className = PsiElementUtils.getText(psiElement);
4652

47-
if(YamlHelper.isValidParameterName(className)) {
53+
if (YamlHelper.isValidParameterName(className)) {
4854
String resolvedParameter = ContainerCollectionResolver.resolveParameter(psiElement.getProject(), className);
49-
if(resolvedParameter != null && PhpIndex.getInstance(psiElement.getProject()).getAnyByFQN(resolvedParameter).size() > 0) {
50-
return ;
55+
if (resolvedParameter != null && PhpIndex.getInstance(psiElement.getProject()).getAnyByFQN(resolvedParameter).size() > 0) {
56+
return;
5157
}
5258
}
5359

54-
if(PhpElementsUtil.getClassInterface(psiElement.getProject(), className) == null) {
55-
holder.registerProblem(psiElement, "Missing Class", ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
60+
PhpClass foundClass = PhpElementsUtil.getClassInterface(psiElement.getProject(), className);
61+
if (foundClass == null) {
62+
holder.registerProblem(psiElement, MESSAGE_MISSING_CLASS, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
63+
} else if (!foundClass.getPresentableFQN().equals(className)) {
64+
holder.registerProblem(psiElement, MESSAGE_WRONG_CASING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CorrectClassNameCasingYamlLocalQuickFix(foundClass.getPresentableFQN()));
5665
}
5766
}
5867
}
Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.dic.inspection;
22

3+
import fr.adrienbrault.idea.symfony2plugin.dic.inspection.YamlClassInspection;
34
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
45

5-
import java.io.File;
6-
76
/**
87
* @author Daniel Espendiller <daniel@espendiller.net>
98
* @see fr.adrienbrault.idea.symfony2plugin.dic.inspection.YamlClassInspection
@@ -20,15 +19,26 @@ public String getTestDataPath() {
2019
}
2120

2221
public void testInspectionForClass() {
23-
assertLocalInspectionContains("services.yml", "services:\n class: Args\\Fo<caret>oBar", "Missing Class");
24-
assertLocalInspectionContains("services.yml", "services:\n class: 'Args\\Fo<caret>oBar'", "Missing Class");
25-
assertLocalInspectionContains("services.yml", "services:\n class: \"Args\\Fo<caret>oBar\"", "Missing Class");
26-
assertLocalInspectionContains("services.yml", "services:\n factory_class: Args\\Fo<caret>oBar", "Missing Class");
27-
assertLocalInspectionNotContains("services.yml", "services:\n factory_class: Args\\Fo<caret>o", "Missing Class");
28-
29-
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>oBar", "Missing Class");
30-
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: 'Args\\Fo<caret>oBar'", "Missing Class");
31-
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: \"Args\\Fo<caret>oBar\"", "Missing Class");
32-
assertLocalInspectionNotContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>o", "Missing Class");
22+
assertLocalInspectionContains("services.yml", "services:\n class: Args\\Fo<caret>oBar", YamlClassInspection.MESSAGE_MISSING_CLASS);
23+
assertLocalInspectionContains("services.yml", "services:\n class: 'Args\\Fo<caret>oBar'", YamlClassInspection.MESSAGE_MISSING_CLASS);
24+
assertLocalInspectionContains("services.yml", "services:\n class: \"Args\\Fo<caret>oBar\"", YamlClassInspection.MESSAGE_MISSING_CLASS);
25+
assertLocalInspectionContains("services.yml", "services:\n factory_class: Args\\Fo<caret>oBar", YamlClassInspection.MESSAGE_MISSING_CLASS);
26+
assertLocalInspectionNotContains("services.yml", "services:\n factory_class: Args\\Fo<caret>o", YamlClassInspection.MESSAGE_MISSING_CLASS);
27+
28+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>oBar", YamlClassInspection.MESSAGE_MISSING_CLASS);
29+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: 'Args\\Fo<caret>oBar'", YamlClassInspection.MESSAGE_MISSING_CLASS);
30+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: \"Args\\Fo<caret>oBar\"", YamlClassInspection.MESSAGE_MISSING_CLASS);
31+
assertLocalInspectionNotContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>o", YamlClassInspection.MESSAGE_MISSING_CLASS);
32+
33+
assertLocalInspectionContains("services.yml", "services:\n class: Args\\Fo<caret>O", YamlClassInspection.MESSAGE_WRONG_CASING);
34+
assertLocalInspectionContains("services.yml", "services:\n class: 'Args\\Fo<caret>O'", YamlClassInspection.MESSAGE_WRONG_CASING);
35+
assertLocalInspectionContains("services.yml", "services:\n class: \"Args\\Fo<caret>O\"", YamlClassInspection.MESSAGE_WRONG_CASING);
36+
assertLocalInspectionContains("services.yml", "services:\n factory_class: Args\\Fo<caret>O", YamlClassInspection.MESSAGE_WRONG_CASING);
37+
assertLocalInspectionNotContains("services.yml", "services:\n factory_class: Args\\Fo<caret>o", YamlClassInspection.MESSAGE_WRONG_CASING);
38+
39+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>O", YamlClassInspection.MESSAGE_WRONG_CASING);
40+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: 'Args\\Fo<caret>O'", YamlClassInspection.MESSAGE_WRONG_CASING);
41+
assertLocalInspectionContains("services.yml", "parameters:\n foo.class: \"Args\\Fo<caret>O\"", YamlClassInspection.MESSAGE_WRONG_CASING);
42+
assertLocalInspectionNotContains("services.yml", "parameters:\n foo.class: Args\\Fo<caret>o", YamlClassInspection.MESSAGE_WRONG_CASING);
3343
}
3444
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/twig/annotation/TemplateAnnotationAnnotatorTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
1010
import de.espend.idea.php.annotation.extension.parameter.PhpAnnotationDocTagAnnotatorParameter;
1111
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
12-
import fr.adrienbrault.idea.symfony2plugin.twig.annotation.TemplateAnnotationAnnotator;
1312
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
14-
15-
import java.io.File;
13+
import fr.adrienbrault.idea.symfony2plugin.twig.annotation.TemplateAnnotationAnnotator;
1614

1715
/**
1816
* @author Daniel Espendiller <daniel@espendiller.net>

0 commit comments

Comments
 (0)