Skip to content

Commit 3c48e7d

Browse files
committed
dont annotate missing twig template in interpolated or concatenated strings #488
1 parent 2104872 commit 3c48e7d

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

src/fr/adrienbrault/idea/symfony2plugin/TwigHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class TwigHelper {
6363
/**
6464
* ([) "FOO", 'FOO' (])
6565
*/
66-
private static final ElementPattern<PsiElement> STRING_WRAP_PATTERN = PlatformPatterns.or(
66+
public static final ElementPattern<PsiElement> STRING_WRAP_PATTERN = PlatformPatterns.or(
6767
PlatformPatterns.psiElement(PsiWhiteSpace.class),
6868
PlatformPatterns.psiElement(TwigTokenTypes.WHITE_SPACE),
6969
PlatformPatterns.psiElement(TwigTokenTypes.DOUBLE_QUOTE),

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigAnnotator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private void annotateRoute(@NotNull final PsiElement element, @NotNull Annotatio
138138

139139
private void annotateTemplate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) {
140140

141-
if(!(TwigHelper.getTemplateFileReferenceTagPattern().accepts(element) || TwigHelper.getPrintBlockFunctionPattern("include", "source").accepts(element))) {
141+
if(!(TwigHelper.getTemplateFileReferenceTagPattern().accepts(element) || TwigHelper.getPrintBlockFunctionPattern("include", "source").accepts(element)) || !TwigUtil.isValidTemplateString(element)) {
142142
return;
143143
}
144144

src/fr/adrienbrault/idea/symfony2plugin/templating/util/TwigUtil.java

+28-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import com.intellij.openapi.vfs.VfsUtil;
55
import com.intellij.openapi.vfs.VirtualFile;
66
import com.intellij.patterns.PlatformPatterns;
7-
import com.intellij.psi.PsiElement;
8-
import com.intellij.psi.PsiFile;
9-
import com.intellij.psi.PsiManager;
10-
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
7+
import com.intellij.psi.*;
118
import com.intellij.psi.search.GlobalSearchScope;
129
import com.intellij.psi.util.PsiElementFilter;
1310
import com.intellij.psi.util.PsiTreeUtil;
@@ -20,6 +17,7 @@
2017
import com.jetbrains.php.lang.psi.elements.*;
2118
import com.jetbrains.twig.TwigFile;
2219
import com.jetbrains.twig.TwigFileType;
20+
import com.jetbrains.twig.TwigTokenTypes;
2321
import com.jetbrains.twig.elements.TwigBlockTag;
2422
import com.jetbrains.twig.elements.TwigCompositeElement;
2523
import com.jetbrains.twig.elements.TwigElementTypes;
@@ -648,5 +646,31 @@ public static String getTemplateNameByOverwrite(@NotNull Project project, @NotNu
648646
return TwigHelper.normalizeTemplateName(containingBundle.getName() + ":" + relative.substring("Resources/views/".length(), relative.length()));
649647
}
650648

649+
/**
650+
* {% include "foo/#{segment.typeKey}.html.twig" with {'segment': segment} %}
651+
* {% include "foo/#{1 + 2}.html.twig" %}
652+
* {% include "foo/" ~ segment.typeKey ~ ".html.twig" %}
653+
*/
654+
public static boolean isValidTemplateString(@NotNull PsiElement element) {
655+
String templateName = element.getText();
656+
657+
if(templateName.matches(".*#\\{.*\\}.*")) {
658+
return false;
659+
}
651660

661+
if(PlatformPatterns.psiElement()
662+
.afterLeafSkipping(
663+
TwigHelper.STRING_WRAP_PATTERN,
664+
PlatformPatterns.psiElement(TwigTokenTypes.CONCAT)
665+
).accepts(element) ||
666+
PlatformPatterns.psiElement().beforeLeafSkipping(
667+
TwigHelper.STRING_WRAP_PATTERN,
668+
PlatformPatterns.psiElement(TwigTokenTypes.CONCAT)
669+
).accepts(element)) {
670+
671+
return false;
672+
};
673+
674+
return true;
675+
}
652676
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/templating/util/TwigUtilIntegrationTest.java

+40
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.templating.util;
22

33
import com.intellij.openapi.vfs.VfsUtil;
4+
import com.intellij.psi.PsiElement;
5+
import com.intellij.psi.PsiRecursiveElementVisitor;
6+
import com.intellij.psi.tree.IElementType;
47
import com.jetbrains.twig.TwigFileType;
8+
import com.jetbrains.twig.TwigTokenTypes;
9+
import com.jetbrains.twig.elements.TwigElementFactory;
10+
import com.jetbrains.twig.elements.TwigElementTypes;
511
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
612
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
13+
import org.jetbrains.annotations.NotNull;
714

815
public class TwigUtilIntegrationTest extends SymfonyLightCodeInsightFixtureTestCase {
916

@@ -57,4 +64,37 @@ public void testTemplateOverwriteNavigation() {
5764
assertNavigationContainsFile(TwigFileType.INSTANCE, "{% extends '<caret>TwigUtilIntegrationBundle:Foo/Bar/layout.html.twig' %}", "/views/Foo/Bar/layout.html.twig");
5865
}
5966

67+
/**
68+
* @see fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil#isValidTemplateString
69+
*/
70+
public void testIsValidTemplateString() {
71+
assertFalse(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include \"foo/#{segment.typeKey}.html.twig\" %}", TwigElementTypes.INCLUDE_TAG)));
72+
assertFalse(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include \"foo/#{1 + 2}.html.twig\" %}", TwigElementTypes.INCLUDE_TAG)));
73+
assertFalse(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include ~ \"foo.html.twig\" ~ %}", TwigElementTypes.INCLUDE_TAG)));
74+
assertFalse(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include \"foo.html.twig\" ~ %}", TwigElementTypes.INCLUDE_TAG)));
75+
assertFalse(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include ~ \"foo.html.twig\" %}", TwigElementTypes.INCLUDE_TAG)));
76+
77+
assertTrue(TwigUtil.isValidTemplateString(createPsiElementAndFindString("{% include \"foo.html.twig\" %}", TwigElementTypes.INCLUDE_TAG)));
78+
}
79+
80+
private PsiElement createPsiElementAndFindString(@NotNull String content, @NotNull IElementType type) {
81+
PsiElement psiElement = TwigElementFactory.createPsiElement(getProject(), content, type);
82+
if(psiElement == null) {
83+
fail();
84+
}
85+
86+
final PsiElement[] string = {null};
87+
psiElement.acceptChildren(new PsiRecursiveElementVisitor() {
88+
@Override
89+
public void visitElement(PsiElement element) {
90+
if (string[0] == null && element.getNode().getElementType() == TwigTokenTypes.STRING_TEXT) {
91+
string[0] = element;
92+
}
93+
super.visitElement(element);
94+
}
95+
});
96+
97+
return string[0];
98+
}
99+
60100
}

0 commit comments

Comments
 (0)