feat(FC0007): Statement blocks should be separated by a blank line (opt-in) - #424
Conversation
- Replace WellKnownFixAllProviders.BatchFixer with a custom FixAllProvider.Create(FixAllAsync) that removes all matching ParameterSyntax nodes in one root.RemoveNodes pass. BatchFixer's ReplaceNode(parameterList, …) merge dropped all but one edit when multiple parameters in the same signature were flagged. - Split registration into three CodeActions with distinct EquivalenceKeys (.All, .RegularProcedure, .EventSubscriber). FixAllAsync reads CodeActionEquivalenceKey to scope the batch; single-fix path uses RemoveNode(KeepNoTrivia) so trivia handling matches FixAll. - Guard fixAllSpans with !IsDefaultOrEmpty and fall back to GetDocumentDiagnosticsAsync — the AL SDK reports HasValue=true with an empty array under document-scope FixAll. - Add multiline HasFix fixture and three HasFixAll fixtures (single-method dual removal, multi-method, event subscriber). All 25 ParameterNotReferenced tests pass. - Update codefix-development, testing, and LC0095 instruction files: document the custom FixAllProvider exception, the HasFixAll test pattern, new design decisions, and known-issues entry.
…ne" (opt-in) Introduce FC0007, a disabled-by-default formatting rule that enforces blank-line separation around multi-line control-flow blocks (if, case, repeat, while, for, foreach), before scope-leaving statements (exit, built-in Error), and optionally before the else keyword of if/end-else constructs. Configurable via alcops.json under a new StatementBlockSpacing object with five properties: ControlFlowBefore, ControlFlowAfter, ScopeLeavingMode, ElseChainBeforeMode, and OneLinerMode. Three are real C# enums serialized as case-insensitive strings via JsonStringEnumConverter (net8+) and StringEnumConverter (netstandard2.1). Also: - Colocate the new settings type in Settings/StatementBlockSpacingSettings.cs - Harden ALCopsSettingsProvider: malformed alcops.json now silently falls back to defaults (JsonException swallowed in DeserializeSettings) - Add reusable schema-parity guard test template (StatementBlockSpacingSchema) against alcops.schema.json - 21 tests (18 rule + 3 schema-parity), all green No CodeFix. Additional spacing axes are captured on the FC0007 Roadmap.
- Detach StatementBlocksSeparatedByBlankLine from the exception-harness bridge back to plain DiagnosticAnalyzer. Matches the current policy in analyzer-exception-harness.instructions.md — no production analyzer adopts the harness until issue ALCops#389 (AL1003 loader bug) is resolved. - Unify test class on a single [Test]+[TestCase] pattern: two parametrized methods (HasDiagnostic / NoDiagnostic) driven by a named settings dictionary. Drop the fixtureKind parameter — LoadFixtureAsync resolves the folder from the (globally unique) fixture name, removing the "HasDiagnostic" string leaking into NoDiagnostic test cases. - Make StatementBlockSpacingSchema inherit NavCodeAnalysisBase per testing convention (mirrors NamingPatternSettings). - Sync common-library.instructions.md with reality: remove documentation for the removed GetSettings(string?) legacy overload and non-existent ClearCache() method. - Drop a stray blank line in FormattingCop DiagnosticDescriptors.
Collection expressions on ImmutableArray<T> require the CollectionBuilder attribute, which is only present in System.Collections.Immutable v6+ (net8+). The netstandard2.1 target pulls v5.0.0 and therefore fails with CS9210. Replace `[]` and `[.. src]` in GetSiblingStatements with ImmutableArray<T>.Empty and .ToImmutableArray() respectively. Local build (net8 only) missed this; CI covers all three TFMs.
Code Review: FC0007 + bundled LC0095 rewriteReviewed against 🔴 High —
|
|
Back from the holidays! If I can somehow can assist on the PR, please let me know 🙋 |
feat(FC0007): Statement blocks should be separated by a blank line (opt-in)
Adds FC0007 — Statement blocks should be separated by a blank line to
ALCops.FormattingCop. Opt-in (disabled by default) and fully configurable viaalcops.json. Closes #.What it flags
if,case,repeat,while,for,foreach) without a blank line before them and/or after their terminatingend;.exit,exit(<expr>), and built-inError(...)calls that are not preceded by a blank line.
end elsetransition inif … end else … endchains.Single-line (one-liner) control-flow statements are ignored unless
OneLinerModeis set toAll.Configuration surface
New object in
alcops.json:ControlFlowBeforebooltrueControlFlowAfterbooltrueScopeLeavingModeOff/ExitOnly/ErrorOnly/ExitAndErrorExitAndErrorElseChainBeforeModeOff/RequireBlankOffOneLinerModeOff/AllOffEnums are real C# types (
ALCops.Common.Settings.{Scope,ElseChainBefore,OneLiner}Mode),serialized case-insensitively via
JsonStringEnumConverteronnet8+andStringEnumConverteronnetstandard2.1. Both converter registrations wereadded to
ALCopsSettingsProvider.Provider hardening (small, but notable)
ALCopsSettingsProvider.DeserializeSettingsnow swallowsJsonExceptionandreturns defaults. Users with a broken
alcops.json(e.g. an unknown enumvalue) previously would have crashed the analyzer callback and produced an
AD0001; now the rule simply behaves as if no config file existed. A dedicatedtest guards this behavior with a fixture containing
"ScopeLeavingMode":"NotAnEnumValue".Schema parity guard
Settings/alcops.schema.jsonmirrors the three FC0007 enums. Any drift iscaught by
StatementBlockSpacingSchema.cs, a NUnit test template that reflectsover the C# enum values and compares them against the
enumarrays in theschema JSON. Reusable pattern for future enum-typed settings.
Test coverage
one-liner / disabled-by-default / malformed-config regression).
Tests follow a single
[Test] + [TestCase]pattern across two parametrizedmethods (
HasDiagnostic/NoDiagnostic) driven by a named settingsdictionary. The fixture folder (
HasDiagnostic/vsNoDiagnostic/) isresolved implicitly by
LoadFixtureAsync— test signatures stay free ofstorage-layout details.
Docs
.github/instructions/fc0007-statement-blocks-separated-by-blank-line.instructions.mdwith design decisions, test summary counts, known issues, and a Phase-2
roadmap (
CaseBranchMode,GuardClauseMode,LoopControlBeforeMode,TreatCommentOnlyLinesAsSeparator,SkipDirectiveBoundaries).common-library.instructions.mdupdated for the newStatementBlockSpacingsetting and the "add a new setting" enum-converter walkthrough.
alcops.dev
at
content/docs/analyzers/formattingcop/fc0007.md.Not in this PR (roadmap)
Implements #423