11package fr .adrienbrault .idea .symfony2plugin .templating .util ;
22
3+ import com .intellij .openapi .project .Project ;
34import com .intellij .openapi .util .Pair ;
45import com .intellij .psi .PsiElement ;
56import com .intellij .psi .PsiRecursiveElementWalkingVisitor ;
@@ -259,7 +260,7 @@ public static void visitRenderTemplateFunctions(@NotNull PsiElement context, @No
259260 context .accept (new TemplateRenderPsiRecursiveElementWalkingVisitor (context , consumer ));
260261 }
261262
262- private static class TemplateRenderPsiRecursiveElementWalkingVisitor extends PsiRecursiveElementWalkingVisitor {
263+ public static class TemplateRenderPsiRecursiveElementWalkingVisitor extends PsiRecursiveElementWalkingVisitor {
263264 private final PsiElement context ;
264265 private final Consumer <Triple <String , PhpNamedElement , FunctionReference >> consumer ;
265266 private Set <String > methods ;
@@ -283,24 +284,23 @@ public void visitElement(@NotNull PsiElement element) {
283284 }
284285
285286 private void visitPhpAttribute (@ NotNull PhpAttributesList phpAttributesList ) {
286- Collection <@ NotNull PhpAttribute > attributes = phpAttributesList .getAttributes (TwigUtil .TEMPLATE_ANNOTATION_CLASS );
287+ if (phpAttributesList .getParent () instanceof Method method ) {
288+ processMethodAttributes (method , consumer );
289+ }
290+ }
291+
292+ public static void processMethodAttributes (@ NotNull Method method , Consumer <Triple <String , PhpNamedElement , FunctionReference >> consumer ) {
293+ Collection <@ NotNull PhpAttribute > attributes = method .getAttributes (TwigUtil .TEMPLATE_ANNOTATION_CLASS );
287294 for (PhpAttribute attribute : attributes ) {
288295 if (attribute .getArguments ().isEmpty ()) {
289296 // #[@Template()]
290- PsiElement parent = phpAttributesList .getParent ();
291- if (parent instanceof Method ) {
292- visitMethodForGuessing ((Method ) parent );
293- }
297+ visitMethodForGuessing (method , consumer );
294298 } else {
295299 // [@Template("foobar.html.twig")]
296300 // #[@Template(template: "foobar.html.twig")]
297301 String template = PhpPsiAttributesUtil .getAttributeValueByNameAsStringWithDefaultParameterFallback (attribute , "template" );
298302 if (StringUtils .isNotBlank (template )) {
299- PsiElement parent = phpAttributesList .getParent ();
300- if (parent instanceof Method ) {
301- addTemplateWithScope (template , (Method ) parent , null );
302-
303- }
303+ addTemplateWithScope (template , method , null , consumer );
304304 }
305305 }
306306 }
@@ -314,17 +314,32 @@ private void visitMethodReference(@NotNull MethodReference methodReference) {
314314
315315 // init methods once per file
316316 if (methods == null ) {
317- methods = new HashSet <>();
317+ methods = collectMethods (context .getProject ());
318+ }
318319
319- PluginConfigurationExtension [] extensions = Symfony2ProjectComponent . PLUGIN_CONFIGURATION_EXTENSION . getExtensions ( );
320- if ( extensions . length > 0 ) {
321- PluginConfigurationExtensionParameter pluginConfiguration = new PluginConfigurationExtensionParameter ( context . getProject ());
322- for ( PluginConfigurationExtension extension : extensions ) {
323- extension . invokePluginConfiguration ( pluginConfiguration );
324- }
320+ processMethodReference ( methodReference , methods , consumer );
321+ }
322+
323+ @ NotNull
324+ public static Set < String > collectMethods ( Project project ) {
325+ Set < String > methods = new HashSet <>();
325326
326- methods .addAll (pluginConfiguration .getTemplateUsageMethod ());
327+ PluginConfigurationExtension [] extensions = Symfony2ProjectComponent .PLUGIN_CONFIGURATION_EXTENSION .getExtensions ();
328+ if (extensions .length > 0 ) {
329+ PluginConfigurationExtensionParameter pluginConfiguration = new PluginConfigurationExtensionParameter (project );
330+ for (PluginConfigurationExtension extension : extensions ) {
331+ extension .invokePluginConfiguration (pluginConfiguration );
327332 }
333+
334+ methods .addAll (pluginConfiguration .getTemplateUsageMethod ());
335+ }
336+ return methods ;
337+ }
338+
339+ public static void processMethodReference (@ NotNull MethodReference methodReference , Set <String > methods , Consumer <Triple <String , PhpNamedElement , FunctionReference >> consumer ) {
340+ String methodName = methodReference .getName ();
341+ if (methodName == null ) {
342+ return ;
328343 }
329344
330345 if (!methods .contains (methodName ) && !methodName .toLowerCase ().contains ("render" )) {
@@ -337,7 +352,7 @@ private void visitMethodReference(@NotNull MethodReference methodReference) {
337352 }
338353
339354 if (parameters [0 ] instanceof StringLiteralExpression ) {
340- addStringLiteralScope (methodReference , (StringLiteralExpression ) parameters [0 ]);
355+ addStringLiteralScope (methodReference , (StringLiteralExpression ) parameters [0 ], consumer );
341356 } else if (parameters [0 ] instanceof TernaryExpression ) {
342357 // render(true === true ? 'foo.twig.html' : 'foobar.twig.html')
343358 for (PhpPsiElement phpPsiElement : new PhpPsiElement []{((TernaryExpression ) parameters [0 ]).getTrueVariant (), ((TernaryExpression ) parameters [0 ]).getFalseVariant ()}) {
@@ -346,60 +361,60 @@ private void visitMethodReference(@NotNull MethodReference methodReference) {
346361 }
347362
348363 if (phpPsiElement instanceof StringLiteralExpression ) {
349- addStringLiteralScope (methodReference , (StringLiteralExpression ) phpPsiElement );
364+ addStringLiteralScope (methodReference , (StringLiteralExpression ) phpPsiElement , consumer );
350365 } else if (phpPsiElement instanceof PhpReference ) {
351- resolvePhpReference (methodReference , phpPsiElement );
366+ resolvePhpReference (methodReference , phpPsiElement , consumer );
352367 }
353368 }
354369 } else if (parameters [0 ] instanceof AssignmentExpression ) {
355370 // $this->render($template = 'foo.html.twig')
356371 PhpPsiElement value = ((AssignmentExpression ) parameters [0 ]).getValue ();
357372 if (value instanceof StringLiteralExpression ) {
358- addStringLiteralScope (methodReference , (StringLiteralExpression ) value );
373+ addStringLiteralScope (methodReference , (StringLiteralExpression ) value , consumer );
359374 }
360375 } else if (parameters [0 ] instanceof PhpReference ) {
361- resolvePhpReference (methodReference , parameters [0 ]);
376+ resolvePhpReference (methodReference , parameters [0 ], consumer );
362377 } else if (parameters [0 ] instanceof BinaryExpression ) {
363378 // render($foo ?? 'foo.twig.html')
364379 PsiElement phpPsiElement = ((BinaryExpression ) parameters [0 ]).getRightOperand ();
365380
366381 if (phpPsiElement instanceof StringLiteralExpression ) {
367- addStringLiteralScope (methodReference , (StringLiteralExpression ) phpPsiElement );
382+ addStringLiteralScope (methodReference , (StringLiteralExpression ) phpPsiElement , consumer );
368383 } else if (phpPsiElement instanceof PhpReference ) {
369- resolvePhpReference (methodReference , phpPsiElement );
384+ resolvePhpReference (methodReference , phpPsiElement , consumer );
370385 }
371386 }
372387 }
373388
374- private void resolvePhpReference (@ NotNull MethodReference methodReference , PsiElement parameter ) {
389+ private static void resolvePhpReference (@ NotNull MethodReference methodReference , PsiElement parameter , Consumer < Triple < String , PhpNamedElement , FunctionReference >> consumer ) {
375390 for (PhpNamedElement phpNamedElement : ((PhpReference ) parameter ).resolveLocal ()) {
376391 // foo(self::foo)
377392 // foo($this->foo)
378393 if (phpNamedElement instanceof Field ) {
379394 PsiElement defaultValue = ((Field ) phpNamedElement ).getDefaultValue ();
380395 if (defaultValue instanceof StringLiteralExpression ) {
381- addStringLiteralScope (methodReference , (StringLiteralExpression ) defaultValue );
396+ addStringLiteralScope (methodReference , (StringLiteralExpression ) defaultValue , consumer );
382397 }
383398 } else if (phpNamedElement instanceof Variable ) {
384399 // foo($var) => $var = 'test.html.twig'
385400 PsiElement assignmentExpression = phpNamedElement .getParent ();
386401 if (assignmentExpression instanceof AssignmentExpression ) {
387402 PhpPsiElement value = ((AssignmentExpression ) assignmentExpression ).getValue ();
388403 if (value instanceof StringLiteralExpression ) {
389- addStringLiteralScope (methodReference , (StringLiteralExpression ) value );
404+ addStringLiteralScope (methodReference , (StringLiteralExpression ) value , consumer );
390405 }
391406 }
392407 } else if (phpNamedElement instanceof Parameter ) {
393408 // function foobar($defaultParameter = 'default-function-parameter.html.twig')
394409 PsiElement value = ((Parameter ) phpNamedElement ).getDefaultValue ();
395410 if (value instanceof StringLiteralExpression ) {
396- addStringLiteralScope (methodReference , (StringLiteralExpression ) value );
411+ addStringLiteralScope (methodReference , (StringLiteralExpression ) value , consumer );
397412 }
398413 }
399414 }
400415 }
401416
402- private void addStringLiteralScope (@ NotNull MethodReference methodReference , @ NotNull StringLiteralExpression defaultValue ) {
417+ private static void addStringLiteralScope (@ NotNull MethodReference methodReference , @ NotNull StringLiteralExpression defaultValue , Consumer < Triple < String , PhpNamedElement , FunctionReference >> consumer ) {
403418 String contents = defaultValue .getContents ();
404419 if (StringUtils .isBlank (contents ) || !contents .endsWith (".twig" )) {
405420 return ;
@@ -410,14 +425,18 @@ private void addStringLiteralScope(@NotNull MethodReference methodReference, @No
410425 return ;
411426 }
412427
413- addTemplateWithScope (contents , parentOfType , methodReference );
428+ addTemplateWithScope (contents , parentOfType , methodReference , consumer );
414429 }
415430
416431 /**
417432 * "@Template("foobar.html.twig")"
418433 * "@Template(template="foobar.html.twig")"
419434 */
420435 private void visitPhpDocTag (@ NotNull PhpDocTag phpDocTag ) {
436+ processDocTag (phpDocTag , consumer );
437+ }
438+
439+ public static void processDocTag (@ NotNull PhpDocTag phpDocTag , Consumer <Triple <String , PhpNamedElement , FunctionReference >> consumer ) {
421440 // "@var" and user non related tags dont need an action
422441 if (AnnotationBackportUtil .NON_ANNOTATION_TAGS .contains (phpDocTag .getName ())) {
423442 return ;
@@ -440,17 +459,17 @@ private void visitPhpDocTag(@NotNull PhpDocTag phpDocTag) {
440459 // App\Controller\MyNiceController::myAction => my_nice/my.html.twig
441460 Method methodScope = AnnotationBackportUtil .getMethodScope (phpDocTag );
442461 if (methodScope != null ) {
443- visitMethodForGuessing (methodScope );
462+ visitMethodForGuessing (methodScope , consumer );
444463 }
445464 } else if (template .endsWith (".twig" )) {
446465 Method methodScope = AnnotationBackportUtil .getMethodScope (phpDocTag );
447466 if (methodScope != null ) {
448- addTemplateWithScope (template , methodScope , null );
467+ addTemplateWithScope (template , methodScope , null , consumer );
449468 }
450469 }
451470 }
452471
453- private void visitMethodForGuessing (@ NotNull Method methodScope ) {
472+ private static void visitMethodForGuessing (@ NotNull Method methodScope , Consumer < Triple < String , PhpNamedElement , FunctionReference >> consumer ) {
454473 PhpClass phpClass = methodScope .getContainingClass ();
455474 if (phpClass != null ) {
456475 // App\Controller\ "MyNice" Controller
@@ -461,16 +480,16 @@ private void visitMethodForGuessing(@NotNull Method methodScope) {
461480
462481 // __invoke is using controller as template name
463482 if (name .equals ("__invoke" )) {
464- addTemplateWithScope (group + ".html.twig" , methodScope , null );
483+ addTemplateWithScope (group + ".html.twig" , methodScope , null , consumer );
465484 } else {
466485 String action = name .endsWith ("Action" ) ? name .substring (0 , name .length () - "Action" .length ()) : name ;
467- addTemplateWithScope (group + "/" + underscore (action ) + ".html.twig" , methodScope , null );
486+ addTemplateWithScope (group + "/" + underscore (action ) + ".html.twig" , methodScope , null , consumer );
468487 }
469488 }
470489 }
471490 }
472491
473- private void addTemplateWithScope (@ NotNull String contents , @ NotNull PhpNamedElement scope , @ Nullable FunctionReference functionReference ) {
492+ private static void addTemplateWithScope (@ NotNull String contents , @ NotNull PhpNamedElement scope , @ Nullable FunctionReference functionReference , Consumer < Triple < String , PhpNamedElement , FunctionReference >> consumer ) {
474493 String s = TwigUtil .normalizeTemplateName (contents );
475494 consumer .accept (new Triple <>(s , scope , functionReference ));
476495 }
0 commit comments