From 97cb1bc45969d0373962310bf7f1e0ce46ed2338 Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Thu, 2 Apr 2026 19:46:55 +0200 Subject: [PATCH] Refactor annotation patterns to static constants for performance --- .../AnnotationCompletionContributor.java | 6 +- .../DoctrineAddRepositoryGenerateAction.java | 11 +- .../action/DoctrineClassGeneratorAction.java | 9 +- ...nePropertyOrmAnnotationGenerateAction.java | 6 +- .../DoctrineTypeDeprecatedInspection.java | 7 +- .../AnnotationGoToDeclarationHandler.java | 13 +- .../AnnotationUsageLineMarkerProvider.java | 7 +- .../annotation/pattern/AnnotationPattern.java | 345 +++++++++++------- ...tionPropertyValueReferenceContributor.java | 6 +- .../toolbox/PropertyRegistrarMatcher.java | 7 +- .../php/annotation/util/AnnotationUtil.java | 9 +- .../php/annotation/util/PhpElementsUtil.java | 24 +- 12 files changed, 291 insertions(+), 159 deletions(-) diff --git a/src/main/java/de/espend/idea/php/annotation/completion/AnnotationCompletionContributor.java b/src/main/java/de/espend/idea/php/annotation/completion/AnnotationCompletionContributor.java index a2e44529..f76daca8 100644 --- a/src/main/java/de/espend/idea/php/annotation/completion/AnnotationCompletionContributor.java +++ b/src/main/java/de/espend/idea/php/annotation/completion/AnnotationCompletionContributor.java @@ -3,6 +3,7 @@ import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.project.Project; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiWhiteSpace; @@ -46,6 +47,9 @@ */ public class AnnotationCompletionContributor extends CompletionContributor { + private static final ElementPattern DOC_IDENTIFIER_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER); + public AnnotationCompletionContributor() { // @ @@ -309,7 +313,7 @@ protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull return; } - PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(phpDocString, PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER)); + PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(phpDocString, DOC_IDENTIFIER_PATTERN); if(propertyName == null) { return; } diff --git a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineAddRepositoryGenerateAction.java b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineAddRepositoryGenerateAction.java index 58154fa9..3b57deea 100644 --- a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineAddRepositoryGenerateAction.java +++ b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineAddRepositoryGenerateAction.java @@ -4,6 +4,7 @@ import com.intellij.codeInsight.actions.CodeInsightAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -19,6 +20,12 @@ * @author Daniel Espendiller */ public class DoctrineAddRepositoryGenerateAction extends CodeInsightAction { + + private static final ElementPattern INSIDE_PHP_CLASS_PATTERN = + PlatformPatterns.psiElement().inside(PhpClass.class); + private static final ElementPattern INSIDE_PHP_DOC_COMMENT_PATTERN = + PlatformPatterns.psiElement().inside(PhpDocComment.class); + @NotNull @Override protected CodeInsightActionHandler getHandler() { @@ -63,12 +70,12 @@ private static PhpClass getPhpClassOnValidScope(@NotNull Editor editor, @NotNull } // attribute and direct hit - if (PlatformPatterns.psiElement().inside(PhpClass.class).accepts(psiElement)) { + if (INSIDE_PHP_CLASS_PATTERN.accepts(psiElement)) { return PsiTreeUtil.getParentOfType(psiElement, PhpClass.class); } // docblock are outside the phpclass scope - if (PlatformPatterns.psiElement().inside(PhpDocComment.class).accepts(psiElement)) { + if (INSIDE_PHP_DOC_COMMENT_PATTERN.accepts(psiElement)) { PhpDocComment parentOfType = PsiTreeUtil.getParentOfType(psiElement, PhpDocComment.class); if (parentOfType != null) { PhpPsiElement nextPsiSibling = parentOfType.getNextPsiSibling(); diff --git a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineClassGeneratorAction.java b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineClassGeneratorAction.java index 8e7f27e8..e1c0b831 100644 --- a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineClassGeneratorAction.java +++ b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrineClassGeneratorAction.java @@ -4,6 +4,7 @@ import com.intellij.codeInsight.actions.CodeInsightAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -21,6 +22,10 @@ * @author Daniel Espendiller */ abstract public class DoctrineClassGeneratorAction extends CodeInsightAction { + + private static final ElementPattern INSIDE_PHP_CLASS_PATTERN = + PlatformPatterns.psiElement().inside(PhpClass.class); + @Override protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (!(file instanceof PhpFile) || !DoctrineUtil.isDoctrineOrmInVendor(project)) { @@ -37,7 +42,7 @@ protected boolean isValidForFile(@NotNull Project project, @NotNull Editor edito return false; } - if (!PlatformPatterns.psiElement().inside(PhpClass.class).accepts(psiElement)) { + if (!INSIDE_PHP_CLASS_PATTERN.accepts(psiElement)) { return false; } @@ -76,7 +81,7 @@ public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Ps return; } - if(!PlatformPatterns.psiElement().inside(PhpClass.class).accepts(psiElement)) { + if(!INSIDE_PHP_CLASS_PATTERN.accepts(psiElement)) { return; } diff --git a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrinePropertyOrmAnnotationGenerateAction.java b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrinePropertyOrmAnnotationGenerateAction.java index 7150ed20..f755c827 100644 --- a/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrinePropertyOrmAnnotationGenerateAction.java +++ b/src/main/java/de/espend/idea/php/annotation/doctrine/action/DoctrinePropertyOrmAnnotationGenerateAction.java @@ -4,6 +4,7 @@ import com.intellij.codeInsight.actions.CodeInsightAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -22,6 +23,9 @@ */ public class DoctrinePropertyOrmAnnotationGenerateAction extends CodeInsightAction { + private static final ElementPattern INSIDE_PHP_CLASS_PATTERN = + PlatformPatterns.psiElement().inside(PhpClass.class); + private final PhpGenerateFieldAccessorHandlerBase myHandler = new PhpGenerateFieldAccessorHandlerBase() { @@ -78,7 +82,7 @@ protected boolean isValidForFile(@NotNull Project project, @NotNull Editor edito return false; } - if (!PlatformPatterns.psiElement().inside(PhpClass.class).accepts(psiElement)) { + if (!INSIDE_PHP_CLASS_PATTERN.accepts(psiElement)) { return false; } diff --git a/src/main/java/de/espend/idea/php/annotation/doctrine/inspection/DoctrineTypeDeprecatedInspection.java b/src/main/java/de/espend/idea/php/annotation/doctrine/inspection/DoctrineTypeDeprecatedInspection.java index c0c52824..45185ef2 100644 --- a/src/main/java/de/espend/idea/php/annotation/doctrine/inspection/DoctrineTypeDeprecatedInspection.java +++ b/src/main/java/de/espend/idea/php/annotation/doctrine/inspection/DoctrineTypeDeprecatedInspection.java @@ -3,6 +3,7 @@ import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; @@ -34,6 +35,10 @@ * @author Daniel Espendiller */ public class DoctrineTypeDeprecatedInspection extends LocalInspectionTool { + + private static final ElementPattern DOC_IDENTIFIER_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER); + @NotNull @Override public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) { @@ -87,7 +92,7 @@ private static String getContentIfTypeValid(@NotNull StringLiteralExpression str } } } else if (stringLiteralExpression.getNode().getElementType() == PhpDocElementTypes.phpDocString) { - PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(stringLiteralExpression, PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER)); + PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(stringLiteralExpression, DOC_IDENTIFIER_PATTERN); if (propertyName != null && property.equals(propertyName.getText())) { PhpDocTag phpDocTag = PsiTreeUtil.getParentOfType(stringLiteralExpression, PhpDocTag.class); if (phpDocTag != null) { diff --git a/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationGoToDeclarationHandler.java b/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationGoToDeclarationHandler.java index df913e26..508aa202 100644 --- a/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationGoToDeclarationHandler.java +++ b/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationGoToDeclarationHandler.java @@ -3,6 +3,7 @@ import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.PsiElement; @@ -31,6 +32,14 @@ */ public class AnnotationGoToDeclarationHandler implements GotoDeclarationHandler { + // <@Test>, <@Test\Test> + private static final ElementPattern DOC_TAG_NAME_PATTERN = + PlatformPatterns.psiElement(PhpDocElementTypes.DOC_TAG_NAME).withText(StandardPatterns.string().startsWith("@")).withLanguage(PhpLanguage.INSTANCE); + + // @Route(name=::FOO) + private static final ElementPattern DOC_IDENTIFIER_BEFORE_STATIC_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).beforeLeaf(AnnotationPattern.getDocStaticPattern()).withLanguage(PhpLanguage.INSTANCE); + @Nullable @Override public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Editor editor) { @@ -42,12 +51,12 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Edit // <@Test> // <@Test\Test> - if (PlatformPatterns.psiElement(PhpDocElementTypes.DOC_TAG_NAME).withText(StandardPatterns.string().startsWith("@")).withLanguage(PhpLanguage.INSTANCE).accepts(psiElement)) { + if (DOC_TAG_NAME_PATTERN.accepts(psiElement)) { this.addDocTagNameGoto(psiElement, psiElements); } // @Route(name=::FOO) - if (PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).beforeLeaf(AnnotationPattern.getDocStaticPattern()).withLanguage(PhpLanguage.INSTANCE).accepts(psiElement)) { + if (DOC_IDENTIFIER_BEFORE_STATIC_PATTERN.accepts(psiElement)) { this.addStaticClassTargets(psiElement, psiElements); } diff --git a/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationUsageLineMarkerProvider.java b/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationUsageLineMarkerProvider.java index 9ac7ba48..6b13e989 100644 --- a/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationUsageLineMarkerProvider.java +++ b/src/main/java/de/espend/idea/php/annotation/navigation/AnnotationUsageLineMarkerProvider.java @@ -79,8 +79,8 @@ public void collectSlowLineMarkers(@NotNull List psiElemen /** * class "Foo" extends */ - private static PsiElementPattern.Capture getClassNamePattern() { - return PlatformPatterns + private static final PsiElementPattern.Capture CLASS_NAME_PATTERN = + PlatformPatterns .psiElement(PhpTokenTypes.IDENTIFIER) .afterLeafSkipping( PlatformPatterns.psiElement(PsiWhiteSpace.class), @@ -88,5 +88,8 @@ private static PsiElementPattern.Capture getClassNamePattern() { ) .withParent(PhpClass.class) .withLanguage(PhpLanguage.INSTANCE); + + private static PsiElementPattern.Capture getClassNamePattern() { + return CLASS_NAME_PATTERN; } } \ No newline at end of file diff --git a/src/main/java/de/espend/idea/php/annotation/pattern/AnnotationPattern.java b/src/main/java/de/espend/idea/php/annotation/pattern/AnnotationPattern.java index 43a8061f..ae75b5da 100644 --- a/src/main/java/de/espend/idea/php/annotation/pattern/AnnotationPattern.java +++ b/src/main/java/de/espend/idea/php/annotation/pattern/AnnotationPattern.java @@ -22,30 +22,36 @@ * @author Daniel Espendiller */ public class AnnotationPattern { - public static ElementPattern getDocBlockTagAfterBackslash() { - return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TAG_NAME); - } - public static ElementPattern getDocBlockTag() { - return - PlatformPatterns.or( - PlatformPatterns.psiElement() - .withSuperParent(1, PhpDocPsiElement.class) - .withParent(PhpDocComment.class) + private static final ElementPattern DOC_BLOCK_TAG_AFTER_BACKSLASH = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TAG_NAME); + + private static final ElementPattern DOC_BLOCK_TAG = + PlatformPatterns.or( + PlatformPatterns.psiElement() + .withSuperParent(1, PhpDocPsiElement.class) + .withParent(PhpDocComment.class) .withLanguage(PhpLanguage.INSTANCE) - , - // all "@" - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TAG_NAME) - .withLanguage(PhpLanguage.INSTANCE) - ); - } + , + // all "@" + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TAG_NAME) + .withLanguage(PhpLanguage.INSTANCE) + ); - public static ElementPattern getAttributeNamePattern() { - return PlatformPatterns.psiElement(PhpTokenTypes.IDENTIFIER) + private static final ElementPattern ATTRIBUTE_NAME_PATTERN = + PlatformPatterns.psiElement(PhpTokenTypes.IDENTIFIER) .withParent( PlatformPatterns.psiElement(ClassReference.class).withParent(PhpAttribute.class) ); - } + + private static final ElementPattern DOC_STATIC_PATTERN = + PlatformPatterns.or( + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STATIC), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("::") // array lexer workaround having text element in array; WI-32801 + ); + + private static final ElementPattern CLASS_CONSTANT = + PlatformPatterns.psiElement().afterLeaf(DOC_STATIC_PATTERN).withLanguage(PhpLanguage.INSTANCE); /** * fire on: @Callback(), @Callback("", ) @@ -55,8 +61,8 @@ public static ElementPattern getAttributeNamePattern() { * * On nested docs WHITESPACE is DOC_TEXT */ - public static ElementPattern getDocAttribute() { - return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER) + private static final ElementPattern DOC_ATTRIBUTE = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER) .afterLeafSkipping( PlatformPatterns.or( PlatformPatterns.psiElement(PsiWhiteSpace.class), @@ -79,20 +85,18 @@ public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext process .psiElement(PhpDocStubElementTypes.phpDocTag) ) .withLanguage(PhpLanguage.INSTANCE); - } - public static ElementPattern getPossibleDocTag() { - return PlatformPatterns.psiElement() + private static final ElementPattern POSSIBLE_DOC_TAG = + PlatformPatterns.psiElement() .withSuperParent(1, PhpDocPsiElement.class) .withParent(PhpDocComment.class) .withLanguage(PhpLanguage.INSTANCE); - } /** * matches "@Callback(property="")" */ - public static ElementPattern getTextIdentifier() { - return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STRING) + private static final ElementPattern TEXT_IDENTIFIER = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STRING) .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) .afterLeafSkipping( PlatformPatterns.or( @@ -108,40 +112,12 @@ public static ElementPattern getTextIdentifier() { ) ) ); - } - - /** - * matches "@Callback(=)" - */ - public static ElementPattern getPropertyIdentifier(String propertyName) { - return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).withText(propertyName) - .beforeLeafSkipping( - PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=") - ) - .withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)); - } - - /** - * matches "@Callback(propertyName="")" - */ - public static PsiElementPattern.Capture getPropertyIdentifierValue(String propertyName) { - return PlatformPatterns.psiElement(StringLiteralExpression.class) - .afterLeafSkipping( - PlatformPatterns.or( - PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=") - ), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).withText(propertyName) - ) - .withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)); - } /** * matches "@Callback("", foo...)" */ - public static PsiElementPattern.Capture getDefaultPropertyValue() { - return PlatformPatterns + private static final PsiElementPattern.Capture DEFAULT_PROPERTY_VALUE = + PlatformPatterns .psiElement(PhpDocTokenTypes.DOC_STRING) .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class).withParent(PlatformPatterns .psiElement(PhpDocElementTypes.phpDocAttributeList) @@ -150,14 +126,12 @@ public static PsiElementPattern.Capture getDefaultPropertyValue() { ) )) .withLanguage(PhpLanguage.INSTANCE); - } /** * only usable up to phpstorm 7 */ - public static ElementPattern getDefaultPropertyValueString() { - - return PlatformPatterns + private static final ElementPattern DEFAULT_PROPERTY_VALUE_STRING = + PlatformPatterns .psiElement(StringLiteralExpression.class).afterLeaf( PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_LPAREN) ) @@ -168,14 +142,12 @@ public static ElementPattern getDefaultPropertyValueStr ) ) .withLanguage(PhpLanguage.INSTANCE); - } /** * only usable up to phpstorm 7 */ - public static ElementPattern getPropertyValueString() { - - return PlatformPatterns + private static final ElementPattern PROPERTY_VALUE_STRING = + PlatformPatterns .psiElement(StringLiteralExpression.class).afterLeaf( PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=") ) @@ -187,32 +159,86 @@ public static ElementPattern getPropertyValueString() { ) .withLanguage(PhpLanguage.INSTANCE); - } + private static final PatternCondition WHITE_SPACE_AS_TEXT_CONDITION = new PatternCondition("Whitespace as DOC_TEXT fix") { + @Override + public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext processingContext) { + return psiElement.getNode().getElementType() == PhpDocTokenTypes.DOC_TEXT && StringUtils.isBlank(psiElement.getText()); + } + }; /** - * Pattern for @Foo(Foo::), @Foo(name=Foo::) + * Route("/", methods={"", "POST"}) + * Route("/", methods={"GET", ""}) */ - public static ElementPattern getClassConstant() { - return PlatformPatterns.psiElement().afterLeaf(getDocStaticPattern()).withLanguage(PhpLanguage.INSTANCE); - } + private static final ElementPattern PROPERTY_ARRAY_PATTERN = buildPropertyArrayPattern(); /** - * Pattern @Foo(Foo::), @Foo(name=Foo::) + * #[Route('/path', name: 'action', methods: ['test'])] */ - @NotNull - public static ElementPattern getDocStaticPattern() { - return PlatformPatterns.or( - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STATIC), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("::") // array lexer workaround having text element in array; WI-32801 - ); - } + private static final ElementPattern ATTRIBUTES_ARRAY_PATTERN = + PlatformPatterns.psiElement() + .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) + .withParent(PlatformPatterns.psiElement(PhpPsiElement.class) + .withParent(PlatformPatterns.psiElement(ArrayCreationExpression.class).afterLeafSkipping( + PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) + .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) + ) + ))); + + /** + * #[Route('/path', name: '')] + */ + private static final PsiElementPattern.Capture ATTRIBUTES_VALUE_REFERENCES_PATTERN = + PlatformPatterns.psiElement(StringLiteralExpression.class) + .afterLeafSkipping( + PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) + .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) + ).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class)); + + /** + * #[Route('/path', name: '')] + * @return + */ + private static final PsiElementPattern.Capture ATTRIBUTES_VALUE_PATTERN = + PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) + .afterLeafSkipping( + PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) + .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) + ).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class))); + + /** + * #[Route('/path', name: '')] + */ + private static final PsiElementPattern.Capture ATTRIBUTES_DEFAULT_PATTERN = + PlatformPatterns.psiElement(StringLiteralExpression.class).with(new PatternCondition<>("default attribute value") { + @Override + public boolean accepts(@NotNull StringLiteralExpression stringLiteralExpression, ProcessingContext processingContext) { + return stringLiteralExpression.getPrevSibling() == null; + } + }).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class)); /** + * Get property of enum array eg "methods" + * * Route("/", methods={"", "POST"}) * Route("/", methods={"GET", ""}) */ - public static ElementPattern getPropertyArrayPattern() { + private static final ElementPattern PROPERTY_NAME_OF_ARRAY_VALUE_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).beforeLeafSkipping( + PlatformPatterns.or( + PlatformPatterns.psiElement(PsiWhiteSpace.class), + PlatformPatterns.psiElement().with(WHITE_SPACE_AS_TEXT_CONDITION) + ), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=").beforeLeafSkipping( + PlatformPatterns.or( + PlatformPatterns.psiElement(PsiWhiteSpace.class), + PlatformPatterns.psiElement().with(WHITE_SPACE_AS_TEXT_CONDITION) + ), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_LBRACE) + ) + ); + private static ElementPattern buildPropertyArrayPattern() { // "methods={" PsiElementPattern.Capture propertyPattern = PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_LBRACE) .afterLeafSkipping( @@ -232,7 +258,7 @@ public static ElementPattern getPropertyArrayPattern() { .afterLeafSkipping( PlatformPatterns.or( PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement().with(new MyWhiteSpaceAsTextPatternCondition()) + PlatformPatterns.psiElement().with(WHITE_SPACE_AS_TEXT_CONDITION) ), propertyPattern ), @@ -242,12 +268,12 @@ public static ElementPattern getPropertyArrayPattern() { .afterLeafSkipping( PlatformPatterns.or( PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement().with(new MyWhiteSpaceAsTextPatternCondition()) + PlatformPatterns.psiElement().with(WHITE_SPACE_AS_TEXT_CONDITION) ), PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_COMMA).afterLeafSkipping( PlatformPatterns.or( PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement().with(new MyWhiteSpaceAsTextPatternCondition()), + PlatformPatterns.psiElement().with(WHITE_SPACE_AS_TEXT_CONDITION), PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STRING), PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_COMMA) ), @@ -257,29 +283,116 @@ public static ElementPattern getPropertyArrayPattern() { ); } + public static ElementPattern getDocBlockTagAfterBackslash() { + return DOC_BLOCK_TAG_AFTER_BACKSLASH; + } + + public static ElementPattern getDocBlockTag() { + return DOC_BLOCK_TAG; + } + + public static ElementPattern getAttributeNamePattern() { + return ATTRIBUTE_NAME_PATTERN; + } + + public static ElementPattern getDocAttribute() { + return DOC_ATTRIBUTE; + } + + public static ElementPattern getPossibleDocTag() { + return POSSIBLE_DOC_TAG; + } + + /** + * matches "@Callback(property="")" + */ + public static ElementPattern getTextIdentifier() { + return TEXT_IDENTIFIER; + } + + /** + * matches "@Callback(=)" + */ + public static ElementPattern getPropertyIdentifier(String propertyName) { + return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).withText(propertyName) + .beforeLeafSkipping( + PlatformPatterns.psiElement(PsiWhiteSpace.class), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=") + ) + .withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)); + } + + /** + * matches "@Callback(propertyName="")" + */ + public static PsiElementPattern.Capture getPropertyIdentifierValue(String propertyName) { + return PlatformPatterns.psiElement(StringLiteralExpression.class) + .afterLeafSkipping( + PlatformPatterns.or( + PlatformPatterns.psiElement(PsiWhiteSpace.class), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=") + ), + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).withText(propertyName) + ) + .withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)); + } + + /** + * matches "@Callback("", foo...)" + */ + public static PsiElementPattern.Capture getDefaultPropertyValue() { + return DEFAULT_PROPERTY_VALUE; + } + + /** + * only usable up to phpstorm 7 + */ + public static ElementPattern getDefaultPropertyValueString() { + return DEFAULT_PROPERTY_VALUE_STRING; + } + + /** + * only usable up to phpstorm 7 + */ + public static ElementPattern getPropertyValueString() { + return PROPERTY_VALUE_STRING; + } + + /** + * Pattern for @Foo(Foo::), @Foo(name=Foo::) + */ + public static ElementPattern getClassConstant() { + return CLASS_CONSTANT; + } + + /** + * Pattern @Foo(Foo::), @Foo(name=Foo::) + */ + @NotNull + public static ElementPattern getDocStaticPattern() { + return DOC_STATIC_PATTERN; + } + + /** + * Route("/", methods={"", "POST"}) + * Route("/", methods={"GET", ""}) + */ + public static ElementPattern getPropertyArrayPattern() { + return PROPERTY_ARRAY_PATTERN; + } + /** * #[Route('/path', name: 'action', methods: ['test'])] */ public static ElementPattern getAttributesArrayPattern() { - return PlatformPatterns.psiElement() - .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) - .withParent(PlatformPatterns.psiElement(PhpPsiElement.class) - .withParent(PlatformPatterns.psiElement(ArrayCreationExpression.class).afterLeafSkipping( - PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) - .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) - ) - ))); + return ATTRIBUTES_ARRAY_PATTERN; } /** * #[Route('/path', name: '')] */ public static PsiElementPattern.Capture getAttributesValueReferencesPattern() { - return PlatformPatterns.psiElement(StringLiteralExpression.class) - .afterLeafSkipping( - PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) - .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) - ).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class)); + return ATTRIBUTES_VALUE_REFERENCES_PATTERN; } /** @@ -287,24 +400,16 @@ public static PsiElementPattern.Capture getAttributesVa * @return */ public static PsiElementPattern.@NotNull Capture getAttributesValuePattern() { - return PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) - .afterLeafSkipping( - PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.opCOLON) - .afterLeafSkipping(PlatformPatterns.psiElement(PsiWhiteSpace.class), PlatformPatterns.psiElement().withElementType(PhpTokenTypes.IDENTIFIER)) - ).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class))); + return ATTRIBUTES_VALUE_PATTERN; } /** * #[Route('/path', name: '')] */ public static PsiElementPattern.Capture getAttributesDefaultPattern() { - return PlatformPatterns.psiElement(StringLiteralExpression.class).with(new PatternCondition<>("default attribute value") { - @Override - public boolean accepts(@NotNull StringLiteralExpression stringLiteralExpression, ProcessingContext processingContext) { - return stringLiteralExpression.getPrevSibling() == null; - } - }).withParent(PlatformPatterns.psiElement(ParameterList.class).withParent(PhpAttribute.class)); + return ATTRIBUTES_DEFAULT_PATTERN; } + /** * Get property of enum array eg "methods" * @@ -312,34 +417,6 @@ public boolean accepts(@NotNull StringLiteralExpression stringLiteralExpression, * Route("/", methods={"GET", ""}) */ public static ElementPattern getPropertyNameOfArrayValuePattern() { - return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER).beforeLeafSkipping( - PlatformPatterns.or( - PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement().with(new MyWhiteSpaceAsTextPatternCondition()) - ), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=").beforeLeafSkipping( - PlatformPatterns.or( - PlatformPatterns.psiElement(PsiWhiteSpace.class), - PlatformPatterns.psiElement().with(new MyWhiteSpaceAsTextPatternCondition()) - ), - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_LBRACE) - ) - ); - } - - /** - * On array whitespace element is DOC_TEXT element - * - * Route("/", methods={ "GET", ""}) - */ - private static class MyWhiteSpaceAsTextPatternCondition extends PatternCondition { - public MyWhiteSpaceAsTextPatternCondition() { - super("Whitespace as DOC_TEXT fix"); - } - - @Override - public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext processingContext) { - return psiElement.getNode().getElementType() == PhpDocTokenTypes.DOC_TEXT && StringUtils.isBlank(psiElement.getText()); - } + return PROPERTY_NAME_OF_ARRAY_VALUE_PATTERN; } } diff --git a/src/main/java/de/espend/idea/php/annotation/reference/AnnotationPropertyValueReferenceContributor.java b/src/main/java/de/espend/idea/php/annotation/reference/AnnotationPropertyValueReferenceContributor.java index 2b332359..2ba1a43b 100644 --- a/src/main/java/de/espend/idea/php/annotation/reference/AnnotationPropertyValueReferenceContributor.java +++ b/src/main/java/de/espend/idea/php/annotation/reference/AnnotationPropertyValueReferenceContributor.java @@ -1,5 +1,6 @@ package de.espend.idea.php.annotation.reference; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -29,6 +30,9 @@ */ public class AnnotationPropertyValueReferenceContributor extends PsiReferenceContributor { + private static final ElementPattern DOC_IDENTIFIER_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER); + @Override public void registerReferenceProviders(@NotNull PsiReferenceRegistrar psiReferenceRegistrar) { psiReferenceRegistrar.registerReferenceProvider(AnnotationPattern.getDefaultPropertyValueString(), new PropertyValueDefaultReferences()); @@ -74,7 +78,7 @@ private class PropertyValueReferences extends PsiReferenceProvider { return new PsiReference[0]; } - PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(psiElement, PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER)); + PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(psiElement, DOC_IDENTIFIER_PATTERN); if(propertyName == null) { return new PsiReference[0]; } diff --git a/src/main/java/de/espend/idea/php/annotation/toolbox/PropertyRegistrarMatcher.java b/src/main/java/de/espend/idea/php/annotation/toolbox/PropertyRegistrarMatcher.java index c7a87744..943e690d 100644 --- a/src/main/java/de/espend/idea/php/annotation/toolbox/PropertyRegistrarMatcher.java +++ b/src/main/java/de/espend/idea/php/annotation/toolbox/PropertyRegistrarMatcher.java @@ -1,6 +1,7 @@ package de.espend.idea.php.annotation.toolbox; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; @@ -25,6 +26,10 @@ * @author Daniel Espendiller */ public class PropertyRegistrarMatcher implements LanguageRegistrarMatcherInterface { + + private static final ElementPattern DOC_IDENTIFIER_PATTERN = + PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER); + @Override public boolean matches(@NotNull LanguageMatcherParameter parameter) { @@ -48,7 +53,7 @@ public boolean matches(@NotNull LanguageMatcherParameter parameter) { PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch( phpDocString, - PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER) + DOC_IDENTIFIER_PATTERN ); if(propertyName == null) { diff --git a/src/main/java/de/espend/idea/php/annotation/util/AnnotationUtil.java b/src/main/java/de/espend/idea/php/annotation/util/AnnotationUtil.java index dfcdfbbc..62ad1236 100644 --- a/src/main/java/de/espend/idea/php/annotation/util/AnnotationUtil.java +++ b/src/main/java/de/espend/idea/php/annotation/util/AnnotationUtil.java @@ -531,8 +531,9 @@ public static String getPropertyValueOrDefault(@NotNull PhpDocTag phpDocTag, @No } // @Template(template="foobar.html.twig") + PsiElementPattern.Capture propertyPattern = getPropertyIdentifierValue(property); PsiElement psiProperty = Arrays.stream(attributeList.getChildren()) - .filter(psiElement1 -> getPropertyIdentifierValue(property).accepts(psiElement1)) + .filter(psiElement1 -> propertyPattern.accepts(psiElement1)) .findFirst() .orElse(null); @@ -612,8 +613,9 @@ public static StringLiteralExpression getPropertyValueAsPsiElement(@NotNull PhpD return null; } + PsiElementPattern.Capture propertyPattern = getPropertyIdentifierValue(property); PsiElement psiProperty = Arrays.stream(attributeList.getChildren()) - .filter(psiElement1 -> getPropertyIdentifierValue(property).accepts(psiElement1)) + .filter(psiElement1 -> propertyPattern.accepts(psiElement1)) .findFirst() .orElse(null); @@ -639,8 +641,9 @@ public static PsiElement getPropertyValueAsElement(@NotNull PhpDocTag phpDocTag, return null; } + PsiElementPattern.Capture propertyPattern = getPropertyIdentifierValueAsPsiElement(property); return Arrays.stream(attributeList.getChildren()) - .filter(psiElement1 -> getPropertyIdentifierValueAsPsiElement(property).accepts(psiElement1)) + .filter(psiElement1 -> propertyPattern.accepts(psiElement1)) .findFirst() .orElse(null); } diff --git a/src/main/java/de/espend/idea/php/annotation/util/PhpElementsUtil.java b/src/main/java/de/espend/idea/php/annotation/util/PhpElementsUtil.java index c2fb607e..7d58dce6 100644 --- a/src/main/java/de/espend/idea/php/annotation/util/PhpElementsUtil.java +++ b/src/main/java/de/espend/idea/php/annotation/util/PhpElementsUtil.java @@ -33,6 +33,19 @@ */ public class PhpElementsUtil { + private static final ElementPattern CLASS_FIELDS_PATTERN = + PlatformPatterns.psiElement(PhpElementTypes.CLASS_FIELDS); + + private static final ElementPattern METHOD_RETURN_PATTERN = + PlatformPatterns.or( + PlatformPatterns.psiElement(StringLiteralExpression.class) + .withParent(PlatformPatterns.psiElement(PhpReturn.class).inside(Method.class)) + .withLanguage(PhpLanguage.INSTANCE), + PlatformPatterns.psiElement(ClassConstantReference.class) + .withParent(PlatformPatterns.psiElement(PhpReturn.class).inside(Method.class)) + .withLanguage(PhpLanguage.INSTANCE) + ); + @Nullable static public PhpClass getClass(Project project, String className) { Collection classes = PhpIndex.getInstance(project).getClassesByFQN(className); @@ -49,7 +62,7 @@ static public AnnotationTarget findAnnotationTarget(@Nullable PhpDocComment phpD return AnnotationTarget.METHOD; } - if(PlatformPatterns.psiElement(PhpElementTypes.CLASS_FIELDS).accepts(phpDocComment.getNextPsiSibling())) { + if(CLASS_FIELDS_PATTERN.accepts(phpDocComment.getNextPsiSibling())) { return AnnotationTarget.PROPERTY; } @@ -216,14 +229,7 @@ private static String getClassConstantPhpFqn(@NotNull ClassConstantReference cla * return 'value' inside class method */ static public ElementPattern getMethodReturnPattern() { - return PlatformPatterns.or( - PlatformPatterns.psiElement(StringLiteralExpression.class) - .withParent(PlatformPatterns.psiElement(PhpReturn.class).inside(Method.class)) - .withLanguage(PhpLanguage.INSTANCE), - PlatformPatterns.psiElement(ClassConstantReference.class) - .withParent(PlatformPatterns.psiElement(PhpReturn.class).inside(Method.class)) - .withLanguage(PhpLanguage.INSTANCE) - ); + return METHOD_RETURN_PATTERN; } /**