Repository navigation
Releases: bisforboman/stylebro
Release list
StyleBro 0.7.0-alpha.1
129 rules, each fixed by dotnet format. Docs: https://bisforboman.github.io/stylebro/
New
- Preset versions.
<StyleBroPreset>takes a version (1.0, later1.1, ...),latestornone, like .NET's
AnalysisLevel: from 1.1 on, a release's new rules stay off until you raise it, so upgrading the package never adds
warnings by itself. Unset means the package's major version (1.0); before 1.0 every rule is a 1.0 rule, so nothing
changes yet. A version newer than the package warns (STYLEBRO002); any other value fails the build (STYLEBRO001).
See https://bisforboman.github.io/stylebro/versioning/#new-rules
Changed
- Field renames follow your naming rules for non-private fields too (BRO1303/BRO1306): the first
dotnet_naming_rulethat covers a public, internal or protected field, in Roslyn's order, decides its casing, but
only when something enforces it (IDE1006's severity, or the rule's own, issuggestion,warningorerror).
A rule for camelCase internal fields no longer gets them renamed to PascalCase; a style StyleBro doesn't write (a
prefix) leaves the name alone; an unenforced rule leaves StyleCop's defaults.initlets your code decide the
private field style while IDE1006 is off. - StyleBro and CSharpier settle: after
stylebro-migrate formatanddotnet csharpier format ., anotherformat
changes nothing.initwritesstylebro_layout_by = csharpierandstylebro_layout_print_width(the.csharpierrc's
printWidth, elsemax_line_length, else 100), and the opposite of adotnet_sort_system_directives_first = falseordotnet_separate_import_directive_groups = trueit finds, since CSharpier sorts usings System first.- BRO1149 lays out a merged condition the way CSharpier does (also
||chains that don't fit); BRO1514-BRO1516
count a statement CSharpier will split as multi-line, so its braces come in the same run. stylebro-migrate --write(from StyleCop) detects CSharpier likeinit(IDE0055 and the same layout rules off;
the report lists the StyleCop rules they replaced under "CSharpier decides it").
initfollows more conventions: spacing IDE0055 enforces (if(x),( a + b ),(int) x,F( x ): a clear
form is written ascsharp_space_*keys, mixed code turns IDE0055 off), and blank lines between members (BRO1505)
and above doc comments (BRO1513): compact or mixed code turns the rule off.initalso takes--project.- Leftover StyleCop settings (no project references StyleCop.Analyzers any more):
initproceeds and follows the
code, noting the lines;--writesays StyleCop isn't installed and points toinit. - The preset file moved from
build/stylebro.recommended.globalconfigtobuild/presets/stylebro.1.0.globalconfigin
the package. Only matters if your build references the file by path.
Fixed
- Wrong code: BRO1151 no longer unwraps a one-element array the call would take as the array itself
(Take(new Item[] { default! })becameTake(default!), a null array; the compiler now decides), nor an array whose
elements take their type from it (M([new() { ... }])didn't compile). - Rules: BRO1123 and BRO1115 leave doc comment crefs alone (
Func{Nullable{int}}), where the build warned and
dotnet formathad nothing to fix; BRO1311 keeps a tuple element's rename only for a use as a member in code the run
doesn't load (.value,value:; internal members only whereInternalsVisibleToreaches), and says so. - Line endings, charset, final newline:
initjudges them against the.editorconfigthat decides each file (the
nearest one setting the key) and writes its line there (a# BEGIN stylebro-whitespaceblock), so a nested
insert_final_newline = falseno longer makesformatstrip line breaks the report said it would keep. - In-solution source generators (Mapperly):
format --verify-no-changesand--diffpreviews run the generator in
their copy too, so verify no longer fails whereformatis clean and previews no longer show renamesformatkeeps
back. Verify also stays clean where the restore installs git hooks (Husky.Net). - Migration where StyleCop is referenced conditionally: the MSBuild
Conditionis evaluated, so settings go only
where StyleCop ran (aroot = truefolder where it didn't gets none), and StyleBro.Analyzers is added next to the
StyleCop reference under the same condition. - stylebro-migrate:
baselineskips the whitespace pass where IDE0055 is off (CSharpier), likeformat;format
leaves projects no solution configuration builds alone and says so; a secondinitwrites its lines in the same
order; suppressions are no longer carried into generated code or onto IDE0055; lower-casesa1234ids are read; the
line-ending and private-field (SA1309 in a sub-folder) notes judge the code correctly;net4.7andnet47share
one format run; clearer messages.
Upgrading from 0.6.0-alpha.1
Bump the package, then update the tool: dotnet tool update -g StyleBro.Migrate --prerelease.
StyleBroPresetunset means1.0, which is every current rule, so nothing changes.stylebro-migrate init --write
pins<StyleBroPreset>1.0</StyleBroPreset>inDirectory.Build.props; repositories migrated from StyleCop keep
none.- Run
stylebro-migrate init --write(or--writeif you migrated from StyleCop) again if you use CSharpier (for
stylebro_layout_byandstylebro_layout_print_width), have a nested.editorconfigthat sets line endings, the
charset or the final line break, or space your code differently from the SDK's defaults. - Have
dotnet_naming_ruleentries for non-private fields? Check the firstformatrun: BRO1303/BRO1306 now follow
the enforced ones.
Full list of changes: v0.6.0-alpha.1...v0.7.0-alpha.1
StyleBro 0.6.0-alpha.1
129 rules, each fixed by dotnet format. Docs: https://bisforboman.github.io/stylebro/
Breaking changes
- The preset no longer sorts usings (it stopped setting
dotnet_sort_system_directives_first, which makes
dotnet formatsort whenever it's set).initwrites the key when your usings are already sorted, else a comment
on how to turn sorting on. - Sonar mappings never fix what the Sonar rule accepts (
stylebro-migrate): S100, S101, S1118, S1125, S1481,
S1854, S1905, S2325, S3052, S3260 and S3442 are no longer mapped (the report lists them with the reason); S121, S818,
S1066, S1116, S3878 and S8969 use the new Sonar-matching settings below; S927 turns BRO1313 on with
stylebro_match_base_parameter_names = non_generic_methods; S4136 maps tostylebro_keep_overloads_together = same_access. Where StyleCop turns the same rule on (SA1106, SA1503), StyleCop's wider scope stays. - A StyleCop migration applies only where StyleCop ran:
stylebro-migrate --writewrites settings (and turns the
preset off) only for the folders of projects that reference StyleCop.Analyzers, reading each project's own ruleset
andstylecop.json. Other folders are listed in the report, andformatleaves them alone. - More field renames go through: BRO1303/BRO1306 keep a name only for a string that reaches a member by name
(GetField("_count"),Type.GetType(...),[MemberData("...")], ...), no longer for any string with that text. stylebro-migrate format --verify-no-changesexits 1 when a project wasn't loaded in any run, instead of
reporting "Clean." (projects skipped for some frameworks only, or for an F# reference, stay warnings).- Old-style (non-SDK) projects:
formatno longer restores them; runmsbuild -t:restore -p:RestorePackagesConfig=truefirst.packages.configprojects get StyleBro.Analyzers the packages.config way, and
theDirectory.Build.propsreference gets a condition that leaves them out (it broke their restore).
New
stylebro-migratefor scripts and AI agents (docs):--json
on every command,format --files a.cs b.cs(seconds instead of minutes),--agents-mdfor anAGENTS.mdsection,
andllms.txt/llms-full.txton the docs site.- Six rules can report exactly what their Sonar rule does:
stylebro_braces_statements = if_and_loops(BRO1514,
S121),stylebro_upper_case_literal_suffixes = lone_l(BRO1135, S818),stylebro_allow_nested_dynamic_ifs
(BRO1149, S1066),stylebro_allow_semicolon_after_closing_brace(BRO1101, S1116),
stylebro_params_arrays = except_object_and_jagged(BRO1151, S3878),stylebro_allow_null_forgiving_on_unannotated
(BRO1147, S8969). - More settings:
stylebro_match_base_parameter_names = all | non_generic_methods(BRO1313),
stylebro_private_static_field_naming,stylebro_private_mutable_static_field_naming,
stylebro_allow_leading_underscore_in_pascal_fields(BRO1306;--writesets it from SA1309),
stylebro_keep_overloads_together = same_access. - Finding the solution: Traversal projects, the only solution one folder down, and a solution next to several
.slnffilters of it work without naming one.stylebro-migrate --version.
Changed
initfollows more of your code's conventions (clear code sets the style, mixed code turns the rule off):
line endings, charset and final newline (from the files, also against your.editorconfig); naming (static field
casing,s_/t_prefixes,Stringvsstring); layout (member order, one-line statements and jumps, multi-line
auto-properties, grouped list items,#regions in members, combined declarations, implicitprivate, relative
usings, summary wording); other formatters (CSharpier, ReSharper/Rider column alignment). A key the code contradicts,
or one nothing enforces, turns off the rule instead;root = truefolders get their own block; re-runs keep what the
last run wrote.- Rules: BRO1514-BRO1516 allow consecutive
fixedstatements (stylebro_allow_consecutive_usings); BRO1523 leaves
chains whose first line has several calls; BRO1606 and BRO1604 leave summaries in your own words; BRO1504 needs no
blank line before a comment in a list or call chain; BRO1401 skips property patterns; BRO1611/BRO1613/BRO1614 skip
<inheritdoc>; naming rules leave interop names anddotnet_naming_ruleprefixes alone; BRO1142 follows
csharp_style_var_*; nothing is reported in source-generator output. - Faster: a full
dotnet formattakes about half the time, andstylebro-migrate's first run 35-60 % less.
Fixed
- One
dotnet formatrun is enough where several rules used to need a second one (BRO1101, BRO1122, BRO1126,
BRO1149, BRO1509, BRO1514-BRO1516, BRO1527, member sorting with region removal, BRO1107 with BRO1108). - Rules that changed meaning: BRO1001 keeps types read by position through reflection; BRO1301/BRO1302 leave
expression-tree names; BRO1303/BRO1306 don't rename a field to its class's name;nameofand multi-targeted renames
check the right symbols; file headers with;or#are kept whole. formatand--diffare sturdier: the same result on every OS (each file keeps its line ending); no false
"clean" when the analyzers didn't load; restores skip NuGet's audit and explain NU1102; projects sharing files,
linked files,.slnffilters, central package management, nestedDirectory.Build.propsand target framework
spellings (net6,net6.0) are handled; clear errors instead of stack traces.- Migration and
init: Sonar severities per folder and per SonarAnalyzer version; versions from MSBuild properties;
StyleCop 1.0.x; a second--writeorinitgives the same settings; edited files keep their line endings.
Upgrading from 0.5.0-alpha.1
Bump the package, then update the tool: dotnet tool update -g StyleBro.Migrate --prerelease.
Run stylebro-migrate init --write again (or stylebro-migrate --write if you migrated from StyleCop) to pick up the
new conventions; it keeps what it wrote before. Code a format run already sorted keeps BRO1001 on.
- Relied on the preset to sort usings? Re-run
init, or setdotnet_sort_system_directives_first = true. - Migrated from StyleCop with SA1309 off?
--writeaddsstylebro_allow_leading_underscore_in_pascal_fields = true,
so BRO1306 stops renaming_xstatic readonly fields. - Old-style projects: restore with
msbuild -t:restore -p:RestorePackagesConfig=truebeforestylebro-migrate format.
Full list of changes: v0.5.0-alpha.1...v0.6.0-alpha.1
StyleBro 0.5.0-alpha.1
StyleBro 0.5.0-alpha.1
129 rules, each fixed by dotnet format. Docs: https://bisforboman.github.io/stylebro/
Fixed: problems in 0.4.0-alpha.1
- Renames inside
#ifcode broke builds: a type parameter (or another name) used in a branch of#ifthat the
current target framework doesn't compile was left with its old name. Names that appear in disabled code are no
longer renamed. --diffpreviewed without StyleBro in repos whose projects use a nestedDirectory.Build.props: the package
reference now goes where MSBuild picks it up (also for--write), and the preview warns when no StyleBro rule ran.
New
- Findings kept on purpose say why. Renames StyleBro holds back (the name is read by reflection, used in
nameof, public API, ...) get no code action, andstylebro-migrate formatlists them with the reason. - A clean check that means clean:
stylebro-migrate format --verify-no-changesexits 0 when only kept findings
remain (plaindotnet format --verify-no-changeskeeps failing on them). Exit codes are in--helpand the CI guide. initexplains what it adopted: every convention gets a verdict (kept, default, off, too few), a summary says
which rules were turned off because the code mixes both forms and how to choose later, and the written
.editorconfigcomments explain themselves.
Changed
initneeds at least 3 places before following a style; with no clear majority it turns the matching rule off
instead of rewriting the code to StyleBro's default.- SCREAMING_CASE locals are converted word by word (
RANGE_REP_REG→rangeRepReg). - BRO1150 with Sonar: on lists and arrays it writes
Exists/Findwhen the project's Sonar setup asks for them.
Fixed
init: vendored folders are treated as generated code; no hint for settings the repo already sets.format: names skipped projects, stops when restore is broken, lists the files each run changed.--diffdescribes invisible changes (byte order mark, final newline).- BRO1606 no longer prefixes summaries that already start like a constructor sentence.
Upgrading from 0.4.0-alpha.1
Bump the package, then update the tool:
dotnet tool update -g StyleBro.Migrate --prerelease.
Use stylebro-migrate format --verify-no-changes in CI instead of plain dotnet format --verify-no-changes.
StyleBro 0.4.0-alpha.1
StyleBro 0.4.0-alpha.1
129 rules, each fixed by dotnet format. Docs: https://bisforboman.github.io/stylebro/
Fixed: two problems in 0.3.0-alpha.1
- Builds broke after
init: the SDK's IDE0065, whichinitturned on, could move usings out of a
namespace and change what names refer to (CS0104/CS0118). It is replaced by BRO1008, which only
moves usings when every name still means the same, and does nothing unlesscsharp_using_directive_placement
is set (the preset setsoutside_namespace). - Renames changed behavior through
nameof: a name thatnameof(...)turns into a string is no longer
renamed.
New
- SonarQube support:
stylebro-migratereads a team's Sonar setup (.editorconfig/.globalconfig, rulesets, or
--sonar-profile <exported profile>) and turns on the StyleBro and SDK rules that fix what those Sonar
rules report. Sonar suppressions are carried over.- Three new rules mirroring Sonar's: BRO1149 merge nested ifs (S1066), BRO1150
Where(p).Count()→Count(p)(S2971), BRO1151 no explicit array forparams(S3878). - With Sonar's package in the project,
dotnet formatalso fixes Sonar's own S1066, S2971 and S3878.
initadapts to the repo: it detects the repo's conventions for StyleBro's settings (=>and operator
placement, trailing commas,"", null checks, using placement,_fieldnames, ...) and keeps the
majority style.
Changed
- Public API isn't renamed by default: naming rules skip names visible outside the assembly;
stylebro_rename_public_api = trueto include them. stylebro-migrate formatrepeats until a run changes nothing (at most 3) and says how many files each
run changed.
Fixed
- Fix order:
- Fixes that needed a second
dotnet formatrun now converge in one: comments below a field, blank lines
around documented properties,: base(...)/whereat the line limit. - BRO1603 no longer adds a period after custom doc elements.
- Fixes that needed a second
- Migration and
init:- EF Core migrations are treated as generated code.
- One-line
delegate { … }statements are no longer split. - The tool asks which solution to use when there are several.
--diffsamples show the right change.
Upgrading from 0.3.0-alpha.1
Bump the package, then update the tool:
dotnet tool update -g StyleBro.Migrate --prerelease.
Run stylebro-migrate init --diff (or <path> --diff if you migrated from StyleCop) to preview the changes.
StyleBro 0.3.0-alpha.1
StyleBro 0.3.0-alpha.1
125 rules, each fixed by dotnet format. Docs: https://bisforboman.github.io/stylebro/
New
-
BRO1410: unnecessary parentheses in patterns (
x is (> 0)→x is > 0). Unnecessary
parentheses (BRO1405, BRO1410) are now also faded in the IDE, like StyleCop's SA1119_p. -
11 settings where teams prefer otherwise:
defaultliteral;""instead ofstring.Empty;- omit trailing commas;
- empty
{ }on one line; )on its own line;- first item on the
(line; - one-line members together;
<inheritdoc />;: base(...)/whereon the declaration line;l-only literal suffixes.
See Settings.
-
stylebro-migrate --diff: previewsinit, a migration orformaton a temporary copy.
Prints changes per rule and writes the full diff to a.patchfile. -
Docs site with search: each rule's help link now opens its page there.
Changed
stylebro-migrate formatapplies only StyleBro's and the SDK style rules' fixes;
--allfor everything.initadapts to the repo: it keeps_fieldnames when they're the majority, and points
to--writewhen it finds a StyleCop setup.- BRO1604 only rewrites summaries that start like a noun phrase.
Fixed
- Migrating: StyleCop settings kept in a git submodule are read, and
formatno longer
edits submodule files. - File header: never set up with StyleCop's placeholder company.
- Region removal (BRO1517): several empty regions in a row now go in one run.
- Fix order: several cases that needed a second
dotnet formatrun now converge in one
(member sorting with blank lines, call chains with#region, documented fields). - Uneditable files: no findings in NuGet
contentFiles.
Upgrading from 0.2.0-alpha.1
Bump the package and the tool:
dotnet tool update -g StyleBro.Migrate --prerelease.
Run stylebro-migrate init --diff (or <path> --diff if you migrated from StyleCop) to see what
the new version would change before running it for real.
StyleBro 0.2.0-alpha.1
What's Changed
- PR pipeline: StyleCop parity, real-world runs, mutation testing by @bisforboman in #1
- Analyzer cost: BRO1006 walks only directives; benchmark for 88 rules by @bisforboman in #2
- BRO1310: no Hungarian prefixes (SA1305), off by default by @bisforboman in #3
- BRO1001: sort members within regions instead of skipping the type by @bisforboman in #4
- Backlog: work after StyleCop parity by @bisforboman in #5
- Real world: add Jellyfin, FluentValidation, CsvHelper (and fix what they found) by @bisforboman in #6
- stylebro-migrate format: safe dotnet format for multi-targeted repos (IDE0055) by @bisforboman in #7
- BRO1311: tuple element names in PascalCase (SA1316), renamed with every use by @bisforboman in #8
- Getting started page and StyleCop migration sample by @bisforboman in #9
- stylebro-migrate: report dropped rules without survey notes by @bisforboman in #11
- docs: survey of fixable style rules in other analyzers by @bisforboman in #10
- BRO1132: comments between a statement and its block move into the block (SA1108) by @bisforboman in #12
- Small cleanups: SA0001 in the migrate report, stale next steps by @bisforboman in #14
- BRO1520-BRO1522: operator, '=>' and '=' placement when a line wraps by @bisforboman in #15
- BRO1312: namespace names begin with an upper-case letter (SA1300 namespaces), opt-in by @bisforboman in #13
- Convergence: one dotnet format run on every reference repo; stricter real-world check by @bisforboman in #16
- docs: candidates and possible bugs from StyleCop's issue tracker by @bisforboman in #17
- Fix the six tracker bugs; migrate honors documentationCulture and excludeFromPunctuationCheck by @bisforboman in #25
- BRO1514: option to allow 'if (x) return;' without braces (StyleCop #2252) by @bisforboman in #21
- BRO1616: summary layout (tags on their own lines, or one line when it fits) by @bisforboman in #19
- BRO1524: a split conditional expression has the condition, '?' and ':' parts on their own lines (StyleCop #651) by @bisforboman in #22
- BRO1133: null checks in one form, '== null' or 'is null' (RCS1248) by @bisforboman in #18
- BRO1525: no blank line after attributes (StyleCop's proposed SA1521) by @bisforboman in #24
- BRO1135: integer literal suffixes in upper case (StyleCop #1563, Sonar S818) by @bisforboman in #23
- BRO1523: every call of a split call chain starts its own line by @bisforboman in #20
- BRO1134: comments in declaration headers move into the body (StyleCop #605) by @bisforboman in #26
- Analyzer performance: one trivia walk per tree, cheaper null and wrap checks by @bisforboman in #27
- Backlog: supersede StyleCop and performance work by @bisforboman in #28
- CI performance check; FieldNamingAnalyzer ~25-30 % faster by @bisforboman in #29
- Follow StyleCop master where it fixed gaps; document kept differences by @bisforboman in #30
- BRO1104: new nint() always becomes default(nint) by @bisforboman in #31
- Fix StyleCop's open bugs that StyleBro shares, and three of its own by @bisforboman in #33
- stylebro-migrate init --modernize: the SDK's modernization rules in tiers by @bisforboman in #34
- Follow StyleCop master: single-line properties together, no inheritdoc on explicit implementations by @bisforboman in #32
- One walk per tree: analyzers ~35% faster by @bisforboman in #35
- CLAUDE.md: nested split lists note is out of date by @bisforboman in #36
- BRO1617-BRO1619 (generic crefs, langword, doc element order) and BRO1504 exempt prefixes by @bisforboman in #37
- Naming batch D: BRO1306 follows naming rules for private constants, BRO1313 base parameter names, BRO1314 Async suffix by @bisforboman in #38
- Readability batch B: BRO1136-BRO1142 and BRO1408 by @bisforboman in #39
- BRO1526 (switch section blank lines), BRO1143 (no else after a jump), BRO1001 overloads option by @bisforboman in #40
- Fix flaky verify-format: BRO1139 vs BRO1143, and off-by-default rules in isOn by @bisforboman in #42
- BRO1409: internal, not public, on ordinary methods of internal types (off by default) by @bisforboman in #41
- Multi-target guard for the newer-API modernization rules by @bisforboman in #43
- BRO1143: add the brace rules' braces on the 'if' branch, converge in one run by @bisforboman in #44
- BRO1508/BRO1509: expand enclosing single-line blocks in the same edit (fix-order difference) by @bisforboman in #45
- Housekeeping: backlog up to date, CLAUDE.md for 2026-10-04/05 by @bisforboman in #46
- Backlog: IDE check done (Visual Studio 2022) by @bisforboman in #47
- Declaration forms: BRO1527 auto-accessors on one line, BRO1145 empty type body, BRO1146 record class by @bisforboman in #52
- Real world: add eShopOnWeb, MediatR, LibGit2Sharp, Mapperly (+ 3 fixes they found) by @bisforboman in #51
- C# 14: BRO1144 escapes new contextual keywords; BRO1001/BRO1509 handle extension blocks by @bisforboman in #53
- BRO1147 (redundant '!') and BRO1148 (HasValue -> null check), off by default by @bisforboman in #54
- docs: StyleBro vs StyleCop comparison page by @bisforboman in #48
- BRO1313/BRO1314 real-world runs: keep parameter names that reach run time by @bisforboman in #56
- BRO1505/BRO1001: judge a property BRO1527 collapses as one-line by @bisforboman in #55
- Never rename to C# 14's field; IDE0031 to modernize tier B, add IDE0350 by @bisforboman in #49
- Per-file benchmark (IDE) and fixes for analyzers slow on one big file by @bisforboman in #50
- Migrate: pin StyleCop casing, skip submodules, IDE0073 with SA1636, merged format reports by @bisforboman in #58
- README: rule list moves to docs/rules/README.md, contributor sections to CONTRIBUTING.md by @bisforboman in #60
- Docs: round wrap-up (CLAUDE.md for 2026-10-05/06, two decisions, BRO1144/BRO1302 notes) by @bisforboman in #57
- Prepare 0.2.0-alpha.1 by @bisforboman in #61
- First-run fixes: BRO1601 (#if, doc generation), BRO1603, BRO1604/BRO1606 wording, BRO1134 trailing comments by @bisforboman in #59
New Contributors
- @bisforboman made their first contribution in #1
Full Changelog: v0.1.0-alpha.8...v0.2.0-alpha.1