@@ -151,46 +151,68 @@ impl Backend {
151151 /// Parse PHP source text and extract class information.
152152 /// Returns a Vec of ClassInfo for all classes found in the file.
153153 pub fn parse_php ( & self , content : & str ) -> Vec < ClassInfo > {
154- let arena = bumpalo:: Bump :: new ( ) ;
155- let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
156- let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, content) ;
157-
158- let doc_ctx = DocblockCtx {
159- trivias : program. trivia . as_slice ( ) ,
160- content,
161- } ;
162-
163- let mut classes = Vec :: new ( ) ;
164- Self :: extract_classes_from_statements (
165- program. statements . iter ( ) ,
166- & mut classes,
167- Some ( & doc_ctx) ,
168- ) ;
169- classes
154+ let content_owned = content. to_string ( ) ;
155+ let result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
156+ let arena = bumpalo:: Bump :: new ( ) ;
157+ let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
158+ let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, & content_owned) ;
159+
160+ let doc_ctx = DocblockCtx {
161+ trivias : program. trivia . as_slice ( ) ,
162+ content : & content_owned,
163+ } ;
164+
165+ let mut classes = Vec :: new ( ) ;
166+ Self :: extract_classes_from_statements (
167+ program. statements . iter ( ) ,
168+ & mut classes,
169+ Some ( & doc_ctx) ,
170+ ) ;
171+ classes
172+ } ) ) ;
173+
174+ match result {
175+ Ok ( classes) => classes,
176+ Err ( _) => {
177+ log:: error!( "PHPantomLSP: parser panicked in parse_php" ) ;
178+ Vec :: new ( )
179+ }
180+ }
170181 }
171182
172183 /// Parse PHP source text and extract standalone function definitions.
173184 ///
174185 /// Returns a list of `FunctionInfo` for every `function` declaration
175186 /// found at the top level (or inside a namespace block).
176187 pub fn parse_functions ( & self , content : & str ) -> Vec < FunctionInfo > {
177- let arena = bumpalo:: Bump :: new ( ) ;
178- let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
179- let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, content) ;
180-
181- let doc_ctx = DocblockCtx {
182- trivias : program. trivia . as_slice ( ) ,
183- content,
184- } ;
185-
186- let mut functions = Vec :: new ( ) ;
187- Self :: extract_functions_from_statements (
188- program. statements . iter ( ) ,
189- & mut functions,
190- & None ,
191- Some ( & doc_ctx) ,
192- ) ;
193- functions
188+ let content_owned = content. to_string ( ) ;
189+ let result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
190+ let arena = bumpalo:: Bump :: new ( ) ;
191+ let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
192+ let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, & content_owned) ;
193+
194+ let doc_ctx = DocblockCtx {
195+ trivias : program. trivia . as_slice ( ) ,
196+ content : & content_owned,
197+ } ;
198+
199+ let mut functions = Vec :: new ( ) ;
200+ Self :: extract_functions_from_statements (
201+ program. statements . iter ( ) ,
202+ & mut functions,
203+ & None ,
204+ Some ( & doc_ctx) ,
205+ ) ;
206+ functions
207+ } ) ) ;
208+
209+ match result {
210+ Ok ( functions) => functions,
211+ Err ( _) => {
212+ log:: error!( "PHPantomLSP: parser panicked in parse_functions" ) ;
213+ Vec :: new ( )
214+ }
215+ }
194216 }
195217
196218 /// Parse PHP source text and extract constant names from `define()` calls.
@@ -199,13 +221,24 @@ impl Backend {
199221 /// call found at the top level, inside namespace blocks, block
200222 /// statements, or `if` guards.
201223 pub fn parse_defines ( & self , content : & str ) -> Vec < String > {
202- let arena = bumpalo:: Bump :: new ( ) ;
203- let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
204- let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, content) ;
224+ let content_owned = content. to_string ( ) ;
225+ let result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
226+ let arena = bumpalo:: Bump :: new ( ) ;
227+ let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
228+ let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, & content_owned) ;
205229
206- let mut defines = Vec :: new ( ) ;
207- Self :: extract_defines_from_statements ( program. statements . iter ( ) , & mut defines) ;
208- defines
230+ let mut defines = Vec :: new ( ) ;
231+ Self :: extract_defines_from_statements ( program. statements . iter ( ) , & mut defines) ;
232+ defines
233+ } ) ) ;
234+
235+ match result {
236+ Ok ( defines) => defines,
237+ Err ( _) => {
238+ log:: error!( "PHPantomLSP: parser panicked in parse_defines" ) ;
239+ Vec :: new ( )
240+ }
241+ }
209242 }
210243
211244 /// Parse PHP source text and extract `use` statement mappings.
@@ -224,24 +257,46 @@ impl Backend {
224257 /// (function / const imports are skipped — we only track classes)
225258 /// - Use statements inside namespace bodies
226259 pub fn parse_use_statements ( & self , content : & str ) -> std:: collections:: HashMap < String , String > {
227- let arena = bumpalo:: Bump :: new ( ) ;
228- let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
229- let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, content) ;
260+ let content_owned = content. to_string ( ) ;
261+ let result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
262+ let arena = bumpalo:: Bump :: new ( ) ;
263+ let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
264+ let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, & content_owned) ;
230265
231- let mut use_map = std:: collections:: HashMap :: new ( ) ;
232- Self :: extract_use_statements_from_statements ( program. statements . iter ( ) , & mut use_map) ;
233- use_map
266+ let mut use_map = std:: collections:: HashMap :: new ( ) ;
267+ Self :: extract_use_statements_from_statements ( program. statements . iter ( ) , & mut use_map) ;
268+ use_map
269+ } ) ) ;
270+
271+ match result {
272+ Ok ( use_map) => use_map,
273+ Err ( _) => {
274+ log:: error!( "PHPantomLSP: parser panicked in parse_use_statements" ) ;
275+ std:: collections:: HashMap :: new ( )
276+ }
277+ }
234278 }
235279
236280 /// Parse PHP source text and extract the declared namespace (if any).
237281 ///
238282 /// Returns the namespace string (e.g. `"Klarna\Rest\Checkout"`) or
239283 /// `None` if the file has no namespace declaration.
240284 pub fn parse_namespace ( & self , content : & str ) -> Option < String > {
241- let arena = bumpalo:: Bump :: new ( ) ;
242- let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
243- let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, content) ;
285+ let content_owned = content. to_string ( ) ;
286+ let result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
287+ let arena = bumpalo:: Bump :: new ( ) ;
288+ let file_id = mago_database:: file:: FileId :: new ( "input.php" ) ;
289+ let program = mago_syntax:: parser:: parse_file_content ( & arena, file_id, & content_owned) ;
290+
291+ Self :: extract_namespace_from_statements ( program. statements . iter ( ) )
292+ } ) ) ;
244293
245- Self :: extract_namespace_from_statements ( program. statements . iter ( ) )
294+ match result {
295+ Ok ( ns) => ns,
296+ Err ( _) => {
297+ log:: error!( "PHPantomLSP: parser panicked in parse_namespace" ) ;
298+ None
299+ }
300+ }
246301 }
247302}
0 commit comments