Skip to content

FC0007: roadmap - planned StatementBlockSpacing settings (CaseBranchMode, GuardClauseMode, LoopControlBeforeMode, comment and directive separators) #514

Description

@Arthurvdv

Deferred ideas for this rule, moved out of .claude/rules/diagnostics/fc0007-statement-blocks-separated-by-blank-line.md so the rule doc describes current state only. None of these is scheduled; names and defaults may change when an item is picked up.

Planned settings — none of these are implemented yet, and none has a scheduled milestone. Names, defaults, and value sets may change when a roadmap item is picked up. Track work here.

CaseBranchMode (planned, not implemented)

A future StatementBlockSpacing.CaseBranchMode setting to control blank-line separation between the individual branches of a case statement, orthogonal to ControlFlowBefore / ControlFlowAfter (which govern the whole case block relative to its siblings).

Scope:

  • Between case Value: label branches (single-statement form).
  • Between case Value: begin ... end; block branches.
  • Between the last branch and the else clause, and between else and end;.

Proposed values (final naming to be decided when implemented):

Value Behavior
Off Do not enforce blank lines between branches (current behavior).
BlocksOnly Require a blank line after each begin ... end; block branch, but not between label-only branches.
All Require a blank line after every branch, regardless of whether the branch uses a block.

Design questions to answer before implementation:

  • Where is the diagnostic located? On the following branch's case-value token, or on the missing-blank position?
  • Does it apply to one-line branches ("A": DoA();) or does OneLinerMode gate it?
  • Is the else clause treated as just another branch, or is it a separate axis?
  • Should adjacent label-only branches ("A":\n"B":\n DoAOrB();) be exempt because they share a statement?

Implementation notes: CaseStatementSyntax.CaseLines (SyntaxList<CaseLineSyntax>) exposes each branch; caseLine.Statement is BlockSyntax distinguishes block-form from single-statement form. Estimated effort ~2.5 h including tests, schema, docs.

GuardClauseMode (planned, not implemented)

A future StatementBlockSpacing.GuardClauseMode setting to define dedicated spacing for the widely-used guard clause early-exit pattern (if X then exit; / if X then Error(...); at the top of a method). Currently the direct branch is not analyzed as an independent scope-leaver; the containing if follows ControlFlowBefore / ControlFlowAfter and is excluded as a one-liner unless OneLinerMode = All.

Proposed values (final naming to be decided when implemented):

Value Behavior
Off No dedicated guard-clause handling; the containing if follows the regular control-flow settings (current behavior).
AllowStacked Consecutive guard clauses at the top of a method may be stacked without blank lines between them, but a blank line is required before the first non-guard statement below the guard block.
Isolated Every guard clause requires a blank line before AND after it, regardless of stacking.

Design questions to answer before implementation:

  • What counts as a guard clause? Reuse the IsGuardClause heuristic already in CognitiveComplexity.cs (LC0090) so definitions do not drift.
  • Is the "at the top of a method" positional requirement strict, or does any early-exit inside a loop also qualify?
  • Interaction with ScopeLeavingMode = Off: should GuardClauseMode still activate? Recommended answer: no — if the user disabled scope-leaver spacing globally, the guard exception is moot.

LoopControlBeforeMode (planned, not implemented)

A future StatementBlockSpacing.LoopControlBeforeMode setting for blank-line enforcement before loop-control statements — currently the analyzer only handles exit and built-in Error(...), but break, continue, and Skip (the report/xmlport equivalents) share the same "control-flow-leaving" semantics and benefit from the same visual separation.

Proposed values (final naming to be decided when implemented):

Value Behavior
Off Do not enforce (current behavior).
RequireBlank Require a blank line before break, continue, and Skip when they follow another statement in the same block.

Design questions to answer before implementation:

  • Does this share the Off short-circuit with ScopeLeavingMode, or is it fully independent? Recommendation: fully independent — teams may want blank before break but not before exit.
  • Is Skip (report/xmlport-only) covered under the same axis or its own? Recommendation: same axis for simplicity; add a separate mode only if user feedback demands it.
  • Reuse the existing sibling-lookup + blank-line helpers (GetSiblingStatements, HasBlankLineBetween) — no new infrastructure needed.

TreatCommentOnlyLinesAsSeparator (planned, not implemented)

A future StatementBlockSpacing.TreatCommentOnlyLinesAsSeparator boolean to decide whether comment-only lines between two statements satisfy the "blank line" requirement. Today only true empty lines count; a //---- section divider on its own line does not.

Proposed default: false (current behavior — only empty lines count). Setting to true opts in to the more lenient interpretation, where any non-empty line consisting solely of leading whitespace + a comment token counts as a separator.

Design questions to answer before implementation:

  • Which comment kinds count? Line comments (//), block comments (/* */), XML-doc comments (///)? Recommendation: all three, because visual effect is the same.
  • Is a multi-line block comment on a single line (/* foo */) a separator? Recommendation: yes.
  • What about comments on a statement line (trailing comment)? Recommendation: no — the statement line still counts as "a statement line", the comment is trivia on it.

Implementation notes: the current check walks SourceText.Lines strictly between the two token positions and returns true iff any is whitespace-only. To support this setting, additionally count lines whose sole non-whitespace content is a comment token as blank-equivalent. Estimated effort ~1 h including tests.

SkipDirectiveBoundaries (planned, not implemented)

A future StatementBlockSpacing.SkipDirectiveBoundaries boolean to suppress FC0007 diagnostics across compiler-directive boundaries (#region / #endregion, #pragma, etc.). Directives visually break the code but do not represent statements. Enforcing blank lines around them can conflict with team conventions that already collapse spacing at region boundaries.

Proposed default: false (current behavior — directive-only lines are non-blank, so spacing rules fire across them). Setting to true opts in to treating the boundary as a natural separator.

Design questions to answer before implementation:

  • Which directives count? #region / #endregion clearly; #pragma is less obviously a "visual break". Recommendation: #region / #endregion only, with a follow-up if #pragma demand emerges.
  • Does the setting suppress "before" checks, "after" checks, or both? Recommendation: both — a region boundary breaks the block conceptually in both directions.
  • Interaction with TreatCommentOnlyLinesAsSeparator: independent — one is about comments, the other about directives.

Implementation notes: requires walking leading/trailing trivia of the surrounding tokens for RegionDirectiveTrivia / EndRegionDirectiveTrivia. Estimated effort ~2.5 h including tests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions