S3L0002: Create, then return

An object built across many lines is created into a named variable first, then returned.

Category Snail
Severity warning — an error under TreatWarningsAsErrors, which every Snail project builds with
Analyzer ReturnShape in Snail.Sdk.Analyzers
Code fix Create '<name>', then return it

What it reports

An object built inside a return or yield return that spans more than 15 lines: new T { … }, a target-typed new(…) { … }, an anonymous new { … }, or a collection expression [ … ]. The message gives the length: This object spans 22 lines inside the return: assign it to a named variable first.

What it leaves alone

An expression-bodied member that only builds an object, Theme Theme() => new(…); — its name already names what it builds — and objects of 15 lines or fewer.

Why

The answer of a method hides behind its construction: the reader sees return new and twenty lines of initialisers before learning what comes back. A named variable, then return name;, shows it.

Measured across the fleet on 2026-10-12: an object built inside a return spans 7 lines at the median, and 7.5 % pass fifteen.

How to fix

// Holds
var settings = new Settings
{
    // … twenty lines …
};

return settings;

The code fix

Inside a block, the fix declares a variable before the return and returns it after a blank line. The variable is named after the type in camelCase (Point gives point), or result for an anonymous object or a collection expression, with 2, 3… added when the name is taken. It is declared with var when the expression names its type; for a collection expression or a target-typed new(…) with the type it converts to, written as briefly as the file's usings allow (IReadOnlyList<int> result = [ … ];). No fix is offered when that type cannot be written (an anonymous or unresolved type) or for an expression body. The fix keeps the document's line endings. Fix All is not offered.

Suppressing it

Fix the code rather than silence the rule: the rule is part of the standard every Snail repository keeps. Where one place truly must differ, suppress that place and say why:

[SuppressMessage("Snail", "S3L0002:Create, then return", Justification = "<why this place differs>")]

A NoWarn in a project or props file would hide the rule from every new line too; the conformance check reports one as migration debt (S3LC0017).