diff --git a/content/docs/analyzers/LinterCop/LC0100.md b/content/docs/analyzers/LinterCop/LC0100.md new file mode 100644 index 0000000..7fd985c --- /dev/null +++ b/content/docs/analyzers/LinterCop/LC0100.md @@ -0,0 +1,64 @@ ++++ +title = 'Global variable could be local' +linkTitle = 'LC0100' + +[params] + id = 'LC0100' + severity = 'Hidden' + category = 'Design' + codeAction = false + ignoreObsolete = true ++++ + +An AL global variable lives as long as its object instance and is visible to every procedure in that object. When only one procedure uses it and replaces its value before every read, that lifetime and visibility serve no purpose. A later edit can otherwise turn an isolated calculation into shared state without changing the declaration. + +Declare the variable inside the procedure so its lifetime and visibility match its actual use. + +### Example + +{{< highlight al "hl_lines=2" >}} +var + MyGlobalVariable: Integer; // Global variable 'MyGlobalVariable' (Integer) is only used in 'ShowValue' and appears to be reinitialized before every read. Consider moving it to local scope. [LC0100] + +local procedure ShowValue() +begin + MyGlobalVariable := 1; + Message('%1', MyGlobalVariable); +end; +{{< /highlight >}} + +Move the declaration into the procedure: + +{{< highlight al "hl_lines=3" >}} +local procedure ShowValue() +var + MyLocalVariable: Integer; +begin + MyLocalVariable := 1; + Message('%1', MyLocalVariable); +end; +{{< /highlight >}} + +### When the diagnostic is reported + +- The global variable is declared in a normal codeunit. +- Every reference binds to the same global variable and occurs in one procedure or trigger. +- Every reachable read is preceded by an unconditional assignment, `Clear`, or equivalent initialization on that path. +- A normal record field is read after a successful `Record.Get(...)` with key arguments or a whole-record assignment. +- The variable is a value-semantic scalar, label, or normal non-temporary record. + +The analysis follows branches and guards. A variable initialized in both sides of an `if` statement qualifies; a variable initialized in only one side does not. + +For immutable labels, the message omits the reinitialization wording: `Global variable 'MyLabel' (Label) is only used in 'ShowMessage'. Consider moving it to local scope.` + +### Exception + +LC0100 deliberately stays silent when object state can affect behavior. This includes variables outside normal codeunits, variables passed through a `var` parameter, recursive paths that read state retained by an inner call, temporary records, handle-like types such as `List`, `SingleInstance` or manual-subscriber codeunits, non-normal codeunit subtypes, `ClearAll()`, integration/business/internal event publishers that expose the sender, integration events that expose global variables, collectible errors, and record operations whose retained view or company context is not fully modeled. + +Any non-modeled invocation between initialization and a later read also suppresses the diagnostic. Called code and callback-capable built-ins may reenter the same codeunit instance, so the analysis requires a fresh initialization after such a call. + +The rule is disabled by default. Enable it in a ruleset when the project is ready to review localization suggestions. + +### See also + +- [Discussion #499: Detect global variables which can be moved to a local scope](https://github.com/ALCops/Analyzers/discussions/499) diff --git a/content/docs/analyzers/LinterCop/_index.md b/content/docs/analyzers/LinterCop/_index.md index fedab73..d9f2faf 100644 --- a/content/docs/analyzers/LinterCop/_index.md +++ b/content/docs/analyzers/LinterCop/_index.md @@ -42,3 +42,4 @@ The LinterCop is a code linter for AL, comparable to widely used static analysis | [LC0097](lc0097/) | Avoid mixing exit() and named return variable assignments | Info | — | | | [LC0098](lc0098/) | Event subscriber name does not match the configured template | Info | ✓ | ✓ | | [LC0099](lc0099/) | Event subscriber parameter is not referenced | Info | ✓ | ✓ | +| [LC0100](lc0100/) | Global variable could be local | Hidden | | |