move-variable-outside-iteration
- Group
- Performance
- Path
lint/performance/move-variable-outside-iteration- Default
- Off, opt in
- Origin
- Falcon
- Rule
- 272 of 512
Reports loop-local final variables whose computation is independent of the loop.
Moving a repeated computation before the loop avoids doing the same work on
every iteration. This conservative rule checks direct loop-body declarations:
non-throwing SDK numeric addition, subtraction and multiplication, and the
SDK List.reversed view of a final local list literal. Dependencies must be
final locals declared before the loop, never reassigned, and used with their
declaration-time type rather than a loop-local promotion. Numeric expressions
must depend on a local, not consist entirely of literals. List sources and
reversed views may only be iterated or have read-only properties inspected;
aliases, escaping identities, mutations and closure captures are excluded.
Calls, constructors, fresh collection literals, user-defined operators and
getters, late declarations and conditional declarations are not candidates.
Invalid
void reversedView() {
final list = [1, 2, 3];
for (final element in list) {
final reversed = list.reversed;
for (final value in reversed) {
print(value + element);
}
}
}
void addition() {
final width = 10;
for (var i = 0; i < 3; i++) {
final padded = width + 2;
print(padded + i);
}
}
void multiplication() {
final scale = 2.5;
var remaining = 3;
while (remaining-- > 0) {
final doubled = scale * 2;
print(doubled);
}
}
void subtraction() {
final maximum = 100;
var remaining = 3;
do {
final limit = maximum - 1;
print(limit);
} while (remaining-- > 0);
}
void compound() {
final width = 10;
final height = 20;
for (final value in [1, 2]) {
final area = (width + 2) * (height - 1);
print(area + value);
}
}
void nested() {
for (final value in [1, 2]) {
final size = value + 1;
for (var i = 0; i < 3; i++) {
final doubled = size * 2;
print(doubled + i);
}
}
} for (final element in list) { final reversed = list.reversed; for (var i = 0; i < 3; i++) { final padded = width + 2; while (remaining-- > 0) { final doubled = scale * 2; do { final limit = maximum - 1; for (final value in [1, 2]) { final area = (width + 2) * (height - 1); for (var i = 0; i < 3; i++) { final doubled = size * 2;Valid
void loopBound() {
for (final element in [1, 2, 3]) {
final doubled = element * 2;
print(doubled);
}
}
void mutableBinding() {
var width = 10;
for (var i = 0; i < 3; i++) {
final padded = width + 2;
print(padded);
width++;
}
}
void unwrittenMutableBinding() {
var width = 10;
for (var i = 0; i < 3; i++) {
final padded = width + 2;
print(padded);
}
}
void mutableResult() {
final width = 10;
for (var i = 0; i < 3; i++) {
var padded = width + 2;
print(padded++);
}
}
void mutatedSource() {
final list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
list.add(i);
}
}
void mutatedLength() {
final list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
list.length--;
}
}
void escapingSource() {
final list = [1, 2, 3];
final alias = list;
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
alias.add(i);
}
}
void escapingView(List<Iterable<int>> results) {
final list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
results.add(reversed);
}
}
void freshIdentity(List<List<int>> results) {
for (var i = 0; i < 3; i++) {
final list = <int>[];
results.add(list);
}
}
void sideEffects(int Function() next) {
for (var i = 0; i < 3; i++) {
final value = next();
print(value);
}
}
void closures(List<int Function()> callbacks) {
final width = 10;
for (var i = 0; i < 3; i++) {
final callback = () => width + i;
callbacks.add(callback);
}
}
void capturedSource(List<void Function()> callbacks) {
final list = [1, 2, 3];
callbacks.add(() => list.add(4));
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
}
}
void unknownCollection(List<int> list) {
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
}
}
void possibleThrow() {
final numerator = 10;
final denominator = 0;
for (var i = 0; i < 3; i++) {
final quotient = numerator ~/ denominator;
print(quotient);
}
}
void conditionalDeclaration(bool enabled) {
final width = 10;
for (var i = 0; i < 3; i++) {
if (enabled) {
final padded = width + 2;
print(padded);
}
}
}
class Custom {
Custom operator +(Custom other) => Custom();
Iterable<int> get reversed => [DateTime.now().microsecond];
}
void customOperations() {
final value = Custom();
for (var i = 0; i < 3; i++) {
final sum = value + value;
final reversed = value.reversed;
print(sum);
print(reversed.length);
}
}
void alreadyHoisted() {
final list = [1, 2, 3];
final reversed = list.reversed;
for (final element in list) {
print(reversed.length + element);
}
}
void promotedNullable(int? input) {
final width = input;
for (var i = 0; i < 3; i++) {
if (width == null) continue;
final padded = width + 1;
print(padded);
}
}
void promotedCollection() {
final Object list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
if (list is! List<int>) continue;
final reversed = list.reversed;
print(reversed.length);
}
}
void literalArithmetic() {
for (var i = 0; i < 3; i++) {
final value = (2 + 3) * 4;
print(value);
}
}
void indexMutation() {
final list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
list[0] = i;
}
}
void passingSource(void Function(List<int>) mutate) {
final list = [1, 2, 3];
for (var i = 0; i < 3; i++) {
final reversed = list.reversed;
print(reversed.length);
mutate(list);
}
}Configure move-variable-outside-iteration
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"performance": {
"move-variable-outside-iteration": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/performance/move-variable-outside-iteration: <reason>More performance rules
- noop-primitive-operations
noop_primitive_operationsrecommendedFlags primitive operations that return their receiver unchanged.
- prefer-const-border-radius
prefer-const-border-radiusrecommendedflutterFlags
BorderRadius.only(...)whose four corner radii are all equal. - prefer-contains
prefer_containsrecommendedPrefers
containsto comparing the result ofindexOfwith a constant. - prefer-correct-edge-insets-constructor
prefer-correct-edge-insets-constructorrecommendedflutterFlags an
EdgeInsets.only(...)that a more specific constructor expresses better. - prefer-declaring-const-constructor
prefer_declaring_const_constructorflutterFlags a generative constructor that is legally eligible to be
const. - prefer-foreach
prefer_foreachPrefers
forEachto afor-in loop that only passes each element to a function. - prefer-return-await
Await returned SDK Futures inside a try body protected by a catch clause.
- prefer-single-setstateflutter
Merge consecutive Flutter State.setState statements in the same block.