Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unused Declaration Detection (#4377)
# Unused Declaration Detection Detection of unused program declarations with compiler warnings. Program example `example.mo`: ``` import Array "mo:base/Array"; import Debug "mo:base/Debug"; actor { var variable1 = 0; var variable2 = "TEST"; func testUnusedFunction(parameter1 : Bool, parameter2 : Int) { var variable2 = 2; var variable3 = 3; let variable4 = 4; if (variable1 == 0 and variable3 == 3) { let variable2 = parameter1; Debug.print(debug_show(variable2)); }; }; }; ``` Compiler messages: ``` example.mo:1.8-1.13: warning [M0194], Unused declaration Array example.mo:6.9-6.18: warning [M0194], Unused declaration variable2 example.mo:8.10-8.28: warning [M0194], Unused declaration testUnusedFunction example.mo:8.48-8.58: warning [M0194], Unused declaration parameter2 example.mo:9.13-9.22: warning [M0194], Unused declaration variable2 example.mo:11.13-11.22: warning [M0194], Unused declaration variable4 ``` ## Coverage The analysis detects the following unused declarations: * Variables * Parameters, including shared context * Functions * Classes * Objects * Modules * Imports * Private fields in objects and classes Special aspects: * System functions are considered implicitly used. * Non-accessed stable variables are considered unused, even if they could be accessed in a future upgraded program version. ## Warnings The warning of an unused declaration can be suppressed by prefixing the identifier by an underscore. Example: ``` object Silence { public func log(_message: Text) { // Suppress the warning for the unused `_message` parameter. } } ``` ## Tweaks from #4407 * don't warn about unused declarations in code from packages (assuming packaces are third party you can't silence them anyway): * annotate LibPath Ast nodes with source package, if any, as tracked and determined during import resolution. * predicate unused declaration warnings on package origin. * don't reject unused declarations in the repl treating top-level code as belonging to fake package "<top-level>" (a mild hack). The repl can't know the rest of the interaction so any warning is premature and a nuisance. * change terminology of declarations/variables to bindings/indentifiers (for consistency with rest of code) * add error-code description in M0194.md * add changelog entry. Future: we could suppress all warnings, not just unused declarations - from imported package code this way, should we want to. A --lint mode could re-enable them for further auditing. The rationale is that the warnings are of interest to and actionable on only by the author of the package, not the client. ## Future Work The following analyses are not yet implemented but would be beneficial to support: * Unused recursive function calls (direct or indirect recursion). * Unused type definitions, unused type parameters * Unused branch labels * Unused variant options * Unused public fields: Additional aspects to consider: - Accesses via paths outside the declaration scope. - Possible usage before declaration. - Polymorphism of structural typing. - A library module may expose more (directly or indirectly) public declarations than used. * Write-only mutable variables: Mutable variables that are never read but only written * Unnecessary mutability of read-only variables: Recommend `let` instead of `var`.
- Loading branch information