@@ -81,6 +81,10 @@ public function getConfigurationDefinition(): FixerConfigurationResolverInterfac
8181 ->setAllowedValues (Separate::getList ())
8282 ->setDefault (Separate::Both->value )
8383 ->getOption (),
84+ (new FixerOptionBuilder ('add_class_name ' , 'Add class name before annotations ' ))
85+ ->setAllowedTypes (['bool ' ])
86+ ->setDefault (false )
87+ ->getOption (),
8488 ]);
8589 }
8690
@@ -103,27 +107,50 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void
103107 continue ;
104108 }
105109
106- $ this ->processClassDocBlock ($ tokens , $ index , $ annotations );
110+ $ className = $ this ->getClassName ($ tokens , $ index );
111+ $ this ->processClassDocBlock ($ tokens , $ index , $ annotations , $ className );
107112 }
108113 }
109114
110115 /**
111116 * @param array<string, string|array<string>> $annotations
112117 */
113- private function processClassDocBlock (Tokens $ tokens , int $ classIndex , array $ annotations ): void
118+ private function processClassDocBlock (Tokens $ tokens , int $ classIndex , array $ annotations, string $ className ): void
114119 {
115120 $ existingDocBlockIndex = $ this ->findExistingDocBlock ($ tokens , $ classIndex );
116121 $ preserveExisting = $ this ->resolvedConfiguration ['preserve_existing ' ] ?? true ;
117122
118123 if (null !== $ existingDocBlockIndex ) {
119124 if ($ preserveExisting ) {
120- $ this ->mergeWithExistingDocBlock ($ tokens , $ existingDocBlockIndex , $ annotations );
125+ $ this ->mergeWithExistingDocBlock ($ tokens , $ existingDocBlockIndex , $ annotations, $ className );
121126 } else {
122- $ this ->replaceDocBlock ($ tokens , $ existingDocBlockIndex , $ annotations );
127+ $ this ->replaceDocBlock ($ tokens , $ existingDocBlockIndex , $ annotations, $ className );
123128 }
124129 } else {
125- $ this ->insertNewDocBlock ($ tokens , $ classIndex , $ annotations );
130+ $ this ->insertNewDocBlock ($ tokens , $ classIndex , $ annotations , $ className );
131+ }
132+ }
133+
134+ private function getClassName (Tokens $ tokens , int $ classIndex ): string
135+ {
136+ // Look for the class name token after the 'class' keyword
137+ for ($ i = $ classIndex + 1 , $ limit = $ tokens ->count (); $ i < $ limit ; ++$ i ) {
138+ $ token = $ tokens [$ i ];
139+
140+ if ($ token ->isWhitespace ()) {
141+ continue ;
142+ }
143+
144+ // The first non-whitespace token after 'class' should be the class name
145+ if ($ token ->isGivenKind (T_STRING )) {
146+ return $ token ->getContent ();
147+ }
148+
149+ // If we hit anything else, stop looking
150+ break ;
126151 }
152+
153+ return '' ;
127154 }
128155
129156 private function findExistingDocBlock (Tokens $ tokens , int $ classIndex ): ?int
@@ -151,29 +178,29 @@ private function findExistingDocBlock(Tokens $tokens, int $classIndex): ?int
151178 /**
152179 * @param array<string, string|array<string>> $annotations
153180 */
154- private function mergeWithExistingDocBlock (Tokens $ tokens , int $ docBlockIndex , array $ annotations ): void
181+ private function mergeWithExistingDocBlock (Tokens $ tokens , int $ docBlockIndex , array $ annotations, string $ className ): void
155182 {
156183 $ existingContent = $ tokens [$ docBlockIndex ]->getContent ();
157184 $ existingAnnotations = $ this ->parseExistingAnnotations ($ existingContent );
158185 $ mergedAnnotations = $ this ->mergeAnnotations ($ existingAnnotations , $ annotations );
159186
160- $ newDocBlock = $ this ->buildDocBlock ($ mergedAnnotations );
187+ $ newDocBlock = $ this ->buildDocBlock ($ mergedAnnotations, $ className );
161188 $ tokens [$ docBlockIndex ] = new Token ([T_DOC_COMMENT , $ newDocBlock ]);
162189 }
163190
164191 /**
165192 * @param array<string, string|array<string>> $annotations
166193 */
167- private function replaceDocBlock (Tokens $ tokens , int $ docBlockIndex , array $ annotations ): void
194+ private function replaceDocBlock (Tokens $ tokens , int $ docBlockIndex , array $ annotations, string $ className ): void
168195 {
169- $ newDocBlock = $ this ->buildDocBlock ($ annotations );
196+ $ newDocBlock = $ this ->buildDocBlock ($ annotations, $ className );
170197 $ tokens [$ docBlockIndex ] = new Token ([T_DOC_COMMENT , $ newDocBlock ]);
171198 }
172199
173200 /**
174201 * @param array<string, string|array<string>> $annotations
175202 */
176- private function insertNewDocBlock (Tokens $ tokens , int $ classIndex , array $ annotations ): void
203+ private function insertNewDocBlock (Tokens $ tokens , int $ classIndex , array $ annotations, string $ className ): void
177204 {
178205 $ separate = $ this ->resolvedConfiguration ['separate ' ] ?? 'both ' ;
179206 $ insertIndex = $ this ->findInsertPosition ($ tokens , $ classIndex );
@@ -186,7 +213,7 @@ private function insertNewDocBlock(Tokens $tokens, int $classIndex, array $annot
186213 }
187214
188215 // Add the DocBlock
189- $ docBlock = $ this ->buildDocBlock ($ annotations );
216+ $ docBlock = $ this ->buildDocBlock ($ annotations, $ className );
190217 $ tokensToInsert [] = new Token ([T_DOC_COMMENT , $ docBlock ]);
191218
192219 // Add separation after comment if needed
@@ -255,14 +282,26 @@ private function mergeAnnotations(array $existing, array $new): array
255282 /**
256283 * @param array<string, string|array<string>> $annotations
257284 */
258- private function buildDocBlock (array $ annotations ): string
285+ private function buildDocBlock (array $ annotations, string $ className ): string
259286 {
260- if (empty ($ annotations )) {
287+ $ addClassName = $ this ->resolvedConfiguration ['add_class_name ' ] ?? false ;
288+
289+ if (empty ($ annotations ) && !$ addClassName ) {
261290 return "/** \n */ " ;
262291 }
263292
264293 $ docBlock = "/** \n" ;
265294
295+ // Add class name with dot if configured
296+ if ($ addClassName && !empty ($ className )) {
297+ $ docBlock .= " * {$ className }. \n" ;
298+
299+ // Add empty line after class name if there are annotations
300+ if (!empty ($ annotations )) {
301+ $ docBlock .= " * \n" ;
302+ }
303+ }
304+
266305 foreach ($ annotations as $ tag => $ value ) {
267306 if (empty ($ value )) {
268307 $ docBlock .= " * @ {$ tag }\n" ;
0 commit comments