Skip to content

Commit 628922f

Browse files
authored
Merge pull request #1994 from Haehnchen/feature/1990-attribute-autoconfiure
#1991 support "tags" inside "Autoconfigure" attribute
2 parents 29fddd9 + ddfa69c commit 628922f

File tree

5 files changed

+127
-5
lines changed

5 files changed

+127
-5
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public class ServiceContainerUtil {
7474
public static final String TAGGED_ITERATOR_ATTRIBUTE_CLASS = "\\Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator";
7575
public static final String TAGGED_LOCATOR_ATTRIBUTE_CLASS = "\\Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator";
7676
public static final String DECORATOR_ATTRIBUTE_CLASS = "\\Symfony\\Component\\DependencyInjection\\Attribute\\AsDecorator";
77+
public static final String AUTOCONFIGURE_ATTRIBUTE_CLASS = "\\Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure";
7778

7879
@NotNull
7980
public static Collection<ServiceSerializable> getServicesInFile(@NotNull PsiFile psiFile) {

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/registrar/DicGotoCompletionRegistrar.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,42 @@ public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
8989
}
9090
);
9191

92-
// #[TaggedIterator('app.handler')] iterable $handlers
93-
// #[TaggedLocator('app.handler')] ContainerInterface $handlers
9492
registrar.register(
9593
PlatformPatterns.or(
94+
// #[TaggedIterator('app.handler')] iterable $handlers
95+
// #[TaggedIterator(tag: 'app.handler')] iterable $handlers
9696
PhpElementsUtil.getFirstAttributeStringPattern(ServiceContainerUtil.TAGGED_ITERATOR_ATTRIBUTE_CLASS),
9797
PhpElementsUtil.getAttributeNamedArgumentStringPattern(ServiceContainerUtil.TAGGED_ITERATOR_ATTRIBUTE_CLASS, "tag"),
98+
99+
// #[TaggedLocator('app.handler')] ContainerInterface $handlers
100+
// #[TaggedLocator(tag: 'app.handler')] ContainerInterface $handlers
98101
PhpElementsUtil.getFirstAttributeStringPattern(ServiceContainerUtil.TAGGED_LOCATOR_ATTRIBUTE_CLASS),
99-
PhpElementsUtil.getAttributeNamedArgumentStringPattern(ServiceContainerUtil.TAGGED_LOCATOR_ATTRIBUTE_CLASS, "tag")
102+
PhpElementsUtil.getAttributeNamedArgumentStringPattern(ServiceContainerUtil.TAGGED_LOCATOR_ATTRIBUTE_CLASS, "tag"),
103+
104+
// #[Autoconfigure(['app.some_tag'])]
105+
// #[Autoconfigure(tags: ['app.some_tag'])]
106+
PhpElementsUtil.getFirstAttributeArrayStringPattern(ServiceContainerUtil.AUTOCONFIGURE_ATTRIBUTE_CLASS),
107+
PhpElementsUtil.getAttributeNamedArgumentArrayStringPattern(ServiceContainerUtil.AUTOCONFIGURE_ATTRIBUTE_CLASS, "tags")
108+
), psiElement -> {
109+
PsiElement context = psiElement.getContext();
110+
if (!(context instanceof StringLiteralExpression)) {
111+
return null;
112+
}
113+
114+
PhpAttribute phpAttribute = PsiTreeUtil.getParentOfType(context, PhpAttribute.class);
115+
if (phpAttribute != null) {
116+
return new TaggedIteratorContributor((StringLiteralExpression) context);
117+
}
118+
119+
return null;
120+
}
121+
);
122+
123+
// #[Autoconfigure(tags: ['app.some_tag'])]
124+
// #[Autoconfigure(['app.some_tag'])]
125+
registrar.register(
126+
PlatformPatterns.or(
127+
100128
), psiElement -> {
101129
PsiElement context = psiElement.getContext();
102130
if (!(context instanceof StringLiteralExpression)) {

src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java

+49-2
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,9 @@ public boolean accepts(@NotNull FunctionReference functionReference, ProcessingC
382382
.withLanguage(PhpLanguage.INSTANCE);
383383
}
384384

385-
private static final PatternCondition<StringLiteralExpression> EMPTY_PREVIOUS_LEAF = new PatternCondition<>("previous leaf empty") {
385+
private static final PatternCondition<PsiElement> EMPTY_PREVIOUS_LEAF = new PatternCondition<>("previous leaf empty") {
386386
@Override
387-
public boolean accepts(@NotNull StringLiteralExpression stringLiteralExpression, ProcessingContext context) {
387+
public boolean accepts(@NotNull PsiElement stringLiteralExpression, ProcessingContext context) {
388388
return stringLiteralExpression.getPrevSibling() == null;
389389
}
390390
};
@@ -408,6 +408,26 @@ public static PsiElementPattern.Capture<PsiElement> getFirstAttributeStringPatte
408408
);
409409
}
410410

411+
/**
412+
* #[Security("is_granted(['POST_SHOW'])")]
413+
*/
414+
@NotNull
415+
public static PsiElementPattern.Capture<PsiElement> getFirstAttributeArrayStringPattern(@NotNull String clazz) {
416+
return PlatformPatterns.psiElement().withElementType(PlatformPatterns.elementType().or(
417+
PhpTokenTypes.STRING_LITERAL_SINGLE_QUOTE,
418+
PhpTokenTypes.STRING_LITERAL
419+
))
420+
.withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
421+
.withParent(PlatformPatterns.psiElement(PhpElementTypes.ARRAY_VALUE).withParent(
422+
PlatformPatterns.psiElement(ArrayCreationExpression.class).with(EMPTY_PREVIOUS_LEAF).withParent(PlatformPatterns.psiElement(ParameterList.class)
423+
.withParent(PlatformPatterns.psiElement(PhpAttribute.class)
424+
.with(new AttributeInstancePatternCondition(clazz))
425+
)
426+
)
427+
))
428+
);
429+
}
430+
411431
/**
412432
* #[Security(foobar: "is_granted('POST_SHOW')")]
413433
*/
@@ -433,6 +453,33 @@ public static PsiElementPattern.Capture<PsiElement> getAttributeNamedArgumentStr
433453
);
434454
}
435455

456+
/**
457+
* #[Security(tags: ['foobar']])]
458+
*/
459+
@NotNull
460+
public static PsiElementPattern.Capture<PsiElement> getAttributeNamedArgumentArrayStringPattern(@NotNull String clazz, @NotNull String namedArgument) {
461+
return PlatformPatterns.psiElement().withElementType(PlatformPatterns.elementType().or(
462+
PhpTokenTypes.STRING_LITERAL_SINGLE_QUOTE,
463+
PhpTokenTypes.STRING_LITERAL
464+
))
465+
.withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
466+
.withParent(PlatformPatterns.psiElement(PhpElementTypes.ARRAY_VALUE).withParent(
467+
PlatformPatterns.psiElement(ArrayCreationExpression.class).afterLeafSkipping(
468+
PlatformPatterns.psiElement(PsiWhiteSpace.class),
469+
PlatformPatterns.psiElement(PhpTokenTypes.opCOLON).afterLeafSkipping(
470+
PlatformPatterns.psiElement(PsiWhiteSpace.class),
471+
PlatformPatterns.psiElement(PhpTokenTypes.IDENTIFIER).withText(namedArgument)
472+
)
473+
)
474+
.withParent(PlatformPatterns.psiElement(ParameterList.class)
475+
.withParent(PlatformPatterns.psiElement(PhpAttribute.class)
476+
.with(new AttributeInstancePatternCondition(clazz))
477+
)
478+
)
479+
))
480+
);
481+
}
482+
436483
/**
437484
* Check if given Attribute
438485
*/

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/dic/registrar/DicGotoCompletionRegistrarTest.java

+30
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,34 @@ public void testServiceContributorDecoratesAttribute() {
258258
PlatformPatterns.psiElement()
259259
);
260260
}
261+
262+
public void testTagContributorForAutoconfigureTagsAttribute() {
263+
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
264+
"use Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure;\n" +
265+
"#[Autoconfigure(['<caret>'])]\n" +
266+
"class HandlerCollection {}",
267+
"yaml_type_tag"
268+
);
269+
270+
assertNavigationMatch(PhpFileType.INSTANCE, "<?php\n" +
271+
"use Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure;\n" +
272+
"#[Autoconfigure(['yaml_<caret>type_tag'])]\n" +
273+
"class HandlerCollection {}",
274+
PlatformPatterns.psiElement()
275+
);
276+
277+
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
278+
"use Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure;\n" +
279+
"#[Autoconfigure(tags: ['<caret>'])]\n" +
280+
"class HandlerCollection {}",
281+
"yaml_type_tag"
282+
);
283+
284+
assertNavigationMatch(PhpFileType.INSTANCE, "<?php\n" +
285+
"use Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure;\n" +
286+
"#[Autoconfigure(tags: ['yaml_<caret>type_tag'])]\n" +
287+
"class HandlerCollection {}",
288+
PlatformPatterns.psiElement()
289+
);
290+
}
261291
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/dic/registrar/fixtures/classes.php

+16
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ public function __construct(
5757
) {
5858
}
5959
}
60+
61+
class Autoconfigure
62+
{
63+
public function __construct(
64+
public ?array $tags = null,
65+
public ?array $calls = null,
66+
public ?array $bind = null,
67+
public bool|string|null $lazy = null,
68+
public ?bool $public = null,
69+
public ?bool $shared = null,
70+
public ?bool $autowire = null,
71+
public ?array $properties = null,
72+
public array|string|null $configurator = null,
73+
) {
74+
}
75+
}
6076
}
6177

6278
namespace

0 commit comments

Comments
 (0)