prefer-const-constructors-in-immutables
Same as prefer_const_constructors_in_immutables in Dart lints
- Group
- Style
- Path
lint/style/prefer-const-constructors-in-immutables- Default
- Off, opt in
- Origin
- Dart lints
- Domain
- flutter
- Rule
- 328 of 512
Prefers const constructors in immutable classes and extension types.
Classes and mixin classes are checked only when they have no with clause;
mixin declarations and classes applying mixins are skipped. The declaration
must be annotated @immutable or inherit it through extends only, not
through implements or applied mixins. Extension types are also checked
when annotated @immutable.
A non-const, non-primary constructor whose body is ; is reported when:
- it is a redirecting factory to a
constconstructor; or - it is generative, delegates to a
constconstructor, has no non-final instance fields on its superclass/mixin chain, and every field initializer, initializer-list expression, assert, andsuper/thisargument is potentially constant.
Delegation follows an explicit super or this call, otherwise the
superclass's unnamed constructor (or an extension type's representation
constructor). Implicit default constructors are not const.
Ordinary constructor diagnostics cover their first token after metadata.
Analyzer 3.13 class and mixin-class primary constructors use the same body,
delegation and field-finality checks, but do not reject nonconstant
initializer expressions. Immutable extension-type primary constructors need
only lack const and a block or expression body; even an empty block
disqualifies them, but delegation and field finality are not checked.
Invalid
// @dart = 3.13
import 'package:meta/meta.dart';
class ConstValue {
const ConstValue.named();
}
@immutable
class ConstFieldInitializer {
final ConstValue value = const ConstValue.named();
ConstFieldInitializer();
}
@immutable
class LaxOperands {
final Object value;
LaxOperands(Object a, Object b, List<int> l) : value = (a == b, '$a', l.length, a is int, int);
external LaxOperands.external();
}
@immutable
class Value {
final int value;
Value(this.value);
}
@immutable
abstract class ImmutableBase {
const ImmutableBase.named();
}
class Inherited extends ImmutableBase {
final int value;
Inherited(this.value) : super.named();
}
@immutable
class Redirecting {
final int value;
const Redirecting.target(this.value);
Redirecting(int value) : this.target(value);
}
@immutable
abstract class Interface {
factory Interface() = Implementation;
}
class Implementation implements Interface {
const Implementation();
}
@immutable
class Primary() {}
@immutable
class PrimaryField(final int value) {}
@immutable
class NamedPrimary<T>.named(final T value) {}
@immutable
abstract class WidgetBase {
const WidgetBase({Object? key});
}
abstract class PrimaryWidget({super.key}) extends WidgetBase {}
abstract class PrimaryWidgetWithoutKey() extends WidgetBase {}
abstract class PrimaryWidgetBody() extends WidgetBase {
@deprecated
this;
}
@immutable
class PrimaryInitializer(int value) {
final int field;
this : field = value, assert(value >= 0);
}
class PrimaryNamedSuper(final int value) extends ImmutableBase {
this : super.named();
}
@immutable
extension type Representation(List<int> value) {}
@immutable
extension type NamedRepresentation<T>.named(T value) {}
@immutable
class PrimaryRuntimeInitializer() {
final DateTime value;
this : value = DateTime.now();
}
@immutable
class PrimaryRuntimeFieldInitializer() {
final DateTime value = DateTime.now();
}
@immutable
mixin class PrimaryMixin() {}
@immutable
extension type const ConstPrimaryOrdinary(int value) {
ConstPrimaryOrdinary.other(this.value);
}
@immutable
extension type NonConstPrimaryOrdinary(int value) {
NonConstPrimaryOrdinary.other(this.value);
}
@immutable
extension type EmptyRepresentationBody(int value) {
this;
}
@immutable
class TearoffInitializer {
final Object callback;
TearoffInitializer() : callback = TearoffInitializer.target;
const TearoffInitializer.target() : callback = 0;
factory TearoffInitializer.redirect() = TearoffInitializer.target;
}
@Immutable()
class AnnotationConstructor {
AnnotationConstructor();
}
@immutable
extension type const ConstRepresentation(int value) {
ConstRepresentation.named(this.value);
}
@immutable
extension type RuntimeRepresentation(int value) {} final ConstValue value = const ConstValue.named(); ConstFieldInitializer(); final Object value; LaxOperands(Object a, Object b, List<int> l) : value = (a == b, '$a', l.length, a is int, int); LaxOperands(Object a, Object b, List<int> l) : value = (a == b, '$a', l.length, a is int, int); external LaxOperands.external(); final int value; Value(this.value); final int value; Inherited(this.value) : super.named(); const Redirecting.target(this.value); Redirecting(int value) : this.target(value);abstract class Interface { factory Interface() = Implementation;@immutableclass Primary() {}@immutableclass PrimaryField(final int value) {}@immutableclass NamedPrimary<T>.named(final T value) {} abstract class PrimaryWidget({super.key}) extends WidgetBase {} abstract class PrimaryWidgetWithoutKey() extends WidgetBase {} abstract class PrimaryWidgetBody() extends WidgetBase {@immutableclass PrimaryInitializer(int value) { class PrimaryNamedSuper(final int value) extends ImmutableBase {@immutableextension type Representation(List<int> value) {}@immutableextension type NamedRepresentation<T>.named(T value) {}@immutableclass PrimaryRuntimeInitializer() {@immutableclass PrimaryRuntimeFieldInitializer() {@immutablemixin class PrimaryMixin() {}extension type const ConstPrimaryOrdinary(int value) { ConstPrimaryOrdinary.other(this.value);@immutableextension type NonConstPrimaryOrdinary(int value) {@immutableextension type EmptyRepresentationBody(int value) { final Object callback; TearoffInitializer() : callback = TearoffInitializer.target; const TearoffInitializer.target() : callback = 0; factory TearoffInitializer.redirect() = TearoffInitializer.target;class AnnotationConstructor { AnnotationConstructor();extension type const ConstRepresentation(int value) { ConstRepresentation.named(this.value);@immutableextension type RuntimeRepresentation(int value) {}Valid
// @dart = 3.13
import 'package:meta/meta.dart' as meta;
@meta.immutable
class Value {
final int value;
const Value(this.value);
}
@meta.immutable
abstract class NonConstBase {
final DateTime created;
NonConstBase() : created = DateTime.now();
}
class CannotInheritConst extends NonConstBase {
final int value;
CannotInheritConst(this.value);
}
@meta.immutable
class RuntimeInitializer {
final DateTime value;
RuntimeInitializer() : value = DateTime.now();
}
@meta.immutable
class RuntimeFieldInitializer {
final DateTime value = DateTime.now();
RuntimeFieldInitializer();
}
@meta.immutable
class ShadowedConstConstructor {
final Value value;
ShadowedConstConstructor(Value Function() Value) : value = Value();
}
@meta.immutable
class GenericCalleeShadow<ConstValue> {
final Object value;
GenericCalleeShadow() : value = ConstValue.named();
}
@meta.immutable
class MemberCalleeShadow {
static final ConstValue = () => const Value(0);
final Object value;
MemberCalleeShadow() : value = ConstValue();
}
@meta.immutable
class FactoryBody {
const FactoryBody._();
factory FactoryBody() => const FactoryBody._();
}
class ConstValue {
const ConstValue.named();
}
@meta.immutable
class CallShapedFieldInitializer {
final ConstValue value = ConstValue.named();
CallShapedFieldInitializer();
}
@meta.immutable
abstract class ImplicitConstructorBase {}
class ImplicitSuper extends ImplicitConstructorBase {
final int value;
ImplicitSuper(this.value);
}
@meta.immutable
class BlockBody {
final int value;
const BlockBody.named(this.value);
BlockBody(this.value) {}
}
@meta.immutable
class NonLengthProperty {
final bool value;
const NonLengthProperty.named(this.value);
NonLengthProperty(int x) : value = x.isEven;
NonLengthProperty.list(int x) : value = [x].isEmpty;
NonLengthProperty.bang(bool? x) : value = x!;
}
@meta.immutable
abstract class Marker {}
class InterfaceOnly implements Marker {
final int value;
InterfaceOnly(this.value);
}
@meta.immutable
class const ConstPrimary(final int value) {}
class UnannotatedPrimary(final int value) {}
@meta.immutable
class MutablePrimary(var int value) {}
@meta.immutable
class MutableBodyField() {
int value = 0;
}
@meta.immutable
class PrimaryBlock() {
this {}
}
@meta.immutable
abstract class AbstractPrimaryBlock() {
this {}
}
class PrimaryNonConstSuper(final int value) extends NonConstBase {}
class PrimaryImplicitSuper(final int value) extends ImplicitConstructorBase {}
class PrimaryInterfaceOnly(final int value) implements Marker {}
mixin EmptyMixin {}
@meta.immutable
class PrimaryWithMixin() with EmptyMixin {}
@meta.immutable
mixin class ImmutableMixin {}
class PrimaryMixinAnnotationOnly() with ImmutableMixin {}
@meta.immutable
extension type const ConstRepresentation(List<int> value) {}
extension type UnannotatedRepresentation(List<int> value) {}
@meta.immutable
extension type const NamedConstRepresentation<T>.named(T value) {}
@meta.immutable
mixin class const ConstPrimaryMixin() {}
mixin class UnannotatedPrimaryMixin() {}
@meta.immutable
extension type const ConstOrdinaryRepresentation(int value) {
const ConstOrdinaryRepresentation.other(this.value);
ConstOrdinaryRepresentation.block(this.value) {}
}
@meta.immutable
extension type BlockRepresentationBody(int value) {
this {}
BlockRepresentationBody.other(this.value);
}
@meta.immutable
class NonConstCollectionField {
final List<int> values = [];
final List<int> nonEmpty = [1];
final Set<int> emptySet = <int>{};
NonConstCollectionField();
}
@meta.immutable
class NonConstCollectionInitializers {
final Object value;
NonConstCollectionInitializers.list() : value = [1];
NonConstCollectionInitializers.map() : value = <int, int>{};
NonConstCollectionInitializers.set() : value = <int>{};
}Configure prefer-const-constructors-in-immutables
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"style": {
"prefer-const-constructors-in-immutables": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/style/prefer-const-constructors-in-immutables: <reason>More style rules
- prefer-const-declarations
prefer_const_declarationsrecommendedFlags
finaldeclarations whose initializers are all constant expressions. - 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.