@@ -43,6 +43,14 @@ const TM_READONLY: u32 = 1 << 2;
4343const TM_DEPRECATED : u32 = 1 << 3 ;
4444const TM_ABSTRACT : u32 = 1 << 4 ;
4545const TM_DEFINITION : u32 = 1 << 5 ;
46+ const TM_DEFAULT_LIBRARY : u32 = 1 << 6 ;
47+
48+ // ─── Helpers ────────────────────────────────────────────────────────────────
49+
50+ /// Assert that a decoded token has a specific modifier bit set.
51+ fn has_modifier ( tok : & DecodedToken , modifier : u32 ) -> bool {
52+ tok. modifiers & modifier != 0
53+ }
4654
4755/// Decode all tokens to absolute positions for easier assertion.
4856#[ derive( Debug ) ]
@@ -184,7 +192,7 @@ function make() {
184192"# ;
185193 let tokens = get_tokens ( php) ;
186194 let decoded = decode_tokens ( & tokens) ;
187- // "Item" on line 3 (after `new `)
195+ // "Item" on line 3 (after `new `) should be a class reference.
188196 let item_refs: Vec < _ > = decoded
189197 . iter ( )
190198 . filter ( |t| t. token_type == TT_CLASS && t. length == 4 && t. line == 3 )
@@ -396,7 +404,7 @@ function main() {
396404}
397405
398406#[ test]
399- fn this_is_variable_with_readonly ( ) {
407+ fn this_is_variable_with_readonly_and_default_library ( ) {
400408 let php = r#"<?php
401409class Foo {
402410 public function bar(): void {
@@ -406,42 +414,76 @@ class Foo {
406414"# ;
407415 let tokens = get_tokens ( php) ;
408416 let decoded = decode_tokens ( & tokens) ;
409- // "$this" on line 3 should be a variable with readonly modifier
417+ // "$this" on line 3 should be a variable with readonly + defaultLibrary
410418 let this_tokens: Vec < _ > = decoded
411419 . iter ( )
412420 . filter ( |t| t. token_type == TT_VARIABLE && t. length == 5 && t. line == 3 )
413421 . collect ( ) ;
414422 assert ! ( !this_tokens. is_empty( ) , "expected variable token for $this" ) ;
415423 assert ! (
416- this_tokens. iter( ) . any( |t| t. modifiers & TM_READONLY != 0 ) ,
417- "expected readonly modifier on $this"
424+ this_tokens
425+ . iter( )
426+ . any( |t| has_modifier( t, TM_READONLY ) && has_modifier( t, TM_DEFAULT_LIBRARY ) ) ,
427+ "expected readonly + defaultLibrary modifiers on $this"
418428 ) ;
419429}
420430
421431#[ test]
422- fn self_static_parent_are_type_tokens ( ) {
432+ fn self_static_are_type_with_default_library ( ) {
423433 let php = r#"<?php
424- class Base {}
425- class Child extends Base {
434+ class Foo {
426435 public static function make(): static {
427436 return new static();
428437 }
429- public function parent_ref (): void {
430- parent::class ;
438+ public function selfRef (): self {
439+ return $this ;
431440 }
432441}
433442"# ;
434443 let tokens = get_tokens ( php) ;
435444 let decoded = decode_tokens ( & tokens) ;
436- // "self", "static", and "parent" are type references (TT_TYPE or class-kind).
437- // "static" appears in type hint position on line 3
445+ // "static" in return type hint (line 2) → type + defaultLibrary
438446 let static_types: Vec < _ > = decoded
439447 . iter ( )
440- . filter ( |t| t. token_type == TT_TYPE && t. length == 6 )
448+ . filter ( |t| t. token_type == TT_TYPE && t. length == 6 && has_modifier ( t , TM_DEFAULT_LIBRARY ) )
441449 . collect ( ) ;
442450 assert ! (
443451 !static_types. is_empty( ) ,
444- "expected type token for static keyword"
452+ "expected type + defaultLibrary token for static keyword"
453+ ) ;
454+ // "self" in return type hint (line 5) → type + defaultLibrary
455+ let self_types: Vec < _ > = decoded
456+ . iter ( )
457+ . filter ( |t| t. token_type == TT_TYPE && t. length == 4 && has_modifier ( t, TM_DEFAULT_LIBRARY ) )
458+ . collect ( ) ;
459+ assert ! (
460+ !self_types. is_empty( ) ,
461+ "expected type + defaultLibrary token for self keyword"
462+ ) ;
463+ }
464+
465+ #[ test]
466+ fn parent_has_default_library ( ) {
467+ let php = r#"<?php
468+ class Base {}
469+ class Child extends Base {
470+ public function test(): void {
471+ parent::class;
472+ }
473+ }
474+ "# ;
475+ let tokens = get_tokens ( php) ;
476+ let decoded = decode_tokens ( & tokens) ;
477+ // "parent" on line 4 should carry the defaultLibrary modifier.
478+ // The token type is resolved from the parent class kind (TT_CLASS
479+ // for Base) or falls back to TT_TYPE.
480+ let parent_tokens: Vec < _ > = decoded
481+ . iter ( )
482+ . filter ( |t| t. length == 6 && t. line == 4 && has_modifier ( t, TM_DEFAULT_LIBRARY ) )
483+ . collect ( ) ;
484+ assert ! (
485+ !parent_tokens. is_empty( ) ,
486+ "expected defaultLibrary modifier on parent keyword"
445487 ) ;
446488}
447489
0 commit comments