@@ -29,114 +29,94 @@ public function process(File $phpcsFile, $stackPtr): void
2929 {
3030 $ tokens = $ phpcsFile ->getTokens ();
3131
32- $ previousType = '' ;
32+ $ typeSeen = [];
33+ $ previousTag = false ;
34+ $ previousIsCustom = false ;
35+
3336 foreach ($ tokens [$ stackPtr ]['comment_tags ' ] as $ commentTag ) {
3437 $ currentType = $ tokens [$ commentTag ]['content ' ];
35- $ commentTagLine = $ tokens [$ commentTag ]['line ' ];
36-
37- $ previousString = $ phpcsFile ->findPrevious (
38- T_DOC_COMMENT_STRING ,
39- $ commentTag ,
40- $ stackPtr
41- );
38+ $ currentIsCustom = !in_array ($ currentType , SniffHelper::TAGS );
39+ $ isNewType = !in_array ($ currentType , $ typeSeen );
4240
43- $ previousTag = $ phpcsFile ->findPrevious (
44- T_DOC_COMMENT_TAG ,
45- $ commentTag - 1 ,
46- $ stackPtr
47- );
41+ $ commentTagLine = $ tokens [$ commentTag ]['line ' ];
4842
43+ $ previousString = $ phpcsFile ->findPrevious (T_DOC_COMMENT_STRING , $ commentTag , $ stackPtr );
4944 $ previousLine = -1 ;
45+
5046 if (false !== $ previousString ) {
5147 $ previousLine = $ tokens [$ previousString ]['line ' ];
5248 $ previousElement = $ previousString ;
5349 }
5450
5551 if (false !== $ previousTag ) {
52+ $ previousType = $ tokens [$ previousTag ]['content ' ];
5653 $ previousTagLine = $ tokens [$ previousTag ]['line ' ];
5754
5855 if ($ previousTagLine > $ previousLine ) {
5956 $ previousLine = $ previousTagLine ;
6057 $ previousElement = $ previousTag ;
6158 }
59+ } else {
60+ $ previousType = null ;
6261 }
6362
6463 if (isset ($ previousElement ) && $ previousLine >= 0 ) {
65- $ currentIsCustom = !in_array ($ currentType , SniffHelper::TAGS );
66- $ previousIsCustom = '' !== $ previousType
67- && !in_array ($ previousType , SniffHelper::TAGS );
68-
69- if (($ previousType === $ currentType ) || ($ currentIsCustom && $ previousIsCustom )) {
64+ if ($ previousType === $ currentType ) {
7065 if ($ previousLine !== $ commentTagLine - 1 ) {
71- if ($ previousType === $ currentType ) {
72- $ fix = $ phpcsFile ->addFixableError (
73- 'Expected no empty lines between annotations of the same type ' ,
74- $ commentTag ,
75- 'SameType '
76- );
77- } else {
78- $ fix = $ phpcsFile ->addFixableError (
79- 'Expected no empty lines between custom annotations ' ,
80- $ commentTag ,
81- 'CustomType '
82- );
83- }
66+ $ fix = $ phpcsFile ->addFixableError (
67+ 'Expected no empty lines between annotations of the same type ' ,
68+ $ commentTag ,
69+ 'SameType '
70+ );
8471
8572 if ($ fix ) {
86- $ phpcsFile ->fixer ->beginChangeset ();
87- $ this ->removeLines (
88- $ phpcsFile ,
89- $ previousElement ,
90- $ previousLine + 1 ,
91- $ commentTagLine - 1
92- );
93- $ phpcsFile ->fixer ->endChangeset ();
73+ $ this ->removeLines ($ phpcsFile , $ previousElement , $ previousLine + 1 , $ commentTagLine - 1 );
9474 }
9575 }
96- } else {
97- if ($ previousLine !== $ commentTagLine - 2 ) {
76+ } elseif ( $ currentIsCustom && $ previousIsCustom ) {
77+ if ($ previousLine !== $ commentTagLine - 1 ) {
9878 $ fix = $ phpcsFile ->addFixableError (
99- 'Expected exactly one empty line between annotations of different types ' ,
79+ 'Expected no empty lines between custom annotations ' ,
10080 $ commentTag ,
101- 'DifferentType '
81+ 'CustomType '
10282 );
10383
10484 if ($ fix ) {
105- $ phpcsFile ->fixer ->beginChangeset ();
106-
107- if ($ previousLine === $ commentTagLine - 1 ) {
108- $ firstOnLine = $ phpcsFile ->findFirstOnLine (
109- [],
110- $ commentTag ,
111- true
112- );
113- $ star = $ phpcsFile ->findNext (
114- T_DOC_COMMENT_STAR ,
115- $ firstOnLine
116- );
117- $ content = $ phpcsFile ->getTokensAsString (
118- $ firstOnLine ,
119- $ star - $ firstOnLine + 1
120- );
121- $ phpcsFile ->fixer ->addContentBefore (
122- $ firstOnLine ,
123- $ content .$ phpcsFile ->eolChar
124- );
125- } else {
126- $ this ->removeLines (
127- $ phpcsFile ,
128- $ previousElement ,
129- $ previousLine + 2 ,
130- $ commentTagLine - 1
131- );
132- }
133- $ phpcsFile ->fixer ->endChangeset ();
85+ $ this ->removeLines ($ phpcsFile , $ previousElement , $ previousLine + 1 , $ commentTagLine - 1 );
86+ }
87+ }
88+ } elseif (!$ currentIsCustom && !$ isNewType ) {
89+ $ phpcsFile ->addError (
90+ 'Annotation of the same type should be together ' ,
91+ $ commentTag ,
92+ 'GroupSameType '
93+ );
94+ } elseif ($ previousLine !== $ commentTagLine - 2 ) {
95+ $ fix = $ phpcsFile ->addFixableError (
96+ 'Expected exactly one empty line between annotations of different types ' ,
97+ $ commentTag ,
98+ 'DifferentType '
99+ );
100+
101+ if ($ fix ) {
102+ if ($ previousLine === $ commentTagLine - 1 ) {
103+ $ firstOnLine = $ phpcsFile ->findFirstOnLine ([], $ commentTag , true );
104+ $ star = $ phpcsFile ->findNext (T_DOC_COMMENT_STAR , $ firstOnLine );
105+ $ content = $ phpcsFile ->getTokensAsString ($ firstOnLine , $ star - $ firstOnLine + 1 );
106+
107+ $ phpcsFile ->fixer ->addContentBefore ($ firstOnLine , $ content .$ phpcsFile ->eolChar );
108+ } else {
109+ $ this ->removeLines ($ phpcsFile , $ previousElement , $ previousLine + 2 , $ commentTagLine - 1 );
134110 }
135111 }
136112 }
137113 }
138114
139- $ previousType = $ currentType ;
115+ $ previousTag = $ commentTag ;
116+ $ previousIsCustom = $ currentIsCustom ;
117+ if (!$ currentIsCustom && $ isNewType ) {
118+ $ typeSeen [] = $ currentType ;
119+ }
140120 }
141121 }
142122
@@ -150,6 +130,8 @@ private function removeLines(File $phpcsFile, int $fromPtr, int $fromLine, int $
150130 {
151131 $ tokens = $ phpcsFile ->getTokens ();
152132
133+ $ phpcsFile ->fixer ->beginChangeset ();
134+
153135 for ($ i = $ fromPtr ;; $ i ++) {
154136 if ($ tokens [$ i ]['line ' ] > $ toLine ) {
155137 break ;
@@ -159,5 +141,7 @@ private function removeLines(File $phpcsFile, int $fromPtr, int $fromLine, int $
159141 $ phpcsFile ->fixer ->replaceToken ($ i , '' );
160142 }
161143 }
144+
145+ $ phpcsFile ->fixer ->endChangeset ();
162146 }
163147}
0 commit comments