avoid_nested_shorthands
v1.0.0 Warning Shorthand Patterns
This rule flags a dot shorthand that sits inside the arguments of another dot shorthand invocation.
Why use this rule
Section titled “Why use this rule”A shorthand drops the type name on the promise that context makes it obvious. That holds for the outermost one — its type comes from the variable or parameter right next to it. It breaks for the inner ones: their types come from the outer constructor’s signature, which is not on the screen, so the reader has to go look up each parameter’s declared type to find out what is being built.
The report lands on the nested shorthand, not the outer one, so the fix stays local: name the inner type and the outer shorthand keeps its brevity.
See also: Dart language — dot shorthands
class Duration_ { const Duration_(this.seconds);
final int seconds;
static const Duration_ instant = Duration_(0);}
class Animation { const Animation({required this.duration});
final Duration_ duration;}
class Transition { const Transition(this.animation);}
void build() { // Nothing here names a type — the reader cannot tell what is being built. final Transition fade = .new(.new(duration: .new(300))); // LINT x2
final Transition instant = .new(.new(duration: .instant)); // LINT x2}Name the inner types; the outer shorthand still drops Transition:
void build() { final Transition fade = .new(Animation(duration: Duration_(300)));
final Transition instant = .new(Animation(duration: Duration_.instant));}Naming the outer type instead works just as well, as long as only one level of shorthand remains:
void build() { final fade = Transition(.new(duration: Duration_(300)));}What is and is not “nested”
Section titled “What is and is not “nested””Siblings are fine
Section titled “Siblings are fine”Two shorthands in the same statement, neither inside the other, are not reported:
void build() { final Duration_ quick = .instant; final Animation slide = .new(duration: Duration_(300));}A shorthand as the only argument of an explicit call is fine
Section titled “A shorthand as the only argument of an explicit call is fine”// Not reported — `Animation(...)` names the outer typevoid build() { final slide = Animation(duration: .instant);}Depth does not save it
Section titled “Depth does not save it”The search is deep, so a shorthand buried inside a sub-expression of the outer shorthand’s arguments still counts, even when its direct parent names a type:
// Reported: `.instant` is inside the outer `.new(...)` argument listvoid build() { final Transition fade = .new(Animation(duration: .instant));}
// Dovoid build() { final Transition fade = .new(Animation(duration: Duration_.instant));}Known limitations
Section titled “Known limitations”All three shorthand forms count, as either the outer or the inner node where the syntax allows: constructor invocations (.new(...)), static method invocations (.make(...)), and property accesses (.zero). A property access has no argument list, so it can only ever be the nested one.
Closures are not a boundary. A shorthand inside a callback passed as an argument still resolves against the enclosing invocation’s parameter type, so it reads just as poorly and is reported.
Configuration
Section titled “Configuration”This rule appears only in the pedantic preset, because compact nested
shorthands are a readability choice on which coherent codebases disagree.
rules: avoid_nested_shorthands: trueTo turn it off again:
rules: avoid_nested_shorthands: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”prefer_returning_shorthands— Use dot shorthand constructors in expression function return values.prefer_shorthands_with_constructors— Use dot shorthand constructors for common Flutter classes.prefer_shorthands_with_enums— Use dot shorthands instead of explicit enum prefixes.prefer_shorthands_with_static_fields— Use dot shorthands instead of explicit class prefixes for static fields.