From 0f36cd7a9eedccc355b8253d6f16ccb09916fcd2 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:50:53 -0400 Subject: [PATCH 01/36] chore: add `bevy` as a dev-dependency for testing purposes --- Cargo.lock | 793 ++++++++++++++++++++++++++++++++++++++++++- bevy_lint/Cargo.toml | 5 + 2 files changed, 791 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9eee87..47d88a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "accesskit" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf780eb737f2d4a49ffbd512324d53ad089070f813f7be7f99dbd5123a7f448" + [[package]] name = "ahash" version = "0.8.11" @@ -34,6 +40,18 @@ dependencies = [ "as-slice", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + [[package]] name = "anstream" version = "0.6.15" @@ -110,6 +128,25 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "auth-git2" version = "0.5.4" @@ -127,6 +164,45 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "bevy" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043c9ad4b6fc4ca52d779873a8ca792a4e37842d07fce95363c9e17e36a1d8a0" +dependencies = [ + "bevy_internal", +] + +[[package]] +name = "bevy_a11y" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a976cb539d6a5a3ff579cdb78187a6bcfbffa7e8224ea28f23d8b983d9389" +dependencies = [ + "accesskit", + "bevy_app", + "bevy_derive", + "bevy_ecs", +] + +[[package]] +name = "bevy_app" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5361d0f8a8677a5d0102cfe7321a7ecd2a8b9a4f887ce0dde1059311cf9cd42" +dependencies = [ + "bevy_derive", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "console_error_panic_hook", + "downcast-rs", + "thiserror", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "bevy_cli" version = "0.1.0-dev" @@ -136,14 +212,300 @@ dependencies = [ "clap", ] +[[package]] +name = "bevy_core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de706862871a1fe99ea619bff2f99d73e43ad82f19ef866a9e19a14c957c8537" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "uuid", +] + +[[package]] +name = "bevy_derive" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbfc33a4c6b80760bb8bf850a2cc65a1e031da62fd3ca8b552189104dc98514" +dependencies = [ + "bevy_macro_utils", + "quote", + "syn", +] + +[[package]] +name = "bevy_diagnostic" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebb154e0cc78e3bbfbfdb42fb502b14c1cd47e72f16e6d4228dfe6233ba6cbd" +dependencies = [ + "bevy_app", + "bevy_core", + "bevy_ecs", + "bevy_tasks", + "bevy_time", + "bevy_utils", + "const-fnv1a-hash", +] + +[[package]] +name = "bevy_ecs" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee4222406637f3c8e3991a99788cfcde76097bf997c311f1b6297364057483f" +dependencies = [ + "bevy_ecs_macros", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags 2.6.0", + "concurrent-queue", + "fixedbitset 0.5.7", + "nonmax", + "petgraph", + "serde", + "thiserror", +] + +[[package]] +name = "bevy_ecs_macros" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b573430b67aff7bde8292257494f39343401379bfbda64035ba4918bba7b20" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bevy_hierarchy" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88b912b37e1bc4dbb2aa40723199f74c8b06c4fbb6da0bb4585131df28ef66e" +dependencies = [ + "bevy_app", + "bevy_core", + "bevy_ecs", + "bevy_reflect", + "bevy_utils", + "smallvec", +] + +[[package]] +name = "bevy_input" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd3a54e67cc3ba17971de7b1a7e64eda84493c1e7bb6bfa11c6cf8ac124377b" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_utils", + "smol_str", + "thiserror", +] + +[[package]] +name = "bevy_internal" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d435cac77c568f3aef65f786a5fee0e53c81950c5258182dd2c1d6cd6c4fec" +dependencies = [ + "bevy_a11y", + "bevy_app", + "bevy_core", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_hierarchy", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bevy_window", +] + [[package]] name = "bevy_lint" version = "0.1.0-dev" dependencies = [ "anyhow", + "bevy", "clippy_utils", ] +[[package]] +name = "bevy_log" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67240c7596c8f0653e50fce35a60196516817449235193246599facba9002e02" +dependencies = [ + "android_log-sys", + "bevy_app", + "bevy_ecs", + "bevy_utils", + "tracing-log", + "tracing-subscriber", + "tracing-wasm", +] + +[[package]] +name = "bevy_macro_utils" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfc65e570012e64a21f3546df68591aaede8349e6174fb500071677f54f06630" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "toml_edit 0.22.20", +] + +[[package]] +name = "bevy_math" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5421792749dda753ab3718e77d27bfce38443daf1850b836b97530b6245a4581" +dependencies = [ + "bevy_reflect", + "glam", + "rand", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "bevy_ptr" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61baa1bdc1f4a7ac2c18217570a7cc04e1cd54d38456e91782f0371c79afe0a8" + +[[package]] +name = "bevy_reflect" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2508785a4a5809f25a237eec4fee2c91a4dbcf81324b2bbc2d6c52629e603781" +dependencies = [ + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "downcast-rs", + "erased-serde", + "glam", + "serde", + "smallvec", + "smol_str", + "thiserror", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "967d5da1882ec3bb3675353915d3da909cafac033cbf31e58727824a1ad2a288" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", + "uuid", +] + +[[package]] +name = "bevy_tasks" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77865f310b1fc48fb05b7c4adbe76607ec01d0c14f8ab4caba4d714c86439946" +dependencies = [ + "async-executor", + "futures-lite", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_time" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e4d53ec32a1b16492396951d04de0d2d90e924bf9adcb8d1adacab5ab6c17c" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_reflect", + "bevy_utils", + "crossbeam-channel", + "thiserror", +] + +[[package]] +name = "bevy_transform" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5493dce84427d00a9266e8e4386d738a72ee8640423b62dfcecb6dfccbfe0d2" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_hierarchy", + "bevy_math", + "bevy_reflect", + "thiserror", +] + +[[package]] +name = "bevy_utils" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb0ec333b5965771153bd746f92ffd8aeeb9d008a8620ffd9ed474859381a5e" +dependencies = [ + "ahash", + "bevy_utils_proc_macros", + "getrandom", + "hashbrown", + "thread_local", + "tracing", + "web-time", +] + +[[package]] +name = "bevy_utils_proc_macros" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f1ab8f2f6f58439d260081d89a42b02690e5fdd64f814edc9417d33fcf2857" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bevy_window" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e88a20db64ea8204540afb4699295947c454738fd50293f7b32ab8be857a6" +dependencies = [ + "bevy_a11y", + "bevy_app", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_utils", + "raw-window-handle", + "smol_str", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -172,10 +534,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata", + "regex-automata 0.4.7", "serde", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" + [[package]] name = "byteorder" version = "1.5.0" @@ -315,6 +689,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" version = "0.15.8" @@ -328,6 +711,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const-fnv1a-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" + [[package]] name = "const-random" version = "0.1.18" @@ -357,6 +756,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -466,6 +874,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "either" version = "1.13.0" @@ -507,6 +921,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" version = "0.3.9" @@ -529,6 +953,18 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -561,6 +997,31 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -578,8 +1039,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -821,6 +1284,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" +dependencies = [ + "bytemuck", + "rand", + "serde", +] + [[package]] name = "globset" version = "0.4.14" @@ -830,8 +1304,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -839,6 +1313,11 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] [[package]] name = "heck" @@ -881,7 +1360,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata", + "regex-automata 0.4.7", "same-file", "walkdir", "winapi-util", @@ -959,6 +1438,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kstring" version = "2.0.2" @@ -1110,6 +1598,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1146,6 +1643,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + [[package]] name = "normpath" version = "1.3.0" @@ -1155,6 +1658,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1215,6 +1728,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1313,6 +1838,22 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "pkg-config" version = "0.3.30" @@ -1394,6 +1935,12 @@ dependencies = [ "getrandom", ] +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + [[package]] name = "redox_syscall" version = "0.5.3" @@ -1422,8 +1969,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1434,9 +1990,15 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" @@ -1588,6 +2150,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -1600,6 +2171,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -1617,6 +2197,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1704,6 +2293,16 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.36" @@ -1821,6 +2420,84 @@ dependencies = [ "winnow 0.6.18", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" version = "1.17.0" @@ -1889,6 +2566,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1917,6 +2609,93 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/bevy_lint/Cargo.toml b/bevy_lint/Cargo.toml index 1d5c336..bcdb77a 100644 --- a/bevy_lint/Cargo.toml +++ b/bevy_lint/Cargo.toml @@ -15,6 +15,7 @@ name = "bevy_lint_driver" path = "src/bin/driver.rs" [dependencies] +# Easy error propagation and contexts anyhow = "1.0.86" # Contains a series of useful utilities when writing lints. The version and commit were chosen to @@ -25,6 +26,10 @@ version = "=0.1.82" git = "https://github.com/rust-lang/rust-clippy" rev = "e8ac4ea4187498052849531b86114a1eec5314a1" +[dev-dependencies] +# Used to test lints that need Bevy's types +bevy = { version = "0.14.2", default-features = false } + [package.metadata.rust-analyzer] # Enables Rust-Analyzer support for `rustc` crates. rustc_private = true From c346eb5fb6df1952834d1598b48492d9420a1b16 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:52:12 -0400 Subject: [PATCH 02/36] feat: create lints module --- bevy_lint/src/lib.rs | 2 ++ bevy_lint/src/lints/mod.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 bevy_lint/src/lints/mod.rs diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 15553cf..e0a8591 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -5,7 +5,9 @@ // it here! extern crate rustc_driver; extern crate rustc_interface; +extern crate rustc_lint; mod callback; +pub mod lints; pub use self::callback::BevyLintCallback; diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs new file mode 100644 index 0000000..a63ae06 --- /dev/null +++ b/bevy_lint/src/lints/mod.rs @@ -0,0 +1,16 @@ +macro_rules! define_lints { + { + $(mod $module:ident { + lints: [$($lint:ident),+], + passes: [], + })* + } => { + // Declare all modules as private. + $(mod $module;)* + + // Re-export all lint definitions. + $(pub use self::$module::{$($lint),*};)* + }; +} + +define_lints! {} From d9df05aa2520510bdc984d180130e8561897d9c4 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:22:30 -0400 Subject: [PATCH 03/36] feat: export and register lints --- bevy_lint/src/callback.rs | 2 ++ bevy_lint/src/lints/mod.rs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/bevy_lint/src/callback.rs b/bevy_lint/src/callback.rs index b039b38..bf7b4fc 100644 --- a/bevy_lint/src/callback.rs +++ b/bevy_lint/src/callback.rs @@ -14,6 +14,8 @@ impl Callbacks for BevyLintCallback { if let Some(previous) = &previous { (previous)(session, store); } + + store.register_lints(crate::lints::LINTS); })); } } diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index a63ae06..f59fca5 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -1,3 +1,5 @@ +use rustc_lint::Lint; + macro_rules! define_lints { { $(mod $module:ident { @@ -10,6 +12,10 @@ macro_rules! define_lints { // Re-export all lint definitions. $(pub use self::$module::{$($lint),*};)* + + pub static LINTS: &[&Lint] = &[ + $($(self::$module::$lint)*,)* + ]; }; } From 60cf179b80e112f28964db834da70b433f9eb0a2 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:33:36 -0400 Subject: [PATCH 04/36] feat: make modules public, don't re-export lints, and only support 1 lint per module --- bevy_lint/src/lints/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index f59fca5..32a0fe9 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -3,18 +3,14 @@ use rustc_lint::Lint; macro_rules! define_lints { { $(mod $module:ident { - lints: [$($lint:ident),+], - passes: [], + lint: $lint:ident$(,)? })* } => { // Declare all modules as private. - $(mod $module;)* - - // Re-export all lint definitions. - $(pub use self::$module::{$($lint),*};)* + $(pub mod $module;)* pub static LINTS: &[&Lint] = &[ - $($(self::$module::$lint)*,)* + $(self::$module::$lint,)* ]; }; } From a4241ed619f69f117ce1f804e46ca9977d6159b7 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sun, 15 Sep 2024 23:01:48 -0400 Subject: [PATCH 05/36] feat: begin first lint --- bevy_lint/src/callback.rs | 4 ++ bevy_lint/src/lib.rs | 4 ++ .../src/lints/main_return_without_appexit.rs | 45 +++++++++++++++++++ bevy_lint/src/lints/mod.rs | 6 ++- 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 bevy_lint/src/lints/main_return_without_appexit.rs diff --git a/bevy_lint/src/callback.rs b/bevy_lint/src/callback.rs index bf7b4fc..38bcad5 100644 --- a/bevy_lint/src/callback.rs +++ b/bevy_lint/src/callback.rs @@ -16,6 +16,10 @@ impl Callbacks for BevyLintCallback { } store.register_lints(crate::lints::LINTS); + + store.register_late_pass(|_| { + Box::new(crate::lints::main_return_without_appexit::MainReturnWithoutAppExit) + }); })); } } diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index e0a8591..6d9dc79 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -1,11 +1,15 @@ // Enables linking to `rustc` crates. #![feature(rustc_private)] +// Allows chaining `if let` multiple times using `&&`. +#![feature(let_chains)] // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! extern crate rustc_driver; +extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_lint; +extern crate rustc_span; mod callback; pub mod lints; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs new file mode 100644 index 0000000..f532105 --- /dev/null +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -0,0 +1,45 @@ +use clippy_utils::{diagnostics::span_lint, is_entrypoint_fn}; +use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy}; +use rustc_lint::{LateContext, LateLintPass, Level, Lint, LintPass, LintVec}; +use rustc_span::Span; + +pub static MAIN_RETURN_WITHOUT_APPEXIT: &Lint = &Lint { + name: "bevy::main_return_without_appexit", + default_level: Level::Warn, + desc: "an entrypoint that calls `App::run()` does not return `AppExit`", + is_externally_loaded: true, + ..Lint::default_fields_for_macro() +}; + +#[derive(Clone, Copy, Debug)] +pub struct MainReturnWithoutAppExit; + +impl LintPass for MainReturnWithoutAppExit { + fn name(&self) -> &'static str { + MAIN_RETURN_WITHOUT_APPEXIT.name + } +} + +impl MainReturnWithoutAppExit { + pub fn get_lints() -> LintVec { + vec![MAIN_RETURN_WITHOUT_APPEXIT] + } +} + +impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + declaration: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + _: Span, + local_def_id: LocalDefId, + ) { + // We're looking for `fn main()` with no return type that calls `App::run()`. + if is_entrypoint_fn(cx, local_def_id.into()) + && let FnRetTy::DefaultReturn(return_span) = declaration.output { + span_lint(cx, MAIN_RETURN_WITHOUT_APPEXIT, return_span, "AAAA!"); + } + } +} diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index 32a0fe9..0f50af8 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -15,4 +15,8 @@ macro_rules! define_lints { }; } -define_lints! {} +define_lints! { + mod main_return_without_appexit { + lint: MAIN_RETURN_WITHOUT_APPEXIT, + } +} From 59801820ea43abe191632b5a94990d01cc1c24a8 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:47:03 -0400 Subject: [PATCH 06/36] feat: scan expressions for `App::run()` --- .../src/lints/main_return_without_appexit.rs | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index f532105..52fab7e 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -1,5 +1,6 @@ -use clippy_utils::{diagnostics::span_lint, is_entrypoint_fn}; -use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy}; +use std::ops::ControlFlow; +use clippy_utils::{diagnostics::span_lint, is_entrypoint_fn, match_def_path, sym, visitors::for_each_expr}; +use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy}; use rustc_lint::{LateContext, LateLintPass, Level, Lint, LintPass, LintVec}; use rustc_span::Span; @@ -32,14 +33,39 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { cx: &LateContext<'tcx>, _: FnKind<'tcx>, declaration: &'tcx FnDecl<'tcx>, - _: &'tcx Body<'tcx>, + body: &'tcx Body<'tcx>, _: Span, local_def_id: LocalDefId, ) { // We're looking for `fn main()` with no return type that calls `App::run()`. if is_entrypoint_fn(cx, local_def_id.into()) - && let FnRetTy::DefaultReturn(return_span) = declaration.output { - span_lint(cx, MAIN_RETURN_WITHOUT_APPEXIT, return_span, "AAAA!"); + && let FnRetTy::DefaultReturn(_) = declaration.output + { + // Iterate over each expression within the entrypoint function, finding and reporting + // `App::run()` calls. + for_each_expr(cx, body, |expr| find_app_run_call(cx, expr)); } } } + +fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> ControlFlow<()> { + // Find a method call that matches `.run()`. + if let ExprKind::MethodCall(path, src, _, span) = expr.kind + && path.ident.name == sym!(run) + { + // Get the type of `src` for `src.run()`. + let ty = cx.typeck_results().expr_ty(src); + + // May not be necessary if `match_ty` is used instead. + let Some(adt) = ty.ty_adt_def() else { + return ControlFlow::Continue(()); + }; + + // Syms may be incorrect. + if match_def_path(cx, adt.did(), &["bevy", "prelude", "App"]) { + span_lint(cx, MAIN_RETURN_WITHOUT_APPEXIT, span, "AAA!!"); + } + } + + ControlFlow::Continue(()) +} From fee57216592e4bc5ba7bf46f30033abf6605e0e2 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:05:21 -0400 Subject: [PATCH 07/36] feat: finish mvp of `main_return_without_appexit` --- .../src/lints/main_return_without_appexit.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 52fab7e..fa9f02d 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -1,8 +1,10 @@ -use std::ops::ControlFlow; -use clippy_utils::{diagnostics::span_lint, is_entrypoint_fn, match_def_path, sym, visitors::for_each_expr}; +use clippy_utils::{ + diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, +}; use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy}; use rustc_lint::{LateContext, LateLintPass, Level, Lint, LintPass, LintVec}; use rustc_span::Span; +use std::ops::ControlFlow; pub static MAIN_RETURN_WITHOUT_APPEXIT: &Lint = &Lint { name: "bevy::main_return_without_appexit", @@ -56,14 +58,14 @@ fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Control // Get the type of `src` for `src.run()`. let ty = cx.typeck_results().expr_ty(src); - // May not be necessary if `match_ty` is used instead. - let Some(adt) = ty.ty_adt_def() else { - return ControlFlow::Continue(()); - }; - - // Syms may be incorrect. - if match_def_path(cx, adt.did(), &["bevy", "prelude", "App"]) { - span_lint(cx, MAIN_RETURN_WITHOUT_APPEXIT, span, "AAA!!"); + // If `src` is a Bevy `App`, emit the lint. + if match_type(cx, ty, &["bevy_app", "app", "App"]) { + span_lint( + cx, + MAIN_RETURN_WITHOUT_APPEXIT, + span, + MAIN_RETURN_WITHOUT_APPEXIT.desc, + ); } } From 8166785700b584e8059cb9d22a2a8922ad8e5bff Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:13:16 -0400 Subject: [PATCH 08/36] refactor: replace `define_lints!` macro with hardcoded values `rustfmt` doesn't format the lint modules because it can't find `mod name;` syntax for them. And honestly? This is fine until it becomes incredibly cumbersome. --- bevy_lint/src/lints/mod.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index 0f50af8..d2a2946 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -1,22 +1,5 @@ use rustc_lint::Lint; -macro_rules! define_lints { - { - $(mod $module:ident { - lint: $lint:ident$(,)? - })* - } => { - // Declare all modules as private. - $(pub mod $module;)* +pub mod main_return_without_appexit; - pub static LINTS: &[&Lint] = &[ - $(self::$module::$lint,)* - ]; - }; -} - -define_lints! { - mod main_return_without_appexit { - lint: MAIN_RETURN_WITHOUT_APPEXIT, - } -} +pub static LINTS: &[&Lint] = &[main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT]; From d3c93654c70d4b7f0a76f73542fd224ad88749e2 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:43:45 -0400 Subject: [PATCH 09/36] refactor: move pass registration to `lints/mod.rs` This puts it all together, so you're less likely to forget to register the pass. --- bevy_lint/src/callback.rs | 5 +---- bevy_lint/src/lints/mod.rs | 6 +++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bevy_lint/src/callback.rs b/bevy_lint/src/callback.rs index 38bcad5..2032b66 100644 --- a/bevy_lint/src/callback.rs +++ b/bevy_lint/src/callback.rs @@ -16,10 +16,7 @@ impl Callbacks for BevyLintCallback { } store.register_lints(crate::lints::LINTS); - - store.register_late_pass(|_| { - Box::new(crate::lints::main_return_without_appexit::MainReturnWithoutAppExit) - }); + crate::lints::register_passes(store); })); } } diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index d2a2946..ea90f82 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -1,5 +1,9 @@ -use rustc_lint::Lint; +use rustc_lint::{Lint, LintStore}; pub mod main_return_without_appexit; pub static LINTS: &[&Lint] = &[main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT]; + +pub fn register_passes(store: &mut LintStore) { + store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit)); +} From da5c4b98bcef2920ae435788b8466a7376b52966 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:44:21 -0400 Subject: [PATCH 10/36] refactor: replace manual lint and pass definitions with macro --- bevy_lint/src/lib.rs | 1 + .../src/lints/main_return_without_appexit.rs | 28 ++++++------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 6d9dc79..705ab7d 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -9,6 +9,7 @@ extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_lint; +extern crate rustc_session; extern crate rustc_span; mod callback; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index fa9f02d..853b10d 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -2,31 +2,19 @@ use clippy_utils::{ diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy}; -use rustc_lint::{LateContext, LateLintPass, Level, Lint, LintPass, LintVec}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use std::ops::ControlFlow; -pub static MAIN_RETURN_WITHOUT_APPEXIT: &Lint = &Lint { - name: "bevy::main_return_without_appexit", - default_level: Level::Warn, - desc: "an entrypoint that calls `App::run()` does not return `AppExit`", - is_externally_loaded: true, - ..Lint::default_fields_for_macro() -}; - -#[derive(Clone, Copy, Debug)] -pub struct MainReturnWithoutAppExit; - -impl LintPass for MainReturnWithoutAppExit { - fn name(&self) -> &'static str { - MAIN_RETURN_WITHOUT_APPEXIT.name - } +declare_tool_lint! { + pub bevy::MAIN_RETURN_WITHOUT_APPEXIT, + Warn, + "an entrypoint that calls `App::run()` does not return `AppExit`" } -impl MainReturnWithoutAppExit { - pub fn get_lints() -> LintVec { - vec![MAIN_RETURN_WITHOUT_APPEXIT] - } +declare_lint_pass! { + MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT] } impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { From 7097fb9769c0c54f3eb618cec180ec5967430b0d Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:55:57 -0400 Subject: [PATCH 11/36] feat: add module documentation --- .../src/lints/main_return_without_appexit.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 853b10d..ca39111 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -1,3 +1,32 @@ +//! Checks for `fn main()` entrypoints that call `App::run()` but do not return `AppExit`. +//! +//! # Why is this bad? +//! +//! `AppExit` is used to determine whether the `App` exited successful or due to an error. Returning +//! it from `main()` will set the exit code, which allows external processes to detect whether there +//! was an error. +//! +//! # Example +//! +//! ```rust +//! # use bevy::prelude::*; +//! # +//! fn main() { +//! App::new().run(); +//! } +//! ``` +//! +//! Use instead: +//! +//! ```rust +//! # use bevy::prelude::*; +//! # +//! fn main() -> AppExit { +//! // Note the removed semicolon. +//! App::new().run() +//! } +//! ``` + use clippy_utils::{ diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; From 3cf0422aa569c99617130e26916ab7df261a6328 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:22:00 -0400 Subject: [PATCH 12/36] fix: edge case where `fn main() -> ()` --- .../src/lints/main_return_without_appexit.rs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index ca39111..0a00cee 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -1,5 +1,8 @@ //! Checks for `fn main()` entrypoints that call `App::run()` but do not return `AppExit`. //! +//! This lint will not be emitted if `fn main()` returns a non-[`unit`] type, even if that type is +//! not `AppExit`. +//! //! # Why is this bad? //! //! `AppExit` is used to determine whether the `App` exited successful or due to an error. Returning @@ -30,7 +33,9 @@ use clippy_utils::{ diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; -use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy}; +use rustc_hir::{ + def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy, Ty, TyKind, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -56,9 +61,17 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { _: Span, local_def_id: LocalDefId, ) { - // We're looking for `fn main()` with no return type that calls `App::run()`. + // Look for `fn main()`. if is_entrypoint_fn(cx, local_def_id.into()) - && let FnRetTy::DefaultReturn(_) = declaration.output + // Ensure the function either returns nothing or the unit type. If the entrypoint + // returns something else, we're assuming that the user knows what they're doing. + && match declaration.output { + // The function signature is the default `fn main()`. + FnRetTy::DefaultReturn(_) => true, + // The function signature is `fn main() -> ()`. + FnRetTy::Return(&Ty { kind: TyKind::Tup(&[]), .. }) => {true}, + _ => false, + } { // Iterate over each expression within the entrypoint function, finding and reporting // `App::run()` calls. @@ -67,6 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { } } +/// Finds expressions that call `App::run()` and emits [`MAIN_RETURN_WITHOUT_APPEXIT`]. fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> ControlFlow<()> { // Find a method call that matches `.run()`. if let ExprKind::MethodCall(path, src, _, span) = expr.kind From b38c3028c96fd454c9c8a5d56799e34029ca6f27 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:23:34 -0400 Subject: [PATCH 13/36] chore: make `register_passes` `pub(crate)` --- bevy_lint/src/lints/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index ea90f82..c778bd0 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -4,6 +4,6 @@ pub mod main_return_without_appexit; pub static LINTS: &[&Lint] = &[main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT]; -pub fn register_passes(store: &mut LintStore) { +pub(crate) fn register_passes(store: &mut LintStore) { store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit)); } From f8625062f15ae4772182119be2bb56b5c7c6c998 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:55:31 -0400 Subject: [PATCH 14/36] feat: begin add suggestions --- bevy_lint/src/lib.rs | 1 + .../src/lints/main_return_without_appexit.rs | 43 +++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 705ab7d..7e36a85 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -6,6 +6,7 @@ // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_lint; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 0a00cee..9259a3d 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -31,8 +31,9 @@ //! ``` use clippy_utils::{ - diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, + diagnostics::span_lint_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; +use rustc_errors::Applicability; use rustc_hir::{ def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy, Ty, TyKind, }; @@ -61,27 +62,37 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { _: Span, local_def_id: LocalDefId, ) { - // Look for `fn main()`. - if is_entrypoint_fn(cx, local_def_id.into()) + // Only check `fn main()`. + if is_entrypoint_fn(cx, local_def_id.into()) { // Ensure the function either returns nothing or the unit type. If the entrypoint // returns something else, we're assuming that the user knows what they're doing. - && match declaration.output { + // Additionally, we collect the span of the return position for better diagnostics. + let fn_return_span = match declaration.output { // The function signature is the default `fn main()`. - FnRetTy::DefaultReturn(_) => true, + FnRetTy::DefaultReturn(span) => span, // The function signature is `fn main() -> ()`. - FnRetTy::Return(&Ty { kind: TyKind::Tup(&[]), .. }) => {true}, - _ => false, - } - { + FnRetTy::Return(&Ty { + kind: TyKind::Tup(&[]), + span, + .. + }) => span, + // The function returns something else, exit early. + _ => return, + }; + // Iterate over each expression within the entrypoint function, finding and reporting // `App::run()` calls. - for_each_expr(cx, body, |expr| find_app_run_call(cx, expr)); + for_each_expr(cx, body, |expr| find_app_run_call(cx, expr, fn_return_span)); } } } /// Finds expressions that call `App::run()` and emits [`MAIN_RETURN_WITHOUT_APPEXIT`]. -fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> ControlFlow<()> { +fn find_app_run_call<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + fn_return_span: Span, +) -> ControlFlow<()> { // Find a method call that matches `.run()`. if let ExprKind::MethodCall(path, src, _, span) = expr.kind && path.ident.name == sym!(run) @@ -91,11 +102,19 @@ fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Control // If `src` is a Bevy `App`, emit the lint. if match_type(cx, ty, &["bevy_app", "app", "App"]) { - span_lint( + span_lint_and_then( cx, MAIN_RETURN_WITHOUT_APPEXIT, span, MAIN_RETURN_WITHOUT_APPEXIT.desc, + |diag| { + diag.span_suggestion( + fn_return_span, + "try", + "-> AppExit", + Applicability::MaybeIncorrect, + ); + }, ); } } From 01146303193c34e863ec7b73299bd21b322e78ab Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:56:52 -0400 Subject: [PATCH 15/36] Revert "feat: begin add suggestions" This reverts commit f8625062f15ae4772182119be2bb56b5c7c6c998. --- bevy_lint/src/lib.rs | 1 - .../src/lints/main_return_without_appexit.rs | 43 ++++++------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 7e36a85..705ab7d 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -6,7 +6,6 @@ // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_lint; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 9259a3d..0a00cee 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -31,9 +31,8 @@ //! ``` use clippy_utils::{ - diagnostics::span_lint_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, + diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; -use rustc_errors::Applicability; use rustc_hir::{ def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy, Ty, TyKind, }; @@ -62,37 +61,27 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { _: Span, local_def_id: LocalDefId, ) { - // Only check `fn main()`. - if is_entrypoint_fn(cx, local_def_id.into()) { + // Look for `fn main()`. + if is_entrypoint_fn(cx, local_def_id.into()) // Ensure the function either returns nothing or the unit type. If the entrypoint // returns something else, we're assuming that the user knows what they're doing. - // Additionally, we collect the span of the return position for better diagnostics. - let fn_return_span = match declaration.output { + && match declaration.output { // The function signature is the default `fn main()`. - FnRetTy::DefaultReturn(span) => span, + FnRetTy::DefaultReturn(_) => true, // The function signature is `fn main() -> ()`. - FnRetTy::Return(&Ty { - kind: TyKind::Tup(&[]), - span, - .. - }) => span, - // The function returns something else, exit early. - _ => return, - }; - + FnRetTy::Return(&Ty { kind: TyKind::Tup(&[]), .. }) => {true}, + _ => false, + } + { // Iterate over each expression within the entrypoint function, finding and reporting // `App::run()` calls. - for_each_expr(cx, body, |expr| find_app_run_call(cx, expr, fn_return_span)); + for_each_expr(cx, body, |expr| find_app_run_call(cx, expr)); } } } /// Finds expressions that call `App::run()` and emits [`MAIN_RETURN_WITHOUT_APPEXIT`]. -fn find_app_run_call<'tcx>( - cx: &LateContext<'tcx>, - expr: &Expr<'tcx>, - fn_return_span: Span, -) -> ControlFlow<()> { +fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> ControlFlow<()> { // Find a method call that matches `.run()`. if let ExprKind::MethodCall(path, src, _, span) = expr.kind && path.ident.name == sym!(run) @@ -102,19 +91,11 @@ fn find_app_run_call<'tcx>( // If `src` is a Bevy `App`, emit the lint. if match_type(cx, ty, &["bevy_app", "app", "App"]) { - span_lint_and_then( + span_lint( cx, MAIN_RETURN_WITHOUT_APPEXIT, span, MAIN_RETURN_WITHOUT_APPEXIT.desc, - |diag| { - diag.span_suggestion( - fn_return_span, - "try", - "-> AppExit", - Applicability::MaybeIncorrect, - ); - }, ); } } From 82d4e142add597d35ad02c6a0a56cf54340cb622 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:15:30 -0400 Subject: [PATCH 16/36] feat: better diagnostics --- bevy_lint/src/lib.rs | 1 + .../src/lints/main_return_without_appexit.rs | 70 ++++++++++++------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 705ab7d..7e36a85 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -6,6 +6,7 @@ // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_lint; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 0a00cee..4371582 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -31,10 +31,11 @@ //! ``` use clippy_utils::{ - diagnostics::span_lint, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, + diagnostics::span_lint_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; +use rustc_errors::Applicability; use rustc_hir::{ - def_id::LocalDefId, intravisit::FnKind, Body, Expr, ExprKind, FnDecl, FnRetTy, Ty, TyKind, + def_id::LocalDefId, intravisit::FnKind, Body, ExprKind, FnDecl, FnRetTy, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -69,36 +70,55 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { // The function signature is the default `fn main()`. FnRetTy::DefaultReturn(_) => true, // The function signature is `fn main() -> ()`. - FnRetTy::Return(&Ty { kind: TyKind::Tup(&[]), .. }) => {true}, + FnRetTy::Return(&Ty { kind: TyKind::Tup(&[]), .. }) => true, _ => false, } { // Iterate over each expression within the entrypoint function, finding and reporting // `App::run()` calls. - for_each_expr(cx, body, |expr| find_app_run_call(cx, expr)); - } - } -} + for_each_expr(cx, body, |expr| { + // Find a method call that matches `.run()`. + if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind + && path.ident.name == sym!(run) + { + // Get the type of `src` for `src.run()`. + let ty = cx.typeck_results().expr_ty(src); -/// Finds expressions that call `App::run()` and emits [`MAIN_RETURN_WITHOUT_APPEXIT`]. -fn find_app_run_call<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> ControlFlow<()> { - // Find a method call that matches `.run()`. - if let ExprKind::MethodCall(path, src, _, span) = expr.kind - && path.ident.name == sym!(run) - { - // Get the type of `src` for `src.run()`. - let ty = cx.typeck_results().expr_ty(src); + // If `src` is a Bevy `App`, emit the lint. + if match_type(cx, ty, &["bevy_app", "app", "App"]) { + span_lint_and_then( + cx, + MAIN_RETURN_WITHOUT_APPEXIT, + method_span, + MAIN_RETURN_WITHOUT_APPEXIT.desc, + |diag| { + diag.note("`App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not"); + match declaration.output { + // When it is just `fn main()`, we need to suggest the `->`. + FnRetTy::DefaultReturn(fn_return_span) => diag.span_suggestion( + fn_return_span, + "try", + " -> AppExit", + Applicability::MaybeIncorrect, + ), + // When it is `fn main() -> ()`, we just need to override `()`. + FnRetTy::Return(&Ty { + span: fn_return_span, + .. + }) => diag.span_suggestion( + fn_return_span, + "try", + "AppExit", + Applicability::MaybeIncorrect, + ), + }; + }, + ); + } + } - // If `src` is a Bevy `App`, emit the lint. - if match_type(cx, ty, &["bevy_app", "app", "App"]) { - span_lint( - cx, - MAIN_RETURN_WITHOUT_APPEXIT, - span, - MAIN_RETURN_WITHOUT_APPEXIT.desc, - ); + ControlFlow::<()>::Continue(()) + }); } } - - ControlFlow::Continue(()) } From e269046cc31f9b6cbd543d11837140e64b57bf8e Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:49:29 -0400 Subject: [PATCH 17/36] refactor: create paths module --- bevy_lint/src/lib.rs | 1 + bevy_lint/src/lints/main_return_without_appexit.rs | 2 +- bevy_lint/src/paths.rs | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 bevy_lint/src/paths.rs diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 7e36a85..a3e74ba 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -15,5 +15,6 @@ extern crate rustc_span; mod callback; pub mod lints; +pub mod paths; pub use self::callback::BevyLintCallback; diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 4371582..23ea07e 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { let ty = cx.typeck_results().expr_ty(src); // If `src` is a Bevy `App`, emit the lint. - if match_type(cx, ty, &["bevy_app", "app", "App"]) { + if match_type(cx, ty, &crate::paths::APP) { span_lint_and_then( cx, MAIN_RETURN_WITHOUT_APPEXIT, diff --git a/bevy_lint/src/paths.rs b/bevy_lint/src/paths.rs new file mode 100644 index 0000000..4a0f56f --- /dev/null +++ b/bevy_lint/src/paths.rs @@ -0,0 +1,9 @@ +//! A collection of hardcoded types and functions that the linter uses. +//! +//! Since Bevy is a 3rd-party crate, we cannot easily add diagnostic items to it. In lieu of this, +//! we hardcode the paths to the items we need here, for easy referencing. +//! +//! Also see: [`match_type()`](clippy_utils::ty::match_type), +//! [`match_def_path()`](clippy_utils::match_def_path). + +pub const APP: [&str; 3] = ["bevy_app", "app", "App"]; From 996b7dce1f754ace1556f1c3166233a61bdf02e9 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:43:36 -0400 Subject: [PATCH 18/36] fix: peel source references --- bevy_lint/src/lints/main_return_without_appexit.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 23ea07e..cf96a4b 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -31,7 +31,8 @@ //! ``` use clippy_utils::{ - diagnostics::span_lint_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, + diagnostics::span_lint_and_then, is_entrypoint_fn, peel_middle_ty_refs, sym, ty::match_type, + visitors::for_each_expr, }; use rustc_errors::Applicability; use rustc_hir::{ @@ -81,8 +82,9 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind && path.ident.name == sym!(run) { - // Get the type of `src` for `src.run()`. - let ty = cx.typeck_results().expr_ty(src); + // Get the type of `src` for `src.run()`. We peel away all references because + // both `App` and `&mut App` are allowed. + let ty = peel_middle_ty_refs(cx.typeck_results().expr_ty(src)).0; // If `src` is a Bevy `App`, emit the lint. if match_type(cx, ty, &crate::paths::APP) { From 96576833990107d18f3f01f559122dc4391000b0 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:13:27 -0400 Subject: [PATCH 19/36] refactor: use `Ty::peel_refs()` instead of `peel_middle_ty_refs()` --- bevy_lint/src/lints/main_return_without_appexit.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index cf96a4b..2898abd 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -31,8 +31,7 @@ //! ``` use clippy_utils::{ - diagnostics::span_lint_and_then, is_entrypoint_fn, peel_middle_ty_refs, sym, ty::match_type, - visitors::for_each_expr, + diagnostics::span_lint_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, }; use rustc_errors::Applicability; use rustc_hir::{ @@ -84,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { { // Get the type of `src` for `src.run()`. We peel away all references because // both `App` and `&mut App` are allowed. - let ty = peel_middle_ty_refs(cx.typeck_results().expr_ty(src)).0; + let ty = cx.typeck_results().expr_ty(src).peel_refs(); // If `src` is a Bevy `App`, emit the lint. if match_type(cx, ty, &crate::paths::APP) { From 03ccbf31c43f32d6ac62e4903d7922384fc0476a Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 08:38:35 -0400 Subject: [PATCH 20/36] feat: create `init_event_resource` scaffold --- bevy_lint/src/lints/init_event_resource.rs | 16 ++++++++++++++++ bevy_lint/src/lints/mod.rs | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 bevy_lint/src/lints/init_event_resource.rs diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/init_event_resource.rs new file mode 100644 index 0000000..d51ed9d --- /dev/null +++ b/bevy_lint/src/lints/init_event_resource.rs @@ -0,0 +1,16 @@ +//! TODO + +use rustc_lint::LateLintPass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_tool_lint! { + pub bevy::INIT_EVENT_RESOURCE, + Deny, + "called `App::init_resource::>() instead of `App::add_event::()`" +} + +declare_lint_pass! { + InitEventResource => [INIT_EVENT_RESOURCE] +} + +impl<'tcx> LateLintPass<'tcx> for InitEventResource {} diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index c778bd0..8fe7dda 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -1,9 +1,14 @@ use rustc_lint::{Lint, LintStore}; +pub mod init_event_resource; pub mod main_return_without_appexit; -pub static LINTS: &[&Lint] = &[main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT]; +pub static LINTS: &[&Lint] = &[ + init_event_resource::INIT_EVENT_RESOURCE, + main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT, +]; pub(crate) fn register_passes(store: &mut LintStore) { + store.register_late_pass(|_| Box::new(init_event_resource::InitEventResource)); store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit)); } From 92f3557b0113db3179871c15221a08800aff13ce Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:09:58 -0400 Subject: [PATCH 21/36] feat: first working prototype --- bevy_lint/src/lib.rs | 1 + bevy_lint/src/lints/init_event_resource.rs | 37 ++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index a3e74ba..c8c0044 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -8,6 +8,7 @@ extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_hir_analysis; extern crate rustc_interface; extern crate rustc_lint; extern crate rustc_session; diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/init_event_resource.rs index d51ed9d..d4f9977 100644 --- a/bevy_lint/src/lints/init_event_resource.rs +++ b/bevy_lint/src/lints/init_event_resource.rs @@ -1,6 +1,9 @@ //! TODO -use rustc_lint::LateLintPass; +use clippy_utils::{diagnostics::span_lint, sym, ty::match_type}; +use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs}; +use rustc_hir_analysis::lower_ty; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_tool_lint! { @@ -13,4 +16,34 @@ declare_lint_pass! { InitEventResource => [INIT_EVENT_RESOURCE] } -impl<'tcx> LateLintPass<'tcx> for InitEventResource {} +impl<'tcx> LateLintPass<'tcx> for InitEventResource { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + // Find a method call that matches `.init_resource()`. + // TODO: Also check for `insert_resource()`. + if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind + && path.ident.name == sym!(init_resource) + { + // Get the type for `src` in `src.init_resource()`. + let src_ty = cx.typeck_results().expr_ty(src); + + // Ensure `src` is a Bevy `App`. + if match_type(cx, src_ty, &crate::paths::APP) + && let Some(&GenericArgs { + args: &[GenericArg::Type(generic_ty)], + .. + }) = path.args + { + let generic_ty = dbg!(lower_ty(cx.tcx, generic_ty)); + + if match_type(cx, generic_ty, &["bevy_ecs", "event", "Events"]) { + span_lint( + cx, + INIT_EVENT_RESOURCE, + method_span, + INIT_EVENT_RESOURCE.desc, + ); + } + } + } + } +} From c955cf56f1cb9c304ab5acbd3837bd45c59ad150 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:25:10 -0400 Subject: [PATCH 22/36] refactor: to begin supporting both `init_resource()` and `insert_resource()` --- bevy_lint/src/lints/init_event_resource.rs | 63 ++++++++++++++-------- bevy_lint/src/paths.rs | 1 + 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/init_event_resource.rs index d4f9977..511e059 100644 --- a/bevy_lint/src/lints/init_event_resource.rs +++ b/bevy_lint/src/lints/init_event_resource.rs @@ -1,10 +1,11 @@ //! TODO use clippy_utils::{diagnostics::span_lint, sym, ty::match_type}; -use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs}; +use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, PathSegment}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; declare_tool_lint! { pub bevy::INIT_EVENT_RESOURCE, @@ -18,32 +19,48 @@ declare_lint_pass! { impl<'tcx> LateLintPass<'tcx> for InitEventResource { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - // Find a method call that matches `.init_resource()`. - // TODO: Also check for `insert_resource()`. - if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind - && path.ident.name == sym!(init_resource) - { - // Get the type for `src` in `src.init_resource()`. + // Find a method call. + if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind { + // Get the type for `src` in `src.method()`. let src_ty = cx.typeck_results().expr_ty(src); - // Ensure `src` is a Bevy `App`. - if match_type(cx, src_ty, &crate::paths::APP) - && let Some(&GenericArgs { - args: &[GenericArg::Type(generic_ty)], - .. - }) = path.args - { - let generic_ty = dbg!(lower_ty(cx.tcx, generic_ty)); - - if match_type(cx, generic_ty, &["bevy_ecs", "event", "Events"]) { - span_lint( - cx, - INIT_EVENT_RESOURCE, - method_span, - INIT_EVENT_RESOURCE.desc, - ); + // If `src` is not a Bevy `App`, exit. + if !match_type(cx, src_ty, &crate::paths::APP) { + return; + } + + // If the method is `App::init_resource()` or `App::insert_resource()`, check it with + // its corresponding function. + match path.ident.name { + symbol if symbol == sym!(init_resource) => { + check_init_resource(cx, path, method_span) } + symbol if symbol == sym!(insert_resource) => todo!(), + _ => {} } } } } + +fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { + if let Some(&GenericArgs { + // `App::init_resource()` has one generic type argument: T. + args: &[GenericArg::Type(generic_ty)], + .. + }) = path.args + { + // Lower `rustc_hir::Ty` to `ty::Ty`, so we can inspect type information. For more + // information, see . + let generic_ty = lower_ty(cx.tcx, generic_ty); + + // If the generic argument is `Events`, emit the lint. + if match_type(cx, generic_ty, &crate::paths::EVENTS) { + span_lint( + cx, + INIT_EVENT_RESOURCE, + method_span, + INIT_EVENT_RESOURCE.desc, + ); + } + } +} diff --git a/bevy_lint/src/paths.rs b/bevy_lint/src/paths.rs index 4a0f56f..c36a21f 100644 --- a/bevy_lint/src/paths.rs +++ b/bevy_lint/src/paths.rs @@ -7,3 +7,4 @@ //! [`match_def_path()`](clippy_utils::match_def_path). pub const APP: [&str; 3] = ["bevy_app", "app", "App"]; +pub const EVENTS: [&str; 3] = ["bevy_ecs", "event", "Events"]; From 8f0c8e9390dfca38ed45b350bcedf81cf9b1b714 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:48:48 -0400 Subject: [PATCH 23/36] feat: finish support for `App::insert_resource()` --- bevy_lint/src/lints/init_event_resource.rs | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/init_event_resource.rs index 511e059..c28e3f0 100644 --- a/bevy_lint/src/lints/init_event_resource.rs +++ b/bevy_lint/src/lints/init_event_resource.rs @@ -20,7 +20,7 @@ declare_lint_pass! { impl<'tcx> LateLintPass<'tcx> for InitEventResource { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { // Find a method call. - if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind { + if let ExprKind::MethodCall(path, src, args, method_span) = expr.kind { // Get the type for `src` in `src.method()`. let src_ty = cx.typeck_results().expr_ty(src); @@ -35,7 +35,9 @@ impl<'tcx> LateLintPass<'tcx> for InitEventResource { symbol if symbol == sym!(init_resource) => { check_init_resource(cx, path, method_span) } - symbol if symbol == sym!(insert_resource) => todo!(), + symbol if symbol == sym!(insert_resource) => { + check_insert_resource(cx, args, method_span) + } _ => {} } } @@ -51,6 +53,8 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m { // Lower `rustc_hir::Ty` to `ty::Ty`, so we can inspect type information. For more // information, see . + // Note that `lower_ty()` is quasi-deprecated, and should be removed if a adequate + // replacement is found. let generic_ty = lower_ty(cx.tcx, generic_ty); // If the generic argument is `Events`, emit the lint. @@ -64,3 +68,22 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m } } } + +fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_span: Span) { + // Extract the argument if there is only 1 (which there should be!), else exit. + let [arg] = args else { + return; + }; + + // Find the type of `arg` in `App::insert_resource(arg)`. + let ty = cx.typeck_results().expr_ty(arg); + + if match_type(cx, ty, &crate::paths::EVENTS) { + span_lint( + cx, + INIT_EVENT_RESOURCE, + method_span, + INIT_EVENT_RESOURCE.desc, + ); + } +} From 36edd1897492d0f221467ab3f278799c44f384cd Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:08:15 -0400 Subject: [PATCH 24/36] fix: peel source type of all references --- bevy_lint/src/lints/init_event_resource.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/init_event_resource.rs index c28e3f0..7352139 100644 --- a/bevy_lint/src/lints/init_event_resource.rs +++ b/bevy_lint/src/lints/init_event_resource.rs @@ -1,6 +1,6 @@ //! TODO -use clippy_utils::{diagnostics::span_lint, sym, ty::match_type}; +use clippy_utils::{diagnostics::span_lint, peel_middle_ty_refs, sym, ty::match_type}; use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, PathSegment}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -21,8 +21,9 @@ impl<'tcx> LateLintPass<'tcx> for InitEventResource { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { // Find a method call. if let ExprKind::MethodCall(path, src, args, method_span) = expr.kind { - // Get the type for `src` in `src.method()`. - let src_ty = cx.typeck_results().expr_ty(src); + // Get the type for `src` in `src.method()`. We peel all references because the type + // could either be `App` or `&mut App`. + let src_ty = peel_middle_ty_refs(cx.typeck_results().expr_ty(src)).0; // If `src` is not a Bevy `App`, exit. if !match_type(cx, src_ty, &crate::paths::APP) { From 6925da4a06e921e0647482acea83180bb59f1451 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:51:15 -0400 Subject: [PATCH 25/36] refactor: rename `init_event_resource` to `insert_event_resource` --- ...t_resource.rs => insert_event_resource.rs} | 59 ++++++++++--------- bevy_lint/src/lints/mod.rs | 6 +- 2 files changed, 33 insertions(+), 32 deletions(-) rename bevy_lint/src/lints/{init_event_resource.rs => insert_event_resource.rs} (82%) diff --git a/bevy_lint/src/lints/init_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs similarity index 82% rename from bevy_lint/src/lints/init_event_resource.rs rename to bevy_lint/src/lints/insert_event_resource.rs index 7352139..fddf1d2 100644 --- a/bevy_lint/src/lints/init_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -8,16 +8,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_tool_lint! { - pub bevy::INIT_EVENT_RESOURCE, + pub bevy::INSERT_EVENT_RESOURCE, Deny, - "called `App::init_resource::>() instead of `App::add_event::()`" + "called `App::insert_resource(Events)` or `App::init_resource::>()` instead of `App::add_event::()`" } declare_lint_pass! { - InitEventResource => [INIT_EVENT_RESOURCE] + InsertEventResource => [INSERT_EVENT_RESOURCE] } -impl<'tcx> LateLintPass<'tcx> for InitEventResource { +impl<'tcx> LateLintPass<'tcx> for InsertEventResource { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { // Find a method call. if let ExprKind::MethodCall(path, src, args, method_span) = expr.kind { @@ -30,21 +30,41 @@ impl<'tcx> LateLintPass<'tcx> for InitEventResource { return; } - // If the method is `App::init_resource()` or `App::insert_resource()`, check it with + // If the method is `App::insert_resource()` or `App::init_resource()`, check it with // its corresponding function. match path.ident.name { - symbol if symbol == sym!(init_resource) => { - check_init_resource(cx, path, method_span) - } symbol if symbol == sym!(insert_resource) => { check_insert_resource(cx, args, method_span) } + symbol if symbol == sym!(init_resource) => { + check_init_resource(cx, path, method_span) + } _ => {} } } } } +fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_span: Span) { + // Extract the argument if there is only 1 (which there should be!), else exit. + let [arg] = args else { + return; + }; + + // Find the type of `arg` in `App::insert_resource(arg)`. + let ty = cx.typeck_results().expr_ty(arg); + + // If `arg` is `Events`, emit the lint. + if match_type(cx, ty, &crate::paths::EVENTS) { + span_lint( + cx, + INSERT_EVENT_RESOURCE, + method_span, + INSERT_EVENT_RESOURCE.desc, + ); + } +} + fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { if let Some(&GenericArgs { // `App::init_resource()` has one generic type argument: T. @@ -62,29 +82,10 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m if match_type(cx, generic_ty, &crate::paths::EVENTS) { span_lint( cx, - INIT_EVENT_RESOURCE, + INSERT_EVENT_RESOURCE, method_span, - INIT_EVENT_RESOURCE.desc, + INSERT_EVENT_RESOURCE.desc, ); } } } - -fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_span: Span) { - // Extract the argument if there is only 1 (which there should be!), else exit. - let [arg] = args else { - return; - }; - - // Find the type of `arg` in `App::insert_resource(arg)`. - let ty = cx.typeck_results().expr_ty(arg); - - if match_type(cx, ty, &crate::paths::EVENTS) { - span_lint( - cx, - INIT_EVENT_RESOURCE, - method_span, - INIT_EVENT_RESOURCE.desc, - ); - } -} diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index 8fe7dda..87fc32f 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -1,14 +1,14 @@ use rustc_lint::{Lint, LintStore}; -pub mod init_event_resource; +pub mod insert_event_resource; pub mod main_return_without_appexit; pub static LINTS: &[&Lint] = &[ - init_event_resource::INIT_EVENT_RESOURCE, + insert_event_resource::INSERT_EVENT_RESOURCE, main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT, ]; pub(crate) fn register_passes(store: &mut LintStore) { - store.register_late_pass(|_| Box::new(init_event_resource::InitEventResource)); + store.register_late_pass(|_| Box::new(insert_event_resource::InsertEventResource)); store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit)); } From cdf2eddae227e0e9ef6233885f70e0ac67f0ef0c Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:12:34 -0400 Subject: [PATCH 26/36] refactor: use `Ty::peel_refs()` instead of `peel_middle_ty_refs()` --- bevy_lint/src/lints/insert_event_resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index fddf1d2..94baf0d 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -23,7 +23,7 @@ impl<'tcx> LateLintPass<'tcx> for InsertEventResource { if let ExprKind::MethodCall(path, src, args, method_span) = expr.kind { // Get the type for `src` in `src.method()`. We peel all references because the type // could either be `App` or `&mut App`. - let src_ty = peel_middle_ty_refs(cx.typeck_results().expr_ty(src)).0; + let src_ty = cx.typeck_results().expr_ty(src).peel_refs(); // If `src` is not a Bevy `App`, exit. if !match_type(cx, src_ty, &crate::paths::APP) { From 37d33c0931be9dd0ea4132fea6fa0ffb4f400169 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:39:52 -0400 Subject: [PATCH 27/36] feat: add suggestions to diagnostic for `init_resource()` --- bevy_lint/src/lints/insert_event_resource.rs | 61 ++++++++++++++++++-- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 94baf0d..26f613d 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -1,11 +1,18 @@ //! TODO -use clippy_utils::{diagnostics::span_lint, peel_middle_ty_refs, sym, ty::match_type}; -use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, PathSegment}; +use clippy_utils::{ + diagnostics::{span_lint, span_lint_and_sugg}, + source::snippet_with_applicability, + sym, + ty::match_type, +}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath, Ty, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; +use std::borrow::Cow; declare_tool_lint! { pub bevy::INSERT_EVENT_RESOURCE, @@ -68,7 +75,7 @@ fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_spa fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { if let Some(&GenericArgs { // `App::init_resource()` has one generic type argument: T. - args: &[GenericArg::Type(generic_ty)], + args: &[GenericArg::Type(generic_hir_ty)], .. }) = path.args { @@ -76,15 +83,57 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m // information, see . // Note that `lower_ty()` is quasi-deprecated, and should be removed if a adequate // replacement is found. - let generic_ty = lower_ty(cx.tcx, generic_ty); + let generic_ty = lower_ty(cx.tcx, generic_hir_ty); // If the generic argument is `Events`, emit the lint. if match_type(cx, generic_ty, &crate::paths::EVENTS) { - span_lint( + let mut applicability = Applicability::MachineApplicable; + + // Get the `str` representation of the type; this will usually look like + // `Events`. If the snippet cannot be found, fallback to the default and + // update the applicability to reflect this. + let generic_ty_span = match generic_hir_ty.kind { + TyKind::Path(QPath::Resolved( + _, + &Path { + segments: + [PathSegment { + args: + Some(GenericArgs { + args: [GenericArg::Type(Ty { span, .. })], + .. + }), + .. + }], + .. + }, + )) => Some(*span), + _ => None, + }; + + const DEFAULT_SNIPPET: &str = "Events"; + + let ty_snippet = match generic_ty_span { + Some(generic_ty_span) => snippet_with_applicability( + cx, + generic_ty_span, + DEFAULT_SNIPPET, + &mut applicability, + ), + None => { + applicability = Applicability::HasPlaceholders; + Cow::Borrowed(DEFAULT_SNIPPET) + } + }; + + span_lint_and_sugg( cx, INSERT_EVENT_RESOURCE, method_span, - INSERT_EVENT_RESOURCE.desc, + "called `App::init_resource::>()` instead of `App::add_event::()`", /* TODO: customize */ + "use", + format!("add_event::<{ty_snippet}>()"), + applicability, ); } } From c59accd2f37fab8d4736b98068de8ae8f660a118 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:27:35 -0400 Subject: [PATCH 28/36] refactor: spin out `extract_event_snippet()` --- bevy_lint/src/lints/insert_event_resource.rs | 103 +++++++++++-------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 26f613d..75cd942 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -7,7 +7,7 @@ use clippy_utils::{ ty::match_type, }; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -75,7 +75,7 @@ fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_spa fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { if let Some(&GenericArgs { // `App::init_resource()` has one generic type argument: T. - args: &[GenericArg::Type(generic_hir_ty)], + args: &[GenericArg::Type(resource_hir_ty)], .. }) = path.args { @@ -83,48 +83,13 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m // information, see . // Note that `lower_ty()` is quasi-deprecated, and should be removed if a adequate // replacement is found. - let generic_ty = lower_ty(cx.tcx, generic_hir_ty); + let resource_ty = lower_ty(cx.tcx, resource_hir_ty); - // If the generic argument is `Events`, emit the lint. - if match_type(cx, generic_ty, &crate::paths::EVENTS) { + // If the resource type is `Events`, emit the lint. + if match_type(cx, resource_ty, &crate::paths::EVENTS) { let mut applicability = Applicability::MachineApplicable; - // Get the `str` representation of the type; this will usually look like - // `Events`. If the snippet cannot be found, fallback to the default and - // update the applicability to reflect this. - let generic_ty_span = match generic_hir_ty.kind { - TyKind::Path(QPath::Resolved( - _, - &Path { - segments: - [PathSegment { - args: - Some(GenericArgs { - args: [GenericArg::Type(Ty { span, .. })], - .. - }), - .. - }], - .. - }, - )) => Some(*span), - _ => None, - }; - - const DEFAULT_SNIPPET: &str = "Events"; - - let ty_snippet = match generic_ty_span { - Some(generic_ty_span) => snippet_with_applicability( - cx, - generic_ty_span, - DEFAULT_SNIPPET, - &mut applicability, - ), - None => { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed(DEFAULT_SNIPPET) - } - }; + let event_ty_snippet = extract_event_snippet(cx, resource_hir_ty, &mut applicability); span_lint_and_sugg( cx, @@ -132,9 +97,63 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m method_span, "called `App::init_resource::>()` instead of `App::add_event::()`", /* TODO: customize */ "use", - format!("add_event::<{ty_snippet}>()"), + format!("add_event::<{event_ty_snippet}>()"), applicability, ); } } } + +/// Tries to extract the snippet `MyEvent` from the [`rustc_hir::Ty`] representing +/// `Events`. +/// +/// Note that this works on a best-effort basis, and will return `"T"` if the type cannot be +/// extracted. If so, it will mutate the passed applicability to [`Applicability::HasPlaceholders`], +/// similar to [`snippet_with_applicability()`]. +fn extract_event_snippet<'tcx>( + cx: &LateContext<'tcx>, + events_hir_ty: &rustc_hir::Ty<'tcx>, + applicability: &mut Applicability, +) -> Cow<'static, str> { + const DEFAULT: Cow = Cow::Borrowed("T"); + + // This is some crazy pattern matching. Let me walk you through it: + let event_span = match events_hir_ty.kind { + // There are multiple kinds of HIR types, but we're looking for a path to a type + // definition. This path is likely `Events`, and contains the generic argument that we're + // searching for. + rustc_hir::TyKind::Path(QPath::Resolved( + _, + &Path { + // There can be multiple segments in a path, but in our case we just have one: + // `Events`. + segments: + &[PathSegment { + // Find the arguments to `Events`, extracting `T`. + args: + Some(&GenericArgs { + args: &[GenericArg::Type(ty)], + .. + }), + .. + }], + .. + }, + )) => { + // We now have the HIR type `T` for `Events`, let's return its span. + ty.span + } + // Something in the above pattern matching went wrong, likely due to an edge case. For + // this, we set the applicability to `HasPlaceholders` and return the default snippet. + _ => { + if let Applicability::MachineApplicable = applicability { + *applicability = Applicability::HasPlaceholders; + } + + return DEFAULT; + } + }; + + // We now have the span to the event type, so let's try to extract it into a string. + snippet_with_applicability(cx, event_span, &DEFAULT, applicability) +} From d773f91ec699791dcc52894eea0ffdd08c7c3e76 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:35:16 -0400 Subject: [PATCH 29/36] fix: there can be multiple segments in the path to `Events` --- bevy_lint/src/lints/insert_event_resource.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 75cd942..d05363d 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -125,10 +125,10 @@ fn extract_event_snippet<'tcx>( rustc_hir::TyKind::Path(QPath::Resolved( _, &Path { - // There can be multiple segments in a path, but in our case we just have one: - // `Events`. + // There can be multiple segments in a path, such as if it were + // `bevy::prelude::Events`, but in this case we just care about the last: `Events`. segments: - &[PathSegment { + &[.., PathSegment { // Find the arguments to `Events`, extracting `T`. args: Some(&GenericArgs { From 6ad420e89d757af2fde6bbd576bfc8f41a9034d2 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:50:07 -0400 Subject: [PATCH 30/36] feat: add suggestion for `insert_resource()` with placeholder --- bevy_lint/src/lints/insert_event_resource.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index d05363d..001455c 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -1,10 +1,7 @@ //! TODO use clippy_utils::{ - diagnostics::{span_lint, span_lint_and_sugg}, - source::snippet_with_applicability, - sym, - ty::match_type, + diagnostics::span_lint_and_sugg, source::snippet_with_applicability, sym, ty::match_type, }; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath}; @@ -52,6 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for InsertEventResource { } } +/// Checks if `App::insert_resource()` inserts an `Events`, and emits a diagnostic if so. fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_span: Span) { // Extract the argument if there is only 1 (which there should be!), else exit. let [arg] = args else { @@ -63,15 +61,19 @@ fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_spa // If `arg` is `Events`, emit the lint. if match_type(cx, ty, &crate::paths::EVENTS) { - span_lint( + span_lint_and_sugg( cx, INSERT_EVENT_RESOURCE, method_span, - INSERT_EVENT_RESOURCE.desc, + "called `App::insert_resource(Events)` instead of `App::add_event::()`", + "inserting an `Events` resource does not fully setup that event", + format!("init_resource::()"), + Applicability::HasPlaceholders, ); } } +/// Checks if `App::init_resource()` inserts an `Events`, and emits a diagnostic if so. fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { if let Some(&GenericArgs { // `App::init_resource()` has one generic type argument: T. @@ -95,8 +97,8 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m cx, INSERT_EVENT_RESOURCE, method_span, - "called `App::init_resource::>()` instead of `App::add_event::()`", /* TODO: customize */ - "use", + "called `App::init_resource::>()` instead of `App::add_event::()`", + "inserting an `Events` resource does not fully setup that event", format!("add_event::<{event_ty_snippet}>()"), applicability, ); From 95c8b0fff002829fec0a803ea1cdd37cdb6b3709 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:04:45 -0400 Subject: [PATCH 31/36] feat: machine applicable suggestions when `insert_resource()` is used --- bevy_lint/src/lib.rs | 1 + bevy_lint/src/lints/insert_event_resource.rs | 39 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index c8c0044..fde970f 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -11,6 +11,7 @@ extern crate rustc_hir; extern crate rustc_hir_analysis; extern crate rustc_interface; extern crate rustc_lint; +extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 001455c..f62f1e3 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -7,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Ty, TyKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use std::borrow::Cow; @@ -61,18 +62,47 @@ fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_spa // If `arg` is `Events`, emit the lint. if match_type(cx, ty, &crate::paths::EVENTS) { + let mut applicability = Applicability::MachineApplicable; + + let event_ty_snippet = extract_ty_event_snippet(ty, &mut applicability); + span_lint_and_sugg( cx, INSERT_EVENT_RESOURCE, method_span, "called `App::insert_resource(Events)` instead of `App::add_event::()`", "inserting an `Events` resource does not fully setup that event", - format!("init_resource::()"), - Applicability::HasPlaceholders, + format!("add_event::<{event_ty_snippet}>()"), + applicability, ); } } +fn extract_ty_event_snippet<'tcx>( + events_ty: Ty<'tcx>, + applicability: &mut Applicability, +) -> Cow<'tcx, str> { + const DEFAULT: Cow = Cow::Borrowed("T"); + + let TyKind::Adt(_, events_arguments) = events_ty.kind() else { + if let Applicability::MachineApplicable = applicability { + *applicability = Applicability::HasPlaceholders; + } + + return DEFAULT; + }; + + let Some(event_snippet) = events_arguments.iter().next() else { + if let Applicability::MachineApplicable = applicability { + *applicability = Applicability::HasPlaceholders; + } + + return DEFAULT; + }; + + format!("{event_snippet:?}").into() +} + /// Checks if `App::init_resource()` inserts an `Events`, and emits a diagnostic if so. fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, method_span: Span) { if let Some(&GenericArgs { @@ -91,7 +121,8 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m if match_type(cx, resource_ty, &crate::paths::EVENTS) { let mut applicability = Applicability::MachineApplicable; - let event_ty_snippet = extract_event_snippet(cx, resource_hir_ty, &mut applicability); + let event_ty_snippet = + extract_hir_event_snippet(cx, resource_hir_ty, &mut applicability); span_lint_and_sugg( cx, @@ -112,7 +143,7 @@ fn check_init_resource<'tcx>(cx: &LateContext<'tcx>, path: &PathSegment<'tcx>, m /// Note that this works on a best-effort basis, and will return `"T"` if the type cannot be /// extracted. If so, it will mutate the passed applicability to [`Applicability::HasPlaceholders`], /// similar to [`snippet_with_applicability()`]. -fn extract_event_snippet<'tcx>( +fn extract_hir_event_snippet<'tcx>( cx: &LateContext<'tcx>, events_hir_ty: &rustc_hir::Ty<'tcx>, applicability: &mut Applicability, From fdddec3e7c12c5d9cb2d00989f5ef90811ea4aea Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:07:35 -0400 Subject: [PATCH 32/36] chore: some final documentation --- bevy_lint/src/lints/insert_event_resource.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index f62f1e3..973a36c 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -78,6 +78,10 @@ fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_spa } } +/// Creates a string representation of type `T` for [`Ty`] `Events`. +/// +/// This takes a mutable applicability reference, and will set it to +/// [`Applicability::HasPlaceholders`] if the type cannot be stringified. fn extract_ty_event_snippet<'tcx>( events_ty: Ty<'tcx>, applicability: &mut Applicability, From 3b03ac7a9d033b4839ea7f4dc850aa88969e7a77 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:40:16 -0400 Subject: [PATCH 33/36] feat: write documentation --- bevy_lint/src/lints/insert_event_resource.rs | 32 +++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 973a36c..10bbd81 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -1,4 +1,34 @@ -//! TODO +//! Checks for the `Events` resource being manually inserted through `App::init_resource()` or +//! `App::insert_resource()` instead of with `App::add_event()`. +//! +//! # Why is this bad? +//! +//! While `Events` is technically a `Resource`, you cannot register an event by _just_ inserting +//! it into the `App`. There are other steps necessary as well, which are usually orchestrated by +//! `EventRegistry::register_event()`. Instead of inserting the `Events` resource manually, call +//! `App::add_event()`, which will handle this all for you and result in desired behavior. +//! +//! # Example +//! +//! ```rust +//! # use bevy::prelude::*; +//! # +//! #[derive(Event)] +//! struct MyEvent; +//! +//! App::new().init_resource::>().run(); +//! ``` +//! +//! Use instead: +//! +//! ```rust +//! # use bevy::prelude::*; +//! # +//! #[derive(Event)] +//! struct MyEvent; +//! +//! App::new().add_event::().run(); +//! ``` use clippy_utils::{ diagnostics::span_lint_and_sugg, source::snippet_with_applicability, sym, ty::match_type, From 28aba235202b48e10ceca23d0356b55b1d881f07 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:33:05 -0400 Subject: [PATCH 34/36] feat: improve documentation on why this lint exists Co-authored-by: Christopher Biscardi --- bevy_lint/src/lints/insert_event_resource.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 10bbd81..c4a8811 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -3,10 +3,15 @@ //! //! # Why is this bad? //! -//! While `Events` is technically a `Resource`, you cannot register an event by _just_ inserting -//! it into the `App`. There are other steps necessary as well, which are usually orchestrated by -//! `EventRegistry::register_event()`. Instead of inserting the `Events` resource manually, call -//! `App::add_event()`, which will handle this all for you and result in desired behavior. +//! Unless you have intentionally and knowingly initialized the `Events` resource in this way, +//! events and their resources should be initialized with `App::add_event()` because it +//! automatically handles dropping old events. Just adding `Events` makes no such guarantee, and +//! will likely result in a memory leak. +//! +//! For more information, please see the documentation on [`App::add_event()`] and [`Events`]. +//! +//! [`Events`]: https://dev-docs.bevyengine.org/bevy/ecs/event/struct.Events.html +//! [`App::add_event()`]: https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.add_event //! //! # Example //! From 5cd697c7a505bf1a9fb057875dc21c0cb7b1cdea Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:36:23 -0400 Subject: [PATCH 35/36] chore: remove lifetime that can be elided --- bevy_lint/src/lints/insert_event_resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index c4a8811..876dc52 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for InsertEventResource { } /// Checks if `App::insert_resource()` inserts an `Events`, and emits a diagnostic if so. -fn check_insert_resource<'tcx>(cx: &LateContext<'tcx>, args: &[Expr], method_span: Span) { +fn check_insert_resource(cx: &LateContext<'_>, args: &[Expr], method_span: Span) { // Extract the argument if there is only 1 (which there should be!), else exit. let [arg] = args else { return; From 2aa5b2b1e52ea9f55254a5cad194d7cc6defa758 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:13:54 -0400 Subject: [PATCH 36/36] chore: replace "Why is this bad?" with "Motivation" --- bevy_lint/src/lints/insert_event_resource.rs | 2 +- bevy_lint/src/lints/main_return_without_appexit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 876dc52..0873e59 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -1,7 +1,7 @@ //! Checks for the `Events` resource being manually inserted through `App::init_resource()` or //! `App::insert_resource()` instead of with `App::add_event()`. //! -//! # Why is this bad? +//! # Motivation //! //! Unless you have intentionally and knowingly initialized the `Events` resource in this way, //! events and their resources should be initialized with `App::add_event()` because it diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index b335b79..d4da3d0 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -3,7 +3,7 @@ //! This lint will not be emitted if `fn main()` returns a non-[`unit`] type, even if that type is //! not `AppExit`. //! -//! # Why is this bad? +//! # Motivation //! //! `AppExit` is used to determine whether the `App` exited successful or due to an error. Returning //! it from `main()` will set the exit code, which allows external processes to detect whether there