@@ -395,6 +395,157 @@ public function dataAttributeOnParameters()
395395 }//end dataAttributeOnParameters()
396396
397397
398+ /**
399+ * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly.
400+ *
401+ * @param string $testMarker The comment which prefaces the target token in the test file.
402+ * @param int $length The number of tokens between opener and closer.
403+ * @param array $expectedTokensAttribute The codes of tokens inside the attributes.
404+ * @param array $expectedTokensAfter The codes of tokens after the attributes.
405+ *
406+ * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute
407+ *
408+ * @dataProvider dataAttributeOnTextLookingLikeCloseTag
409+ *
410+ * @return void
411+ */
412+ public function testAttributeContainingTextLookingLikeCloseTag ($ testMarker , $ length , array $ expectedTokensAttribute , array $ expectedTokensAfter )
413+ {
414+ $ tokens = self ::$ phpcsFile ->getTokens ();
415+
416+ $ attribute = $ this ->getTargetToken ($ testMarker , T_ATTRIBUTE );
417+
418+ $ this ->assertSame ('T_ATTRIBUTE ' , $ tokens [$ attribute ]['type ' ]);
419+ $ this ->assertArrayHasKey ('attribute_closer ' , $ tokens [$ attribute ]);
420+
421+ $ closer = $ tokens [$ attribute ]['attribute_closer ' ];
422+ $ this ->assertSame (($ attribute + $ length ), $ closer );
423+ $ this ->assertSame (T_ATTRIBUTE_END , $ tokens [$ closer ]['code ' ]);
424+ $ this ->assertSame ('T_ATTRIBUTE_END ' , $ tokens [$ closer ]['type ' ]);
425+
426+ $ this ->assertSame ($ tokens [$ attribute ]['attribute_opener ' ], $ tokens [$ closer ]['attribute_opener ' ]);
427+ $ this ->assertSame ($ tokens [$ attribute ]['attribute_closer ' ], $ tokens [$ closer ]['attribute_closer ' ]);
428+
429+ $ i = ($ attribute + 1 );
430+ foreach ($ expectedTokensAttribute as $ item ) {
431+ list ($ expectedType , $ expectedContents ) = $ item ;
432+ $ this ->assertSame ($ expectedType , $ tokens [$ i ]['type ' ]);
433+ $ this ->assertSame ($ expectedContents , $ tokens [$ i ]['content ' ]);
434+ $ this ->assertArrayHasKey ('attribute_opener ' , $ tokens [$ i ]);
435+ $ this ->assertArrayHasKey ('attribute_closer ' , $ tokens [$ i ]);
436+ ++$ i ;
437+ }
438+
439+ $ i = ($ closer + 1 );
440+ foreach ($ expectedTokensAfter as $ expectedCode ) {
441+ $ this ->assertSame ($ expectedCode , $ tokens [$ i ]['code ' ]);
442+ ++$ i ;
443+ }
444+
445+ }//end testAttributeContainingTextLookingLikeCloseTag()
446+
447+
448+ /**
449+ * Data provider.
450+ *
451+ * @see dataAttributeOnTextLookingLikeCloseTag()
452+ *
453+ * @return array
454+ */
455+ public function dataAttributeOnTextLookingLikeCloseTag ()
456+ {
457+ return [
458+ [
459+ '/* testAttributeContainingTextLookingLikeCloseTag */ ' ,
460+ 5 ,
461+ [
462+ [
463+ 'T_STRING ' ,
464+ 'DeprecationReason ' ,
465+ ],
466+ [
467+ 'T_OPEN_PARENTHESIS ' ,
468+ '( ' ,
469+ ],
470+ [
471+ 'T_CONSTANT_ENCAPSED_STRING ' ,
472+ "'reason: <https://some-website/reason?>' " ,
473+ ],
474+ [
475+ 'T_CLOSE_PARENTHESIS ' ,
476+ ') ' ,
477+ ],
478+ [
479+ 'T_ATTRIBUTE_END ' ,
480+ '] ' ,
481+ ],
482+ ],
483+ [
484+ T_WHITESPACE ,
485+ T_FUNCTION ,
486+ T_WHITESPACE ,
487+ T_STRING ,
488+ T_OPEN_PARENTHESIS ,
489+ T_CLOSE_PARENTHESIS ,
490+ T_WHITESPACE ,
491+ T_OPEN_CURLY_BRACKET ,
492+ T_CLOSE_CURLY_BRACKET ,
493+ ],
494+ ],
495+ [
496+ '/* testAttributeContainingMultilineTextLookingLikeCloseTag */ ' ,
497+ 8 ,
498+ [
499+ [
500+ 'T_STRING ' ,
501+ 'DeprecationReason ' ,
502+ ],
503+ [
504+ 'T_OPEN_PARENTHESIS ' ,
505+ '( ' ,
506+ ],
507+ [
508+ 'T_WHITESPACE ' ,
509+ "\n" ,
510+ ],
511+ [
512+ 'T_WHITESPACE ' ,
513+ " " ,
514+ ],
515+ [
516+ 'T_CONSTANT_ENCAPSED_STRING ' ,
517+ "'reason: <https://some-website/reason?>' " ,
518+ ],
519+ [
520+ 'T_WHITESPACE ' ,
521+ "\n" ,
522+ ],
523+ [
524+ 'T_CLOSE_PARENTHESIS ' ,
525+ ') ' ,
526+ ],
527+ [
528+ 'T_ATTRIBUTE_END ' ,
529+ '] ' ,
530+ ],
531+ ],
532+ [
533+ T_WHITESPACE ,
534+ T_FUNCTION ,
535+ T_WHITESPACE ,
536+ T_STRING ,
537+ T_OPEN_PARENTHESIS ,
538+ T_CLOSE_PARENTHESIS ,
539+ T_WHITESPACE ,
540+ T_OPEN_CURLY_BRACKET ,
541+ T_CLOSE_CURLY_BRACKET ,
542+ ],
543+ ],
544+ ];
545+
546+ }//end dataAttributeOnTextLookingLikeCloseTag()
547+
548+
398549 /**
399550 * Test that invalid attribute (or comment starting with #[ and without ]) are parsed correctly.
400551 *
0 commit comments