Skip to content

Enforce .NET code formatting: add dotnet format to CI and fix all existing violations#5954

Closed
Robbie-Microsoft wants to merge 12 commits intomainfrom
rginsburg/formatting
Closed

Enforce .NET code formatting: add dotnet format to CI and fix all existing violations#5954
Robbie-Microsoft wants to merge 12 commits intomainfrom
rginsburg/formatting

Conversation

@Robbie-Microsoft
Copy link
Copy Markdown
Contributor

Summary

This PR adds automated code formatting enforcement to the MSAL.NET repository — the .NET equivalent of JavaScript's Prettier — using dotnet format, and fixes all pre-existing violations in the core library.

What's Added

CI Enforcement

  • dotnet format --severity info --verify-no-changes added to emplate-prebuild-code-analysis.yaml
  • Every PR will now fail if it introduces formatting violations

Developer Tooling

  • .vscode/settings.json: format-on-save + fix-all for VS Code users
  • .gitignore: allows .vscode/settings.json to be committed
  • CONTRIBUTING.md: new Code Formatting section explaining the tooling

.editorconfig Improvements

  • Added rim_trailing_whitespace = true and charset = utf-8 globally (parity with msal-js Prettier config)
  • Re-enabled VSTHRD110 (unawaited task warning) — was previously silenced
  • Scoped s_ prefix naming rule to private/internal statics only (not public static fields, which use PascalCase per convention)
  • Suppressed rules that produce false positives in multi-target projects (see below)

Violations Fixed (~3,000+ across 700+ files)

Rule Count Description
WHITESPACE ~666 files Indentation, trailing whitespace, blank lines
IDE0090 ~575
ew T() →
ew() target-typed new
IDE0008 ~1,436 Explicit types replacing ambiguous �ar
IDE0290 ~298 Primary constructors
IDE1006 ~382 s_ prefix on static fields, _ on instance fields
CA1859 ~68 Concrete types instead of interface types for performance
CA1860/CA1861/CA1854 various Collection/dictionary best practices
IDE0044/0049/0063/0028/0017/0300/0301/0083/0305/1005/… hundreds Misc style modernization
VSTHRD110 13 Fixed real bugs: 4 were silent test failures (async void test methods whose assertions never ran)

Real Bugs Found and Fixed

Re-enabling VSTHRD110 surfaced 4 genuine test bugs:

  • BrokerRequestTests.cs: 2 �sync void test methods — assertions never executed
  • TokenCacheTests.cs: 2 �sync void test methods — cache saves were never awaited before assertions
  • SeleniumInfrastructureTests.NetFwk.cs: Task.Delay in sync context replaced with Thread.Sleep

Suppressed (False Positives)

Rules suppressed in .editorconfig with comments explaining why:

Rule Reason
CA1866/CA1845/CA1846/CA1850 APIs only available in .NET 5+; project also targets net462/netstandard2.0
CA1510/CA2250/IDE0039 .NET 6+ APIs
CA1512/CA1513 .NET 8+ APIs
IDE0057 Range operator requires System.Index (.NET 5+)
IDE0019/IDE0051/IDE0052 Multi-target #if preprocessor false positives
IDE0130 Flat Microsoft.Identity.Client namespace is intentional public API design
IDE1006 (public statics) Prompt., BrokerResponseConst.iOSBroker — renaming would be a breaking change

Testing

  • dotnet build → 0 errors, 0 warnings
  • dotnet format --verify-no-changes --severity info → exit code 0
  • No behavioral changes — purely formatting and naming conventions

Copilot AI review requested due to automatic review settings April 27, 2026 19:48
@Robbie-Microsoft Robbie-Microsoft requested a review from a team as a code owner April 27, 2026 19:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@Robbie-Microsoft Robbie-Microsoft marked this pull request as draft April 27, 2026 19:56
Robbie-Microsoft and others added 11 commits April 27, 2026 15:58
…itorconfig

- trim_trailing_whitespace = true: matches msal-js editorconfig
- charset = utf-8: makes encoding explicit (compiler default, but documents intent)
- VSTHRD110 warning: re-enable 'Observe result of async calls' to match
  msal-js no-floating-promises enforcement; was previously silently disabled

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Six files fixed across src and tests:

MacMainThreadScheduler.cs, WebView2WebUi.cs:
  Intentional fire-and-forget: ContinueWith result discarded via _ =
  since outcomes are propagated through TaskCompletionSource.

SeleniumInfrastructureTests.NetFwk.cs:
  Bug: Task.Delay() in Action<IWebDriver> lambda was a no-op.
  Replaced with Thread.Sleep() to actually block as intended.

BrokerRequestTests.cs:
  Bug: Two test methods called TaskThrowsAsync without await in sync
  test methods, so assertions never ran. Converted to async Task.

TokenCacheTests.cs:
  Bug: SaveTokenResponseAsync unawaited in two sync test methods,
  so token writes may not complete before assertions ran.
  Converted to async Task.

InteractiveRequestOrchestrationTests.cs:
  NSubstitute Received.InOrder() takes Action, so async method calls
  inside are intercepted, not executed. Discarded via _ = to make
  the intent explicit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- build/template-prebuild-code-analysis.yaml: Add dotnet format
  --severity info --verify-no-changes to PreBuildCheck stage so PRs
  fail if formatting violations are introduced in the core library.

- .vscode/settings.json: New file — enables format-on-save and
  fix-all code actions for VS Code users automatically.

- CONTRIBUTING.md: Add Code Formatting section documenting how to
  run dotnet format locally, and how to configure VS 2022 Code
  Cleanup on Save for auto-fix behavior.

Note: suggestion-level rules are enforced via dotnet format in CI
rather than by bumping .editorconfig severities to :warning, since
the codebase has existing violations that will be cleaned up
separately.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Auto-fix trailing whitespace, indentation, and blank line violations
detected by dotnet format whitespace. Excludes vendored json/ folder.
Style and analyzer rules (IDE0008, IDE0090, etc.) require manual review
due to multi-target framework complexity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace interface-typed fields, local variables, and return types
with their concrete implementations across 14 files:

- IEnumerable<IAccount> -> List<IAccount> (ClientApplicationBase)
- ISet<string> -> HashSet<string> (WwwAuthenticateParameters,
  AadAuthority, KnownMetadataProvider x2, MsalServiceExceptionFactory,
  UsernamePasswordRequest, UserFederatedIdentityCredentialRequest,
  TokenCache.ITokenCacheInternal x2)
- IDictionary<K,V> -> Dictionary<K,V> (UserMetadataProvider,
  KnownMetadataProvider, MsalAccessTokenCacheItem,
  DeviceAuthHelper, TokenCache.ITokenCacheInternal)
- IDictionary<string,JToken> -> Dictionary<string,JToken>
  (CacheSerializationContract)
- IRegionManager -> RegionManager (RegionAndMtlsDiscoveryProvider)
- RSA -> RSACng (InMemoryManagedIdentityKeyProvider)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- IDE0090: Use target-typed new() expressions (core library + unit tests)
- IDE0008: Use explicit types instead of var (core library + unit tests)
  - AbstractManagedIdentity.cs: pragma suppress for TFM-dependent JSON types
- IDE0290: Use primary constructor syntax where applicable (286 core + 210 test files)
- .editorconfig: Suppress CA1866 (char overloads require .NET 5+, not available
  in net462/netstandard2.0 targets; multi-target false positive)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… tests

Style rules applied (dotnet format style):
- IDE0044: Make field readonly
- IDE0063: Use simple using statement (pattern)
- IDE0049: Use language keywords (String->string, Int32->int, etc.)
- IDE0003: Remove 'this.' qualification
- IDE2000: Remove extra blank lines
- IDE0059: Remove unnecessary value assignments
- IDE0028/IDE0017: Use collection and object initializers
- IDE0300/IDE0301: Use collection expressions
- IDE0066: Use switch expressions
- IDE0074: Use compound assignments (x += y)
- IDE0071: Simplify string interpolation
- IDE0034: Simplify default expression
- IDE0031: Use null propagation
- IDE0270: Simplify null checks
- IDE0075: Simplify conditional expressions
- IDE0251/IDE0250: Make members/structs readonly
- IDE0016: Use throw expressions

Analyzer rules applied (dotnet format analyzers):
- CA1860: Avoid Enumerable.Any() extension method
- CA1861: Use static readonly fields over constant array arguments

.editorconfig suppressions added (multi-target false positives):
- CA1866: char overloads require .NET 5+ (not available in net462/netstandard2.0)
- CA1510: ThrowIfNull requires .NET 6+
- IDE0057: Range operator requires System.Index (.NET 5+)
- IDE0019: Pattern matching causes duplicate variable issues in #if blocks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… .editorconfig

Additional fixes applied:
- IDE0018: Inline variable declaration
- IDE0059: Remove unnecessary value assignments
- IDE0036: Order modifiers
- IDE1005: Use conditional delegate call
- IDE0305: Use collection expression (fluent)
- IDE0083: Use pattern matching 'is not null'
- IDE0300/IDE0301: Use collection expressions
- IDE0290: Additional primary constructor fixes
- CA1854: Prefer TryGetValue over ContainsKey
- CA1860/CA1861: Enumerable.Any, constant array fixes

.editorconfig: Suppress rules that are multi-target false positives:
- IDE0039: Lambda->local function breaks VSTHRD200 naming convention
- IDE0051/IDE0052: Removes members used in other TFMs via #if blocks
- IDE0056: Range/index operator requires .NET 5+
- CA1845/CA1846: Span-based overloads require .NET 5+
- CA1850: HashData requires .NET 5+
- CA2250/CA1512/CA1513: ThrowIfX methods require .NET 6+/8+

Remaining unfixable violations:
- IDE1006 (382): Naming - no Fix All support in dotnet format
- IDE0130 (359): Namespace != folder - crashes dotnet format
- IDE0090 (44): new() in preprocessor blocks
- CA1859 (20): No code fix available
- IDE0060 (16): Unused parameter - no code fix

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- IDE1006 naming: renamed 89 private/internal static fields to s_ prefix
  and instance fields to _ prefix; suppressed public API constants that
  can't be renamed without breaking changes (iOSBroker*, Prompt.*, XmlNamespace.*)
- IDE1006: renamed private Base64* constants, IosBroker* internal members
- IDE0060: added #pragma suppress for 4 unused params reserved for future use
- IDE0090: fixed new() in 8 more files (HashSet, StringBuilder, Dictionary)
- CA1859: changed IDictionary/ISet/IRegionManager to concrete types in 5 files
- IDE0130: suppressed globally - intentional flat namespace Microsoft.Identity.Client
- editorconfig: scoped static_fields naming rule to private+internal (not public)
  to avoid false positives on public static fields

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rmat command

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- MacNativeMethods.cs: add pragma IDE0060 for P/Invoke params, convert
  UnmanagedCallConv new Type[]{} to collection expressions
- WindowsNativeDpiHelper.cs: same pragma + collection expression fixes
- WindowsNativeMethods.cs: add pragma IDE0060, fix collection expression
- WindowsNativeUtils.cs: add pragma IDE0060 for CoInitializeSecurity params
- MsalIdHelper.cs: fix IDE0008 var -> Regex explicit type
- .editorconfig: suppress SYSLIB1054 (LibraryImport requires .NET 7+)
- CI yaml: add --exclude json\ to dotnet format command

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 27, 2026 20:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

….editorconfig

dotnet format --severity info incorrectly applied SYSLIB1054 (DllImport -> LibraryImport)
and SYSLIB1045 (new Regex -> [GeneratedRegex]) to files that must compile on net462 and
netstandard2.0. LibraryImport, UnmanagedCallConv, and GeneratedRegex require .NET 7+.

Restore these 5 files to their main baseline (DllImport/extern) and apply only safe
whitespace/style fixes (IDE0008, IDE0090, IDE0250):
- MacNativeMethods.cs
- WindowsNativeMethods.cs
- WindowsNativeDpiHelper.cs
- WindowsNativeUtils.cs
- MsalIdHelper.cs

Also add SYSLIB1045.severity = none to .editorconfig alongside the existing SYSLIB1054
suppression so future dotnet format runs don't re-introduce these violations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants