From 74a8af0f58dd2479ab95ac6fb41e0ee088d29011 Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Fri, 15 Dec 2023 20:36:08 +0100 Subject: [PATCH] support new routing class "\Symfony\Component\Routing\Attribute\Route" --- .../SymfonyImplicitUsageProvider.java | 9 ++------- .../idea/symfony2plugin/routing/RouteHelper.java | 16 ++++++++-------- .../RouteNameAnnotationCompletionProvider.java | 2 +- .../RouteUrlAnnotationCompletionProvider.java | 2 +- .../DuplicateLocalRouteInspection.java | 14 +++++++++----- .../symfony2plugin/util/PhpElementsUtil.java | 4 ++++ 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInsight/SymfonyImplicitUsageProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInsight/SymfonyImplicitUsageProvider.java index 66ea88158..475b40c4b 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInsight/SymfonyImplicitUsageProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInsight/SymfonyImplicitUsageProvider.java @@ -26,11 +26,6 @@ * @author Daniel Espendiller */ public class SymfonyImplicitUsageProvider implements ImplicitUsageProvider { - private static final String[] ROUTE_ANNOTATIONS = new String[] { - "\\Symfony\\Component\\Routing\\Annotation\\Route", - "\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route" - }; - @Override public boolean isImplicitUsage(@NotNull PsiElement element) { if (element instanceof Method method && method.getAccess() == PhpModifier.Access.PUBLIC) { @@ -128,11 +123,11 @@ public boolean isImplicitWrite(@NotNull PsiElement element) { private boolean isMethodARoute(@NotNull Method method) { PhpDocCommentAnnotation phpDocCommentAnnotationContainer = AnnotationUtil.getPhpDocCommentAnnotationContainer(method.getDocComment()); - if (phpDocCommentAnnotationContainer != null && phpDocCommentAnnotationContainer.getFirstPhpDocBlock(ROUTE_ANNOTATIONS) != null) { + if (phpDocCommentAnnotationContainer != null && phpDocCommentAnnotationContainer.getFirstPhpDocBlock(RouteHelper.ROUTE_ANNOTATIONS) != null) { return true; } - for (String route : ROUTE_ANNOTATIONS) { + for (String route : RouteHelper.ROUTE_ANNOTATIONS) { Collection<@NotNull PhpAttribute> attributes = method.getAttributes(route); if (!attributes.isEmpty()) { return true; diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteHelper.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteHelper.java index 0f882b22b..a4c687206 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteHelper.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteHelper.java @@ -64,6 +64,11 @@ * @author Daniel Espendiller */ public class RouteHelper { + public static final String[] ROUTE_ANNOTATIONS = new String[] { + "\\Symfony\\Component\\Routing\\Annotation\\Route", + "\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route", + "\\Symfony\\Component\\Routing\\Attribute\\Route" + }; private static final Key>> ROUTE_CACHE = new Key<>("SYMFONY:ROUTE_CACHE"); private static final Key>> ROUTE_CONTROLLER_RESOLVED_CACHE = new Key<>("ROUTE_CONTROLLER_RESOLVED_CACHE"); @@ -72,11 +77,6 @@ public class RouteHelper { private static final Key>> SYMFONY_COMPILED_CACHE_ROUTES_FILES = new Key<>("SYMFONY_COMPILED_CACHE_ROUTES_FILES"); private static final Key>> SYMFONY_COMPILED_GUESTED_FILES = new Key<>("SYMFONY_COMPILED_GUESTED_FILES"); - public static Set ROUTE_CLASSES = new HashSet<>(Arrays.asList( - "Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route", - "Symfony\\Component\\Routing\\Annotation\\Route" - )); - private static final ExtensionPointName ROUTING_LOADER = new ExtensionPointName<>( "fr.adrienbrault.idea.symfony2plugin.extension.RoutingLoader" ); @@ -1162,7 +1162,7 @@ public static Collection getRouteNameTarget(@NotNull Project project private static String getRouteNamePrefix(@NotNull PhpClass phpClass) { PhpDocCommentAnnotation phpClassContainer = AnnotationUtil.getPhpDocCommentAnnotationContainer(phpClass.getDocComment()); if(phpClassContainer != null) { - PhpDocTagAnnotation firstPhpDocBlock = phpClassContainer.getFirstPhpDocBlock(ROUTE_CLASSES.toArray(new String[0])); + PhpDocTagAnnotation firstPhpDocBlock = phpClassContainer.getFirstPhpDocBlock(ROUTE_ANNOTATIONS); if(firstPhpDocBlock != null) { String name = firstPhpDocBlock.getPropertyValue("name"); if(name != null && StringUtils.isNotBlank(name)) { @@ -1342,8 +1342,8 @@ private static String normalizeRouteController(@NotNull String string) { * Support "use Symfony\Component\Routing\Annotation\Route as BaseRoute;" */ public static boolean isRouteClassAnnotation(@NotNull String clazz) { - String myClazz = StringUtils.stripStart(clazz, "\\"); - return ROUTE_CLASSES.stream().anyMatch(s -> s.equalsIgnoreCase(myClazz)); + String myClazz = "\\" + StringUtils.stripStart(clazz, "\\"); + return Arrays.stream(ROUTE_ANNOTATIONS).anyMatch(s -> s.equalsIgnoreCase(myClazz)); } private static class CompiledRoutePathFilesModificationTracker extends SimpleModificationTracker { diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteNameAnnotationCompletionProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteNameAnnotationCompletionProvider.java index dceea46e2..14aa67d51 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteNameAnnotationCompletionProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteNameAnnotationCompletionProvider.java @@ -27,7 +27,7 @@ public class RouteNameAnnotationCompletionProvider implements PhpAnnotationCompletionProvider { @Override public void getPropertyValueCompletions(AnnotationPropertyParameter annotationPropertyParameter, AnnotationCompletionProviderParameter annotationCompletionProviderParameter) { - if (!Symfony2ProjectComponent.isEnabled(annotationPropertyParameter.getProject()) || !PhpElementsUtil.isInstanceOf(annotationPropertyParameter.getPhpClass(), "\\Symfony\\Component\\Routing\\Annotation\\Route")) { + if (!Symfony2ProjectComponent.isEnabled(annotationPropertyParameter.getProject()) || !PhpElementsUtil.isInstanceOf(annotationPropertyParameter.getPhpClass(), "\\Symfony\\Component\\Routing\\Annotation\\Route", "\\Symfony\\Component\\Routing\\Annotation\\Route")) { return; } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteUrlAnnotationCompletionProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteUrlAnnotationCompletionProvider.java index de4ed020c..7c143455d 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteUrlAnnotationCompletionProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/annotation/RouteUrlAnnotationCompletionProvider.java @@ -15,7 +15,7 @@ public class RouteUrlAnnotationCompletionProvider implements PhpAnnotationCompletionProvider { @Override public void getPropertyValueCompletions(AnnotationPropertyParameter annotationPropertyParameter, AnnotationCompletionProviderParameter annotationCompletionProviderParameter) { - if (!Symfony2ProjectComponent.isEnabled(annotationPropertyParameter.getProject()) || !PhpElementsUtil.isInstanceOf(annotationPropertyParameter.getPhpClass(), "\\Symfony\\Component\\Routing\\Annotation\\Route")) { + if (!Symfony2ProjectComponent.isEnabled(annotationPropertyParameter.getProject()) || !PhpElementsUtil.isInstanceOf(annotationPropertyParameter.getPhpClass(), "\\Symfony\\Component\\Routing\\Annotation\\Route", "\\Symfony\\Component\\Routing\\Annotation\\Route")) { return; } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/inspection/DuplicateLocalRouteInspection.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/inspection/DuplicateLocalRouteInspection.java index af7300777..ccba5cf67 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/inspection/DuplicateLocalRouteInspection.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/inspection/DuplicateLocalRouteInspection.java @@ -23,13 +23,14 @@ import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper; import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil; import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.yaml.YAMLLanguage; import org.jetbrains.yaml.psi.YAMLDocument; import org.jetbrains.yaml.psi.YAMLKeyValue; import org.jetbrains.yaml.psi.YAMLMapping; +import java.util.Collection; + /** * @author Daniel Espendiller */ @@ -95,14 +96,17 @@ private void visitYaml(@NotNull YAMLKeyValue yamlKeyValue) { } private void visitPhp(@NotNull StringLiteralExpression element) { - if (PhpElementsUtil.isAttributeNamedArgumentString(element, "\\Symfony\\Component\\Routing\\Annotation\\Route", "name")) { + if (PhpElementsUtil.isAttributeNamedArgumentString(element, "\\Symfony\\Component\\Routing\\Annotation\\Route", "name") || PhpElementsUtil.isAttributeNamedArgumentString(element, "\\Symfony\\Component\\Routing\\Attribute\\Route", "name")) { PhpAttribute parentOfType = PsiTreeUtil.getParentOfType(element, PhpAttribute.class); if (parentOfType.getOwner() instanceof Method method && method.getAccess().isPublic() && method.getContainingClass() != null) { int found = 0; String contents = element.getContents(); for (Method ownMethod : method.getContainingClass().getOwnMethods()) { - for (PhpAttribute attribute : ownMethod.getAttributes("\\Symfony\\Component\\Routing\\Annotation\\Route")) { + Collection attributes = ownMethod.getAttributes("\\Symfony\\Component\\Routing\\Annotation\\Route"); + attributes.addAll(ownMethod.getAttributes("\\Symfony\\Component\\Routing\\Attribute\\Route")); + + for (PhpAttribute attribute : attributes) { String name = PhpElementsUtil.getAttributeArgumentStringByName(attribute, "name"); if (contents.equals(name)) { found++; @@ -121,7 +125,7 @@ private void visitPhp(@NotNull StringLiteralExpression element) { PhpDocTag phpDocTag = PsiTreeUtil.getParentOfType(element, PhpDocTag.class); if (phpDocTag != null) { PhpClass phpClass = AnnotationUtil.getAnnotationReference(phpDocTag); - if (phpClass != null && RouteHelper.ROUTE_CLASSES.contains(StringUtils.stripStart(phpClass.getFQN(), "\\"))) { + if (phpClass != null && RouteHelper.isRouteClassAnnotation(phpClass.getFQN())) { PhpDocComment phpDocComment = PsiTreeUtil.getParentOfType(element, PhpDocComment.class); if (phpDocComment.getNextPsiSibling() instanceof Method method && method.getAccess().isPublic() && method.getContainingClass() != null) { int found = 0; @@ -130,7 +134,7 @@ private void visitPhp(@NotNull StringLiteralExpression element) { for (Method ownMethod : method.getContainingClass().getOwnMethods()) { PhpDocCommentAnnotation phpClassContainer = AnnotationUtil.getPhpDocCommentAnnotationContainer(ownMethod.getDocComment()); if(phpClassContainer != null) { - PhpDocTagAnnotation firstPhpDocBlock = phpClassContainer.getFirstPhpDocBlock(RouteHelper.ROUTE_CLASSES.toArray(String[]::new)); + PhpDocTagAnnotation firstPhpDocBlock = phpClassContainer.getFirstPhpDocBlock(RouteHelper.ROUTE_ANNOTATIONS); if(firstPhpDocBlock != null) { String name = firstPhpDocBlock.getPropertyValue("name"); if (contents.equals(name)) { diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java index bf2d9d39a..bf79834dd 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java @@ -812,6 +812,10 @@ public static boolean isInstanceOf(@NotNull PhpClass subjectClass, @NotNull Stri return false; } + public static boolean isInstanceOf(@NotNull PhpClass subjectClass, @NotNull String ...expectedClassAsString) { + return Arrays.stream(expectedClassAsString).anyMatch(clazz -> isInstanceOf(subjectClass, clazz)); + } + /** * @param subjectClassAsString eg DateTime * @param expectedClass eg DateTimeInterface