diff --git a/Cargo.lock b/Cargo.lock index 59b43695..cf523550 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "adler2" version = "2.0.1" @@ -50,6 +40,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -106,12 +102,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - [[package]] name = "arbitrary" version = "1.4.2" @@ -139,9 +129,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "async-trait" @@ -151,7 +141,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -162,7 +152,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -200,9 +190,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "blake3" @@ -218,6 +208,16 @@ dependencies = [ "cpufeatures 0.3.0", ] +[[package]] +name = "blink-alloc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e669f146bb8b2327006ed94c69cf78c8ec81c100192564654230a40b4f091d82" +dependencies = [ + "allocator-api2", + "parking_lot", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -229,12 +229,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] @@ -242,9 +242,6 @@ name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" -dependencies = [ - "serde", -] [[package]] name = "byteorder" @@ -254,9 +251,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "bzip2" @@ -279,9 +276,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" [[package]] name = "cast" @@ -291,9 +288,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.63" +version = "1.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" dependencies = [ "find-msvc-tools", "jobserver", @@ -376,7 +373,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -494,9 +491,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -504,18 +501,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -578,7 +575,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -600,7 +597,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -690,18 +687,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -770,7 +755,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -839,15 +824,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "wasip2", - "wasip3", ] [[package]] @@ -886,20 +869,16 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -924,9 +903,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -1020,12 +999,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "idna" version = "1.1.0" @@ -1049,9 +1022,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.25" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +checksum = "2adf14691c72bcfc1058740436a35bdd3ae9c07d1a941ef00b749e9ea16aefa7" dependencies = [ "crossbeam-deque", "globset", @@ -1071,26 +1044,24 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", - "serde", - "serde_core", ] [[package]] name = "inotify" -version = "0.11.1" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +checksum = "153be1941a183ec9ccd095ddbe17a8b8d435ef6c76e9e02451b933c3999af2c8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "inotify-sys", "libc", ] [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -1138,31 +1109,30 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] [[package]] name = "kqueue" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" dependencies = [ "kqueue-sys", "libc", @@ -1174,7 +1144,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "libc", ] @@ -1184,12 +1154,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" version = "0.2.186" @@ -1231,9 +1195,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lsp-types" @@ -1269,132 +1233,139 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "mago-allocator" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e759f5cc3fa7481129c81844233aa6774153035f7c7765eacce520e436a632" +dependencies = [ + "allocator-api2", + "blink-alloc", + "hashbrown 0.17.1", +] + +[[package]] +name = "mago-bytes" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f3c0bd98650b6ea4577a1f8c7210e197b32522c8f4f1e9887faf3c6f4950d4" + [[package]] name = "mago-composer" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e00649bab75e5c849458e2566ff0f7716bbc7484180784a2a8c02fa8dfdc666" +checksum = "95a706f6a34420e8edb232e3ce425654704e1e79c4ecd51d85e5d55e96c3fcb0" dependencies = [ - "foldhash 0.2.0", + "foldhash", "serde", "serde_json", ] [[package]] name = "mago-database" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158a76ec7e5dd1ef1d17713ba65a3c295a7a8039cbe693b9eac72888d528c5da" +checksum = "644f1b2283b906e4cbf8025bcb3a1133626cd1f203e334bd76032f6f4d433224" dependencies = [ - "foldhash 0.2.0", + "foldhash", "glob", "globset", "memchr", "notify", "rayon", - "serde", - "simdutf8", "tracing", "walkdir", ] [[package]] name = "mago-docblock" -version = "1.29.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b884e1588c7ab65b7c36522178db85d67ee5c6338c2ac73b09142ba14f3b661c" +checksum = "6a95eb832594a48e2751c3a3de0f94bffbb73aecb4d70cfc6703e74dde6018d0" dependencies = [ - "bumpalo", + "mago-allocator", "mago-span", "mago-syntax", "memchr", - "serde", ] [[package]] name = "mago-formatter" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319a99c6cf28b2d64bd0882c750f18a7e9c5ba8e83c0ecf190dfa28e72451dde" +checksum = "4402722886e69a28d17a7badb1a9a67242e926a7600548e6d6c5104e35c76b2d" dependencies = [ - "bumpalo", - "foldhash 0.2.0", + "foldhash", + "mago-allocator", "mago-database", "mago-php-version", "mago-span", "mago-syntax", "memchr", "schemars", - "serde", - "strum 0.28.0", "unicode-width", ] [[package]] name = "mago-names" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d729463b43077f2b402682b1984cc51524c499faaac8ba1826bf22be6d6295" +checksum = "546d2e6feb72899eddbbeefd93053a66549942edf9bfa787f4c171f149e61951" dependencies = [ - "bumpalo", - "foldhash 0.2.0", + "foldhash", + "mago-allocator", "mago-span", "mago-syntax", + "mago-word", "memchr", - "serde", - "strum 0.28.0", + "strum", ] [[package]] name = "mago-php-version" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44774a07cdf13842778820d19bbbbbeedf6a5723844f9b108dd80ae7443c7f4" +checksum = "a8e7a049df77bbe08738e1287e63d5b4c5bdabce776356c1e75a4c156c308f15" dependencies = [ "schemars", - "serde", ] [[package]] name = "mago-reporting" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8a03bf7eb0a583479d997164ad3c04441747386dffc69fe213125cdbcddc42" +checksum = "f7566b474595477a439228a8e7671e317d8f8c287c292bf0d6610ed2b4be225e" dependencies = [ "ariadne", "blake3", "codespan-reporting", - "foldhash 0.2.0", + "foldhash", "mago-database", "mago-span", "mago-text-edit", "regex", "schemars", - "serde", - "serde-sarif", - "serde_json", - "strum 0.28.0", + "strum", "termcolor", "tracing", ] [[package]] name = "mago-span" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c60dc85a6a26d3d66090774a40a47fb120c1c4c715f46acd7115a9939e5f56" +checksum = "c1c25a703e9e2e554338f1b92970b2b5e6051dafea20c528c50da830b621d814" dependencies = [ "mago-database", - "serde", ] [[package]] name = "mago-syntax" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266987ea49906ddacc4d06d61bc8c6dd78a8971d8ee969e8f51bd02691b09a28" +checksum = "098297d346a0d3ef68c2996628350d7ea589448eddeccfc85086327de0d54a4b" dependencies = [ - "bumpalo", + "mago-allocator", "mago-database", "mago-php-version", "mago-reporting", @@ -1403,47 +1374,51 @@ dependencies = [ "memchr", "ordered-float", "paste", - "serde", - "strum 0.28.0", + "strum", ] [[package]] name = "mago-syntax-core" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40955657014793afd27b3dd3411b8cf8bd5c43ae9c14f689ed2be49a542b04b" +checksum = "29b7be35b1522d084ea7c98f302c4ba092db9c8068b3515accaed24ab0635681" dependencies = [ - "bumpalo", + "mago-allocator", "mago-database", "mago-span", "memchr", - "serde", ] [[package]] name = "mago-text-edit" -version = "1.29.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad030e56695a2cbedfb74aa97b8dff2ddd9dbc68816d9e348c26d9074554256d" -dependencies = [ - "serde", - "strum 0.28.0", - "tracing", -] +checksum = "c321af313d7a0123806384510027a5bf1b9665bb48c66733a99c115bf0c12f02" [[package]] name = "mago-type-syntax" -version = "1.29.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b2cbea9198ebcb0b10c975c028e670431e5be9962e089543f368871d3988043" +checksum = "195d414236a48cbd23fa61fa5aad32dc741b4e5c318276bc73a6fa61bbcea1c6" dependencies = [ - "bumpalo", + "mago-allocator", "mago-database", "mago-span", "mago-syntax-core", "ordered-float", - "serde", - "strum 0.28.0", + "strum", +] + +[[package]] +name = "mago-word" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57023b20c4eb1085283e55212d5be7d1be832571f321da11e1a540d607ece48b" +dependencies = [ + "foldhash", + "itoa", + "mago-bytes", + "ryu", ] [[package]] @@ -1457,9 +1432,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "miniz_oxide" @@ -1473,9 +1448,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -1489,7 +1464,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "fsevent-sys", "inotify", "kqueue", @@ -1507,7 +1482,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -1560,7 +1535,6 @@ checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", "rand", - "serde", ] [[package]] @@ -1612,7 +1586,6 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" name = "phpantom_lsp" version = "0.8.0" dependencies = [ - "bumpalo", "clap", "criterion", "datatest-stable", @@ -1620,6 +1593,7 @@ dependencies = [ "flate2", "globset", "ignore", + "mago-allocator", "mago-composer", "mago-database", "mago-docblock", @@ -1664,7 +1638,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1722,16 +1696,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -1743,9 +1707,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -1764,12 +1728,11 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "rand_core", - "serde", ] [[package]] @@ -1777,9 +1740,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "serde", -] [[package]] name = "rayon" @@ -1807,7 +1767,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -1827,14 +1787,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" dependencies = [ "aho-corasick", "memchr", @@ -1844,9 +1804,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" dependencies = [ "aho-corasick", "memchr", @@ -1855,9 +1815,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "ring" @@ -1879,7 +1839,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -1888,9 +1848,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" dependencies = [ "log", "once_cell", @@ -1903,9 +1863,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] @@ -1923,9 +1883,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -1936,33 +1902,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schemafy_core" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bec29dddcfe60f92f3c0d422707b8b56473983ef0481df8d5236ed3ab8fdf24" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "schemafy_lib" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3d87f1df246a9b7e2bfd1f4ee5f88e48b11ef9cfc62e63f0dead255b1a6f5f" -dependencies = [ - "Inflector", - "proc-macro2", - "quote", - "schemafy_core", - "serde", - "serde_derive", - "serde_json", - "syn 1.0.109", - "uriparse", -] - [[package]] name = "schemars" version = "1.2.1" @@ -1985,7 +1924,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn", ] [[package]] @@ -2005,12 +1944,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - [[package]] name = "serde" version = "1.0.228" @@ -2021,26 +1954,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-sarif" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a053c46f18a8043570d4e32fefc4c6377f82bf29ec310a33e93f273048e3b0be" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "schemafy_lib", - "serde", - "serde_json", - "strum 0.27.2", - "strum_macros 0.27.2", - "syn 2.0.117", - "thiserror", - "typed-builder", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -2058,7 +1971,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2069,7 +1982,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2094,7 +2007,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2108,9 +2021,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -2144,15 +2057,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[package]] -name = "simdutf8" -version = "0.1.5" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "slab" @@ -2162,15 +2069,15 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -2188,31 +2095,13 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" - [[package]] name = "strum" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ - "strum_macros 0.28.0", -] - -[[package]] -name = "strum_macros" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.117", + "strum_macros", ] [[package]] @@ -2224,7 +2113,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2235,20 +2124,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", @@ -2263,7 +2141,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2284,7 +2162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2326,14 +2204,14 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if", ] @@ -2402,7 +2280,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2420,9 +2298,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" dependencies = [ "indexmap", "serde_core", @@ -2453,9 +2331,9 @@ dependencies = [ [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tower" @@ -2508,7 +2386,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2536,7 +2414,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2578,26 +2456,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "typed-builder" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" -dependencies = [ - "typed-builder-macro", -] - -[[package]] -name = "typed-builder-macro" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "typenum" version = "1.20.1" @@ -2616,12 +2474,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -2657,16 +2509,6 @@ dependencies = [ "log", ] -[[package]] -name = "uriparse" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" -dependencies = [ - "fnv", - "lazy_static", -] - [[package]] name = "url" version = "2.5.8" @@ -2740,27 +2582,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -2771,9 +2604,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2781,65 +2614,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.1", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -2847,9 +2646,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] @@ -3027,18 +2826,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" [[package]] name = "wit-bindgen" @@ -3046,85 +2836,6 @@ version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.1", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "writeable" version = "0.6.3" @@ -3158,9 +2869,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -3175,28 +2886,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.50" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.50" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3216,15 +2927,15 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] @@ -3237,7 +2948,7 @@ checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3270,7 +2981,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3305,9 +3016,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" diff --git a/Cargo.toml b/Cargo.toml index c6c6d1b0..058d2866 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,16 +17,16 @@ serde_json = "1.0" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tokio = { version = "1.39", features = ["full"] } -mago-syntax = "=1.29.0" -mago-database = "=1.29.0" -mago-docblock = "=1.29.0" -mago-names = "=1.29.0" -mago-span = "=1.29.0" -mago-type-syntax = "=1.29.0" -mago-formatter = "=1.29.0" -mago-php-version = "=1.29.0" -mago-composer = "=1.29.0" -bumpalo = "3" +mago-syntax = "=1.43.0" +mago-allocator = "=1.43.0" +mago-database = "=1.43.0" +mago-docblock = "=1.42.0" +mago-names = "=1.43.0" +mago-span = "=1.43.0" +mago-type-syntax = "=1.42.0" +mago-formatter = "=1.43.0" +mago-php-version = "=1.43.0" +mago-composer = "=1.43.0" ignore = "0.4" globset = "0.4" regex = "1" diff --git a/src/call_args.rs b/src/call_args.rs index e290e1e1..95575cf8 100644 --- a/src/call_args.rs +++ b/src/call_args.rs @@ -10,7 +10,7 @@ //! This module is the single place that encodes PHP's binding rules so the //! various consumers stay consistent. -use mago_syntax::ast::{Argument, ArgumentList, Expression}; +use mago_syntax::cst::{Argument, ArgumentList, Expression}; use crate::atom::bytes_to_str; use crate::types::ParameterInfo; diff --git a/src/code_actions/change_visibility.rs b/src/code_actions/change_visibility.rs index 76cebab9..35c7eff5 100644 --- a/src/code_actions/change_visibility.rs +++ b/src/code_actions/change_visibility.rs @@ -28,10 +28,10 @@ use std::collections::HashMap; use std::sync::Arc; #[cfg(test)] -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::class_like::property::Property; -use mago_syntax::ast::modifier::Modifier; +use mago_syntax::cst::class_like::property::Property; +use mago_syntax::cst::modifier::Modifier; use tower_lsp::lsp_types::*; use super::cursor_context::{CursorContext, MemberContext, find_cursor_context}; @@ -548,7 +548,7 @@ fn find_visibility_from_context(ctx: &CursorContext<'_>, cursor: u32) -> Option< /// For constructor methods, check if the cursor is on a promoted /// parameter with a visibility modifier. fn find_promoted_param_visibility( - method: &mago_syntax::ast::class_like::method::Method<'_>, + method: &mago_syntax::cst::class_like::method::Method<'_>, cursor: u32, ) -> Option { use mago_span::HasSpan; @@ -602,7 +602,7 @@ mod tests { /// Helper: parse PHP and find visibility at a given byte offset. fn find_vis(php: &str, offset: u32) -> Option { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); let ctx = find_cursor_context(&program.statements, offset); diff --git a/src/code_actions/convert_switch_to_match.rs b/src/code_actions/convert_switch_to_match.rs index 74811003..c9766609 100644 --- a/src/code_actions/convert_switch_to_match.rs +++ b/src/code_actions/convert_switch_to_match.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; @@ -430,7 +430,7 @@ mod tests { use super::*; fn try_convert(php: &str) -> Option { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"test.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); diff --git a/src/code_actions/convert_to_arrow_function.rs b/src/code_actions/convert_to_arrow_function.rs index 062c20e4..b14fb8bd 100644 --- a/src/code_actions/convert_to_arrow_function.rs +++ b/src/code_actions/convert_to_arrow_function.rs @@ -12,9 +12,9 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::access::Access; -use mago_syntax::ast::call::Call; -use mago_syntax::ast::*; +use mago_syntax::cst::access::Access; +use mago_syntax::cst::call::Call; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; @@ -451,7 +451,7 @@ mod tests { use super::*; fn find_conversion(php: &str) -> Option { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); diff --git a/src/code_actions/convert_to_closure.rs b/src/code_actions/convert_to_closure.rs index 4ae179f9..84095fa2 100644 --- a/src/code_actions/convert_to_closure.rs +++ b/src/code_actions/convert_to_closure.rs @@ -12,9 +12,9 @@ use std::collections::{HashMap, HashSet}; use mago_span::HasSpan; -use mago_syntax::ast::access::Access; -use mago_syntax::ast::call::Call; -use mago_syntax::ast::*; +use mago_syntax::cst::access::Access; +use mago_syntax::cst::call::Call; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; @@ -491,7 +491,9 @@ fn find_arrow_in_expression( Expression::AnonymousClass(anon) => { if let Some(args) = &anon.argument_list { for a in args.arguments.iter() { - find_arrow_in_expression(a.value(), cursor, content, best); + if let Some(value) = a.value() { + find_arrow_in_expression(value, cursor, content, best); + } } } } @@ -801,7 +803,9 @@ fn collect_variables_in_expression( Expression::AnonymousClass(anon) => { if let Some(args) = &anon.argument_list { for a in args.arguments.iter() { - collect_variables_in_expression(a.value(), content, param_names, out); + if let Some(value) = a.value() { + collect_variables_in_expression(value, content, param_names, out); + } } } } @@ -834,7 +838,7 @@ mod tests { use super::*; fn find_conversion(php: &str) -> Option { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); diff --git a/src/code_actions/convert_to_instance_variable.rs b/src/code_actions/convert_to_instance_variable.rs index d294cf03..4d3f1578 100644 --- a/src/code_actions/convert_to_instance_variable.rs +++ b/src/code_actions/convert_to_instance_variable.rs @@ -17,11 +17,11 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::MethodBody; -use mago_syntax::ast::class_like::property::Property; -use mago_syntax::ast::sequence::Sequence; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::MethodBody; +use mago_syntax::cst::class_like::property::Property; +use mago_syntax::cst::sequence::Sequence; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; diff --git a/src/code_actions/cursor_context.rs b/src/code_actions/cursor_context.rs index 785f1e83..351d1067 100644 --- a/src/code_actions/cursor_context.rs +++ b/src/code_actions/cursor_context.rs @@ -7,12 +7,12 @@ //! namespace → class-like → member traversal. use mago_span::HasSpan; -use mago_syntax::ast::class_like::constant::ClassLikeConstant; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::Method; -use mago_syntax::ast::class_like::property::Property; -use mago_syntax::ast::function_like::function::Function; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::constant::ClassLikeConstant; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::Method; +use mago_syntax::cst::class_like::property::Property; +use mago_syntax::cst::function_like::function::Function; +use mago_syntax::cst::*; // ── Public types ──────────────────────────────────────────────────────────── @@ -204,7 +204,7 @@ fn find_member_at_cursor<'a>( #[cfg(test)] mod tests { use super::*; - use bumpalo::Bump; + use mago_allocator::LocalArena; /// Helper: parse PHP and find cursor context at a given byte offset. fn ctx_at(php: &str, offset: u32) -> CursorContext<'_> { @@ -212,7 +212,7 @@ mod tests { // borrows from the Program) lives long enough for the test // assertions. This is fine in tests — the memory is reclaimed // when the process exits. - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(arena, file_id, php.as_bytes()); find_cursor_context(&program.statements, offset) diff --git a/src/code_actions/extract_constant.rs b/src/code_actions/extract_constant.rs index ec4df740..daebf7f5 100644 --- a/src/code_actions/extract_constant.rs +++ b/src/code_actions/extract_constant.rs @@ -13,8 +13,8 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; diff --git a/src/code_actions/extract_function.rs b/src/code_actions/extract_function.rs index 882b161d..ebd07924 100644 --- a/src/code_actions/extract_function.rs +++ b/src/code_actions/extract_function.rs @@ -10,7 +10,7 @@ //! variable-type resolution pipeline. use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use std::collections::HashMap; use std::sync::Arc; use tower_lsp::lsp_types::*; diff --git a/src/code_actions/generate_constructor.rs b/src/code_actions/generate_constructor.rs index ebabda6a..2aabe812 100644 --- a/src/code_actions/generate_constructor.rs +++ b/src/code_actions/generate_constructor.rs @@ -14,12 +14,12 @@ use std::collections::HashMap; #[cfg(test)] -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::property::{Property, PropertyItem}; -use mago_syntax::ast::modifier::Modifier; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::property::{Property, PropertyItem}; +use mago_syntax::cst::modifier::Modifier; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use super::cursor_context::{CursorContext, MemberContext, find_cursor_context}; @@ -828,7 +828,7 @@ mod tests { #[test] fn detects_existing_constructor() { - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let php = " Vec { - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(arena, file_id, php.as_bytes()); @@ -1070,7 +1070,7 @@ mod tests { #[test] fn skips_hooked_property() { let php = " $this->name; }\n}"; - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(arena, file_id, php.as_bytes()); @@ -1094,7 +1094,7 @@ mod tests { #[test] fn finds_existing_methods() { - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let php = "name; }\n public function setName(string $name): self { $this->name = $name; return $this; }\n}"; let program = mago_syntax::parser::parse_file_content(arena, file_id, php.as_bytes()); diff --git a/src/code_actions/generate_property_hooks.rs b/src/code_actions/generate_property_hooks.rs index 32369db2..4c02f4fa 100644 --- a/src/code_actions/generate_property_hooks.rs +++ b/src/code_actions/generate_property_hooks.rs @@ -21,8 +21,8 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::class_like::property::Property; -use mago_syntax::ast::modifier::Modifier; +use mago_syntax::cst::class_like::property::Property; +use mago_syntax::cst::modifier::Modifier; use tower_lsp::lsp_types::*; use super::cursor_context::{ diff --git a/src/code_actions/inline_variable.rs b/src/code_actions/inline_variable.rs index faf8efab..06ac4fd3 100644 --- a/src/code_actions/inline_variable.rs +++ b/src/code_actions/inline_variable.rs @@ -19,9 +19,9 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::MethodBody; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::MethodBody; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; diff --git a/src/code_actions/mod.rs b/src/code_actions/mod.rs index 57bb5a8b..f745537b 100644 --- a/src/code_actions/mod.rs +++ b/src/code_actions/mod.rs @@ -99,8 +99,8 @@ mod simplify_null; mod update_docblock; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::sequence::Sequence; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::sequence::Sequence; use serde::{Deserialize, Serialize}; use tower_lsp::lsp_types::*; diff --git a/src/code_actions/phpstan/add_throws.rs b/src/code_actions/phpstan/add_throws.rs index 9b9abe55..384278db 100644 --- a/src/code_actions/phpstan/add_throws.rs +++ b/src/code_actions/phpstan/add_throws.rs @@ -23,9 +23,9 @@ use std::collections::HashMap; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::MethodBody; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::MethodBody; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; diff --git a/src/code_actions/promote_constructor_param.rs b/src/code_actions/promote_constructor_param.rs index 5117c21b..5822638f 100644 --- a/src/code_actions/promote_constructor_param.rs +++ b/src/code_actions/promote_constructor_param.rs @@ -13,13 +13,13 @@ //! unaffected because constructor promotion is transparent to callers. #[cfg(test)] -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::MethodBody; -use mago_syntax::ast::class_like::property::{PlainProperty, Property, PropertyItem}; -use mago_syntax::ast::modifier::Modifier; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::MethodBody; +use mago_syntax::cst::class_like::property::{PlainProperty, Property, PropertyItem}; +use mago_syntax::cst::modifier::Modifier; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use super::cursor_context::{CursorContext, MemberContext, find_cursor_context}; @@ -466,7 +466,7 @@ mod tests { /// Helper: parse PHP and find a promotion candidate at the given byte offset. fn find_candidate(php: &str, offset: u32) -> Option { - let arena = Box::leak(Box::new(Bump::new())); + let arena = Box::leak(Box::new(LocalArena::new())); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(arena, file_id, php.as_bytes()); let ctx = find_cursor_context(&program.statements, offset); diff --git a/src/code_actions/simplify_null.rs b/src/code_actions/simplify_null.rs index 62cfbaa4..779e0572 100644 --- a/src/code_actions/simplify_null.rs +++ b/src/code_actions/simplify_null.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; @@ -827,7 +827,7 @@ mod tests { offset: u32, php_version: PhpVersion, ) -> Option<(Simplification, u32, u32)> { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); @@ -1061,7 +1061,7 @@ mod tests { #[test] fn null_literal_detected() { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let php = " Option { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); let ctx = find_cursor_context(&program.statements, offset); diff --git a/src/completion/laravel_route_controller.rs b/src/completion/laravel_route_controller.rs index c20cd073..db08a157 100644 --- a/src/completion/laravel_route_controller.rs +++ b/src/completion/laravel_route_controller.rs @@ -22,7 +22,7 @@ use std::ops::ControlFlow; use tower_lsp::lsp_types::*; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::Backend; use crate::atom::bytes_to_str; diff --git a/src/completion/resolver.rs b/src/completion/resolver.rs index d2fb2946..f0dcd74e 100644 --- a/src/completion/resolver.rs +++ b/src/completion/resolver.rs @@ -1692,12 +1692,12 @@ pub(crate) fn apply_property_narrowing( /// Walk top-level statements to find the class + method containing the /// cursor, then apply narrowing to `results` for the given property path. fn walk_property_narrowing_in_statements<'b>( - statements: impl Iterator>, + statements: impl Iterator>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { use mago_span::HasSpan; - use mago_syntax::ast::*; + use mago_syntax::cst::*; for stmt in statements { match stmt { @@ -1765,12 +1765,12 @@ fn walk_property_narrowing_in_statements<'b>( /// Walk class members to find the method containing the cursor, then /// apply instanceof / guard-clause narrowing for the property path. fn walk_property_narrowing_in_members<'b>( - members: impl Iterator>, + members: impl Iterator>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; for member in members { if let ClassLikeMember::Method(method) = member { @@ -1791,12 +1791,12 @@ fn walk_property_narrowing_in_members<'b>( /// Walk statements applying only narrowing (no assignment scanning) /// for a property path like `$this->prop`. fn walk_property_narrowing_stmts<'b>( - statements: impl Iterator>, + statements: impl Iterator>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { use mago_span::HasSpan; - use mago_syntax::ast::*; + use mago_syntax::cst::*; use super::types::narrowing; @@ -1881,13 +1881,13 @@ fn walk_property_narrowing_stmts<'b>( /// Apply property-level narrowing inside an if / elseif / else chain. fn walk_property_narrowing_if<'b>( - if_stmt: &'b mago_syntax::ast::If<'b>, - enclosing_stmt: &'b mago_syntax::ast::Statement<'b>, + if_stmt: &'b mago_syntax::cst::If<'b>, + enclosing_stmt: &'b mago_syntax::cst::Statement<'b>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { use mago_span::HasSpan; - use mago_syntax::ast::*; + use mago_syntax::cst::*; use super::types::narrowing; @@ -2012,7 +2012,7 @@ fn walk_property_narrowing_if<'b>( /// Dispatch a single statement to `walk_property_narrowing_stmts`. fn walk_property_narrowing_stmt<'b>( - stmt: &'b mago_syntax::ast::Statement<'b>, + stmt: &'b mago_syntax::cst::Statement<'b>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { @@ -2030,12 +2030,12 @@ fn walk_property_narrowing_stmt<'b>( /// through those containers so a ternary nested inside them is still /// reached. fn walk_property_narrowing_expr<'b>( - expr: &'b mago_syntax::ast::Expression<'b>, + expr: &'b mago_syntax::cst::Expression<'b>, ctx: &VarResolutionCtx<'_>, results: &mut Vec, ) { use mago_span::HasSpan; - use mago_syntax::ast::*; + use mago_syntax::cst::*; use super::types::narrowing; diff --git a/src/completion/types/conditional.rs b/src/completion/types/conditional.rs index 341047c4..f0a28d0c 100644 --- a/src/completion/types/conditional.rs +++ b/src/completion/types/conditional.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::sync::Arc; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::php_type::PhpType; use crate::types::{ClassInfo, ParameterInfo}; diff --git a/src/completion/types/narrowing.rs b/src/completion/types/narrowing.rs index 5cef3ceb..4ac10a23 100644 --- a/src/completion/types/narrowing.rs +++ b/src/completion/types/narrowing.rs @@ -33,7 +33,7 @@ use crate::atom::{Atom, bytes_to_str}; use crate::php_type::PhpType; use crate::types::{AssertionKind, ClassInfo, ParameterInfo, ResolvedType, TypeAssertion}; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use super::conditional::extract_class_string_from_expr; use crate::completion::resolver::VarResolutionCtx; @@ -132,9 +132,9 @@ pub(in crate::completion) fn expr_to_subject_key(expr: &Expression<'_>) -> Optio /// coercion so `$a[0]` and `$a["0"]` narrow the same subject). Returns /// `None` for non-literal keys like `$a[$i]`. pub(in crate::completion) fn array_access_key_as_string( - aa: &mago_syntax::ast::ArrayAccess<'_>, + aa: &mago_syntax::cst::ArrayAccess<'_>, ) -> Option { - use mago_syntax::ast::Literal; + use mago_syntax::cst::Literal; match aa.index { Expression::Literal(Literal::String(s)) => { // `value` is the unquoted content; fall back to stripping @@ -1303,8 +1303,8 @@ pub(in crate::completion) fn statement_unconditionally_exits(stmt: &Statement<'_ Statement::Expression(es) => matches!( es.expression, Expression::Throw(_) - | Expression::Construct(mago_syntax::ast::Construct::Exit(_)) - | Expression::Construct(mago_syntax::ast::Construct::Die(_)) + | Expression::Construct(mago_syntax::cst::Construct::Exit(_)) + | Expression::Construct(mago_syntax::cst::Construct::Die(_)) ), // A block exits if its last statement exits. Statement::Block(block) => block diff --git a/src/completion/variable/class_string_resolution.rs b/src/completion/variable/class_string_resolution.rs index 0506bbd4..1dde2ec9 100644 --- a/src/completion/variable/class_string_resolution.rs +++ b/src/completion/variable/class_string_resolution.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::atom::bytes_to_str; use crate::parser::with_parsed_program; @@ -199,8 +199,8 @@ fn walk_class_string_assignments<'b>( } // Also walk the foreach body for nested assignments. let body_stmts: Vec<&Statement> = match &foreach.body { - mago_syntax::ast::ForeachBody::Statement(s) => vec![s], - mago_syntax::ast::ForeachBody::ColonDelimited(b) => { + mago_syntax::cst::ForeachBody::Statement(s) => vec![s], + mago_syntax::cst::ForeachBody::ColonDelimited(b) => { b.statements.iter().collect() } }; diff --git a/src/completion/variable/closure_resolution.rs b/src/completion/variable/closure_resolution.rs index 6a41f4d5..4da8bc49 100644 --- a/src/completion/variable/closure_resolution.rs +++ b/src/completion/variable/closure_resolution.rs @@ -27,8 +27,8 @@ use std::cell::Cell; use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::sequence::TokenSeparatedSequence; -use mago_syntax::ast::*; +use mago_syntax::cst::sequence::TokenSeparatedSequence; +use mago_syntax::cst::*; use crate::atom::bytes_to_str; use crate::completion::resolver::ResolutionCtx; diff --git a/src/completion/variable/foreach_resolution.rs b/src/completion/variable/foreach_resolution.rs index 6ac3915d..34dfd1ac 100644 --- a/src/completion/variable/foreach_resolution.rs +++ b/src/completion/variable/foreach_resolution.rs @@ -25,7 +25,7 @@ use crate::completion::resolver::VarResolutionCtx; /// `Option`. Returns `None` when the unified pipeline /// produces no results or an empty type string. pub(crate) fn resolve_expression_type<'b>( - expr: &'b mago_syntax::ast::Expression<'b>, + expr: &'b mago_syntax::cst::Expression<'b>, ctx: &VarResolutionCtx<'_>, ) -> Option { let resolved = super::rhs_resolution::resolve_rhs_expression(expr, ctx); diff --git a/src/completion/variable/forward_walk.rs b/src/completion/variable/forward_walk.rs index 00cceeef..21207437 100644 --- a/src/completion/variable/forward_walk.rs +++ b/src/completion/variable/forward_walk.rs @@ -44,9 +44,9 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::argument::Argument; -use mago_syntax::ast::sequence::TokenSeparatedSequence; -use mago_syntax::ast::*; +use mago_syntax::cst::argument::Argument; +use mago_syntax::cst::sequence::TokenSeparatedSequence; +use mago_syntax::cst::*; use crate::atom::{Atom, AtomMap, atom, bytes_to_str}; use crate::completion::resolver::{Loaders, VarResolutionCtx}; @@ -610,7 +610,7 @@ fn walk_closures_in_expr<'b>( // Constructor arguments evaluate in the outer scope (with the // outer `$this`), so scan them for closures there. if let Some(ref args) = anon.argument_list { - walk_closures_in_call_args(&args.arguments, outer_scope, ctx, |_| vec![]); + walk_closure_in_partial_call_args(&args.arguments, outer_scope, ctx, |_| vec![]); } // The anonymous class's own method bodies have their own // `$this` (the anonymous class), so walk them separately. @@ -798,6 +798,45 @@ fn walk_closures_in_call_args<'b, F>( } } +/// Walk the partial arguments of a call expression, invoking `infer_fn` for +/// each argument index to get inferred callable parameter types. +/// When an argument is a closure/arrow function, the inferred types +/// are passed through so untyped parameters get the correct types. +fn walk_closure_in_partial_call_args<'b, F>( + arguments: &'b TokenSeparatedSequence<'b, PartialArgument<'b>>, + outer_scope: &ScopeState, + ctx: &ForwardWalkCtx<'_>, + infer_fn: F, +) where + F: Fn(usize) -> Vec, +{ + for (arg_idx, arg) in arguments.iter().enumerate() { + let arg_expr = match arg { + PartialArgument::Positional(a) => a.value, + PartialArgument::Named(a) => a.value, + _ => continue, + }; + match arg_expr { + Expression::Closure(_) | Expression::ArrowFunction(_) => { + let inferred = infer_fn(arg_idx); + walk_closures_in_expr( + arg_expr, + outer_scope, + ctx, + if inferred.is_empty() { + None + } else { + Some(&inferred) + }, + ); + } + _ => { + walk_closures_in_expr(arg_expr, outer_scope, ctx, None); + } + } + } +} + /// Seed a closure/arrow function scope with parameter types, using /// inferred callable types as fallback for untyped parameters. /// @@ -1682,11 +1721,11 @@ fn walk_top_level_statements<'a, 'b: 'a>( /// and analyze each one. Handles the common PHP pattern: /// `if (!function_exists('name')) { function name(...) { ... } }` fn walk_functions_in_if_body<'b>( - body: &'b mago_syntax::ast::control_flow::r#if::IfBody<'b>, + body: &'b mago_syntax::cst::control_flow::r#if::IfBody<'b>, default_class: &ClassInfo, diag_ctx: &DiagnosticWalkCtx<'_>, ) { - use mago_syntax::ast::control_flow::r#if::IfBody; + use mago_syntax::cst::control_flow::r#if::IfBody; let statements: &[Statement<'b>] = match body { IfBody::Statement(stmt_body) => { @@ -1728,12 +1767,12 @@ fn walk_functions_in_if_body<'b>( /// Walk a class member to find method bodies and run the forward walker. fn walk_class_member_body<'b>( - member: &'b mago_syntax::ast::class_like::member::ClassLikeMember<'b>, + member: &'b mago_syntax::cst::class_like::member::ClassLikeMember<'b>, enclosing_class: &ClassInfo, diag_ctx: &DiagnosticWalkCtx<'_>, ) { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; if let ClassLikeMember::Method(method) = member && let MethodBody::Concrete(block) = &method.body @@ -1863,8 +1902,8 @@ fn seed_and_walk_function_body<'b>( /// accesses like `$this->prop` inside the anonymous class would then /// resolve against the outer class and be flagged as unknown. fn walk_anonymous_class_member_bodies<'b>(anon: &'b AnonymousClass<'b>, ctx: &ForwardWalkCtx<'_>) { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; // The parser extracts anonymous classes as `ClassInfo` with the // synthetic name `__anonymous@`. Look it up so @@ -3233,7 +3272,7 @@ fn process_increment_decrement<'b>( scope: &mut ScopeState, _ctx: &ForwardWalkCtx<'_>, ) { - use mago_syntax::ast::unary::{UnaryPostfixOperator, UnaryPrefixOperator}; + use mago_syntax::cst::unary::{UnaryPostfixOperator, UnaryPrefixOperator}; let var_expr = match expr { Expression::UnaryPostfix(postfix) => match &postfix.operator { @@ -4425,7 +4464,7 @@ fn process_compound_assignment<'b>( scope: &mut ScopeState, ctx: &ForwardWalkCtx<'_>, ) { - use mago_syntax::ast::assignment::AssignmentOperator; + use mago_syntax::cst::assignment::AssignmentOperator; let var_name = match assignment.lhs { Expression::Variable(Variable::Direct(dv)) => bytes_to_str(dv.name).to_string(), @@ -4655,7 +4694,7 @@ fn resolve_rhs_with_scope<'b>( if let Expression::Assignment(assignment) = rhs && !assignment.operator.is_assign() { - use mago_syntax::ast::assignment::AssignmentOperator; + use mago_syntax::cst::assignment::AssignmentOperator; let result_type = match &assignment.operator { AssignmentOperator::Concat(_) => Some(PhpType::string()), AssignmentOperator::Modulo(_) => Some(PhpType::int()), @@ -4777,7 +4816,7 @@ fn resolve_rhs_with_scope<'b>( // Type casts: (int)$x → int, (string)$x → string, etc. if let Expression::UnaryPrefix(prefix) = rhs { - use mago_syntax::ast::unary::UnaryPrefixOperator; + use mago_syntax::cst::unary::UnaryPrefixOperator; let cast_type = match &prefix.operator { UnaryPrefixOperator::IntCast(..) | UnaryPrefixOperator::IntegerCast(..) => { Some(PhpType::int()) @@ -4840,7 +4879,7 @@ fn resolve_rhs_with_scope<'b>( // Bitwise NOT (~): returns string when operand is string, int otherwise. if let Expression::UnaryPrefix(prefix) = rhs { - use mago_syntax::ast::unary::UnaryPrefixOperator; + use mago_syntax::cst::unary::UnaryPrefixOperator; if matches!(prefix.operator, UnaryPrefixOperator::BitwiseNot(_)) { let operand_types = resolve_rhs_with_scope(prefix.operand, scope, ctx); let is_string = !operand_types.is_empty() @@ -4920,7 +4959,7 @@ fn resolve_rhs_with_scope<'b>( // Binary operators — the result type depends on the operator kind. if let Expression::Binary(binary) = rhs { - use mago_syntax::ast::binary::BinaryOperator; + use mago_syntax::cst::binary::BinaryOperator; // Spaceship (<=>): always int (-1, 0, or 1). if matches!(binary.operator, BinaryOperator::Spaceship(_)) { @@ -6412,7 +6451,7 @@ fn collect_expr_assignment_deps( expr: &Expression<'_>, deps: &mut HashMap>, ) { - use mago_syntax::ast::variable::Variable; + use mago_syntax::cst::variable::Variable; if let Expression::Assignment(assign) = expr && let Expression::Variable(Variable::Direct(dv)) = assign.lhs @@ -6426,7 +6465,7 @@ fn collect_expr_assignment_deps( /// Collect all variable references from an expression (cheap, no type resolution). fn collect_rhs_variables(expr: &Expression<'_>, vars: &mut HashSet) { - use mago_syntax::ast::variable::Variable; + use mago_syntax::cst::variable::Variable; match expr { Expression::Variable(Variable::Direct(dv)) => { @@ -6467,16 +6506,16 @@ fn collect_rhs_variables(expr: &Expression<'_>, vars: &mut HashSet) { } } Expression::Access(access) => match access { - mago_syntax::ast::access::Access::Property(pa) => { + mago_syntax::cst::access::Access::Property(pa) => { collect_rhs_variables(pa.object, vars); } - mago_syntax::ast::access::Access::NullSafeProperty(pa) => { + mago_syntax::cst::access::Access::NullSafeProperty(pa) => { collect_rhs_variables(pa.object, vars); } - mago_syntax::ast::access::Access::StaticProperty(sp) => { + mago_syntax::cst::access::Access::StaticProperty(sp) => { collect_rhs_variables(sp.class, vars); } - mago_syntax::ast::access::Access::ClassConstant(cc) => { + mago_syntax::cst::access::Access::ClassConstant(cc) => { collect_rhs_variables(cc.class, vars); } }, @@ -6507,7 +6546,7 @@ fn collect_rhs_variables(expr: &Expression<'_>, vars: &mut HashSet) { /// Collect variable references from an argument list. fn collect_arglist_variables( - args: &mago_syntax::ast::argument::ArgumentList<'_>, + args: &mago_syntax::cst::argument::ArgumentList<'_>, vars: &mut HashSet, ) { for arg in args.arguments.iter() { diff --git a/src/completion/variable/raw_type_inference.rs b/src/completion/variable/raw_type_inference.rs index 4a9ebc3b..810a592f 100644 --- a/src/completion/variable/raw_type_inference.rs +++ b/src/completion/variable/raw_type_inference.rs @@ -5,7 +5,7 @@ /// resolver in [`super::forward_walk`] and the foreach/destructuring /// resolution module. use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use super::{ARRAY_ELEMENT_FUNCS, ARRAY_PRESERVING_FUNCS}; @@ -336,7 +336,7 @@ pub(in crate::completion) fn resolve_array_func_element_type( /// extracting their spans. This avoids serialising the argument list /// to a flat string and then re-splitting with `split_text_args`. pub(in crate::completion) fn extract_arg_texts_from_ast( - argument_list: &mago_syntax::ast::ArgumentList<'_>, + argument_list: &mago_syntax::cst::ArgumentList<'_>, content: &str, ) -> Vec { argument_list @@ -344,8 +344,8 @@ pub(in crate::completion) fn extract_arg_texts_from_ast( .iter() .map(|arg| { let span = match arg { - mago_syntax::ast::argument::Argument::Positional(pos) => pos.value.span(), - mago_syntax::ast::argument::Argument::Named(named) => named.value.span(), + mago_syntax::cst::argument::Argument::Positional(pos) => pos.value.span(), + mago_syntax::cst::argument::Argument::Named(named) => named.value.span(), }; let start = span.start.offset as usize; let end = span.end.offset as usize; diff --git a/src/completion/variable/resolution.rs b/src/completion/variable/resolution.rs index 951661da..a3f3d7b4 100644 --- a/src/completion/variable/resolution.rs +++ b/src/completion/variable/resolution.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::atom::{atom, bytes_to_str, last_segment}; use crate::docblock; @@ -844,7 +844,7 @@ fn find_anonymous_class_containing_cursor<'a>( /// Walk a list of call arguments. fn walk_args<'a>( - arguments: &'a mago_syntax::ast::sequence::TokenSeparatedSequence<'a, Argument<'a>>, + arguments: &'a mago_syntax::cst::sequence::TokenSeparatedSequence<'a, Argument<'a>>, cursor: u32, ) -> Option<&'a AnonymousClass<'a>> { for arg in arguments.iter() { diff --git a/src/completion/variable/rhs_resolution.rs b/src/completion/variable/rhs_resolution.rs index 0f5a8910..7f4cf143 100644 --- a/src/completion/variable/rhs_resolution.rs +++ b/src/completion/variable/rhs_resolution.rs @@ -27,8 +27,8 @@ use std::collections::HashMap; use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::*; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::*; use crate::Backend; use crate::atom::{Atom, AtomMap, bytes_to_str}; @@ -2554,7 +2554,7 @@ fn resolve_rhs_function_call<'b>( // invoking it with `()` returns the underlying method's return // type. Delegate to the matching call-resolution path. if let Expression::PartialApplication(pa) = func_call.function { - use mago_syntax::ast::ast::partial_application::PartialApplication; + use mago_syntax::cst::partial_application::PartialApplication; match pa { PartialApplication::StaticMethod(sma) => { // For first-class callable invocation through late-static-binding @@ -2606,7 +2606,7 @@ fn resolve_rhs_function_call<'b>( } } // Build a synthetic StaticMethodCall and resolve it. - let synthetic = mago_syntax::ast::ast::call::StaticMethodCall { + let synthetic = mago_syntax::cst::call::StaticMethodCall { class: sma.class, double_colon: sma.double_colon, method: sma.method.clone(), diff --git a/src/diagnostics/type_errors.rs b/src/diagnostics/type_errors.rs index 586894b2..5978842e 100644 --- a/src/diagnostics/type_errors.rs +++ b/src/diagnostics/type_errors.rs @@ -13,12 +13,12 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; use mago_span::HasSpan; -use mago_syntax::ast::Program; -use mago_syntax::ast::argument::Argument; -use mago_syntax::ast::call::Call; -use mago_syntax::ast::expression::Expression; -use mago_syntax::ast::literal::Literal; -use mago_syntax::ast::statement::Statement; +use mago_syntax::cst::argument::Argument; +use mago_syntax::cst::call::Call; +use mago_syntax::cst::expression::Expression; +use mago_syntax::cst::literal::Literal; +use mago_syntax::cst::statement::Statement; +use mago_syntax::cst::{PartialArgument, Program}; use tower_lsp::lsp_types::*; @@ -828,7 +828,7 @@ fn contains_self_or_parent(ty: &PhpType) -> bool { /// Try to register the argument expressions of an [`ArgumentList`] if its /// `args_start` offset matches one of the call sites we are interested in. fn try_collect_argument_list<'a>( - arg_list: &'a mago_syntax::ast::argument::ArgumentList<'a>, + arg_list: &'a mago_syntax::cst::argument::ArgumentList<'a>, call_site_starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { @@ -852,6 +852,38 @@ fn try_collect_argument_list<'a>( result.insert(args_start, expressions); } +/// Try to register the partial argument expressions of an [`PartialArgumentList`] if its +/// `args_start` offset matches one of the call sites we are interested in. +fn try_collect_partial_argument_list<'a>( + arg_list: &'a mago_syntax::cst::argument::PartialArgumentList<'a>, + call_site_starts: &HashSet, + result: &mut HashMap, usize, usize)>>, +) { + let args_start = arg_list.left_parenthesis.end.offset; + if !call_site_starts.contains(&args_start) { + return; + } + // Placeholders have no expression and therefore no type to validate. + // Keep only supplied positional/named arguments. + let expressions: Vec<(&'a Expression<'a>, usize, usize)> = arg_list + .arguments + .iter() + .filter_map(|arg| { + let value = match arg { + PartialArgument::Positional(pos) => pos.value, + PartialArgument::Named(named) => named.value, + PartialArgument::NamedPlaceholder(_) + | PartialArgument::Placeholder(_) + | PartialArgument::VariadicPlaceholder(_) => return None, + }; + let start = value.span().start.offset as usize; + let end = value.span().end.offset as usize; + Some((value, start, end)) + }) + .collect(); + result.insert(args_start, expressions); +} + // ── Recursive AST walkers ─────────────────────────────────────────────────── fn collect_from_statement<'a>( @@ -972,7 +1004,7 @@ fn collect_from_statement<'a>( } } Statement::Declare(declare) => { - use mago_syntax::ast::declare::DeclareBody; + use mago_syntax::cst::declare::DeclareBody; match &declare.body { DeclareBody::Statement(inner) => { collect_from_statement(inner, starts, result); @@ -1007,13 +1039,13 @@ fn collect_from_statement<'a>( } fn collect_from_class_member<'a>( - member: &'a mago_syntax::ast::class_like::member::ClassLikeMember<'a>, + member: &'a mago_syntax::cst::class_like::member::ClassLikeMember<'a>, starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; - use mago_syntax::ast::class_like::property::{ + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; + use mago_syntax::cst::class_like::property::{ Property, PropertyHookBody, PropertyHookConcreteBody, PropertyItem, }; match member { @@ -1060,7 +1092,7 @@ fn collect_from_class_member<'a>( } } ClassLikeMember::EnumCase(ec) => { - use mago_syntax::ast::class_like::enum_case::EnumCaseItem; + use mago_syntax::cst::class_like::enum_case::EnumCaseItem; match &ec.item { EnumCaseItem::Backed(b) => { collect_from_expression(b.value, starts, result); @@ -1073,11 +1105,11 @@ fn collect_from_class_member<'a>( } fn collect_from_if_body<'a>( - body: &'a mago_syntax::ast::control_flow::r#if::IfBody<'a>, + body: &'a mago_syntax::cst::control_flow::r#if::IfBody<'a>, starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { - use mago_syntax::ast::control_flow::r#if::IfBody; + use mago_syntax::cst::control_flow::r#if::IfBody; match body { IfBody::Statement(if_stmt_body) => { collect_from_statement(if_stmt_body.statement, starts, result); @@ -1109,11 +1141,11 @@ fn collect_from_if_body<'a>( } fn collect_from_switch_body<'a>( - body: &'a mago_syntax::ast::control_flow::switch::SwitchBody<'a>, + body: &'a mago_syntax::cst::control_flow::switch::SwitchBody<'a>, starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { - use mago_syntax::ast::control_flow::switch::SwitchBody; + use mago_syntax::cst::control_flow::switch::SwitchBody; match body { SwitchBody::BraceDelimited(b) => { for case in b.cases.iter() { @@ -1222,7 +1254,7 @@ fn collect_from_expression<'a>( } Expression::Match(match_expr) => { collect_from_expression(match_expr.expression, starts, result); - use mago_syntax::ast::control_flow::r#match::MatchArm; + use mago_syntax::cst::control_flow::r#match::MatchArm; for arm in match_expr.arms.iter() { match arm { MatchArm::Expression(expr_arm) => { @@ -1238,7 +1270,7 @@ fn collect_from_expression<'a>( } } Expression::Yield(yield_expr) => { - use mago_syntax::ast::r#yield::Yield; + use mago_syntax::cst::r#yield::Yield; match yield_expr { Yield::Value(v) => { if let Some(val) = v.value { @@ -1261,7 +1293,7 @@ fn collect_from_expression<'a>( collect_from_expression(clone.object, starts, result); } Expression::Access(access) => { - use mago_syntax::ast::access::Access; + use mago_syntax::cst::access::Access; match access { Access::Property(pa) => { collect_from_expression(pa.object, starts, result); @@ -1278,7 +1310,7 @@ fn collect_from_expression<'a>( } } Expression::Construct(construct) => { - use mago_syntax::ast::construct::Construct; + use mago_syntax::cst::construct::Construct; match construct { Construct::Isset(c) => { for val in c.values.iter() { @@ -1327,8 +1359,8 @@ fn collect_from_expression<'a>( collect_from_expression(pipe.callable, starts, result); } Expression::CompositeString(cs) => { - use mago_syntax::ast::string::{CompositeString, StringPart}; - let walk_parts = |parts: &'a mago_syntax::ast::sequence::Sequence< + use mago_syntax::cst::string::{CompositeString, StringPart}; + let walk_parts = |parts: &'a mago_syntax::cst::sequence::Sequence< 'a, StringPart<'a>, >, @@ -1363,8 +1395,8 @@ fn collect_from_expression<'a>( } Expression::AnonymousClass(anon) => { if let Some(ref args) = anon.argument_list { - try_collect_argument_list(args, starts, result); - collect_from_argument_list(args, starts, result); + try_collect_partial_argument_list(args, starts, result); + collect_from_partial_argument_list(args, starts, result); } for member in anon.members.iter() { collect_from_class_member(member, starts, result); @@ -1391,7 +1423,7 @@ fn collect_from_expression<'a>( } fn collect_from_argument_list<'a>( - arg_list: &'a mago_syntax::ast::argument::ArgumentList<'a>, + arg_list: &'a mago_syntax::cst::argument::ArgumentList<'a>, starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { @@ -1400,15 +1432,27 @@ fn collect_from_argument_list<'a>( } } +fn collect_from_partial_argument_list<'a>( + arg_list: &'a mago_syntax::cst::argument::PartialArgumentList<'a>, + starts: &HashSet, + result: &mut HashMap, usize, usize)>>, +) { + for arg in arg_list.arguments.iter() { + if let Some(value) = arg.value() { + collect_from_expression(value, starts, result); + } + } +} + fn collect_from_array_elements<'a>( - elements: &'a mago_syntax::ast::sequence::TokenSeparatedSequence< + elements: &'a mago_syntax::cst::sequence::TokenSeparatedSequence< 'a, - mago_syntax::ast::array::ArrayElement<'a>, + mago_syntax::cst::array::ArrayElement<'a>, >, starts: &HashSet, result: &mut HashMap, usize, usize)>>, ) { - use mago_syntax::ast::array::ArrayElement; + use mago_syntax::cst::array::ArrayElement; for elem in elements.iter() { match elem { ArrayElement::KeyValue(kv) => { @@ -1561,7 +1605,7 @@ impl Backend { Expression::UnaryPrefix(unary) if matches!( unary.operator, - mago_syntax::ast::unary::UnaryPrefixOperator::Negation(_) + mago_syntax::cst::unary::UnaryPrefixOperator::Negation(_) ) => { match unary.operand { diff --git a/src/diagnostics/undefined_variables.rs b/src/diagnostics/undefined_variables.rs index b6ba2855..9e34a05f 100644 --- a/src/diagnostics/undefined_variables.rs +++ b/src/diagnostics/undefined_variables.rs @@ -52,7 +52,7 @@ use std::collections::HashSet; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; @@ -1535,7 +1535,7 @@ fn expr_has_get_defined_vars(expr: &Expression<'_>) -> bool { Expression::AnonymousClass(anon) => anon.argument_list.as_ref().is_some_and(|args| { args.arguments .iter() - .any(|a| expr_has_get_defined_vars(a.value())) + .any(|a| a.value().is_some_and(expr_has_get_defined_vars)) }), // Don't recurse into closures/arrow functions. Expression::Closure(_) | Expression::ArrowFunction(_) => false, diff --git a/src/diagnostics/unused_variables.rs b/src/diagnostics/unused_variables.rs index 694fbf4d..c115ebfe 100644 --- a/src/diagnostics/unused_variables.rs +++ b/src/diagnostics/unused_variables.rs @@ -13,7 +13,7 @@ use std::collections::{HashMap, HashSet}; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::*; use crate::Backend; diff --git a/src/docblock/parser.rs b/src/docblock/parser.rs index 69e4f453..975bcbfb 100644 --- a/src/docblock/parser.rs +++ b/src/docblock/parser.rs @@ -17,7 +17,7 @@ //! without borrowing from the arena. This keeps the arena lifetime //! contained within each call. -use bumpalo::Bump; +use mago_allocator::{Arena, LocalArena}; use mago_docblock::document::{Element, TagKind, TextSegment}; use mago_span::Span; @@ -92,7 +92,7 @@ impl DocblockInfo { /// work with standalone strings), pass [`Span::default()`] or a /// zero-offset span. pub fn parse_docblock(docblock: &str, base_span: Span) -> Option { - let arena = Bump::new(); + let arena = LocalArena::new(); // Work around a `mago-docblock` lexer quirk before parsing (see // `normalize_tag_indentation`). The rewrite is length-preserving, @@ -210,7 +210,7 @@ fn collect_tags(document: &mago_docblock::document::Document<'_>) -> DocblockInf let mut description_parts: Vec = Vec::new(); let mut seen_tag = false; - for element in &document.elements { + for element in document.elements { match element { Element::Tag(tag) => { seen_tag = true; @@ -223,7 +223,7 @@ fn collect_tags(document: &mago_docblock::document::Document<'_>) -> DocblockInf }); } Element::Text(text) if !seen_tag => { - for seg in &text.segments { + for seg in text.segments { match seg { TextSegment::Paragraph { content, .. } => { description_parts.push(bytes_to_str(content).to_owned()); diff --git a/src/docblock/tags.rs b/src/docblock/tags.rs index 1ff9d74a..a66112a3 100644 --- a/src/docblock/tags.rs +++ b/src/docblock/tags.rs @@ -19,7 +19,7 @@ use mago_docblock::document::TagKind; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::symbol_map::docblock::get_docblock_text_with_offset; use crate::types::{AssertionKind, PhpVersion, TypeAssertion}; diff --git a/src/document_links.rs b/src/document_links.rs index 65eb47f8..6abfa59e 100644 --- a/src/document_links.rs +++ b/src/document_links.rs @@ -5,9 +5,9 @@ use std::path::{Path, PathBuf}; -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{DocumentLink, Range, Url}; use crate::Backend; @@ -33,7 +33,7 @@ impl Backend { let file_path = Url::parse(uri).ok().and_then(|u| u.to_file_path().ok()); let file_dir = file_path.as_deref().and_then(|p| p.parent()); - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); diff --git a/src/folding.rs b/src/folding.rs index c8f1b170..e169d9fd 100644 --- a/src/folding.rs +++ b/src/folding.rs @@ -4,9 +4,9 @@ /// (class bodies, function/method bodies, closures, arrays, control-flow /// blocks, argument/parameter lists), and scans trivia for doc-block and /// consecutive single-line comment ranges. -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{FoldingRange, FoldingRangeKind}; use crate::Backend; @@ -19,7 +19,7 @@ impl Backend { /// Re-parses the source with `mago_syntax` (the raw AST is not cached) /// and walks every statement/expression to emit `FoldingRange` entries. pub fn handle_folding_range(&self, content: &str) -> Option> { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); @@ -558,7 +558,9 @@ fn collect_from_expression( ranges, ); for arg in arg_list.arguments.iter() { - collect_from_expression(arg.value(), idx, ranges); + if let Some(value) = arg.value() { + collect_from_expression(value, idx, ranges); + } } } for member in anon.members.iter() { diff --git a/src/formatting.rs b/src/formatting.rs index a6bde80c..8aa78ae5 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -213,7 +213,7 @@ fn format_with_mago( content: &str, php_version: mago_php_version::PHPVersion, ) -> Result { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let settings = mago_formatter::settings::FormatSettings::default(); let formatter = mago_formatter::Formatter::new(&arena, php_version, settings); diff --git a/src/parser/ast_update.rs b/src/parser/ast_update.rs index ef0c20f9..23eac069 100644 --- a/src/parser/ast_update.rs +++ b/src/parser/ast_update.rs @@ -15,10 +15,10 @@ use crate::php_type::PhpType; use crate::symbol_map::extract_symbol_map; use crate::types::TypeAliasDef; -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use mago_syntax::parser::parse_file_content; use crate::Backend; @@ -26,11 +26,11 @@ use crate::types::ClassInfo; use super::DocblockCtx; -/// Run `f` with a parsing arena, reusing a thread-local `Bump` across +/// Run `f` with a parsing arena, reusing a thread-local `LocalArena` across /// calls instead of allocating a fresh one each time. /// /// `update_ast_inner` is invoked on every keystroke (each `didChange`), -/// so a fresh `Bump::new()` per call returns its backing pages to the OS +/// so a fresh `LocalArena::new()` per call returns its backing pages to the OS /// via `munmap` on drop and re-acquires them via `mmap` on the next /// parse. Reusing one arena and `reset()`ing it (an O(1) bump-pointer /// rewind that keeps the pages allocated) eliminates those syscalls @@ -39,11 +39,11 @@ use super::DocblockCtx; /// Resolution can trigger a nested parse on the same thread (e.g. /// `find_or_load_function` calls `update_ast` while the outer parse is /// still using the arena). Such re-entrant calls fall back to a throwaway -/// `Bump` so the shared arena is never aliased — the borrow held for the +/// `LocalArena` so the shared arena is never aliased — the borrow held for the /// duration of `f` makes `try_borrow_mut` fail for the nested call. -fn with_reusable_arena(f: impl FnOnce(&Bump) -> R) -> R { +fn with_reusable_arena(f: impl FnOnce(&LocalArena) -> R) -> R { thread_local! { - static ARENA: RefCell = RefCell::new(Bump::with_capacity(512 * 1024)); + static ARENA: RefCell = const { RefCell::new(LocalArena::new()) }; } ARENA.with(|cell| match cell.try_borrow_mut() { @@ -51,7 +51,7 @@ fn with_reusable_arena(f: impl FnOnce(&Bump) -> R) -> R { arena.reset(); f(&arena) } - Err(_) => f(&Bump::new()), + Err(_) => f(&LocalArena::new()), }) } diff --git a/src/parser/classes.rs b/src/parser/classes.rs index 837edf7b..fcd72895 100644 --- a/src/parser/classes.rs +++ b/src/parser/classes.rs @@ -4,15 +4,15 @@ use crate::php_type::PhpType; use crate::types::TypeAliasDef; use crate::util::strip_fqn_prefix; use mago_span::HasSpan; -use mago_syntax::ast::attribute::AttributeList; -use mago_syntax::ast::class_like::enum_case::EnumCaseItem; -use mago_syntax::ast::class_like::member::ClassLikeMember; -use mago_syntax::ast::class_like::method::{Method, MethodBody}; -use mago_syntax::ast::class_like::property::{Property, PropertyItem}; -use mago_syntax::ast::class_like::trait_use::{ +use mago_syntax::cst::attribute::AttributeList; +use mago_syntax::cst::class_like::enum_case::EnumCaseItem; +use mago_syntax::cst::class_like::member::ClassLikeMember; +use mago_syntax::cst::class_like::method::{Method, MethodBody}; +use mago_syntax::cst::class_like::property::{Property, PropertyItem}; +use mago_syntax::cst::class_like::trait_use::{ TraitUseAdaptation, TraitUseMethodReference, TraitUseSpecification, }; -use mago_syntax::ast::sequence::Sequence; +use mago_syntax::cst::sequence::Sequence; /// Check whether a method has the `#[Scope]` attribute (Laravel 11+). /// @@ -143,7 +143,7 @@ fn parse_attribute_target_flags(text: &str) -> u8 { /// given synthetic names of the form `__anonymous@` so that /// [`find_class_at_offset`](crate::util::find_class_at_offset) can resolve /// `$this` inside their bodies. -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::Backend; use crate::atom::{Atom, AtomMap, atom, atom_bytes, bytes_to_str, last_segment}; @@ -2727,7 +2727,7 @@ impl Backend { }; let alias = alias_adapt.alias.as_ref().map(|a| atom_bytes(a.value)); - let visibility = alias_adapt.visibility.as_ref().map(|m| { + let visibility = alias_adapt.modifier.as_ref().map(|m| { if m.is_private() { Visibility::Private } else if m.is_protected() { diff --git a/src/parser/error_format.rs b/src/parser/error_format.rs index 129a31f7..cd35adf5 100644 --- a/src/parser/error_format.rs +++ b/src/parser/error_format.rs @@ -22,7 +22,7 @@ pub(crate) fn format_parse_error(error: &ParseError) -> String { match error { ParseError::SyntaxError(e) => format_syntax_error(e), ParseError::UnexpectedEndOfFile(expected, _, _) => { - let expected = friendly_token_list(expected); + let expected = friendly_token_list(expected.kinds()); if expected.is_empty() { "Syntax error: unexpected end of file".to_string() } else { @@ -31,7 +31,7 @@ pub(crate) fn format_parse_error(error: &ParseError) -> String { } ParseError::UnexpectedToken(expected, found, _) => { let found = friendly_token_name(found); - let expected = friendly_token_list(expected); + let expected = friendly_token_list(expected.kinds()); if expected.is_empty() { format!("Syntax error: unexpected token {found}") } else { @@ -39,7 +39,7 @@ pub(crate) fn format_parse_error(error: &ParseError) -> String { } } ParseError::UnclosedLiteralString(kind, _) => { - use mago_syntax::ast::LiteralStringKind; + use mago_syntax::cst::LiteralStringKind; match kind { LiteralStringKind::SingleQuoted => { "Syntax error: unclosed single-quoted string".to_string() @@ -116,6 +116,9 @@ fn friendly_token_name(kind: &TokenKind) -> String { TokenKind::LiteralString => "a string", TokenKind::PartialLiteralString => "a string", TokenKind::StringPart => "a string part", + TokenKind::OffsetNumber => "an offset number", + TokenKind::OffsetString => "an offset string", + TokenKind::StringVariableName => "a string variable name", // ── Keywords ───────────────────────────────────────────── TokenKind::Abstract => "`abstract`", @@ -320,6 +323,7 @@ mod tests { use super::*; use mago_database::file::FileId; use mago_span::{Position, Span}; + use mago_syntax::error::Expected; fn pos(offset: u32) -> Position { Position::new(offset) @@ -332,7 +336,7 @@ mod tests { #[test] fn unexpected_minus_instead_of_variable() { let err = ParseError::UnexpectedToken( - Box::new([TokenKind::Variable]), + Expected::Exactly(TokenKind::Variable), TokenKind::Minus, span(10, 11), ); @@ -346,7 +350,7 @@ mod tests { #[test] fn unexpected_token_with_multiple_expected() { let err = ParseError::UnexpectedToken( - Box::new([TokenKind::Function, TokenKind::Class, TokenKind::Interface]), + Expected::OneOf(&[TokenKind::Function, TokenKind::Class, TokenKind::Interface]), TokenKind::Minus, span(10, 11), ); @@ -360,7 +364,7 @@ mod tests { #[test] fn unexpected_token_with_two_expected() { let err = ParseError::UnexpectedToken( - Box::new([TokenKind::Semicolon, TokenKind::RightBrace]), + Expected::OneOf(&[TokenKind::Semicolon, TokenKind::RightBrace]), TokenKind::LeftParenthesis, span(5, 6), ); @@ -373,7 +377,7 @@ mod tests { #[test] fn unexpected_token_no_expected() { - let err = ParseError::UnexpectedToken(Box::new([]), TokenKind::At, span(0, 1)); + let err = ParseError::UnexpectedToken(Expected::OneOf(&[]), TokenKind::At, span(0, 1)); let msg = format_parse_error(&err); assert_eq!(msg, "Syntax error: unexpected token `@`"); } @@ -381,8 +385,11 @@ mod tests { #[test] fn unexpected_eof_with_expected() { let file_id = FileId::new(b"test.php"); - let err = - ParseError::UnexpectedEndOfFile(Box::new([TokenKind::Semicolon]), file_id, pos(100)); + let err = ParseError::UnexpectedEndOfFile( + Expected::Exactly(TokenKind::Semicolon), + file_id, + pos(100), + ); let msg = format_parse_error(&err); assert_eq!(msg, "Syntax error: unexpected end of file, expected `;`"); } @@ -390,14 +397,14 @@ mod tests { #[test] fn unexpected_eof_no_expected() { let file_id = FileId::new(b"test.php"); - let err = ParseError::UnexpectedEndOfFile(Box::new([]), file_id, pos(50)); + let err = ParseError::UnexpectedEndOfFile(Expected::OneOf(&[]), file_id, pos(50)); let msg = format_parse_error(&err); assert_eq!(msg, "Syntax error: unexpected end of file"); } #[test] fn unclosed_single_quoted_string() { - use mago_syntax::ast::LiteralStringKind; + use mago_syntax::cst::LiteralStringKind; let err = ParseError::UnclosedLiteralString(LiteralStringKind::SingleQuoted, span(5, 20)); let msg = format_parse_error(&err); assert_eq!(msg, "Syntax error: unclosed single-quoted string"); @@ -405,7 +412,7 @@ mod tests { #[test] fn unclosed_double_quoted_string() { - use mago_syntax::ast::LiteralStringKind; + use mago_syntax::cst::LiteralStringKind; let err = ParseError::UnclosedLiteralString(LiteralStringKind::DoubleQuoted, span(5, 20)); let msg = format_parse_error(&err); assert_eq!(msg, "Syntax error: unclosed double-quoted string"); diff --git a/src/parser/functions.rs b/src/parser/functions.rs index f9b96f9e..2d1bbd79 100644 --- a/src/parser/functions.rs +++ b/src/parser/functions.rs @@ -4,7 +4,7 @@ /// definitions and `define('NAME', value)` constant declarations from /// the PHP AST. use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::Backend; use crate::atom::{atom, atom_bytes, bytes_to_str}; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b6c62d63..051c2ca9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -22,7 +22,7 @@ mod use_statements; use crate::atom::{atom, bytes_to_str, last_segment}; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::php_type::PhpType; use crate::types::*; @@ -218,7 +218,7 @@ fn extract_version_availability( for arg in arg_list.arguments.iter() { match arg { - argument::Argument::Named(named) => { + argument::PartialArgument::Named(named) => { let name = bytes_to_str(named.name.value).to_string(); let value = extract_string_literal_value(named.value, ctx.content); if let Some(ver_str) = value { @@ -230,13 +230,14 @@ fn extract_version_availability( } } } - argument::Argument::Positional(positional) => { + argument::PartialArgument::Positional(positional) => { // Positional argument is treated as `from`. let value = extract_string_literal_value(positional.value, ctx.content); if let Some(ver_str) = value { from = PhpVersion::from_composer_constraint(&ver_str); } } + _ => {} } } @@ -277,16 +278,17 @@ pub(crate) fn extract_language_level_type( for arg in arg_list.arguments.iter() { match arg { - argument::Argument::Named(named) => { + argument::PartialArgument::Named(named) => { let name = bytes_to_str(named.name.value).to_string(); if name == "default" { default_type = extract_string_literal_value(named.value, ctx.content); } } - argument::Argument::Positional(positional) => { + argument::PartialArgument::Positional(positional) => { // The positional argument is the version → type array. extract_version_type_pairs(positional.value, ctx.content, &mut version_map); } + _ => {} } } @@ -358,8 +360,9 @@ pub(crate) fn extract_array_shape_type( // an associative array literal ["key" => "type", ...]. let first_arg = arg_list.arguments.first()?; let expr = match first_arg { - argument::Argument::Positional(p) => p.value, - argument::Argument::Named(n) => n.value, + argument::PartialArgument::Positional(p) => p.value, + argument::PartialArgument::Named(n) => n.value, + _ => return None, }; let elements: Box>> = match expr { @@ -607,7 +610,7 @@ pub(crate) fn extract_deprecated_attribute( for arg in arg_list.arguments.iter() { match arg { - argument::Argument::Named(named) => { + argument::PartialArgument::Named(named) => { let name = bytes_to_str(named.name.value).to_string(); let value = extract_string_literal_value(named.value, ctx.content); match name.as_str() { @@ -620,12 +623,11 @@ pub(crate) fn extract_deprecated_attribute( _ => {} } } - argument::Argument::Positional(positional) => { - // First positional argument is the reason/message. - if reason.is_none() { - reason = extract_string_literal_value(positional.value, ctx.content); - } + // First positional argument is the reason/message. + argument::PartialArgument::Positional(positional) if reason.is_none() => { + reason = extract_string_literal_value(positional.value, ctx.content); } + _ => {} } } @@ -724,13 +726,13 @@ fn extract_string_literal_value( // During a single diagnostic pass the file content is immutable and // `with_parsed_program` may be called dozens of times for the same // content string (once per unique variable subject, plus secondary -// helpers). Each call allocates a fresh `Bump` arena and re-parses the +// helpers). Each call allocates a fresh `LocalArena` arena and re-parses the // entire file from scratch. // // The cache below eliminates that redundancy. [`with_parse_cache`] // stores only the content `String` (cheap allocation, no parsing). // The first [`with_parsed_program`] call whose content matches then -// lazily parses the file, storing the `Bump` arena and a raw pointer +// lazily parses the file, storing the `LocalArena` arena and a raw pointer // to the resulting `Program`. Subsequent calls reuse the cached AST. // // This lazy approach avoids paying the parse cost when the cache is @@ -744,7 +746,7 @@ fn extract_string_literal_value( // // ## Safety // -// The `Program<'arena>` borrows from the `Bump` arena. Both live +// The `Program<'arena>` borrows from the `LocalArena` arena. Both live // inside the `Option` stored in the thread-local // `RefCell`. The raw pointer is reconstituted to a reference only // while the `RefCell` borrow is held and the entry is `Some`, so the @@ -760,9 +762,9 @@ fn extract_string_literal_value( struct ParseCacheEntry { /// Owned copy of the source text. Must outlive `program_ptr`. content: String, - /// Bump arena that owns all AST nodes. `None` until the first + /// LocalArena that owns all AST nodes. `None` until the first /// `with_parsed_program` call triggers a lazy parse. - arena: Option, + arena: Option, /// Raw pointer to the `Program` allocated in `arena`. /// `None` until the first `with_parsed_program` call. /// Reconstituted to `&Program<'_>` only while the `RefCell` borrow @@ -842,7 +844,7 @@ pub(crate) fn with_parse_cache(content: &str) -> ParseCacheGuard { /// `Program` (plus the content string) to `f`. /// /// Handles the boilerplate that every parse entry-point needs: -/// allocating a `Bump` arena, creating a `FileId`, calling +/// allocating a `LocalArena` arena, creating a `FileId`, calling /// `parse_file_content`, and wrapping the whole thing in /// `catch_unwind` so that a parser panic doesn't crash the LSP /// server. On panic the error is logged (using `method_name` for @@ -886,7 +888,7 @@ pub(crate) fn with_parsed_program( PARSE_CACHE.with(|cell| { let mut borrow = cell.borrow_mut(); let entry = borrow.as_mut().unwrap(); - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); // SAFETY: `program` borrows from `arena` and // `entry.content`. The arena is moved into @@ -935,7 +937,7 @@ pub(crate) fn with_parsed_program( // ── Slow path: parse from scratch ─────────────────────────── let content_owned = content.to_string(); let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content_owned.as_bytes()); diff --git a/src/parser/use_statements.rs b/src/parser/use_statements.rs index e89956a2..43bbc2be 100644 --- a/src/parser/use_statements.rs +++ b/src/parser/use_statements.rs @@ -5,7 +5,7 @@ /// names to their fully-qualified equivalents. use std::collections::HashMap; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::Backend; use crate::atom::bytes_to_str; diff --git a/src/php_type.rs b/src/php_type.rs index 16476e93..3f09a9d1 100644 --- a/src/php_type.rs +++ b/src/php_type.rs @@ -2,12 +2,12 @@ //! //! This module provides [`PhpType`], an owned enum that represents PHP type //! expressions as a tree. It is converted from the borrowed -//! `mago_type_syntax::ast::Type<'input>` AST and can be displayed back into a +//! `mago_type_syntax::cst::Type<'input>` AST and can be displayed back into a //! canonical string form. //! //! # Design //! -//! `mago_type_syntax::ast::Type` is `#[non_exhaustive]` with 69 variants and +//! `mago_type_syntax::cst::Type` is `#[non_exhaustive]` with 69 variants and //! borrows from input. `PhpType` is simpler: keyword types are collapsed into //! `Named`, generic-parameterised references become `Generic`, and rarely-used //! variants fall back to `Raw`. @@ -17,10 +17,10 @@ use std::fmt; -use bumpalo::Bump; +use mago_allocator::{Arena, LocalArena}; use mago_database::file::FileId; use mago_span::{Position, Span}; -use mago_type_syntax::ast; +use mago_type_syntax::cst; use crate::atom::bytes_to_str; @@ -398,7 +398,7 @@ impl PhpType { Position::new(effective.len() as u32), ); - let arena = Bump::new(); + let arena = LocalArena::new(); let effective = arena.alloc_slice_copy(effective.as_bytes()); match mago_type_syntax::parse_str(&arena, span, effective) { Ok(ty) => convert(&ty), @@ -4313,22 +4313,22 @@ fn native_scalar_name(name: &str) -> Option<&str> { } /// Convert a borrowed mago AST `Type` into an owned `PhpType`. -fn convert(ty: &ast::Type<'_>) -> PhpType { +fn convert(ty: &cst::Type<'_>) -> PhpType { match ty { // -- Composite types -------------------------------------------------- - ast::Type::Union(_) => { + cst::Type::Union(_) => { let members = flatten_union(ty); PhpType::Union(members) } - ast::Type::Intersection(_) => { + cst::Type::Intersection(_) => { let members = flatten_intersection(ty); PhpType::Intersection(members) } - ast::Type::Nullable(n) => PhpType::Nullable(Box::new(convert(n.inner))), - ast::Type::Parenthesized(p) => convert(p.inner), + cst::Type::Nullable(n) => PhpType::Nullable(Box::new(convert(n.inner))), + cst::Type::Parenthesized(p) => convert(p.inner), // -- Named / Reference types ------------------------------------------ - ast::Type::Reference(r) => { + cst::Type::Reference(r) => { let name = bytes_to_str(r.identifier.value).to_string(); match &r.parameters { Some(params) => { @@ -4347,30 +4347,30 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { } // -- Array-like types with optional generic parameters ---------------- - ast::Type::Array(a) => { + cst::Type::Array(a) => { convert_keyword_with_optional_generics(bytes_to_str(a.keyword.value), &a.parameters) } - ast::Type::NonEmptyArray(a) => { + cst::Type::NonEmptyArray(a) => { convert_keyword_with_optional_generics(bytes_to_str(a.keyword.value), &a.parameters) } - ast::Type::AssociativeArray(a) => { + cst::Type::AssociativeArray(a) => { convert_keyword_with_optional_generics(bytes_to_str(a.keyword.value), &a.parameters) } - ast::Type::List(l) => { + cst::Type::List(l) => { convert_keyword_with_optional_generics(bytes_to_str(l.keyword.value), &l.parameters) } - ast::Type::NonEmptyList(l) => { + cst::Type::NonEmptyList(l) => { convert_keyword_with_optional_generics(bytes_to_str(l.keyword.value), &l.parameters) } - ast::Type::Iterable(i) => { + cst::Type::Iterable(i) => { convert_keyword_with_optional_generics(bytes_to_str(i.keyword.value), &i.parameters) } // -- Slice: T[] ------------------------------------------------------- - ast::Type::Slice(s) => PhpType::Array(Box::new(convert(s.inner))), + cst::Type::Slice(s) => PhpType::Array(Box::new(convert(s.inner))), // -- Shape types ------------------------------------------------------ - ast::Type::Shape(s) => { + cst::Type::Shape(s) => { let entries: Vec = s .fields .iter() @@ -4387,16 +4387,16 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { .collect(); match s.kind { - ast::ShapeTypeKind::Array - | ast::ShapeTypeKind::NonEmptyArray - | ast::ShapeTypeKind::AssociativeArray - | ast::ShapeTypeKind::List - | ast::ShapeTypeKind::NonEmptyList => PhpType::ArrayShape(entries), + cst::ShapeTypeKind::Array + | cst::ShapeTypeKind::NonEmptyArray + | cst::ShapeTypeKind::AssociativeArray + | cst::ShapeTypeKind::List + | cst::ShapeTypeKind::NonEmptyList => PhpType::ArrayShape(entries), } } // -- Object type (with optional shape) -------------------------------- - ast::Type::Object(o) => match &o.properties { + cst::Type::Object(o) => match &o.properties { Some(props) => { let entries: Vec = props .fields @@ -4418,7 +4418,7 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { }, // -- Callable types --------------------------------------------------- - ast::Type::Callable(c) => { + cst::Type::Callable(c) => { let kind = bytes_to_str(c.keyword.value).to_string(); match &c.specification { Some(spec) => { @@ -4453,7 +4453,7 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { } // -- Conditional types ------------------------------------------------ - ast::Type::Conditional(c) => PhpType::Conditional { + cst::Type::Conditional(c) => PhpType::Conditional { param: c.subject.to_string(), negated: c.is_negated(), condition: Box::new(convert(c.target)), @@ -4462,14 +4462,14 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { }, // -- class-string / interface-string ---------------------------------- - ast::Type::ClassString(c) => { + cst::Type::ClassString(c) => { let inner = c .parameter .as_ref() .map(|p| Box::new(convert(&p.entry.inner))); PhpType::ClassString(inner) } - ast::Type::InterfaceString(i) => { + cst::Type::InterfaceString(i) => { let inner = i .parameter .as_ref() @@ -4478,68 +4478,68 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { } // -- key-of / value-of ------------------------------------------------ - ast::Type::KeyOf(k) => PhpType::KeyOf(Box::new(convert(&k.parameter.entry.inner))), - ast::Type::ValueOf(v) => PhpType::ValueOf(Box::new(convert(&v.parameter.entry.inner))), + cst::Type::KeyOf(k) => PhpType::KeyOf(Box::new(convert(&k.parameter.entry.inner))), + cst::Type::ValueOf(v) => PhpType::ValueOf(Box::new(convert(&v.parameter.entry.inner))), // -- int range -------------------------------------------------------- - ast::Type::IntRange(r) => PhpType::IntRange(r.min.to_string(), r.max.to_string()), + cst::Type::IntRange(r) => PhpType::IntRange(r.min.to_string(), r.max.to_string()), // -- Index access: T[K] ----------------------------------------------- - ast::Type::IndexAccess(i) => { + cst::Type::IndexAccess(i) => { PhpType::IndexAccess(Box::new(convert(i.target)), Box::new(convert(i.index))) } // -- Variable (e.g. $this in conditional types) ----------------------- - ast::Type::Variable(v) => PhpType::Named(bytes_to_str(v.value).to_string()), + cst::Type::Variable(v) => PhpType::Named(bytes_to_str(v.value).to_string()), // -- Literal types ---------------------------------------------------- - ast::Type::LiteralInt(l) => PhpType::literal_int(bytes_to_str(l.raw).to_string()), - ast::Type::LiteralFloat(l) => PhpType::literal_float(bytes_to_str(l.raw).to_string()), - ast::Type::LiteralString(l) => PhpType::literal_string_raw(bytes_to_str(l.raw).to_string()), + cst::Type::LiteralInt(l) => PhpType::literal_int(bytes_to_str(l.raw).to_string()), + cst::Type::LiteralFloat(l) => PhpType::literal_float(bytes_to_str(l.raw).to_string()), + cst::Type::LiteralString(l) => PhpType::literal_string_raw(bytes_to_str(l.raw).to_string()), // -- Negated / Posited literals (e.g. -42, +42) ----------------------- - ast::Type::Negated(n) => literal_number_type(format!("-{}", n.number)), - ast::Type::Posited(p) => literal_number_type(format!("+{}", p.number)), + cst::Type::Negated(n) => literal_number_type(format!("-{}", n.number)), + cst::Type::Posited(p) => literal_number_type(format!("+{}", p.number)), // -- Keyword types → Named ------------------------------------------- - ast::Type::Mixed(k) - | ast::Type::NonEmptyMixed(k) - | ast::Type::Null(k) - | ast::Type::Void(k) - | ast::Type::Never(k) - | ast::Type::Resource(k) - | ast::Type::ClosedResource(k) - | ast::Type::OpenResource(k) - | ast::Type::True(k) - | ast::Type::False(k) - | ast::Type::Bool(k) - | ast::Type::Float(k) - | ast::Type::Int(k) - | ast::Type::PositiveInt(k) - | ast::Type::NegativeInt(k) - | ast::Type::NonPositiveInt(k) - | ast::Type::NonNegativeInt(k) - | ast::Type::NonZeroInt(k) - | ast::Type::String(k) - | ast::Type::StringableObject(k) - | ast::Type::ArrayKey(k) - | ast::Type::Numeric(k) - | ast::Type::Scalar(k) - | ast::Type::CallableString(k) - | ast::Type::LowercaseCallableString(k) - | ast::Type::UppercaseCallableString(k) - | ast::Type::NumericString(k) - | ast::Type::NonEmptyString(k) - | ast::Type::NonEmptyLowercaseString(k) - | ast::Type::LowercaseString(k) - | ast::Type::NonEmptyUppercaseString(k) - | ast::Type::UppercaseString(k) - | ast::Type::TruthyString(k) - | ast::Type::NonFalsyString(k) - | ast::Type::UnspecifiedLiteralInt(k) - | ast::Type::UnspecifiedLiteralString(k) - | ast::Type::UnspecifiedLiteralFloat(k) - | ast::Type::NonEmptyUnspecifiedLiteralString(k) => { + cst::Type::Mixed(k) + | cst::Type::NonEmptyMixed(k) + | cst::Type::Null(k) + | cst::Type::Void(k) + | cst::Type::Never(k) + | cst::Type::Resource(k) + | cst::Type::ClosedResource(k) + | cst::Type::OpenResource(k) + | cst::Type::True(k) + | cst::Type::False(k) + | cst::Type::Bool(k) + | cst::Type::Float(k) + | cst::Type::Int(k) + | cst::Type::PositiveInt(k) + | cst::Type::NegativeInt(k) + | cst::Type::NonPositiveInt(k) + | cst::Type::NonNegativeInt(k) + | cst::Type::NonZeroInt(k) + | cst::Type::String(k) + | cst::Type::StringableObject(k) + | cst::Type::ArrayKey(k) + | cst::Type::Numeric(k) + | cst::Type::Scalar(k) + | cst::Type::CallableString(k) + | cst::Type::LowercaseCallableString(k) + | cst::Type::UppercaseCallableString(k) + | cst::Type::NumericString(k) + | cst::Type::NonEmptyString(k) + | cst::Type::NonEmptyLowercaseString(k) + | cst::Type::LowercaseString(k) + | cst::Type::NonEmptyUppercaseString(k) + | cst::Type::UppercaseString(k) + | cst::Type::TruthyString(k) + | cst::Type::NonFalsyString(k) + | cst::Type::UnspecifiedLiteralInt(k) + | cst::Type::UnspecifiedLiteralString(k) + | cst::Type::UnspecifiedLiteralFloat(k) + | cst::Type::NonEmptyUnspecifiedLiteralString(k) => { PhpType::Named(normalize_keyword_casing(bytes_to_str(k.value))) } @@ -4553,7 +4553,7 @@ fn convert(ty: &ast::Type<'_>) -> PhpType { /// `iterable`). fn convert_keyword_with_optional_generics( keyword: &str, - parameters: &Option>, + parameters: &Option>, ) -> PhpType { let canonical = normalize_keyword_casing(keyword); match parameters { @@ -4566,9 +4566,9 @@ fn convert_keyword_with_optional_generics( } /// Recursively flatten a left-leaning binary union tree into a flat `Vec`. -fn flatten_union(ty: &ast::Type<'_>) -> Vec { +fn flatten_union(ty: &cst::Type<'_>) -> Vec { match ty { - ast::Type::Union(u) => { + cst::Type::Union(u) => { let mut types = flatten_union(u.left); types.extend(flatten_union(u.right)); types @@ -4578,9 +4578,9 @@ fn flatten_union(ty: &ast::Type<'_>) -> Vec { } /// Recursively flatten a left-leaning binary intersection tree into a flat `Vec`. -fn flatten_intersection(ty: &ast::Type<'_>) -> Vec { +fn flatten_intersection(ty: &cst::Type<'_>) -> Vec { match ty { - ast::Type::Intersection(i) => { + cst::Type::Intersection(i) => { let mut types = flatten_intersection(i.left); types.extend(flatten_intersection(i.right)); types @@ -4940,7 +4940,7 @@ mod tests { Position::new(0), Position::new(input.len() as u32), ); - let arena = Bump::new(); + let arena = LocalArena::new(); let input_arena = arena.alloc_slice_copy(input.as_bytes()); let mago_canonical = match mago_type_syntax::parse_str(&arena, span, input_arena) { Ok(ty) => ty.to_string(), diff --git a/src/scope_collector/mod.rs b/src/scope_collector/mod.rs index b2f96cbe..c077bb14 100644 --- a/src/scope_collector/mod.rs +++ b/src/scope_collector/mod.rs @@ -38,7 +38,7 @@ mod tests; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::atom::bytes_to_str; @@ -1270,7 +1270,7 @@ fn walk_expression(expr: &Expression<'_>, collector: &mut Collector<'_>) { // ── Anonymous class ── Expression::AnonymousClass(anon) => { if let Some(ref args) = anon.argument_list { - walk_arguments(args, collector); + walk_partial_arguments(args, collector); } // Skip members — anonymous class body is a separate scope. } @@ -1450,6 +1450,15 @@ fn walk_arguments(args: &ArgumentList<'_>, collector: &mut Collector<'_>) { } } +/// Walk partial arguments in a function/method call. +fn walk_partial_arguments(args: &PartialArgumentList<'_>, collector: &mut Collector<'_>) { + for arg in args.arguments.iter() { + if let Some(value) = arg.value() { + walk_expression(value, collector); + } + } +} + /// Known PHP functions with by-reference out-parameters. /// /// Each entry maps a function name to a list of 0-based argument diff --git a/src/selection_range.rs b/src/selection_range.rs index c5e20fc8..323c4b25 100644 --- a/src/selection_range.rs +++ b/src/selection_range.rs @@ -10,9 +10,9 @@ //! them from outermost to innermost, and builds the linked `SelectionRange` //! list that the LSP protocol expects. -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{Position, Range, SelectionRange}; use crate::Backend; @@ -27,7 +27,7 @@ impl Backend { content: &str, positions: &[Position], ) -> Option> { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = mago_database::file::FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); diff --git a/src/signature_help.rs b/src/signature_help.rs index db1a5f85..f3d855a2 100644 --- a/src/signature_help.rs +++ b/src/signature_help.rs @@ -319,7 +319,7 @@ impl From for ResolvedCallable { // ─── First-class callable target extraction (AST-based) ──────────────────── use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; /// Walk statements looking for the last assignment to `var_name` (with /// `$` prefix) before `cursor_offset` where the RHS is a @@ -370,8 +370,8 @@ fn collect_fcc_targets( Statement::Block(block) => walk!(block.statements.iter()), Statement::Namespace(ns) => walk!(ns.statements().iter()), Statement::Class(cls) => { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; for member in cls.members.iter() { if let ClassLikeMember::Method(method) = member && let MethodBody::Concrete(block) = &method.body @@ -385,8 +385,8 @@ fn collect_fcc_targets( } } Statement::Trait(t) => { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; for member in t.members.iter() { if let ClassLikeMember::Method(method) = member && let MethodBody::Concrete(block) = &method.body diff --git a/src/signature_help_tests.rs b/src/signature_help_tests.rs index 2599e739..a3e19143 100644 --- a/src/signature_help_tests.rs +++ b/src/signature_help_tests.rs @@ -722,10 +722,10 @@ fn clamp_empty_params() { /// Helper: parse PHP source and build a SymbolMap, then call /// `detect_call_site_from_map` at the given line/character. fn map_detect(content: &str, line: u32, character: u32) -> Option { - use bumpalo::Bump; + use mago_allocator::LocalArena; use mago_database::file::FileId; - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"test.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); let sm = crate::symbol_map::extract_symbol_map(program, content); diff --git a/src/symbol_map/docblock.rs b/src/symbol_map/docblock.rs index ef95dfa7..d08904c1 100644 --- a/src/symbol_map/docblock.rs +++ b/src/symbol_map/docblock.rs @@ -12,12 +12,12 @@ //! structured via [`emit_type_spans`] which uses `mago-type-syntax` to //! parse types and walk the AST with accurate span information. -use bumpalo::Bump; +use mago_allocator::{Arena, LocalArena}; use mago_database::file::FileId; use mago_docblock::document::TagKind; use mago_span::{HasSpan, Position, Span}; -use mago_syntax::ast::*; -use mago_type_syntax::ast as type_ast; +use mago_syntax::cst::*; +use mago_type_syntax::cst as type_ast; use crate::docblock::parser::parse_docblock; use crate::docblock::types::split_type_token; @@ -560,7 +560,7 @@ pub(super) fn emit_type_spans( Position::new(effective_token.len() as u32), ); - let arena = Bump::new(); + let arena = LocalArena::new(); let effective_token = arena.alloc_slice_copy(effective_token.as_bytes()); match mago_type_syntax::parse_str(&arena, parse_span, effective_token) { Ok(ty) => { diff --git a/src/symbol_map/extraction.rs b/src/symbol_map/extraction.rs index 2f390732..228031dc 100644 --- a/src/symbol_map/extraction.rs +++ b/src/symbol_map/extraction.rs @@ -6,8 +6,8 @@ //! [`extract_symbol_map`]. use mago_span::HasSpan; -use mago_syntax::ast::sequence::TokenSeparatedSequence; -use mago_syntax::ast::*; +use mago_syntax::cst::sequence::TokenSeparatedSequence; +use mago_syntax::cst::*; use super::docblock::{ class_ref_span, class_ref_span_ctx, extract_docblock_symbols, extract_param_var_spans, @@ -1003,9 +1003,9 @@ fn extract_from_enum<'a>(enum_def: &'a Enum<'a>, ctx: &mut ExtractionCtx<'a>) { /// Emits a `ClassReference` for the attribute class name and recurses /// into argument expressions. fn extract_from_attribute_lists<'a>( - attribute_lists: &mago_syntax::ast::sequence::Sequence< + attribute_lists: &mago_syntax::cst::sequence::Sequence< 'a, - mago_syntax::ast::attribute::AttributeList<'a>, + mago_syntax::cst::attribute::AttributeList<'a>, >, ctx: &mut ExtractionCtx<'a>, scope_start: u32, @@ -1025,10 +1025,10 @@ fn extract_from_attribute_lists<'a>( // signature help and named parameter completion work // inside `#[Attr(...)]` just like `new Attr(...)`. if let Some(ref arg_list) = attr.argument_list { - extract_from_arguments(&arg_list.arguments, ctx, scope_start); + extract_from_partial_arguments(&arg_list.arguments, ctx, scope_start); let class_name = raw.trim_start_matches('\\'); if !class_name.is_empty() { - emit_call_site( + emit_partial_call_site( format!("new {}", class_name), arg_list, &mut ctx.call_sites, @@ -2580,7 +2580,7 @@ fn extract_from_expression<'a>( Expression::AnonymousClass(anon) => { // Constructor arguments. if let Some(ref args) = anon.argument_list { - extract_from_arguments(&args.arguments, ctx, scope_start); + extract_from_partial_arguments(&args.arguments, ctx, scope_start); } // Extends. @@ -2856,6 +2856,22 @@ fn extract_from_arguments<'a>( } } +/// Walk an argument list and extract symbols from each partial argument expression. +fn extract_from_partial_arguments<'a>( + args: &TokenSeparatedSequence<'a, PartialArgument<'a>>, + ctx: &mut ExtractionCtx<'a>, + scope_start: u32, +) { + for arg in args.iter() { + let arg_expr = match arg { + PartialArgument::Positional(pos) => pos.value, + PartialArgument::Named(named) => named.value, + _ => continue, + }; + extract_from_expression(arg_expr, ctx, scope_start); + } +} + /// Walk array elements and extract symbols from each element expression. fn extract_from_array_elements<'a>( elements: &TokenSeparatedSequence<'a, ArrayElement<'a>>, @@ -3007,6 +3023,81 @@ fn emit_call_site( }); } +/// Build and push a [`CallSite`] from a partial argument list and its call expression string. +fn emit_partial_call_site( + call_expression: String, + argument_list: &PartialArgumentList<'_>, + call_sites: &mut Vec, + untyped_closure_sites: &mut Vec, +) { + let args_start = argument_list.left_parenthesis.end.offset; + let args_end = argument_list.right_parenthesis.start.offset; + let comma_offsets = argument_list + .arguments + .tokens + .iter() + .map(|token| token.start.offset) + .collect(); + let mut arg_offsets = Vec::with_capacity(argument_list.arguments.len()); + let mut named_arg_indices = Vec::new(); + let mut named_arg_names = Vec::new(); + let mut spread_arg_indices = Vec::new(); + + for (index, argument) in argument_list.arguments.iter().enumerate() { + match argument { + PartialArgument::Positional(argument) => { + let offset = argument + .ellipsis + .map(|span| span.start.offset) + .unwrap_or_else(|| argument.value.span().start.offset); + arg_offsets.push(offset); + if argument.ellipsis.is_some() { + spread_arg_indices.push(index as u32); + } + collect_untyped_closure_site( + argument.value, + &call_expression, + index, + untyped_closure_sites, + ); + } + PartialArgument::Named(argument) => { + arg_offsets.push(argument.name.span.start.offset); + named_arg_indices.push(index as u32); + named_arg_names.push(bytes_to_str(argument.name.value).to_string()); + collect_untyped_closure_site( + argument.value, + &call_expression, + index, + untyped_closure_sites, + ); + } + PartialArgument::NamedPlaceholder(argument) => { + arg_offsets.push(argument.name.span.start.offset); + named_arg_indices.push(index as u32); + named_arg_names.push(bytes_to_str(argument.name.value).to_string()); + } + PartialArgument::Placeholder(argument) => arg_offsets.push(argument.span.start.offset), + PartialArgument::VariadicPlaceholder(argument) => { + arg_offsets.push(argument.span.start.offset) + } + } + } + + call_sites.push(CallSite { + args_start, + args_end, + call_expression, + comma_offsets, + arg_count: argument_list.arguments.len() as u32, + has_unpacking: !spread_arg_indices.is_empty(), + arg_offsets, + named_arg_indices, + named_arg_names, + spread_arg_indices, + }); +} + /// If `expr` is a closure or arrow function, collect an [`UntypedClosureSite`] /// with its untyped parameters and (optionally) its close-paren offset for a /// return type hint. @@ -3163,7 +3254,7 @@ fn expr_to_subject_text(expr: &Expression<'_>) -> String { let mut parts = Vec::new(); for element in array.elements.iter() { match element { - mago_syntax::ast::ArrayElement::KeyValue(kv) => { + mago_syntax::cst::ArrayElement::KeyValue(kv) => { let val = expr_to_subject_text(kv.value); if !val.is_empty() { let key = expr_to_subject_text(kv.key); @@ -3176,7 +3267,7 @@ fn expr_to_subject_text(expr: &Expression<'_>) -> String { parts.push("...".to_string()); } } - mago_syntax::ast::ArrayElement::Value(v) => { + mago_syntax::cst::ArrayElement::Value(v) => { let val = expr_to_subject_text(v.value); if val.is_empty() { parts.push("...".to_string()); @@ -3184,7 +3275,7 @@ fn expr_to_subject_text(expr: &Expression<'_>) -> String { parts.push(val); } } - mago_syntax::ast::ArrayElement::Variadic(v) => { + mago_syntax::cst::ArrayElement::Variadic(v) => { let val = expr_to_subject_text(v.value); if val.is_empty() { parts.push("...".to_string()); @@ -3192,7 +3283,7 @@ fn expr_to_subject_text(expr: &Expression<'_>) -> String { parts.push(format!("...{}", val)); } } - mago_syntax::ast::ArrayElement::Missing(_) => { + mago_syntax::cst::ArrayElement::Missing(_) => { parts.push("...".to_string()); } } diff --git a/src/symbol_map/tests.rs b/src/symbol_map/tests.rs index 732dea1f..e8a841fb 100644 --- a/src/symbol_map/tests.rs +++ b/src/symbol_map/tests.rs @@ -131,7 +131,7 @@ fn empty_name_is_not_navigable() { // ── extract_symbol_map integration tests ──────────────────────────── fn parse_and_extract(php: &str) -> SymbolMap { - let arena = bumpalo::Bump::new(); + let arena = mago_allocator::LocalArena::new(); let file_id = mago_database::file::FileId::new(b"test.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, php.as_bytes()); extract_symbol_map(program, php) diff --git a/src/util.rs b/src/util.rs index 5479d71d..9991a875 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2244,11 +2244,11 @@ pub(crate) fn infer_type_from_literal(expr: &str) -> Option { /// similar features that need to locate the method body surrounding /// the cursor. pub(crate) fn find_enclosing_method_block_in_members<'a>( - members: impl Iterator>, + members: impl Iterator>, offset: u32, -) -> Option<&'a mago_syntax::ast::block::Block<'a>> { - use mago_syntax::ast::class_like::member::ClassLikeMember; - use mago_syntax::ast::class_like::method::MethodBody; +) -> Option<&'a mago_syntax::cst::block::Block<'a>> { + use mago_syntax::cst::class_like::member::ClassLikeMember; + use mago_syntax::cst::class_like::method::MethodBody; for member in members { if let ClassLikeMember::Method(method) = member diff --git a/src/virtual_members/laravel/aliases.rs b/src/virtual_members/laravel/aliases.rs index 6bb4e1b4..714ae0bc 100644 --- a/src/virtual_members/laravel/aliases.rs +++ b/src/virtual_members/laravel/aliases.rs @@ -28,11 +28,11 @@ use std::collections::HashMap; use std::sync::Arc; -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; use mago_names::resolver::NameResolver; use mago_span::HasSpan; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use mago_syntax::parser::parse_file_content; use tower_lsp::lsp_types::Url; @@ -180,7 +180,7 @@ fn read_project_config(backend: &Backend, file_name: &str) -> Option { /// program and resolved-name table to `f` (which must extract owned data before /// the arena is dropped). fn with_parsed(content: &str, f: impl FnOnce(&Program<'_>, &OwnedResolvedNames) -> R) -> R { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = parse_file_content(&arena, file_id, content.as_bytes()); let resolved = NameResolver::new(&arena).resolve(program); diff --git a/src/virtual_members/laravel/config_keys.rs b/src/virtual_members/laravel/config_keys.rs index e73fe09b..7bd278a7 100644 --- a/src/virtual_members/laravel/config_keys.rs +++ b/src/virtual_members/laravel/config_keys.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{Location, Position, Url}; use crate::Backend; @@ -58,7 +58,7 @@ pub(crate) fn collect_laravel_config_declarations( content: &str, prefix: &str, ) -> Vec { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); let mut out = Vec::new(); diff --git a/src/virtual_members/laravel/config_values.rs b/src/virtual_members/laravel/config_values.rs index 50580e25..5bc7e562 100644 --- a/src/virtual_members/laravel/config_values.rs +++ b/src/virtual_members/laravel/config_values.rs @@ -19,9 +19,9 @@ //! This is the first consumer of static config-value reading; it is written //! to be reusable (e.g. `Storage::disk()` reading `config/filesystems.php`). -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use crate::atom::bytes_to_str; @@ -169,7 +169,7 @@ impl ConfigNode { /// pattern, mirroring [`config_keys`](super::config_keys)'s declaration /// walker. pub(crate) fn parse_config_tree(content: &str) -> Option { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); diff --git a/src/virtual_members/laravel/env_vars.rs b/src/virtual_members/laravel/env_vars.rs index 8dc92a4c..33086cb5 100644 --- a/src/virtual_members/laravel/env_vars.rs +++ b/src/virtual_members/laravel/env_vars.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{Location, Position, Url}; use crate::Backend; diff --git a/src/virtual_members/laravel/helpers.rs b/src/virtual_members/laravel/helpers.rs index 6b6592d3..68219587 100644 --- a/src/virtual_members/laravel/helpers.rs +++ b/src/virtual_members/laravel/helpers.rs @@ -279,9 +279,9 @@ pub(crate) fn chain_name_prefix<'a>(expr: &Expression<'a>, content: &str) -> Str // ─── Shared PHP AST walker ─────────────────────────────────────────────────── -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; -use mago_syntax::ast::*; +use mago_syntax::cst::*; /// Parse `content` as PHP and call `visitor` for every expression node /// (pre-order, depth-first). Used by navigation modules to find specific @@ -294,7 +294,7 @@ pub(crate) fn walk_all_php_expressions( content: &str, visitor: &mut impl FnMut(&Expression<'_>) -> ControlFlow<()>, ) { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); for stmt in program.statements.iter() { diff --git a/src/virtual_members/laravel/route_names.rs b/src/virtual_members/laravel/route_names.rs index edc48ea9..822549cc 100644 --- a/src/virtual_members/laravel/route_names.rs +++ b/src/virtual_members/laravel/route_names.rs @@ -1,6 +1,6 @@ -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{Location, Url}; use crate::Backend; @@ -38,7 +38,7 @@ pub(crate) fn resolve_route_definitions(backend: &Backend, name: &str) -> Vec Vec { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); let mut results = Vec::new(); diff --git a/src/virtual_members/laravel/trans_keys.rs b/src/virtual_members/laravel/trans_keys.rs index 782ed6e5..96797cc5 100644 --- a/src/virtual_members/laravel/trans_keys.rs +++ b/src/virtual_members/laravel/trans_keys.rs @@ -1,6 +1,6 @@ -use bumpalo::Bump; +use mago_allocator::LocalArena; use mago_database::file::FileId; -use mago_syntax::ast::*; +use mago_syntax::cst::*; use tower_lsp::lsp_types::{Location, Position, Url}; use crate::Backend; @@ -55,7 +55,7 @@ struct TransKeyMatch { } fn collect_trans_declarations(content: &str, file_stem: &str) -> Vec { - let arena = Bump::new(); + let arena = LocalArena::new(); let file_id = FileId::new(b"input.php"); let program = mago_syntax::parser::parse_file_content(&arena, file_id, content.as_bytes()); let mut out = Vec::new();