@@ -55,48 +55,64 @@ class Deprecation
5555 public function __construct ($ message , array $ trace , $ file )
5656 {
5757 $ this ->trace = $ trace ;
58-
59- if ('trigger_error ' === (isset ($ trace [1 ]['function ' ]) ? $ trace [1 ]['function ' ] : null )
60- && (DebugClassLoader::class === ($ class = (isset ($ trace [2 ]['class ' ]) ? $ trace [2 ]['class ' ] : null )) || LegacyDebugClassLoader::class === $ class )
61- && 'checkClass ' === (isset ($ trace [2 ]['function ' ]) ? $ trace [2 ]['function ' ] : null )
62- && null !== ($ extraFile = (isset ($ trace [2 ]['args ' ][1 ]) ? $ trace [2 ]['args ' ][1 ] : null ))
63- && '' !== $ extraFile
64- && false !== $ extraFile = realpath ($ extraFile )
65- ) {
66- $ this ->getOriginalFilesStack ();
67- array_splice ($ this ->originalFilesStack , 2 , 1 , $ extraFile );
68- }
69-
7058 $ this ->message = $ message ;
59+
7160 $ i = \count ($ trace );
7261 while (1 < $ i && $ this ->lineShouldBeSkipped ($ trace [--$ i ])) {
7362 // No-op
7463 }
64+
7565 $ line = $ trace [$ i ];
7666 $ this ->triggeringFile = $ file ;
77- if (isset ($ line ['object ' ]) || isset ($ line ['class ' ])) {
78- if (isset ($ line ['class ' ]) && 0 === strpos ($ line ['class ' ], SymfonyTestsListenerFor::class)) {
79- set_error_handler (function () {});
80- $ parsedMsg = unserialize ($ this ->message );
81- restore_error_handler ();
82- $ this ->message = $ parsedMsg ['deprecation ' ];
83- $ this ->originClass = $ parsedMsg ['class ' ];
84- $ this ->originMethod = $ parsedMsg ['method ' ];
85- if (isset ($ parsedMsg ['files_stack ' ])) {
86- $ this ->originalFilesStack = $ parsedMsg ['files_stack ' ];
87- }
88- // If the deprecation has been triggered via
89- // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
90- // then we need to use the serialized information to determine
91- // if the error has been triggered from vendor code.
92- if (isset ($ parsedMsg ['triggering_file ' ])) {
93- $ this ->triggeringFile = $ parsedMsg ['triggering_file ' ];
67+
68+ for ($ j = 1 ; $ j < $ i ; ++$ j ) {
69+ if (!isset ($ trace [$ j ]['function ' ], $ trace [1 + $ j ]['class ' ], $ trace [1 + $ j ]['args ' ][0 ])) {
70+ continue ;
71+ }
72+
73+ if ('trigger_error ' === $ trace [$ j ]['function ' ] && !isset ($ trace [$ j ]['class ' ])) {
74+ if (\in_array ($ trace [1 + $ j ]['class ' ], [DebugClassLoader::class, LegacyDebugClassLoader::class], true )) {
75+ $ class = $ trace [1 + $ j ]['args ' ][0 ];
76+ $ this ->triggeringFile = isset ($ trace [1 + $ j ]['args ' ][1 ]) ? realpath ($ trace [1 + $ j ]['args ' ][1 ]) : (new \ReflectionClass ($ class ))->getFileName ();
77+ $ this ->getOriginalFilesStack ();
78+ array_splice ($ this ->originalFilesStack , 0 , $ j , [$ this ->triggeringFile ]);
9479 }
9580
81+ break ;
82+ }
83+ }
84+
85+ if (isset ($ line ['object ' ]) || isset ($ line ['class ' ])) {
86+ if (!isset ($ line ['class ' ], $ trace [$ i - 2 ]['function ' ]) || 0 !== strpos ($ line ['class ' ], SymfonyTestsListenerFor::class)) {
87+ $ this ->originClass = isset ($ line ['object ' ]) ? \get_class ($ line ['object ' ]) : $ line ['class ' ];
88+ $ this ->originMethod = $ line ['function ' ];
89+
90+ return ;
91+ }
92+
93+ if ('trigger_error ' !== $ trace [$ i - 2 ]['function ' ] || isset ($ trace [$ i - 2 ]['class ' ])) {
94+ $ this ->originClass = \get_class ($ line ['args ' ][0 ]);
95+ $ this ->originMethod = $ line ['args ' ][0 ]->getName ();
96+
9697 return ;
9798 }
98- $ this ->originClass = isset ($ line ['object ' ]) ? \get_class ($ line ['object ' ]) : $ line ['class ' ];
99- $ this ->originMethod = $ line ['function ' ];
99+
100+ set_error_handler (function () {});
101+ $ parsedMsg = unserialize ($ this ->message );
102+ restore_error_handler ();
103+ $ this ->message = $ parsedMsg ['deprecation ' ];
104+ $ this ->originClass = $ parsedMsg ['class ' ];
105+ $ this ->originMethod = $ parsedMsg ['method ' ];
106+ if (isset ($ parsedMsg ['files_stack ' ])) {
107+ $ this ->originalFilesStack = $ parsedMsg ['files_stack ' ];
108+ }
109+ // If the deprecation has been triggered via
110+ // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
111+ // then we need to use the serialized information to determine
112+ // if the error has been triggered from vendor code.
113+ if (isset ($ parsedMsg ['triggering_file ' ])) {
114+ $ this ->triggeringFile = $ parsedMsg ['triggering_file ' ];
115+ }
100116 }
101117 }
102118
@@ -130,7 +146,9 @@ public function originatingClass()
130146 throw new \LogicException ('Check with originatesFromAnObject() before calling this method. ' );
131147 }
132148
133- return $ this ->originClass ;
149+ $ class = $ this ->originClass ;
150+
151+ return false !== strpos ($ class , "@anonymous \0" ) ? (get_parent_class ($ class ) ?: key (class_implements ($ class )) ?: 'class ' ).'@anonymous ' : $ class ;
134152 }
135153
136154 /**
@@ -158,8 +176,7 @@ public function getMessage()
158176 */
159177 public function isLegacy ()
160178 {
161- $ class = $ this ->originatingClass ();
162- if ((new \ReflectionClass ($ class ))->isInternal ()) {
179+ if (!$ this ->originClass || (new \ReflectionClass ($ this ->originClass ))->isInternal ()) {
163180 return false ;
164181 }
165182
@@ -168,8 +185,8 @@ public function isLegacy()
168185 return 0 === strpos ($ method , 'testLegacy ' )
169186 || 0 === strpos ($ method , 'provideLegacy ' )
170187 || 0 === strpos ($ method , 'getLegacy ' )
171- || strpos ($ class , '\Legacy ' )
172- || \in_array ('legacy ' , Test::getGroups ($ class , $ method ), true );
188+ || strpos ($ this -> originClass , '\Legacy ' )
189+ || \in_array ('legacy ' , Test::getGroups ($ this -> originClass , $ method ), true );
173190 }
174191
175192 /**
@@ -195,11 +212,10 @@ public function isMuted()
195212 */
196213 public function getType ()
197214 {
198- $ triggeringFilePathType = $ this ->getPathType ($ this ->triggeringFile );
199- if (self ::PATH_TYPE_SELF === $ triggeringFilePathType ) {
215+ if (self ::PATH_TYPE_SELF === $ pathType = $ this ->getPathType ($ this ->triggeringFile )) {
200216 return self ::TYPE_SELF ;
201217 }
202- if (self ::PATH_TYPE_UNDETERMINED === $ triggeringFilePathType ) {
218+ if (self ::PATH_TYPE_UNDETERMINED === $ pathType ) {
203219 return self ::TYPE_UNDETERMINED ;
204220 }
205221 $ erroringFile = $ erroringPackage = null ;
@@ -208,10 +224,10 @@ public function getType()
208224 if ('- ' === $ file || 'Standard input code ' === $ file || !realpath ($ file )) {
209225 continue ;
210226 }
211- if (self ::PATH_TYPE_SELF === $ this ->getPathType ($ file )) {
227+ if (self ::PATH_TYPE_SELF === $ pathType = $ this ->getPathType ($ file )) {
212228 return self ::TYPE_DIRECT ;
213229 }
214- if (self ::PATH_TYPE_UNDETERMINED === $ this -> getPathType ( $ file ) ) {
230+ if (self ::PATH_TYPE_UNDETERMINED === $ pathType ) {
215231 return self ::TYPE_UNDETERMINED ;
216232 }
217233 if (null !== $ erroringFile && null !== $ erroringPackage ) {
@@ -233,7 +249,7 @@ private function getOriginalFilesStack()
233249 if (null === $ this ->originalFilesStack ) {
234250 $ this ->originalFilesStack = [];
235251 foreach ($ this ->trace as $ frame ) {
236- if (!isset ($ frame ['file ' ]) || \in_array ($ frame ['function ' ], ['require ' , 'require_once ' , 'include ' , 'include_once ' ], true )) {
252+ if (!isset ($ frame ['file ' ], $ frame [ ' function ' ] ) || (! isset ( $ frame [ ' class ' ]) && \in_array ($ frame ['function ' ], ['require ' , 'require_once ' , 'include ' , 'include_once ' ], true ) )) {
237253 continue ;
238254 }
239255
@@ -259,13 +275,10 @@ private function getPackage($path)
259275 $ relativePath = substr ($ path , \strlen ($ vendorRoot ) + 1 );
260276 $ vendor = strstr ($ relativePath , \DIRECTORY_SEPARATOR , true );
261277 if (false === $ vendor ) {
262- throw new \ RuntimeException ( sprintf ( ' Could not find directory separator "%s" in path "%s". ' , \ DIRECTORY_SEPARATOR , $ relativePath )) ;
278+ return ' symfony ' ;
263279 }
264280
265- return rtrim ($ vendor .'/ ' .strstr (substr (
266- $ relativePath ,
267- \strlen ($ vendor ) + 1
268- ), \DIRECTORY_SEPARATOR , true ), '/ ' );
281+ return rtrim ($ vendor .'/ ' .strstr (substr ($ relativePath , \strlen ($ vendor ) + 1 ), \DIRECTORY_SEPARATOR , true ), '/ ' );
269282 }
270283 }
271284
@@ -279,6 +292,13 @@ private static function getVendors()
279292 {
280293 if (null === self ::$ vendors ) {
281294 self ::$ vendors = $ paths = [];
295+ self ::$ vendors [] = \dirname (__DIR__ ).\DIRECTORY_SEPARATOR .'Legacy ' ;
296+ if (class_exists (DebugClassLoader::class, false )) {
297+ self ::$ vendors [] = \dirname ((new \ReflectionClass (DebugClassLoader::class))->getFileName ());
298+ }
299+ if (class_exists (LegacyDebugClassLoader::class, false )) {
300+ self ::$ vendors [] = \dirname ((new \ReflectionClass (LegacyDebugClassLoader::class))->getFileName ());
301+ }
282302 foreach (get_declared_classes () as $ class ) {
283303 if ('C ' === $ class [0 ] && 0 === strpos ($ class , 'ComposerAutoloaderInit ' )) {
284304 $ r = new \ReflectionClass ($ class );
@@ -354,10 +374,9 @@ public function toString()
354374 $ reflection ->setAccessible (true );
355375 $ reflection ->setValue ($ exception , $ this ->trace );
356376
357- return 'deprecation triggered by ' .$ this ->originatingClass ().':: ' .$ this ->originatingMethod ().': ' .
358- "\n" .$ this ->message .
359- "\nStack trace: " .
360- "\n" .str_replace (' ' .getcwd ().\DIRECTORY_SEPARATOR , ' ' , $ exception ->getTraceAsString ()).
361- "\n" ;
377+ return ($ this ->originatesFromAnObject () ? 'deprecation triggered by ' .$ this ->originatingClass ().':: ' .$ this ->originatingMethod ().": \n" : '' )
378+ .$ this ->message ."\n"
379+ ."Stack trace: \n"
380+ .str_replace (' ' .getcwd ().\DIRECTORY_SEPARATOR , ' ' , $ exception ->getTraceAsString ())."\n" ;
362381 }
363382}
0 commit comments