prefer-const-declarations
Same as prefer_const_declarations in Dart lints
- Group
- Style
- Path
lint/style/prefer-const-declarations- Default
- On (recommended)
- Origin
- Dart lints
- Rule
- 329 of 512
Flags final declarations whose initializers are all constant expressions.
A final local variable, top-level variable, or static field initialized
with a constant expression can be declared const instead. Plain collection
literals and constructor calls without const are not constant expressions.
Instance fields and for-loop initializer declarations are never reported,
and every declarator must qualify.
Diagnostic spans include local metadata and documentation, and include late
but exclude static on fields. They end at the last declarator, before
trailing trivia and the semicolon.
Constant eligibility uses the shared lexical constant checker and evaluator,
including declaration-time local values, type parameters, deferred types,
and failed arithmetic, casts, or non-primitive equality. Analyzer's lint treats
generic type literals and constructor tear-offs as constants even with type
parameters or deferred type arguments. Abstract generative constructor
tear-offs have the same lint-only treatment. These parity quirks do not
guarantee that the suggested const declaration compiles.
Invalid
final o = const <int>[];
const base = 2;
final derived = base * 21;
final String greeting = 'hello', other = 'world';
final Map<String, int> lookup = const {'a': 1};
enum Color { red, green }
final favorite = Color.red;
class A {
static final o = const <int>[];
static const limit = 10;
static final doubled = limit * 2;
static final interpolated = 'n=${1 + 2}';
}
class Point {
const Point(this.x, this.y);
final int x;
final int y;
}
final origin = const Point(0, 0);
void locals() {
final a = 1;
final flag = !true && 3 > 2 ? null : -1;
const step = 5;
final next = step + 1;
final sym = #name;
final viaClass = A.limit;
print([a, flag, next, sym, viaClass]);
}
final tuple = const ("first", 2, true);
final implicitTuple = (number: 123, name: "Main");
void typeTests() {
const c = 1;
final typeTest = c is int;
final cast = c as num;
final interpolatesConstant = 'c=$c';
final length = 'abc'.length;
print([typeTest, cast, interpolatesConstant, length]);
}
void forBodies() {
for (final i = 0; i < 1;) {
final body = 1;
print(body);
break;
}
for (final callback = () {
final nested = 1;
return nested;
}; callback() > 0;) {
break;
}
}
int topLevelFunction() => 0;
class Factory {
const Factory.origin();
static int create() => 0;
static const prefix = 'p';
static final prefixed = prefix + 'q';
}
final functionTearOff = topLevelFunction;
final staticTearOff = Factory.create;
final typeLiteral = Factory;
final colors = Color.values;
final Factory dotShorthand = const .origin();
final equality = 1 == 2.0;
final coalesced = null ?? 'fallback';
final numericMix = 1 + 2.5 * base - 7 ~/ 2;
final bits = (1 << 3) & 0xff | (true ^ false ? 1 : 0);final o = const <int>[];const base = 2;final derived = base * 21; final String greeting = 'hello', other = 'world'; final Map<String, int> lookup = const {'a': 1}; final favorite = Color.red;class A { static final o = const <int>[]; static const limit = 10; static final doubled = limit * 2; static final interpolated = 'n=${1 + 2}'; final origin = const Point(0, 0);void locals() { final a = 1; final a = 1; final flag = !true && 3 > 2 ? null : -1; const step = 5; final next = step + 1; final next = step + 1; final sym = #name; final sym = #name; final viaClass = A.limit; final tuple = const ("first", 2, true);final tuple = const ("first", 2, true);final implicitTuple = (number: 123, name: "Main"); const c = 1; final typeTest = c is int; final typeTest = c is int; final cast = c as num; final cast = c as num; final interpolatesConstant = 'c=$c'; final interpolatesConstant = 'c=$c'; final length = 'abc'.length; for (final i = 0; i < 1;) { final body = 1; for (final callback = () { final nested = 1; static const prefix = 'p'; static final prefixed = prefix + 'q'; final functionTearOff = topLevelFunction;final functionTearOff = topLevelFunction;final staticTearOff = Factory.create;final staticTearOff = Factory.create;final typeLiteral = Factory;final typeLiteral = Factory;final colors = Color.values;final colors = Color.values;final Factory dotShorthand = const .origin();final Factory dotShorthand = const .origin();final equality = 1 == 2.0;final equality = 1 == 2.0;final coalesced = null ?? 'fallback';final coalesced = null ?? 'fallback';final numericMix = 1 + 2.5 * base - 7 ~/ 2;final numericMix = 1 + 2.5 * base - 7 ~/ 2;final bits = (1 << 3) & 0xff | (true ^ false ? 1 : 0);Valid
const o = <int>[];
// Non-const collection literals create fresh mutable values.
final list = <int>[];
final map = {'a': 1};
final set = {1, 2};
// Only every declarator being constant qualifies.
final one = 1, now = DateTime.now();
// Instance fields are out of scope.
class A {
static const o = <int>[];
final instance = 1;
static var mutable = 1;
static final computed = DateTime.now();
}
var counter = 0;
final fromVariable = counter;
// Implicit `new` is not constant even for const constructors.
class Point {
const Point(this.x, this.y);
final int x;
final int y;
}
final implicit = Point(0, 0);
// Unknown names cannot be proven constant.
final unknown = somewhereElse;
late final lazy = DateTime.now();
void locals(int parameter) {
const c = 1;
final fromParam = parameter;
final fromCall = c.toString();
final noInit;
noInit = 2;
final interpolatedVar = 'value $parameter';
print([fromParam, fromCall, noInit, interpolatedVar]);
}
const shadowed = 1;
void shadowing(int shadowed) {
// The parameter shadows the top-level constant.
final copy = shadowed;
print(copy);
}
void loops(List<int> values) {
for (final value in values) {
final copy = value;
print(copy);
}
}
// For-loop initializer declarations are not variable declaration statements.
void forInitializers() {
for (final int i = 0; i < 1;) {
print(i);
break;
}
for (final first = 0, second = 1; first < second;) {
break;
}
}
void divide() {
final bad = 1 ~/ 0;
print(bad);
}
final nonConstantTuple = (1, () {});
// Operators are constant only for the operand types the language allows.
const separatorWidth = 80;
final repeated = '-' * separatorWidth;
final repeatedLiteral = 'ab' * 2;
const numbers = [1, 2];
final joined = const [0] + numbers;
class Holder {
static const label = 'x';
static final labelTimesTwo = label * 2;
int instanceMethod() => 0;
}
final instanceTearOff = Holder().instanceMethod;Configure prefer-const-declarations
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"style": {
"prefer-const-declarations": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/style/prefer-const-declarations: <reason>More style rules
- prefer-const-literals-to-create-immutables
prefer_const_literals_to_create_immutablesPrefers
constlist, set, and map literals as arguments to constructors of@immutableclasses. - prefer-constrained-box-over-containerflutter
Prefers
ConstrainedBoxover aContainerused only forconstraints. - prefer-constructors-over-static-methods
prefer_constructors_over_static_methodsFlags static methods that create and return an instance of their own class.
- prefer-containerflutter
Suggests collapsing compatible nested layout widgets into one
Container. - prefer-correct-callback-field-name
Match callback field names to a configured regular expression.
- prefer-correct-error-name
Require configured error parameter names in catches and SDK error callbacks.
- prefer-correct-handler-name
Match callback handler methods to a configured regular expression.
- prefer-correct-identifier-length
prefer-correct-identifier-lengthFlags declared identifiers that are shorter or longer than the allowed range.