A Dart linter enforcing certain naming conventions when dealing with methods that mutate variables.
There are 4 lints included in this package:
- mut_infect
void callAMut() { /* Calling a `mut` method should mark the caller as `Mut` */ callBMut(); }
- mut_out_of_scope
void assignGlobalMut() { /* Assigning to a variable not owned by this scope should mark the caller as `Mut` */ globalVar = 3; }
- mut_param
void changeIncomingParamterValue(AnObject aoMut) { /* Changing the parameter's properties should mark the parameter as `Mut` */ aoMut.innerField = "hi"; }
- unnecessary_mut_infect
void funcDoesNotMut() { /* this function should not be marked with `Mut` */ }
Taken from custom_lint:
- The application must contain an
analysis_options.yaml
with the following
analyzer:
plugins:
- custom_lint
- The application also needs to add custom_lint and our package(s) as dev dependency in their application:
# The pubspec.yaml of an application using our lints
name: example_app
environment:
sdk: ">=2.16.0 <3.0.0"
dev_dependencies:
custom_lint:
lint_mut_infect:
If you want to disable certain lints, add the following to the analysis_options.yaml
file:
lint_mut_infect:
rules:
- unnecessary_mut_infect: false # disable this rule
All rules are enabled by default.
Produces: Warning
Enforces infectious naming conventions on Method and Function declarations.
Something that invokes a Mut
element should also be called Mut
.
This produces the following message: 'Mut' method invoked but not marked 'Mut'
The suggested fix is to rename the calling function:
function markThisDummyMut() {
dummyMut();
}
This way you can establish a chain of all functions that mutate variables.
This lint is not applied when the element is:
- Marked with
@override
- functions named
main
- A
setter
Produces: Warning
This lint checks that variables that are modified within a function are declared within that function, or are contained entirely within the lexical scope of the function in question. For instance:
In this example, globalScopeVar
is not declared within the outOfScopeModifier
function, but is modified anyway. This produces a warning that the function should be marked with Mut
.
This lint also understands locally defined functions, and won't cause undue warnings for strictly-local declarations:
In the above image, although i
is modified by inner()
, inner will not be marked as requiring Mut, because all declarations are local to the lexical scope of the top-level containing function.
This lint is not applied when the element is:
- Marked with
@override
- functions named
main
- A
setter
Produces: Error
This lint checks that any variable that is passed a parameter and is modified by the function is marked with Mut
.
This lint is stronger than the others because it is very important for a caller to know whether some object of theirs is going to be modified or not.
-
Parameters with Dart primitive types are exempt because they are passed-by-value. These include:
- bool
- int
- double
- num
- String
-
Simply reassigning the variable is exempt as well:
void reassignment(AnObject ao) { ao = AnObject(); }
Produces: Warning
This lint checks that any functions or methods named Mut
actually deserve to be marked. This lint can help keep refactors to your codebase from spiraling out of control with Muts everywhere.
Because this package isn't always aware of what constitutes mutating functionality or not, you should tell the the analyzer to ignore this lint when you need to.
For example:
// ignore: unnecessary_mut_infect
void reallyIsMut() {
someCallYouCantRenameButIsDefinitelyAMutatingCall();
}
Any function or method marked @override
, or any function named main
will not be flagged.
This means you wont be overloaded with warnings when dealing with names you don't control.
This package doesn't integrate with dart fix
, as we can't reliably get all symbol references for renaming. You are encouraged to use F2
rename functionality on your own to add or remove Mut
as appropriate.
#1
Some functions with inner scope Mut
calls mutating a variable owned entirely by the calling scope still require their parent scope to be marked as Mut
, even though they're mutating fully-owned local variables.
To debug,
follow the steps at https://pub.dev/packages/custom_lint
- Add
custom_lint
anddart_lint_infect_mut
to Dev Dependencies of target project - Run
custom_lint --watch
- [Optional] add the dart_lint repo to the Workspace and set breakpoints within
This plugin uses the custom_lint package. To help with the underlying functionality, consider helping out that repo. To contribute to this repo specifically, visit https://github.com/0xNF/dart_lint_mut_infect