From 51780410f8eaca5b370f2f8b8a4ac598508c7754 Mon Sep 17 00:00:00 2001 From: Kieron Lanning Date: Tue, 10 Nov 2026 18:23:22 +0000 Subject: [PATCH 1/4] feat: updated net 11 as the new base --- .csharpierignore | 5 + .editorconfig | 2 +- CHANGELOG.md | 43 +++++ Directory.Packages.props | 22 +-- Justfile | 4 +- README.md | 6 +- docs/wiki/DotNet-11.md | 165 ++++++++++++++++++ docs/wiki/Getting-Started.md | 8 +- docs/wiki/Guide.md | 18 +- docs/wiki/Home.md | 14 +- docs/wiki/Packaging.md | 10 +- docs/wiki/Performance.md | 10 +- docs/wiki/Testing-TUnit.md | 15 +- docs/wiki/Testing.md | 8 +- docs/wiki/Type-Library.md | 3 +- global.json | 6 +- nuget.config | 8 +- package.json | 2 +- .../SKILL.md | 2 +- .../SKILL.md | 8 +- .../purview-sourcegenerator-testing/SKILL.md | 4 +- src/Directory.Build.props | 21 ++- .../SourceGeneratorFramework.Analyzers.csproj | 2 +- ...SourceGeneratorFramework.Benchmarks.csproj | 2 +- ...SourceGeneratorFramework.CodeFixers.csproj | 2 +- ...GeneratorFramework.ExampleGenerator.csproj | 2 +- ...SourceGeneratorFramework.Generators.csproj | 2 +- .../SourceGeneratorFramework.MergeTool.csproj | 6 + .../CodeQueryAssertions.Chaining.cs | 23 --- .../Assertions/CodeQueryResultAssertion.cs | 35 ++++ .../Sdk/README.md | 8 +- .../CompatibilitySuppressions.xml | 21 +++ .../Sdk/README.md | 8 +- .../SourceGeneratorFramework/Sdk/README.md | 8 +- .../Purview.SourceGeneratorFramework.targets | 14 +- .../Fixture.Generator/.editorconfig | 2 +- .../Fixture.Generator.csproj | 2 +- .../Repository.UnitTests.csproj | 2 +- ...atorFramework.BuildIntegrationTests.csproj | 7 +- ...eratorFramework.MergeTool.UnitTests.csproj | 4 +- 40 files changed, 425 insertions(+), 109 deletions(-) create mode 100644 docs/wiki/DotNet-11.md create mode 100644 src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs diff --git a/.csharpierignore b/.csharpierignore index e07e75a..da2625b 100644 --- a/.csharpierignore +++ b/.csharpierignore @@ -2,3 +2,8 @@ **/obj/ **/generated/** **/Resources/** + +# CSharpier 1.3.0 (the latest release) parses with a Roslyn version that predates C# 15 and reports +# a syntax error for the `closed` modifier. This file holds only the closed assertion base so the +# rest of the assertion chain stays formatted. Remove this entry once CSharpier understands C# 15. +src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs diff --git a/.editorconfig b/.editorconfig index f8b3050..a9b39cb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# Purview.BuildSdk 1.3.0 - managed file, do not edit +# Purview.BuildSdk 2.0.0 - managed file, do not edit # # This file is written by Purview.BuildSdk and is replaced whenever the SDK version changes. The version # on the first line is how the SDK recognises a file it owns: a .editorconfig without that marker is diff --git a/CHANGELOG.md b/CHANGELOG.md index 6360ac7..1f6cadd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,49 @@ that version to nuget.org. This file was reconstructed from the conventional-commit history at 1.1.1, so entries before that release summarise what the commits recorded rather than what was written at the time. +## [2.0.0] - 2026-11-10 + +### Changed + +- **.NET 8 and .NET 9 are out of support.** The libraries still ship a `netstandard2.0` asset, so a + .NET 8 or .NET 9 consumer keeps working, but neither runtime is built against or tested. The test + matrix is `net10.0` and `net11.0`, and the benchmarks target the same pair. See + [docs/wiki/DotNet-11.md](docs/wiki/DotNet-11.md). +- **The repository requires the .NET 11 SDK** (`11.0.100`, with `allowPrerelease` now `false` because + .NET 11 has shipped) and `Purview.BuildSdk` 2.0.0. +- **The packaged merge tool supports .NET 10 and .NET 11 from one `tools/` folder.** It targets the + .NET 10 LTS floor with `RollForward=LatestMajor`, so `dotnet exec` uses the installed .NET 10 or + .NET 11 runtime and prefers 11 when both are present. `MergeToolTFM` selects both the build output + and the packed folder, and the merge-tool test suite runs on both runtimes. +- **Roslyn is pinned to `Microsoft.CodeAnalysis` 5.9.0** instead of a floating `5.9.0+` range. A host + that loads the generators must ship Roslyn 5.9 or later; the .NET 11 SDK ships 5.12. +- **`CodeQueryResultAssertion` is `closed` on the `net11.0` asset (C# 15).** It is the public base + for the package's sealed assertion chain, not a consumer extension point, so deriving from it in + another assembly now fails with CS9382 there. Write a custom chained assertion against TUnit's + `Assertion` instead. The `netstandard2.0` and `net10.0` assets keep the previous `abstract` + declaration, because the compiler attribute the modifier emits ships only with .NET 11. + +### Added + +- [docs/wiki/DotNet-11.md](docs/wiki/DotNet-11.md): the support matrix, the .NET 11 features that + `Purview.BuildSdk` enables for `net11.0` (Runtime Async, C# 15, memory-safety rules, `-mt`), and the + features that were evaluated and deliberately left off. It records why no union type was required + and the non-boxing `IUnion`/`HasValue`/`TryGetValue` pattern to use if one is added. +- `dotnet test --results-directory-layout per-module` in the `just test` recipe. A multi-target run + previously had `net10.0` and `net11.0` overwrite each other's reports. +- `minPublishAgeHours="24"` on the `nuget.org` source, the .NET 11 SDK setting that keeps a + just-published package out of automatic version selection until it has had a day of review. + +### Fixed + +- The merge tool's target framework disagreed with itself: the projects built `net11.0` but looked + for the tool under `bin//net10.0`, and the packaged targets looked under + `tools/net10.0`. Both now flow from a single property. +- Removed the redundant `System.Reflection.Metadata` package reference from the build-integration + tests, clearing NU1510 (the assembly is in the shared framework for `net10.0`/`net11.0`). +- `just benchmark` now passes `--framework net11.0`; `dotnet run` cannot choose a target framework for + a multi-targeted project. + ## [1.3.0] - 2026-11-03 ### Changed diff --git a/Directory.Packages.props b/Directory.Packages.props index e84e3b8..889ed3a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,14 +1,14 @@ true - [5.9.0,) - [5.9.0,) - [1.76.0,) + 5.9.0 + 5.9.0 + 1.81.16 - - - + + + @@ -16,13 +16,13 @@ - - - - + + + + - + diff --git a/Justfile b/Justfile index f95b37d..488cabd 100644 --- a/Justfile +++ b/Justfile @@ -82,7 +82,7 @@ build *args: test filter=default_test_filter *args: echo "Running tests for {{ BLUE }}{{ solution }}{{ NORMAL }} with configuration {{ YELLOW }}{{ build_configuration }}{{ NORMAL }}" echo " and filter {{ GREEN }}{{ filter }}{{ NORMAL }}." - dotnet test {{ solution }} -c {{ build_configuration }} --treenode-filter "{{ filter }}" {{ args }} + dotnet test {{ solution }} -c {{ build_configuration }} --treenode-filter "{{ filter }}" --results-directory-layout per-module {{ args }} # Run unit tests only [group('Build and Test')] @@ -93,7 +93,7 @@ test-unit *args: [group('Build and Test')] benchmark *args: echo "Running benchmarks for {{ BLUE }}{{ solution }}{{ NORMAL }}" - dotnet run --project {{ benchmark }} --configuration Release --no-build {{ args }} + dotnet run --project {{ benchmark }} --configuration Release --framework net11.0 --no-build {{ args }} # Clean all projects with the specified configuration, defaulting to "Debug" [group('Build and Test')] diff --git a/README.md b/README.md index ab04e01..0d7af95 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ A set of libraries for building and testing incremental C# source generators usi - [CodeWriter structured API reference](docs/wiki/Code-Writer.md) - [Step-cache tests for incremental generators](docs/wiki/Step-Cache-Tests.md) - [Benchmark results](docs/wiki/Performance.md) +- [.NET 11 support and features](docs/wiki/DotNet-11.md) ## Packages @@ -24,9 +25,10 @@ A set of libraries for building and testing incremental C# source generators usi ## Requirements -- .NET SDK 10.0 or later -- The test projects target `net8.0`, `net9.0`, and `net10.0` +- .NET SDK 11.0 or later (the repository pins `11.0.100` in `global.json`) +- The test projects target `net10.0` and `net11.0`; .NET 8 and .NET 9 are out of support - Source generators target `netstandard2.0` +- The packaged merge tool targets `net10.0` and rolls forward, so it runs on the .NET 10 or .NET 11 runtime while a component is built ## Building diff --git a/docs/wiki/DotNet-11.md b/docs/wiki/DotNet-11.md new file mode 100644 index 0000000..ce62696 --- /dev/null +++ b/docs/wiki/DotNet-11.md @@ -0,0 +1,165 @@ +# .NET 11 support and features + +Version 2.0.0 moves the repository to .NET 11 and drops .NET 8 and .NET 9 from the build and test +matrix. .NET 11 is the current release; .NET 10 remains the LTS target. + +## Support matrix + +| Component | Target frameworks | +| --- | --- | +| Source generators, analysers, code fixers | `netstandard2.0` | +| `Purview.SourceGeneratorFramework` | `netstandard2.0` | +| `Purview.SourceGeneratorFramework.Testing` / `.Testing.TUnit` | `netstandard2.0`, `net10.0`, `net11.0` | +| Test projects | `net10.0`, `net11.0` | +| Merge tool (packaged under `tools/`) | `net10.0`, rolls forward to `net11.0` | +| Benchmarks | `net10.0`, `net11.0` | + +A .NET 8 or .NET 9 consumer still resolves the `netstandard2.0` assets of the libraries, but those +runtimes are no longer built against or tested. + +## Requirements + +- **Build the repository:** .NET SDK 11.0.100 or later. `global.json` pins that SDK and sets + `allowPrerelease: false` now that .NET 11 has shipped. +- **Load a component as an analyser:** Roslyn 5.9 or later, which is the version the framework + compiles against. The .NET 11 SDK ships Roslyn 5.12 (C# 15 / .NET 11 generation), so it satisfies + the requirement; a Visual Studio 2026 release that ships Roslyn 5.9 or later does too. +- **Build a component that embeds the framework:** .NET 10 or later. The merge tool targets the + .NET 10 LTS floor and sets `RollForward=LatestMajor`, so `dotnet exec` runs it on the installed + .NET 10 or .NET 11 runtime (preferring 11 when both are present), independent of the consuming + project's target framework. + +## What the .NET 11 SDK enables for `net11.0` + +`Purview.BuildSdk` 2.0.0 applies these to every project that targets `net11.0`; the repository does +not repeat them per project. + +| Feature | How it is applied | +| --- | --- | +| Runtime Async (V2) | `runtime-async=on`, without `EnablePreviewFeatures` | +| C# 15 | `LangVersion=latest` — collection expression arguments, closed hierarchies, extension indexers, labelled `break`/`continue` | +| Memory safety tier 2 | `updated-memory-safety-rules` with `MemorySafetyRules=2`; tiers `0`, `1` and `2` are supported | +| .NET 11 analysis rules | `AnalysisLevel=latest`, `AnalysisMode=All`; .NET 11 fixed `latest` resolving to the .NET 9 rule set | +| Multithreaded build | MSBuild `-mt`, written into the managed `Directory.Build.rsp` | +| Warmer builds | The .NET 11 SDK enables the MSBuild server by default and matches wildcards faster during evaluation | +| Faster CLI | The SDK's `dotnet` host is NativeAOT-compiled by default (`DOTNET_CLI_ENABLEAOT=false` opts out) | + +Runtime Async and the memory-safety rules only apply to the `net11.0` leg. The `netstandard2.0` and +`net10.0` legs share the C# 15 language level but none of the net11-only runtime behaviour, so shared +sources must stay free of APIs that exist only on .NET 11. + +Opting out is per project: `false` (or the compiler's +`false`), and `0`. + +## What this repository turned on + +- **`--results-directory-layout per-module`** on `dotnet test` (the `just test` recipe). A + multi-target run previously had `net10.0` and `net11.0` writing reports with the same relative file + name; the .NET 11 option gives each test application its own directory. +- **`minPublishAgeHours="24"`** on the `nuget.org` source. The .NET 11 SDK writes this setting for + `dotnet nuget add source --min-publish-age-hours`. It only affects version selection for + `dotnet package add/update` and floating references, so the repository's pinned versions restore + normally while a newly published, not-yet-reviewed version cannot be picked up by accident. +- **Benchmarks default to `net11.0`.** `dotnet run` cannot choose a target framework for a + multi-targeted project, so the recipe now passes `--framework net11.0`; run + `dotnet run --project src/src/SourceGeneratorFramework.Benchmarks --framework net10.0` directly + when a `net10.0` comparison is wanted. +- **No redundant `System.Reflection.Metadata` package.** It is in the shared framework for + `net10.0`/`net11.0`, so referencing it produced NU1510. The `netstandard2.0` library still needs the + package reference. +- **The merge tool's target framework is a single property, and it serves both supported runtimes.** + `$(MergeToolTFM)` selects the build output and the packed `tools/` folder, and + `_PurviewSourceGeneratorFrameworkMergeToolTargetFramework` is the packaged default. Both are + `net10.0`, with `RollForward=LatestMajor` in the tool's runtimeconfig; previously the projects built + `net11.0` while looking under `net10.0`. +- **`closed` on `CodeQueryResultAssertion`, on the `net11.0` asset.** The assertion chain is a fixed + set owned by the package; the public base exists for the sealed assertions, not as a consumer + extension point. `closed` turns that into a compile-time guarantee. `RoslynTestRunner` was the other + candidate but cannot be closed: its derived runners are generic and C# 15 requires a derived generic + type to reference its type parameters in a closed base (CS9383). The `netstandard2.0` and `net10.0` + assets keep the previous `abstract` declaration, because only .NET 11 ships `IsClosedTypeAttribute`. + +## Union types and closed hierarchies + +Both C# 15 features were evaluated against the API surface rather than adopted wholesale. + +### Union types + +No type in this repository is a true exactly-one-of today, so no union was introduced: + +| Candidate | Why it is not a union | +| --- | --- | +| `GeneratorResult` | Carries a value **and** diagnostics (plus blocking/error flags) at the same time. A union is exactly one case, so this would lose information and break every pipeline. | +| `AttributeDataModelProperty` / `PropertySource`, the `TypeLibrary*` models | Sealed records whose value equality is the incremental cache contract. A union adds no equality or `Deconstruct` (the language reference is explicit about this), so converting would require hand-written equality and risk cache invalidation. | +| `ComponentGuard.TryRun` | Returns `bool` plus a `Diagnostic?`. `Diagnostic` is already a reference, so there is no box to remove; a union would add API churn and a second way to express the same result. | +| `AttributeArgument` | Represents a Roslyn `TypedConstant` (an open set of kinds), not a closed set of case types. | + +If a union is added later, it must use the **non-boxing access pattern** from the language +reference: a custom `[Union]` type implementing `IUnion` with a `HasValue` property and a +`TryGetValue(out TCase)` overload per case type. The `union` declaration is not suitable for +performance-sensitive value-type cases because it always stores `object?` and boxes them. The +compiler calls `TryGetValue` for type patterns and `HasValue` for null patterns, so matching never +boxes; a missing member silently falls back to the boxing `Value` path. + +```csharp +using System.Runtime.CompilerServices; + +[Union] +public struct IntOrError : IUnion +{ + readonly int _value; + readonly Exception? _error; + readonly byte _tag; // 0 = none, 1 = int, 2 = error + + public IntOrError(int value) { _value = value; _tag = 1; } + public IntOrError(Exception error) { _error = error; _tag = 2; } + + public object? Value => _tag switch { 1 => _value, 2 => _error, _ => null }; + public bool HasValue => _tag != 0; + public bool TryGetValue(out int value) { value = _value; return _tag == 1; } + public bool TryGetValue(out Exception error) { error = _error!; return _tag == 2; } +} +``` + +### Closed hierarchies + +`CodeQueryResultAssertion` is declared `closed` on the `net11.0` asset. It is a public base for a +fixed set of sealed assertion types, and external derivation is now rejected with CS9382 there instead +of being an unsupported-but-possible extension. A consumer that wants its own chained assertion should +derive from TUnit's `Assertion` directly. The other assets keep `abstract` so their consumers, which +may not compile with a C# 15 compiler, are unaffected. + +`RoslynTestRunner` is the other infrastructure base, but C# 15 rejects a closed base whose derived +types are generic and do not reference their type parameters in it (CS9383); the concrete runners are +`CodeFixTestRunner`, `DiagnosticAnalyzerTestRunner` and +`RefactoringTestRunner`. The documented test bases (`AnalyzerTestBase`, +`SourceGeneratorTestBase` and the TUnit variants) are consumer extension points and stay open. + +## Evaluated and deliberately not enabled + +| Feature | Why not | +| --- | --- | +| `dotnet test --timeout` / `--maximum-failed-tests` as defaults | The reusable workflow already bounds the job. A local default can abort a legitimate long build-integration run; pass the options per invocation instead. | +| SDK artifacts output layout (`ArtifactsPath`) | The Roslyn-version inner build sets its own `BaseOutputPath`/`BaseIntermediateOutputPath`, and pack validation asserts paths under `bin/`; moving to the artifacts layout would change both. | +| NativeAOT or ReadyToRun for the merge tool | The tool ships inside a framework-neutral package. AOT output is per-RID, and R2R would add architecture-specific binaries to `tools/`. | +| `PublishTrimmed` / `InvariantGlobalization` for the merge tool | Not proven safe for ILRepack/Mono.Cecil, which use reflection and culture-sensitive paths. | +| C# 15 runtime-dependent features in shared sources | `closed` is a declaration-only feature and is used above. Union types and net11-only APIs are not, because the `netstandard2.0`/`net10.0` legs still compile shared sources and the language-level declaration would not remove boxing. | +| .NET 11 `Process` helpers, `EqualityComparer.Create`, the new `Stream` wrappers | The call sites are either multi-targeted (would need `#if NET11_0_OR_GREATER`) or on the `netstandard2.0` legs, where the APIs do not exist. No measured benefit for this codebase. | +| `NuGetAuditMode=all` | Auditing direct dependencies is the SDK default and currently reports nothing; transitive auditing can be enabled if the restore cost becomes worthwhile. | +| In-process crash reports (`DOTNET_EnableCrashReport=1`) | Useful when diagnosing a test-host crash on Linux/macOS, but it writes a report to disk, so it stays opt-in. | + +## Useful .NET 11 switches + +```bash +# Run tests with a whole-run limit or failure cap +dotnet test src/SourceGeneratorFramework.slnx --timeout 20m --maximum-failed-tests 5 + +# Select the runner for one session instead of editing global.json +DOTNET_TEST_RUNNER=Microsoft.Testing.Platform dotnet test src/SourceGeneratorFramework.slnx + +# Pass environment variables without a launch profile +dotnet run -e DOTNET_TieredPGO=1 --project src/src/SourceGeneratorFramework.Benchmarks --framework net11.0 + +# Skip building project references when the tree is already built +dotnet test src/SourceGeneratorFramework.slnx --no-build --no-dependencies +``` diff --git a/docs/wiki/Getting-Started.md b/docs/wiki/Getting-Started.md index c9ea74f..323336e 100644 --- a/docs/wiki/Getting-Started.md +++ b/docs/wiki/Getting-Started.md @@ -103,10 +103,10 @@ duplicate framework types. Because the second reference is a normal assembly reference, the generator's Roslyn dependencies also become visible to the test compilation. For a multi-target test project, build the generator against the Roslyn version that supports its API usage and is compatible with the oldest test target. -This framework is built against Roslyn 5.0 (C# 14 / .NET 10 generation), which ships `net8.0` and -`net9.0` package assets, so a `.NET 8`–`.NET 10` test matrix still loads it. Compiler hosts must be -Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026). Do not centrally pin -`System.Collections.Immutable` to a newer runtime version merely to make the generator load. +This framework is built against Roslyn 5.9, which ships `net10.0` and `netstandard2.0` package assets, +so the `net10.0` and `net11.0` test targets both load it. Compiler hosts must be Roslyn 5.9 or later +(`.NET 11` SDK / Visual Studio 2026). Do not centrally pin `System.Collections.Immutable` to a newer +runtime version merely to make the generator load. ## Write a generator diff --git a/docs/wiki/Guide.md b/docs/wiki/Guide.md index a141200..6f2e0f8 100644 --- a/docs/wiki/Guide.md +++ b/docs/wiki/Guide.md @@ -1141,7 +1141,7 @@ for large generated trees. Generated output may use C# 14 features — extension-member blocks (`extension(...)`, via `CodeWriter.ExtensionBlockScope`), the `field` keyword, collection expressions — when the target compilation supports them. The framework is built against Roslyn 5.x, so its generators may emit C# 14 -output; consumers need a matching compiler (`.NET 10` SDK / Roslyn 5.0 or later) to compile it. Gate any +output; consumers need a matching compiler (`.NET 11` SDK / Roslyn 5.9 or later) to compile it. Gate any newer-than-baseline features on `GenerationSettings.LanguageVersion` when a generator must also serve older hosts. @@ -1329,14 +1329,16 @@ Microsoft's published compatibility baseline is: | 4.13 | VS 2022 17.13 | C# 13 / .NET 9 | | 4.14 | VS 2022 17.14 | C# 13 / .NET 9 | | 5.0 | VS 2026 18.0 | C# 14 / .NET 10 | +| 5.12 | VS 2026 18.x | C# 15 / .NET 11 | This table gives the **minimum documented Visual Studio host**. -> **This framework is built against Roslyn 5.0.** The generator, analyzer, and testing assemblies in +> **This framework is built against Roslyn 5.9.** The generator, analyzer, and testing assemblies in > `Purview.SourceGeneratorFramework*` are compiled against `Microsoft.CodeAnalysis` 5.x, so compiler -> hosts that load them must be Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026 18.0). The -> testing packages multi-target `net8.0`–`net10.0`; Roslyn 5.x ships `net8.0`/`net9.0` package assets, -> so those test targets still load the test runner. +> hosts that load them must ship Roslyn 5.9 or later (`.NET 11` SDK / Visual Studio 2026). The .NET 11 +> SDK ships Roslyn 5.12, which satisfies that floor. The testing packages multi-target +> `netstandard2.0`, `net10.0`, and `net11.0`; Roslyn 5.9 ships `net10.0`/`netstandard2.0` package +> assets, so both test targets load the test runner. Do not interpret it as: @@ -1393,6 +1395,7 @@ Typical baseline choices are: | VS 2022 17.12 / initial .NET 9 generation | Roslyn 4.12 | | VS 2022 17.14 | Roslyn 4.14 | | VS 2026 18.0 / initial .NET 10 generation | Roslyn 5.0 | +| .NET 11 SDK | Roslyn 5.12 | If you compile against a later package, you have deliberately raised your minimum host requirement unless you have proven otherwise. @@ -1408,6 +1411,7 @@ Broad release alignment is: .NET 8 / C# 12 ──► Roslyn 4.8 generation .NET 9 / C# 13 ──► Roslyn 4.12 generation .NET 10 / C# 14 ──► Roslyn 5.0 generation +.NET 11 / C# 15 ──► Roslyn 5.12 generation ``` However, SDK servicing and feature bands can contain later compiler versions. @@ -1662,7 +1666,7 @@ This: ```xml - netstandard2.0;net8.0 + netstandard2.0;net11.0 ``` @@ -1672,7 +1676,7 @@ It does **not** mean NuGet will choose: ```text netstandard2.0 analyser for old compiler -net8.0 analyser for new compiler +net11.0 analyser for new compiler ``` for you. diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index ee2fd6b..8828f3f 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -20,6 +20,7 @@ analysers that guide generators back to best practice. - [Step-Cache Tests](Step-Cache-Tests.md) - [Packaging](Packaging.md) - [Performance](Performance.md) +- [.NET 11 support and features](DotNet-11.md) - [Release Flow](Release-Flow.md) ## Packages @@ -60,11 +61,14 @@ analysers that guide generators back to best practice. ## Requirements -- .NET SDK 10.0 or later to build the framework. -- The framework is built against Roslyn 5.0 (`Microsoft.CodeAnalysis` 5.x), so compiler hosts that - load the generator, analyser, and testing assemblies must be Roslyn 5.0 or later (`.NET 10` SDK / - Visual Studio 2026 18.0). -- Source generators target `netstandard2.0`; test projects target `net8.0`, `net9.0`, and `net10.0`. +- .NET SDK 11.0 or later to build the framework. +- The framework is built against Roslyn 5.9 (`Microsoft.CodeAnalysis` 5.x), so compiler hosts that + load the generator, analyser, and testing assemblies must be Roslyn 5.9 or later (`.NET 11` SDK / + Visual Studio 2026). +- Source generators target `netstandard2.0`; test projects target `net10.0` and `net11.0`. .NET 8 and + .NET 9 are out of support. +- The packaged merge tool targets `net10.0` and rolls forward, so it runs on the .NET 10 or .NET 11 + runtime while a component is built. See [.NET 11 support and features](DotNet-11.md). ## Repository layout diff --git a/docs/wiki/Packaging.md b/docs/wiki/Packaging.md index 96a8b33..d59ab27 100644 --- a/docs/wiki/Packaging.md +++ b/docs/wiki/Packaging.md @@ -378,12 +378,14 @@ generation is: | 4.8 | VS 2022 17.8 | C# 12 / .NET 8 | | 4.12 | VS 2022 17.12 | C# 13 / .NET 9 | | 5.0 | VS 2026 18.0 | C# 14 / .NET 10 | +| 5.12 | VS 2026 18.x | C# 15 / .NET 11 | -> **This framework is built against Roslyn 5.0.** The generator, analyzer, and testing assemblies in +> **This framework is built against Roslyn 5.9.** The generator, analyzer, and testing assemblies in > `Purview.SourceGeneratorFramework*` are compiled against `Microsoft.CodeAnalysis` 5.x, so compiler -> hosts that load them must be Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026 18.0). The -> testing packages multi-target `net8.0`–`net10.0`; Roslyn 5.x ships `net8.0`/`net9.0` package assets, -> so those test targets still load the test runner. +> hosts that load them must ship Roslyn 5.9 or later (`.NET 11` SDK / Visual Studio 2026). The .NET 11 +> SDK ships Roslyn 5.12, which satisfies that floor. The testing packages multi-target +> `netstandard2.0`, `net10.0`, and `net11.0`; Roslyn 5.9 ships `net10.0`/`netstandard2.0` package +> assets, so both test targets load the test runner. See [Guide.md](Guide.md) sections 14–18 for the full discussion of Roslyn versioning, multi-version packaging strategies, and the recommended generator project configuration. diff --git a/docs/wiki/Performance.md b/docs/wiki/Performance.md index d5e99ee..2bbf4d0 100644 --- a/docs/wiki/Performance.md +++ b/docs/wiki/Performance.md @@ -22,6 +22,9 @@ block fails fast; see [Code-Writer.md](Code-Writer.md#construction-and-scope-val - .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3 - Toolchain: InProcessEmitToolchain +These numbers are the recorded .NET 10 baseline. The benchmark project also targets `net11.0`; pass +`--framework net11.0` (the default in the `just benchmark` recipe) to measure the current runtime. + ## CodeWriter | Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | @@ -94,8 +97,9 @@ block fails fast; see [Code-Writer.md](Code-Writer.md#construction-and-scope-val Run the benchmarks project and copy the generated reports into the tables above: ```bash -dotnet run -c Release --project src/src/SourceGeneratorFramework.Benchmarks --framework net10.0 +dotnet run -c Release --project src/src/SourceGeneratorFramework.Benchmarks --framework net11.0 ``` -Filter to a single benchmark with `--filter "*Name*"`. The Markdown reports are written to -`BenchmarkDotNet.Artifacts/results/`. \ No newline at end of file +The benchmark project targets `net10.0` and `net11.0`; pass `--framework net10.0` to compare against +the LTS runtime. Filter to a single benchmark with `--filter "*Name*"`. The Markdown reports are +written to `BenchmarkDotNet.Artifacts/results/`. \ No newline at end of file diff --git a/docs/wiki/Testing-TUnit.md b/docs/wiki/Testing-TUnit.md index 46d9436..124e427 100644 --- a/docs/wiki/Testing-TUnit.md +++ b/docs/wiki/Testing-TUnit.md @@ -89,10 +89,11 @@ not add `OutputItemType="Analyzer"` to the normal reference. For multi-target TUnit projects, the normal reference means the generator's Roslyn dependencies participate in reference resolution for every target. Build the generator against the Roslyn version -that supports its API usage; this framework is built against Roslyn 5.0, which ships `net8.0` and -`net9.0` package assets, so a .NET 8–10 test matrix still loads it. Compiler hosts that consume the -generator as an analyzer must be Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026). Do not -force a newer `System.Collections.Immutable` version through central package management. +that supports its API usage; this framework is built against Roslyn 5.9, which ships `net10.0` and +`netstandard2.0` package assets, so a .NET 10–11 test matrix still loads it. Compiler hosts that +consume the generator as an analyzer must be Roslyn 5.9 or later (`.NET 11` SDK / Visual Studio +2026). Do not force a newer `System.Collections.Immutable` version through central package +management. ## Running a packaged (merged) generator in tests @@ -211,6 +212,12 @@ All assertion extensions are under `Purview.SourceGeneratorFramework.Testing.TUn - `HasConstructorArgument(ordinal | parameterName, expected[, form])` / `DoesNotHaveConstructorArgument` / `HasNamedArgument` / `DoesNotHaveNamedArgument` — on an `AttributeData`; see [Attribute argument assertions](#attribute-argument-assertions). + +`CodeQueryResultAssertion` is a `closed` class on the `net11.0` asset (C# 15): the chain is a fixed +set owned by the package, so deriving from it in another assembly fails with CS9382 there. To add a +custom chained assertion, derive from TUnit's `Assertion` directly. The `netstandard2.0` and +`net10.0` assets keep the previous `abstract` declaration, since only .NET 11 ships the attribute the +modifier emits. - `GeneratesCode(expected)` / `ContainsGeneratedCode(expected)` (whitespace-flattened). The `CodeQuery` assertions operate on a `CodeQuery` directly, so they accept a query from any test diff --git a/docs/wiki/Testing.md b/docs/wiki/Testing.md index 4b16442..bbecac4 100644 --- a/docs/wiki/Testing.md +++ b/docs/wiki/Testing.md @@ -98,10 +98,10 @@ the in-memory compilation created by `SourceGeneratorTestRunner`; source supplie still compiled and generated independently. The normal reference also exposes the generator's assembly dependencies to every target framework of -the test project. This framework is built against Roslyn 5.0, which ships `net8.0` and `net9.0` -package assets, so tests targeting .NET 8, .NET 9, and .NET 10 can all load the test runner. The -Roslyn version used to compile a generator establishes the minimum compiler-host requirement for -projects that consume it as an analyzer — Roslyn 5.0 means `.NET 10` SDK / Visual Studio 2026 or +the test project. This framework is built against Roslyn 5.9, which ships `net10.0` and +`netstandard2.0` package assets, so tests targeting .NET 10 and .NET 11 can both load the test runner. +The Roslyn version used to compile a generator establishes the minimum compiler-host requirement for +projects that consume it as an analyzer — Roslyn 5.9 means `.NET 11` SDK / Visual Studio 2026 or later. Do not centrally pin `System.Collections.Immutable` to a newer runtime version merely to make the generator load. diff --git a/docs/wiki/Type-Library.md b/docs/wiki/Type-Library.md index 6430498..0c5b6a9 100644 --- a/docs/wiki/Type-Library.md +++ b/docs/wiki/Type-Library.md @@ -338,7 +338,8 @@ generated class and member. ## Requirements The generated output uses C# 14 features (nested partial types, collection expressions), so consumers -must compile with a C# 14 compiler (.NET SDK 10 / Roslyn 5.0 or later). +must compile with a C# 14 compiler or later. The framework itself requires the .NET 11 SDK / Roslyn 5.9 +or later. ## Disabling diff --git a/global.json b/global.json index 72a60a8..86e68b6 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,11 @@ { "sdk": { - "version": "11.0.100-rc.2.26504.105", + "version": "11.0.100", "rollForward": "latestMajor", - "allowPrerelease": true + "allowPrerelease": false }, "msbuild-sdks": { - "Purview.BuildSdk": "1.3.0" + "Purview.BuildSdk": "2.0.0" }, "test": { "runner": "Microsoft.Testing.Platform" diff --git a/nuget.config b/nuget.config index 7725805..3356507 100644 --- a/nuget.config +++ b/nuget.config @@ -3,7 +3,13 @@ + - + diff --git a/package.json b/package.json index 56744b6..95154d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sourcegenerator-framework", - "version": "1.3.1", + "version": "2.0.0", "license": "MIT", "author": { "name": "Kieron Lanning", diff --git a/skills/purview-sourcegenerator-codewriter/SKILL.md b/skills/purview-sourcegenerator-codewriter/SKILL.md index ee363c9..68e79d3 100644 --- a/skills/purview-sourcegenerator-codewriter/SKILL.md +++ b/skills/purview-sourcegenerator-codewriter/SKILL.md @@ -234,7 +234,7 @@ Guidelines: - The `Microsoft.CodeAnalysis.*` version used to compile the analyser/generator sets the minimum compiler-host requirement. - The consumer's `TargetFramework` does not determine analyser compatibility. - Choose the oldest Roslyn version that contains the APIs you need. -- Common baselines: Roslyn 4.8 for VS 17.8 / .NET 8, 4.12 for VS 17.12 / .NET 9, 5.0 for VS 2026 18.0 / .NET 10. +- Common baselines: Roslyn 4.8 for VS 17.8 / .NET 8, 4.12 for VS 17.12 / .NET 9, 5.0 for VS 2026 18.0 / .NET 10, 5.12 for .NET 11. - Ship one `netstandard2.0` analyser/generator binary unless you have a deliberate multi-version strategy. - Do not mistake multi-targeting for automatic analyser asset selection. - Use `PrivateAssets="all"` for Roslyn development dependencies. diff --git a/skills/purview-sourcegenerator-packaging/SKILL.md b/skills/purview-sourcegenerator-packaging/SKILL.md index a0e7f80..a34f72c 100644 --- a/skills/purview-sourcegenerator-packaging/SKILL.md +++ b/skills/purview-sourcegenerator-packaging/SKILL.md @@ -185,10 +185,12 @@ marker is the preferred configuration. | 4.8 | VS 2022 17.8 | C# 12 / .NET 8 | | 4.12 | VS 2022 17.12 | C# 13 / .NET 9 | | 5.0 | VS 2026 18.0 | C# 14 / .NET 10 | +| 5.12 | VS 2026 18.x | C# 15 / .NET 11 | -**This framework is built against Roslyn 5.0**, so a host loading it must be Roslyn 5.0 or later -(.NET 10 SDK / Visual Studio 2026 18.0). The testing packages multi-target `net8.0`–`net10.0`, and -Roslyn 5.x ships `net8.0`/`net9.0` assets, so those test targets still load the runner. +**This framework is built against Roslyn 5.9**, so a host loading it must ship Roslyn 5.9 or later +(.NET 11 SDK / Visual Studio 2026). The .NET 11 SDK ships Roslyn 5.12. The testing packages +multi-target `netstandard2.0`, `net10.0`, and `net11.0`, and Roslyn 5.9 ships `net10.0`/ +`netstandard2.0` assets, so both test targets load the runner. ## A generator project to start from diff --git a/skills/purview-sourcegenerator-testing/SKILL.md b/skills/purview-sourcegenerator-testing/SKILL.md index a6da554..5590a89 100644 --- a/skills/purview-sourcegenerator-testing/SKILL.md +++ b/skills/purview-sourcegenerator-testing/SKILL.md @@ -215,8 +215,8 @@ var model = LogAttributeData.FromAttributeData(attribute); runner, reference the generator project twice — once `OutputItemType="Analyzer"` and once as a normal reference. - **Multi-target**: build generators against the Roslyn version that supports the test matrix; the - framework is built against Roslyn 5.0 (net8.0/net9.0 assets keep a .NET 8–10 matrix loading); keep - `System.Collections.Immutable` version pinned to the shared one. + framework is built against Roslyn 5.9 (`net10.0`/`netstandard2.0` assets keep a .NET 10–11 matrix + loading); keep `System.Collections.Immutable` version pinned to the shared one. - **Scope validation**: keep `PurviewSourceGeneratorFrameworkValidateCodeWriterScopes` enabled; it makes undisposed `CodeWriter` scopes fail tests. - **Prefer `CodeQuery` over string matching** for structural assertions (members, signatures, namespaces). diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 37e40a0..3e82053 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,8 +1,27 @@ - net8.0;net9.0;net10.0;net11.0; + + net10.0;net11.0; netstandard2.1;$(TestingTargetFrameworks) + net10.0 + Purview.SourceGeneratorFramework true https://github.com/purview-dev/sourcegenerator-framework diff --git a/src/src/SourceGeneratorFramework.Analyzers/SourceGeneratorFramework.Analyzers.csproj b/src/src/SourceGeneratorFramework.Analyzers/SourceGeneratorFramework.Analyzers.csproj index 940b238..2a38d41 100644 --- a/src/src/SourceGeneratorFramework.Analyzers/SourceGeneratorFramework.Analyzers.csproj +++ b/src/src/SourceGeneratorFramework.Analyzers/SourceGeneratorFramework.Analyzers.csproj @@ -27,7 +27,7 @@ <_PurviewSourceGeneratorFrameworkAssembly>$(TargetDir)Purview.SourceGeneratorFramework.dll - <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\$(MergeToolTFM)\Purview.SourceGeneratorFramework.MergeTool.dll <_PurviewSourceGeneratorFrameworkMergeToolProject>..\SourceGeneratorFramework.MergeTool\SourceGeneratorFramework.MergeTool.csproj false diff --git a/src/src/SourceGeneratorFramework.Benchmarks/SourceGeneratorFramework.Benchmarks.csproj b/src/src/SourceGeneratorFramework.Benchmarks/SourceGeneratorFramework.Benchmarks.csproj index 2a740f3..b327d33 100644 --- a/src/src/SourceGeneratorFramework.Benchmarks/SourceGeneratorFramework.Benchmarks.csproj +++ b/src/src/SourceGeneratorFramework.Benchmarks/SourceGeneratorFramework.Benchmarks.csproj @@ -1,7 +1,7 @@ Exe - net8.0;net9.0;net10.0 + net10.0;net11.0 false false $(NoWarn);IDE0130;CA1515; diff --git a/src/src/SourceGeneratorFramework.CodeFixers/SourceGeneratorFramework.CodeFixers.csproj b/src/src/SourceGeneratorFramework.CodeFixers/SourceGeneratorFramework.CodeFixers.csproj index cf556ca..c93c930 100644 --- a/src/src/SourceGeneratorFramework.CodeFixers/SourceGeneratorFramework.CodeFixers.csproj +++ b/src/src/SourceGeneratorFramework.CodeFixers/SourceGeneratorFramework.CodeFixers.csproj @@ -16,7 +16,7 @@ <_PurviewSourceGeneratorFrameworkAssembly>$(TargetDir)Purview.SourceGeneratorFramework.dll - <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\$(MergeToolTFM)\Purview.SourceGeneratorFramework.MergeTool.dll <_PurviewSourceGeneratorFrameworkMergeToolProject>..\SourceGeneratorFramework.MergeTool\SourceGeneratorFramework.MergeTool.csproj false diff --git a/src/src/SourceGeneratorFramework.ExampleGenerator/SourceGeneratorFramework.ExampleGenerator.csproj b/src/src/SourceGeneratorFramework.ExampleGenerator/SourceGeneratorFramework.ExampleGenerator.csproj index c947d1f..e3fe089 100644 --- a/src/src/SourceGeneratorFramework.ExampleGenerator/SourceGeneratorFramework.ExampleGenerator.csproj +++ b/src/src/SourceGeneratorFramework.ExampleGenerator/SourceGeneratorFramework.ExampleGenerator.csproj @@ -35,7 +35,7 @@ <_PurviewSourceGeneratorFrameworkAssembly>$(TargetDir)Purview.SourceGeneratorFramework.dll - <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\$(MergeToolTFM)\Purview.SourceGeneratorFramework.MergeTool.dll <_PurviewSourceGeneratorFrameworkMergeToolProject>..\SourceGeneratorFramework.MergeTool\SourceGeneratorFramework.MergeTool.csproj false diff --git a/src/src/SourceGeneratorFramework.Generators/SourceGeneratorFramework.Generators.csproj b/src/src/SourceGeneratorFramework.Generators/SourceGeneratorFramework.Generators.csproj index b69785e..3c5263c 100644 --- a/src/src/SourceGeneratorFramework.Generators/SourceGeneratorFramework.Generators.csproj +++ b/src/src/SourceGeneratorFramework.Generators/SourceGeneratorFramework.Generators.csproj @@ -14,7 +14,7 @@ <_PurviewSourceGeneratorFrameworkAssembly>$(TargetDir)Purview.SourceGeneratorFramework.dll - <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + <_PurviewSourceGeneratorFrameworkMergeTool>..\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\$(MergeToolTFM)\Purview.SourceGeneratorFramework.MergeTool.dll <_PurviewSourceGeneratorFrameworkMergeToolProject>..\SourceGeneratorFramework.MergeTool\SourceGeneratorFramework.MergeTool.csproj false diff --git a/src/src/SourceGeneratorFramework.MergeTool/SourceGeneratorFramework.MergeTool.csproj b/src/src/SourceGeneratorFramework.MergeTool/SourceGeneratorFramework.MergeTool.csproj index aefbd48..b9ee91d 100644 --- a/src/src/SourceGeneratorFramework.MergeTool/SourceGeneratorFramework.MergeTool.csproj +++ b/src/src/SourceGeneratorFramework.MergeTool/SourceGeneratorFramework.MergeTool.csproj @@ -3,6 +3,12 @@ $(MergeToolTFM) Exe false + + LatestMajor diff --git a/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryAssertions.Chaining.cs b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryAssertions.Chaining.cs index b83acfa..7867d9b 100644 --- a/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryAssertions.Chaining.cs +++ b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryAssertions.Chaining.cs @@ -487,29 +487,6 @@ this IAssertionSource> source } } -/// -/// Base class for node-chain assertions. The chain value is the matched -/// , and awaiting the assertion yields that same non-null result. -/// -/// -/// Initializes a new instance of the class. -/// -public abstract class CodeQueryResultAssertion(AssertionContext> context) - : Assertion>(context) - where T : SyntaxNode -{ - /// - /// Awaits the assertion and returns the matched non-null . - /// - public new TaskAwaiter> GetAwaiter() => ExecuteAndReturnResultAsync().GetAwaiter(); - - async Task> ExecuteAndReturnResultAsync() - { - var value = await AssertAsync(); - return value!; - } -} - /// /// Asserts that the generated code contains a class, and moves the chain onto it. /// diff --git a/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs new file mode 100644 index 0000000..f44624d --- /dev/null +++ b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs @@ -0,0 +1,35 @@ +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; +using TUnit.Assertions.Core; + +namespace Purview.SourceGeneratorFramework.Testing.TUnit.Assertions; + +/// +/// Base class for node-chain assertions. The chain value is the matched +/// , and awaiting the assertion yields that same non-null result. +/// +/// +/// Closed on .NET 11: the assertion chain is a fixed set defined by this package, so the base exists +/// for the sealed assertion types rather than as a consumer extension point. C# 15's closed +/// keeps the type implicitly abstract; the other targets keep the previous abstract declaration +/// because the compiler attribute the modifier emits is only shipped by .NET 11. +/// +#if NET11_0_OR_GREATER +public closed class CodeQueryResultAssertion(AssertionContext> context) +#else +public abstract class CodeQueryResultAssertion(AssertionContext> context) +#endif + : Assertion>(context) + where T : SyntaxNode +{ + /// + /// Awaits the assertion and returns the matched non-null . + /// + public new TaskAwaiter> GetAwaiter() => ExecuteAndReturnResultAsync().GetAwaiter(); + + async Task> ExecuteAndReturnResultAsync() + { + var value = await AssertAsync(); + return value!; + } +} diff --git a/src/src/SourceGeneratorFramework.Testing.TUnit/Sdk/README.md b/src/src/SourceGeneratorFramework.Testing.TUnit/Sdk/README.md index f9bd779..9054a52 100644 --- a/src/src/SourceGeneratorFramework.Testing.TUnit/Sdk/README.md +++ b/src/src/SourceGeneratorFramework.Testing.TUnit/Sdk/README.md @@ -84,10 +84,10 @@ reference. For multi-target TUnit projects, the normal reference means the generator's Roslyn dependencies participate in reference resolution for every target. Build the generator against the Roslyn version -that supports its API usage; this framework is built against Roslyn 5.0, which ships `net8.0` and -`net9.0` package assets, so a .NET 8–10 test matrix still loads it. Compiler hosts that consume the -generator as an analyzer must be Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026). Do not -force a newer `System.Collections.Immutable` version through central package management. +that supports its API usage; this framework is built against Roslyn 5.9, which ships `net10.0` and +`netstandard2.0` package assets, so a .NET 10–11 test matrix still loads it. Compiler hosts that +consume the generator as an analyzer must be Roslyn 5.9 or later (`.NET 11` SDK / Visual Studio 2026). +Do not force a newer `System.Collections.Immutable` version through central package management. ## Which base class and method diff --git a/src/src/SourceGeneratorFramework.Testing/CompatibilitySuppressions.xml b/src/src/SourceGeneratorFramework.Testing/CompatibilitySuppressions.xml index 9f814a0..596d08d 100644 --- a/src/src/SourceGeneratorFramework.Testing/CompatibilitySuppressions.xml +++ b/src/src/SourceGeneratorFramework.Testing/CompatibilitySuppressions.xml @@ -20,4 +20,25 @@ lib/netstandard2.0/Purview.SourceGeneratorFramework.Testing.dll true + + + CP0008 + T:Purview.SourceGeneratorFramework.Testing.HintNameMatchMode + lib/net8.0/Purview.SourceGeneratorFramework.Testing.dll + lib/netstandard2.0/Purview.SourceGeneratorFramework.Testing.dll + true + + + CP0008 + T:Purview.SourceGeneratorFramework.Testing.HintNameMatchMode + lib/net9.0/Purview.SourceGeneratorFramework.Testing.dll + lib/netstandard2.0/Purview.SourceGeneratorFramework.Testing.dll + true + diff --git a/src/src/SourceGeneratorFramework.Testing/Sdk/README.md b/src/src/SourceGeneratorFramework.Testing/Sdk/README.md index 9512b13..a8fc3e3 100644 --- a/src/src/SourceGeneratorFramework.Testing/Sdk/README.md +++ b/src/src/SourceGeneratorFramework.Testing/Sdk/README.md @@ -90,11 +90,11 @@ The normal reference makes the generator's CLR type available to the testing API separate from the in-memory compilation created by `SourceGeneratorTestRunner`; source supplied to the runner is still compiled and generated independently. -The normal reference also exposes the generator's assembly dependencies to every target framework -of the test project. This framework is built against Roslyn 5.0, which ships `net8.0` and `net9.0` -package assets, so tests targeting .NET 8, .NET 9, and .NET 10 can all load the test runner. The +The normal reference also exposes the generator's assembly dependencies to every target framework of +the test project. This framework is built against Roslyn 5.9, which ships `net10.0` and +`netstandard2.0` package assets, so tests targeting .NET 10 and .NET 11 both load the test runner. The Roslyn version used to compile a generator establishes the minimum compiler-host requirement for -projects that consume it as an analyzer — Roslyn 5.0 means `.NET 10` SDK / Visual Studio 2026 or +projects that consume it as an analyzer — Roslyn 5.9 means `.NET 11` SDK / Visual Studio 2026 or later. Do not centrally pin `System.Collections.Immutable` to a newer runtime version merely to make the generator load. diff --git a/src/src/SourceGeneratorFramework/Sdk/README.md b/src/src/SourceGeneratorFramework/Sdk/README.md index 4937ce0..5085cd1 100644 --- a/src/src/SourceGeneratorFramework/Sdk/README.md +++ b/src/src/SourceGeneratorFramework/Sdk/README.md @@ -104,10 +104,10 @@ duplicate framework types. Because the second reference is a normal assembly reference, the generator's Roslyn dependencies also become visible to the test compilation. For a multi-target test project, build the generator against the Roslyn version that supports its API usage and is compatible with the oldest test target. -This framework is built against Roslyn 5.0 (C# 14 / .NET 10 generation), which ships `net8.0` and -`net9.0` package assets, so a `.NET 8`–`.NET 10` test matrix still loads it. Compiler hosts must be -Roslyn 5.0 or later (`.NET 10` SDK / Visual Studio 2026). Do not centrally pin -`System.Collections.Immutable` to a newer runtime version merely to make the generator load. +This framework is built against Roslyn 5.9, which ships `net10.0` and `netstandard2.0` package assets, +so the `net10.0` and `net11.0` test targets both load it. Compiler hosts must be Roslyn 5.9 or later +(`.NET 11` SDK / Visual Studio 2026). Do not centrally pin `System.Collections.Immutable` to a newer +runtime version merely to make the generator load. ## Installation diff --git a/src/src/SourceGeneratorFramework/Sdk/build/Purview.SourceGeneratorFramework.targets b/src/src/SourceGeneratorFramework/Sdk/build/Purview.SourceGeneratorFramework.targets index a19ef44..8fd81b4 100644 --- a/src/src/SourceGeneratorFramework/Sdk/build/Purview.SourceGeneratorFramework.targets +++ b/src/src/SourceGeneratorFramework/Sdk/build/Purview.SourceGeneratorFramework.targets @@ -2,8 +2,18 @@ <_PurviewSourceGeneratorFrameworkAssembly Condition="'$(_PurviewSourceGeneratorFrameworkAssembly)' == ''" >$(MSBuildThisFileDirectory)..\lib\netstandard2.0\Purview.SourceGeneratorFramework.dll + + <_PurviewSourceGeneratorFrameworkMergeToolTargetFramework + Condition="'$(_PurviewSourceGeneratorFrameworkMergeToolTargetFramework)' == ''" + >net10.0 <_PurviewSourceGeneratorFrameworkMergeTool Condition="'$(_PurviewSourceGeneratorFrameworkMergeTool)' == ''" - >$(MSBuildThisFileDirectory)..\tools\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + >$(MSBuildThisFileDirectory)..\tools\$(_PurviewSourceGeneratorFrameworkMergeToolTargetFramework)\Purview.SourceGeneratorFramework.MergeTool.dll true @@ -171,7 +181,7 @@ diff --git a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/.editorconfig b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/.editorconfig index ea03058..a9b39cb 100644 --- a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/.editorconfig +++ b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/.editorconfig @@ -1,4 +1,4 @@ -# Purview.BuildSdk 1.2.0 - managed file, do not edit +# Purview.BuildSdk 2.0.0 - managed file, do not edit # # This file is written by Purview.BuildSdk and is replaced whenever the SDK version changes. The version # on the first line is how the SDK recognises a file it owns: a .editorconfig without that marker is diff --git a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/Fixture.Generator.csproj b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/Fixture.Generator.csproj index 030add7..ca72ecb 100644 --- a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/Fixture.Generator.csproj +++ b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/Fixture.Generator.csproj @@ -40,7 +40,7 @@ <_PurviewSourceGeneratorFrameworkAssembly>..\..\..\..\src\SourceGeneratorFramework\bin\$(Configuration)\netstandard2.0\Purview.SourceGeneratorFramework.dll - <_PurviewSourceGeneratorFrameworkMergeTool>..\..\..\..\src\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\net10.0\Purview.SourceGeneratorFramework.MergeTool.dll + <_PurviewSourceGeneratorFrameworkMergeTool>..\..\..\..\src\SourceGeneratorFramework.MergeTool\bin\$(Configuration)\$(MergeToolTFM)\Purview.SourceGeneratorFramework.MergeTool.dll <_PurviewSourceGeneratorFrameworkMergeToolProject>..\..\..\..\src\SourceGeneratorFramework.MergeTool\SourceGeneratorFramework.MergeTool.csproj diff --git a/src/tests/Repository.UnitTests/Repository.UnitTests.csproj b/src/tests/Repository.UnitTests/Repository.UnitTests.csproj index c064629..99922e1 100644 --- a/src/tests/Repository.UnitTests/Repository.UnitTests.csproj +++ b/src/tests/Repository.UnitTests/Repository.UnitTests.csproj @@ -1,6 +1,6 @@ - net10.0 diff --git a/src/tests/SourceGeneratorFramework.BuildIntegrationTests/SourceGeneratorFramework.BuildIntegrationTests.csproj b/src/tests/SourceGeneratorFramework.BuildIntegrationTests/SourceGeneratorFramework.BuildIntegrationTests.csproj index b6e2367..d1c1d65 100644 --- a/src/tests/SourceGeneratorFramework.BuildIntegrationTests/SourceGeneratorFramework.BuildIntegrationTests.csproj +++ b/src/tests/SourceGeneratorFramework.BuildIntegrationTests/SourceGeneratorFramework.BuildIntegrationTests.csproj @@ -6,8 +6,9 @@ The test framework packages (TUnit) are supplied automatically by Purview.BuildSdk for test projects, so they must not be declared here. + + System.Reflection.Metadata is in the shared framework for net10.0/net11.0, so it is referenced + through the targeting pack rather than as a package. Declaring the package here produced + NU1510 ("automatically available ... does not need to be referenced explicitly"). --> - - - diff --git a/src/tests/SourceGeneratorFramework.MergeTool.UnitTests/SourceGeneratorFramework.MergeTool.UnitTests.csproj b/src/tests/SourceGeneratorFramework.MergeTool.UnitTests/SourceGeneratorFramework.MergeTool.UnitTests.csproj index b142a28..5db4bb8 100644 --- a/src/tests/SourceGeneratorFramework.MergeTool.UnitTests/SourceGeneratorFramework.MergeTool.UnitTests.csproj +++ b/src/tests/SourceGeneratorFramework.MergeTool.UnitTests/SourceGeneratorFramework.MergeTool.UnitTests.csproj @@ -1,6 +1,8 @@ - $(MergeToolTFM) + + net10.0;net11.0 From 9d6b105af9475936fd49ec56ecd93454d151c542 Mon Sep 17 00:00:00 2001 From: Kieron Lanning Date: Tue, 10 Nov 2026 18:24:42 +0000 Subject: [PATCH 2/4] feat: updated net 11 as the new base --- .config/dotnet-tools.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8080adf..ae7b773 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -10,14 +10,14 @@ "rollForward": false }, "dotnet-inspect": { - "version": "0.26.0", + "version": "0.27.0", "commands": [ "dotnet-inspect" ], "rollForward": false }, "purview.build": { - "version": "0.8.0", + "version": "0.9.0", "commands": [ "purview-build" ], From 97419562e95f3c4c66be72127c618ade6f85607a Mon Sep 17 00:00:00 2001 From: Kieron Lanning Date: Wed, 11 Nov 2026 10:23:36 +0000 Subject: [PATCH 3/4] chore: linting --- .config/dotnet-tools.json | 2 +- .csharpierignore | 5 - .../AvoidSymbolsInPipelineModelAnalyzer.cs | 3 +- .../MissingGeneratorAttributeAnalyzer.cs | 11 +- .../TypeLibraryValidationAnalyzer.cs | 3 +- ...eDataModelSymbolPropertyCodeFixProvider.cs | 5 +- ...lineCodeForFrameworkCrefCodeFixProvider.cs | 5 +- ...hanedFixableDiagnosticIdCodeFixProvider.cs | 3 +- .../CodeWriterSampleEmitter.cs | 48 ++- .../ServiceRegistrationGenerator.cs | 6 +- .../AttributeDataModelGenerator.cs | 260 +++++++---------- .../Helpers/AttributeDataModelLibrary.cs | 37 ++- .../Helpers/SourceEmitter.TypeLibrary.cs | 276 +++++++++--------- .../Helpers/TypeLibraryModelLibrary.cs | 11 +- .../TypeLibraryGenerator.cs | 31 +- .../Assertions/DiagnosticAssertions.cs | 6 +- .../AttributeDataFactory.cs | 3 +- .../CodeFixTestRunner.cs | 34 +-- .../CodeQuery.Declarations.cs | 12 +- .../DiagnosticAnalyzerTestRunner.cs | 3 +- .../DriverRunResultExtensions.cs | 3 +- .../RefactoringTestRunner.cs | 20 +- .../SourceGeneratorTestRunner.cs | 37 ++- .../Helpers/EmbeddedResourceHelper.cs | 3 +- src/src/SourceGeneratorShared/CodeWriter.cs | 16 +- ...eneratorInitializationContextExtensions.cs | 37 ++- .../IncrementalValueProviderExtensions.cs | 5 +- .../Helpers/IncrementalPipeline.cs | 4 +- .../Helpers/IncrementalPipelineExtensions.cs | 6 +- .../Fixture.Generator/FixtureGenerator.cs | 35 +-- .../TestingFrameworkTests.cs | 36 +-- .../CodeWriterTests.cs | 273 +++++++---------- .../SourceProductionContextExtensionsTests.cs | 27 +- .../AlwaysNullableContextTestGenerator.cs | 37 ++- .../TestGenerators/DiagnosticTestGenerator.cs | 16 +- .../ExplicitNullableContextTestGenerator.cs | 37 ++- .../GenerationContextTestGenerator.cs | 5 +- .../NullableContextTestGenerator.cs | 37 ++- .../OrderedLoggingTestGenerator.cs | 15 +- .../TestGenerators/ThrowingTestGenerator.cs | 6 +- 40 files changed, 608 insertions(+), 811 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index ae7b773..bc9bc27 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "csharpier": { - "version": "1.3.0", + "version": "1.4.0", "commands": [ "csharpier" ], diff --git a/.csharpierignore b/.csharpierignore index da2625b..e07e75a 100644 --- a/.csharpierignore +++ b/.csharpierignore @@ -2,8 +2,3 @@ **/obj/ **/generated/** **/Resources/** - -# CSharpier 1.3.0 (the latest release) parses with a Roslyn version that predates C# 15 and reports -# a syntax error for the `closed` modifier. This file holds only the closed assertion base so the -# rest of the assertion chain stays formatted. Remove this entry once CSharpier understands C# 15. -src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/CodeQueryResultAssertion.cs diff --git a/src/src/SourceGeneratorFramework.Analyzers/AvoidSymbolsInPipelineModelAnalyzer.cs b/src/src/SourceGeneratorFramework.Analyzers/AvoidSymbolsInPipelineModelAnalyzer.cs index 7c1f0d5..a1bf25c 100644 --- a/src/src/SourceGeneratorFramework.Analyzers/AvoidSymbolsInPipelineModelAnalyzer.cs +++ b/src/src/SourceGeneratorFramework.Analyzers/AvoidSymbolsInPipelineModelAnalyzer.cs @@ -144,8 +144,7 @@ ConcurrentBag diagnostics return; // An extension method's receiver is its first argument; an instance method's is Instance. - var receiver = - invocation.Instance + var receiver = invocation.Instance ?? ( invocation.TargetMethod.IsExtensionMethod && invocation.Arguments.Length > 0 ? invocation.Arguments[0].Value diff --git a/src/src/SourceGeneratorFramework.Analyzers/MissingGeneratorAttributeAnalyzer.cs b/src/src/SourceGeneratorFramework.Analyzers/MissingGeneratorAttributeAnalyzer.cs index e9ce63d..d88fc16 100644 --- a/src/src/SourceGeneratorFramework.Analyzers/MissingGeneratorAttributeAnalyzer.cs +++ b/src/src/SourceGeneratorFramework.Analyzers/MissingGeneratorAttributeAnalyzer.cs @@ -73,12 +73,11 @@ static void AnalyzeNamedType( if (RoslynComponentDiscovery.HasAttribute(type, generatorAttributeType)) return; - var interfaceName = - type.AllInterfaces.FirstOrDefault(i => - SymbolEqualityComparer.Default.Equals(i.OriginalDefinition, incrementalGeneratorType) - || SymbolEqualityComparer.Default.Equals(i.OriginalDefinition, legacyGeneratorType) - ) - ?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) + var interfaceName = type.AllInterfaces.FirstOrDefault(i => + SymbolEqualityComparer.Default.Equals(i.OriginalDefinition, incrementalGeneratorType) + || SymbolEqualityComparer.Default.Equals(i.OriginalDefinition, legacyGeneratorType) + ) + ?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "a generator interface"; context.ReportDiagnostic( diff --git a/src/src/SourceGeneratorFramework.Analyzers/TypeLibraryValidationAnalyzer.cs b/src/src/SourceGeneratorFramework.Analyzers/TypeLibraryValidationAnalyzer.cs index 73c4862..9457af3 100644 --- a/src/src/SourceGeneratorFramework.Analyzers/TypeLibraryValidationAnalyzer.cs +++ b/src/src/SourceGeneratorFramework.Analyzers/TypeLibraryValidationAnalyzer.cs @@ -974,8 +974,7 @@ out string? memberNamespace return false; typeName = typeSymbol.Name; - memberNamespace = - namedNamespace + memberNamespace = namedNamespace ?? GetConstructorArgument(typeRef, 1, (string?)null) ?? typeSymbol.ContainingNamespace.ToDisplayString(); diff --git a/src/src/SourceGeneratorFramework.CodeFixers/AttributeDataModelSymbolPropertyCodeFixProvider.cs b/src/src/SourceGeneratorFramework.CodeFixers/AttributeDataModelSymbolPropertyCodeFixProvider.cs index 804d6b7..4e76f10 100644 --- a/src/src/SourceGeneratorFramework.CodeFixers/AttributeDataModelSymbolPropertyCodeFixProvider.cs +++ b/src/src/SourceGeneratorFramework.CodeFixers/AttributeDataModelSymbolPropertyCodeFixProvider.cs @@ -160,9 +160,8 @@ ImmutableArray diagnostics if (replacements.Count == 0) return document; - var newRoot = root.ReplaceNodes( - replacements.Select(static r => r.oldNode), - (original, _) => replacements.First(r => r.oldNode == original).newNode + var newRoot = root.ReplaceNodes(replacements.Select(static r => r.oldNode), (original, _) => + replacements.First(r => r.oldNode == original).newNode ); return document.WithSyntaxRoot(newRoot); diff --git a/src/src/SourceGeneratorFramework.CodeFixers/PreferInlineCodeForFrameworkCrefCodeFixProvider.cs b/src/src/SourceGeneratorFramework.CodeFixers/PreferInlineCodeForFrameworkCrefCodeFixProvider.cs index c418b77..157bc53 100644 --- a/src/src/SourceGeneratorFramework.CodeFixers/PreferInlineCodeForFrameworkCrefCodeFixProvider.cs +++ b/src/src/SourceGeneratorFramework.CodeFixers/PreferInlineCodeForFrameworkCrefCodeFixProvider.cs @@ -167,9 +167,8 @@ CancellationToken cancellationToken // Replace all the and elements with inline ... elements. return document.WithSyntaxRoot( - root.ReplaceNodes( - owners, - static (original, _) => BuildInlineCodeElement(original, GetCrefText(original)) + root.ReplaceNodes(owners, static (original, _) => + BuildInlineCodeElement(original, GetCrefText(original)) ) ); } diff --git a/src/src/SourceGeneratorFramework.CodeFixers/RemoveOrphanedFixableDiagnosticIdCodeFixProvider.cs b/src/src/SourceGeneratorFramework.CodeFixers/RemoveOrphanedFixableDiagnosticIdCodeFixProvider.cs index 8e9368e..c8d0b4f 100644 --- a/src/src/SourceGeneratorFramework.CodeFixers/RemoveOrphanedFixableDiagnosticIdCodeFixProvider.cs +++ b/src/src/SourceGeneratorFramework.CodeFixers/RemoveOrphanedFixableDiagnosticIdCodeFixProvider.cs @@ -28,8 +28,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) foreach (var diagnostic in context.Diagnostics) { var node = root.FindNode(diagnostic.Location.SourceSpan); - var literal = - node.DescendantNodesAndSelf().OfType().FirstOrDefault() + var literal = node.DescendantNodesAndSelf().OfType().FirstOrDefault() ?? node.FirstAncestorOrSelf(); if (literal is null) continue; diff --git a/src/src/SourceGeneratorFramework.ExampleGenerator/CodeWriterSampleEmitter.cs b/src/src/SourceGeneratorFramework.ExampleGenerator/CodeWriterSampleEmitter.cs index da5139f..e234095 100644 --- a/src/src/SourceGeneratorFramework.ExampleGenerator/CodeWriterSampleEmitter.cs +++ b/src/src/SourceGeneratorFramework.ExampleGenerator/CodeWriterSampleEmitter.cs @@ -98,9 +98,8 @@ options with options => options with { HasSetter = true, Initializer = PurviewTypeLibrary.System.Null } ); - body.HashDefines( - "NET", - conditional => conditional.Comment("This member is emitted only for .NET targets.") + body.HashDefines("NET", conditional => + conditional.Comment("This member is emitted only for .NET targets.") ); using (body.OpenPragmasScope("CS0618")) @@ -167,28 +166,18 @@ options with }, methodBody => { - methodBody.Assignment( - "var hostKitOptions", - expression => - expression.MethodCallChain( - "source.Trim", - [], - chain => chain.Method("ToUpper").Postfix(" ?? string.Empty") - ) + methodBody.Assignment("var hostKitOptions", expression => + expression.MethodCallChain("source.Trim", [], chain => + chain.Method("ToUpper").Postfix(" ?? string.Empty") + ) ); - methodBody.Assignment( - "var", - "optionsBuilder", - expression => - expression.MethodCallChain( - "global::System.Array.Empty", - [], - chain => chain.Method("Clone"), - genericArguments: - [ - new TypeReference(new TypeIdentity("global::System.String", null)), - ] - ) + methodBody.Assignment("var", "optionsBuilder", expression => + expression.MethodCallChain( + "global::System.Array.Empty", + [], + chain => chain.Method("Clone"), + genericArguments: [new TypeReference(new TypeIdentity("global::System.String", null))] + ) ); methodBody.MethodCallOn("onBuilt", "Invoke", [], nullConditional: true); methodBody.Return("hostKitOptions"); @@ -207,14 +196,11 @@ options with }, methodBody => { - methodBody.Assignment( - "var builder", - expression => expression.New("global::System.Text.StringBuilder", "onBuilt") + methodBody.Assignment("var builder", expression => + expression.New("global::System.Text.StringBuilder", "onBuilt") ); - methodBody.Assignment( - "global::System.Text.StringBuilder", - "options", - expression => expression.New(["onBuilt"]) + methodBody.Assignment("global::System.Text.StringBuilder", "options", expression => + expression.New(["onBuilt"]) ); methodBody.Return("options.ToString()"); } diff --git a/src/src/SourceGeneratorFramework.ExampleGenerator/ServiceRegistrationGenerator.cs b/src/src/SourceGeneratorFramework.ExampleGenerator/ServiceRegistrationGenerator.cs index da785e9..d88dde7 100644 --- a/src/src/SourceGeneratorFramework.ExampleGenerator/ServiceRegistrationGenerator.cs +++ b/src/src/SourceGeneratorFramework.ExampleGenerator/ServiceRegistrationGenerator.cs @@ -33,10 +33,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) ); var model = generationContext - .CollectWith( - targets, - static (ctx, targetsArray, _) => - new ServiceRegistrationGenerationModel(ctx, new EquatableArray(targetsArray)) + .CollectWith(targets, static (ctx, targetsArray, _) => + new ServiceRegistrationGenerationModel(ctx, new EquatableArray(targetsArray)) ) .CombineWith(emitServiceInfo, (m, emit, _) => m with { EmitServiceInfo = emit }); diff --git a/src/src/SourceGeneratorFramework.Generators/AttributeDataModelGenerator.cs b/src/src/SourceGeneratorFramework.Generators/AttributeDataModelGenerator.cs index 2744ab2..1395c68 100644 --- a/src/src/SourceGeneratorFramework.Generators/AttributeDataModelGenerator.cs +++ b/src/src/SourceGeneratorFramework.Generators/AttributeDataModelGenerator.cs @@ -29,26 +29,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var outputPipeline = targetPipeline.CombineWithContext(contextPipeline); - context.RegisterSourceOutput( - outputPipeline, - static (spc, outputContext) => - { - var (target, generationContext) = outputContext; + context.RegisterSourceOutput(outputPipeline, static (spc, outputContext) => + { + var (target, generationContext) = outputContext; - if (generationContext.Settings.IsSourceGeneratorDisabled) - { - generationContext.Info("AttributeDataModelGenerator is disabled."); - return; - } + if (generationContext.Settings.IsSourceGeneratorDisabled) + { + generationContext.Info("AttributeDataModelGenerator is disabled."); + return; + } - // Validation diagnostics (ADM0001-ADM0010) are reported by the analyzers; the generator only - // skips processing targets that carry a blocking error. - if (!target.ShouldProcess) - return; + // Validation diagnostics (ADM0001-ADM0010) are reported by the analyzers; the generator only + // skips processing targets that carry a blocking error. + if (!target.ShouldProcess) + return; - GenerateAttributeDataModel(spc, target.Value, generationContext); - } - ); + GenerateAttributeDataModel(spc, target.Value, generationContext); + }); } static void GenerateAttributeDataModel( @@ -230,22 +227,16 @@ static void AllAttributeDataMethod(CodeWriter writer, AttributeDataModelTarget t ], }; - writer.Method( - methodOptions, - body => + writer.Method(methodOptions, body => + { + body.Line("for (var i = 0; i < attributes.Length; i++)"); + body.Block(null, loopBody => { - body.Line("for (var i = 0; i < attributes.Length; i++)"); - body.Block( - null, - loopBody => - { - loopBody.Line("var instance = FromAttributeData(attributes[i]);"); - loopBody.Line("if (instance.Exists)"); - loopBody.Block(null, matchBody => matchBody.Line("yield return (instance, attributes[i]);")); - } - ); - } - ); + loopBody.Line("var instance = FromAttributeData(attributes[i]);"); + loopBody.Line("if (instance.Exists)"); + loopBody.Block(null, matchBody => matchBody.Line("yield return (instance, attributes[i]);")); + }); + }); } static void AllAttributeDataSymbolMethod(CodeWriter writer, AttributeDataModelTarget target) @@ -283,23 +274,17 @@ static void FromAttributeDataArrayMethod(CodeWriter writer, AttributeDataModelTa ], }; - writer.Method( - methodOptions, - w => + writer.Method(methodOptions, w => + { + w.Line("for (var i = 0; i < attributes.Length; i++)"); + w.Block(null, body => { - w.Line("for (var i = 0; i < attributes.Length; i++)"); - w.Block( - null, - body => - { - body.Line("var result = FromAttributeData(attributes[i]);"); - body.Line("if (result.Exists)"); - body.Block(null, inner => inner.Line("return result;")); - } - ); - w.Line("return Empty;"); - } - ); + body.Line("var result = FromAttributeData(attributes[i]);"); + body.Line("if (result.Exists)"); + body.Block(null, inner => inner.Line("return result;")); + }); + w.Line("return Empty;"); + }); } static void FromAttributeDataSymbolMethod(CodeWriter writer, AttributeDataModelTarget target) @@ -354,31 +339,22 @@ static void FromAttributeDataArrayWithOutMethod(CodeWriter writer, AttributeData ], }; - writer.Method( - methodOptions, - w => + writer.Method(methodOptions, w => + { + w.Line("attribute = null;"); + w.Line("for (var i = 0; i < attributes.Length; i++)"); + w.Block(null, body => { - w.Line("attribute = null;"); - w.Line("for (var i = 0; i < attributes.Length; i++)"); - w.Block( - null, - body => - { - body.Line("var result = FromAttributeData(attributes[i]);"); - body.Line("if (result.Exists)"); - body.Block( - null, - inner => - { - inner.Line("attribute = attributes[i];"); - inner.Line("return result;"); - } - ); - } - ); - w.Line("return Empty;"); - } - ); + body.Line("var result = FromAttributeData(attributes[i]);"); + body.Line("if (result.Exists)"); + body.Block(null, inner => + { + inner.Line("attribute = attributes[i];"); + inner.Line("return result;"); + }); + }); + w.Line("return Empty;"); + }); } static void TryFromAttributeDataArrayWithOutMethod(CodeWriter writer, AttributeDataModelTarget target) @@ -406,34 +382,25 @@ static void TryFromAttributeDataArrayWithOutMethod(CodeWriter writer, AttributeD ], }; - writer.Method( - methodOptions, - w => - { - w.Assignment("attributeData", "Empty"); - w.Assignment("attribute", "null"); + writer.Method(methodOptions, w => + { + w.Assignment("attributeData", "Empty"); + w.Assignment("attribute", "null"); - w.Line("for (var i = 0; i < attributes.Length; i++)"); - w.Block( - null, - body => - { - body.Line("var result = FromAttributeData(attributes[i]);"); - body.Line("if (result.Exists)"); - body.Block( - null, - inner => - { - inner.Line("attribute = attributes[i];"); - inner.Line("attributeData = result;"); - inner.Line("return true;"); - } - ); - } - ); - w.Line("return false;"); - } - ); + w.Line("for (var i = 0; i < attributes.Length; i++)"); + w.Block(null, body => + { + body.Line("var result = FromAttributeData(attributes[i]);"); + body.Line("if (result.Exists)"); + body.Block(null, inner => + { + inner.Line("attribute = attributes[i];"); + inner.Line("attributeData = result;"); + inner.Line("return true;"); + }); + }); + w.Line("return false;"); + }); } static void FromAttributeDataSymbolWithOutMethod(CodeWriter writer, AttributeDataModelTarget target) @@ -499,25 +466,22 @@ static void FromAttributeDataMethod(CodeWriter writer, AttributeDataModelTarget Parameters = [new("attributeData", TypeReference("global::Microsoft.CodeAnalysis.AttributeData"))], }; - writer.Method( - methodOptions, - w => + writer.Method(methodOptions, w => + { + if (target.MatchByInheritance) { - if (target.MatchByInheritance) - { - w.Line( - "if (attributeData.AttributeClass is null || (!TargetAttribute.Equals(attributeData.AttributeClass) && !global::Purview.SourceGeneratorFramework.Helpers.TypeHelpers.InheritsFrom(attributeData.AttributeClass, TargetAttribute)))" - ); - } - else - { - w.Line("if (!TargetAttribute.Equals(attributeData.AttributeClass))"); - } - w.Block(null, body => body.Line("return Empty;")); - - w.Return("FromAttributeDataUnchecked(attributeData)"); + w.Line( + "if (attributeData.AttributeClass is null || (!TargetAttribute.Equals(attributeData.AttributeClass) && !global::Purview.SourceGeneratorFramework.Helpers.TypeHelpers.InheritsFrom(attributeData.AttributeClass, TargetAttribute)))" + ); } - ); + else + { + w.Line("if (!TargetAttribute.Equals(attributeData.AttributeClass))"); + } + w.Block(null, body => body.Line("return Empty;")); + + w.Return("FromAttributeDataUnchecked(attributeData)"); + }); } // The extraction body, without the TargetAttribute check. [NestedModel] parameters call this: the outer @@ -542,25 +506,22 @@ static void FromAttributeDataUncheckedMethod(CodeWriter writer, AttributeDataMod .XmlRemarks( "Used to populate a [NestedModel] parameter from the outer model's attribute. The result always has set to , and arguments the attribute does not declare take their mapped default values." ) - .Method( - methodOptions, - w => + .Method(methodOptions, w => + { + foreach (var property in target.Properties) { - foreach (var property in target.Properties) - { - PropertyExtraction(w, property); - } - - List returnValues = ["true"]; - foreach (var property in target.Properties) - { - var value = ToLocalName(property.PropertyName); - returnValues.Add(property.IsNonNullableReferenceType ? value + "!" : value); - } + PropertyExtraction(w, property); + } - w.Line($"return new({string.Join(", ", returnValues)});"); + List returnValues = ["true"]; + foreach (var property in target.Properties) + { + var value = ToLocalName(property.PropertyName); + returnValues.Add(property.IsNonNullableReferenceType ? value + "!" : value); } - ); + + w.Line($"return new({string.Join(", ", returnValues)});"); + }); } static void TryFromAttributeDataMethod(CodeWriter writer, AttributeDataModelTarget target) @@ -579,28 +540,25 @@ static void TryFromAttributeDataMethod(CodeWriter writer, AttributeDataModelTarg ], }; - writer.Method( - methodOptions, - w => + writer.Method(methodOptions, w => + { + w.Assignment("attribute", "Empty"); + if (target.MatchByInheritance) { - w.Assignment("attribute", "Empty"); - if (target.MatchByInheritance) - { - w.Line( - "if (attributeData.AttributeClass is null || (!TargetAttribute.Equals(attributeData.AttributeClass) && !global::Purview.SourceGeneratorFramework.Helpers.TypeHelpers.InheritsFrom(attributeData.AttributeClass, TargetAttribute)))" - ); - } - else - { - w.Line("if (!TargetAttribute.Equals(attributeData.AttributeClass))"); - } - w.Block(null, body => body.Line("return false;")); + w.Line( + "if (attributeData.AttributeClass is null || (!TargetAttribute.Equals(attributeData.AttributeClass) && !global::Purview.SourceGeneratorFramework.Helpers.TypeHelpers.InheritsFrom(attributeData.AttributeClass, TargetAttribute)))" + ); + } + else + { + w.Line("if (!TargetAttribute.Equals(attributeData.AttributeClass))"); + } + w.Block(null, body => body.Line("return false;")); - w.Assignment("attribute", "FromAttributeDataUnchecked(attributeData)"); + w.Assignment("attribute", "FromAttributeDataUnchecked(attributeData)"); - w.Return("attribute.Exists"); - } - ); + w.Return("attribute.Exists"); + }); } static void PropertyExtraction(CodeWriter writer, AttributeDataModelProperty property) diff --git a/src/src/SourceGeneratorFramework.Generators/Helpers/AttributeDataModelLibrary.cs b/src/src/SourceGeneratorFramework.Generators/Helpers/AttributeDataModelLibrary.cs index 3e769be..e948acb 100644 --- a/src/src/SourceGeneratorFramework.Generators/Helpers/AttributeDataModelLibrary.cs +++ b/src/src/SourceGeneratorFramework.Generators/Helpers/AttributeDataModelLibrary.cs @@ -55,13 +55,11 @@ IncrementalGeneratorInitializationContext context ); return attributeCandidates - .CombineWith( - typeLibrarySpecData, - static (structSymbol, specData, _) => (Symbol: structSymbol, Specs: specData) + .CombineWith(typeLibrarySpecData, static (structSymbol, specData, _) => + (Symbol: structSymbol, Specs: specData) ) - .CombineWith( - context.CompilationProvider, - static (pair, compilation, ct) => BuildTarget(pair.Symbol, pair.Specs, compilation, ct) + .CombineWith(context.CompilationProvider, static (pair, compilation, ct) => + BuildTarget(pair.Symbol, pair.Specs, compilation, ct) ) .WithTrackingName("GetAttributeDataTargets"); } @@ -237,20 +235,19 @@ static EquatableArray GetPrimaryConstructorArguments( CancellationToken cancellationToken ) { - var arguments = - structSymbol - .DeclaringSyntaxReferences.Select(reference => reference.GetSyntax(cancellationToken)) - .OfType() - .Select(static declaration => declaration.ParameterList) - .FirstOrDefault(static parameterList => parameterList is not null) - ?.Parameters.Select(parameter => - { - var propertyName = ToPascalCase(parameter.Identifier.ValueText); - return explicitProperties.Any(property => property.PropertyName == propertyName) - ? propertyName - : $"default({parameter.Type})"; - }) - .ToImmutableArray() + var arguments = structSymbol + .DeclaringSyntaxReferences.Select(reference => reference.GetSyntax(cancellationToken)) + .OfType() + .Select(static declaration => declaration.ParameterList) + .FirstOrDefault(static parameterList => parameterList is not null) + ?.Parameters.Select(parameter => + { + var propertyName = ToPascalCase(parameter.Identifier.ValueText); + return explicitProperties.Any(property => property.PropertyName == propertyName) + ? propertyName + : $"default({parameter.Type})"; + }) + .ToImmutableArray() ?? []; return new(arguments); diff --git a/src/src/SourceGeneratorFramework.Generators/Helpers/SourceEmitter.TypeLibrary.cs b/src/src/SourceGeneratorFramework.Generators/Helpers/SourceEmitter.TypeLibrary.cs index cc37516..525e362 100644 --- a/src/src/SourceGeneratorFramework.Generators/Helpers/SourceEmitter.TypeLibrary.cs +++ b/src/src/SourceGeneratorFramework.Generators/Helpers/SourceEmitter.TypeLibrary.cs @@ -51,158 +51,144 @@ static SourceText TypeRefAttribute() return writer .XmlSummary("Declares a type identity member for a generated type library.") - .AttributeClass( - new(GeneratorTypeLibrary.Attributes.TypeRefAttribute), - AttributeTargets.Field, - bodyWriter => - { - bodyWriter - .XmlSummary("Declares a type library member whose type name matches the member name.") - .XmlParam("namespace", "The namespace of the target type.") - .XmlParam("arity", "The generic arity of the target type, or 0 for a non-generic type.") - .XmlParam( - "includeInGetTypes", - "Whether the member is included in the namespace's generated GetTypes() call." - ) - .XmlParam( - "generateFullNameConst", - "Whether the member generates a full name constant; useful for compile-time usage, such as in Attribute Data Model generation." - ) - .Constructor( - new(GeneratorTypeLibrary.Attributes.TypeRefAttribute, TypeDeclarationAccessibility.Public) - { - Parameters = - [ - new("@namespace", PurviewTypeLibrary.System.String), - new("arity", PurviewTypeLibrary.System.Int32) { DefaultValue = "0" }, - new("includeInGetTypes", PurviewTypeLibrary.System.Boolean) - { - DefaultValue = "false", - }, - new("generateFullNameConst", PurviewTypeLibrary.System.Boolean) - { - DefaultValue = "false", - }, - ], - }, - constructorWriter => - constructorWriter - .Assignment("Namespace", "@namespace") - .Assignment("Arity", "arity") - .Assignment("IncludeInGetTypes", "includeInGetTypes") - .Assignment("GenerateFullNameConst", "generateFullNameConst") - ); - - bodyWriter - .XmlSummary("Declares a type library member with an explicit target type.") - .XmlParam("type", "The target type, supplied as a typeof(...) value or a type-name string.") - .XmlParam("namespace", "The namespace of the target type, or null to infer it from the type.") - .XmlParam( - "arity", - "The generic arity of the target type; -1 infers it from the type when possible." - ) - .XmlParam( - "includeInGetTypes", - "Whether the member is included in the namespace's generated GetTypes() call." - ) - .XmlParam( - "generateFullNameConst", - "Whether the member generates a full name constant; useful for compile-time usage, such as in Attribute Data Model generation." - ) - .Constructor( - new(GeneratorTypeLibrary.Attributes.TypeRefAttribute, TypeDeclarationAccessibility.Public) - { - Parameters = - [ - new("type", PurviewTypeLibrary.System.Object.MakeNullable()), - new("@namespace", PurviewTypeLibrary.System.String.MakeNullable()) - { - DefaultValue = "null", - }, - new("arity", PurviewTypeLibrary.System.Int32) { DefaultValue = "-1" }, - new("includeInGetTypes", PurviewTypeLibrary.System.Boolean) - { - DefaultValue = "false", - }, - new("generateFullNameConst", PurviewTypeLibrary.System.Boolean) - { - DefaultValue = "false", - }, - ], - }, - constructorWriter => - constructorWriter - .Assignment("TargetType", "type") - .Assignment("Namespace", "@namespace") - .Assignment("Arity", "arity") - .Assignment("IncludeInGetTypes", "includeInGetTypes") - .Assignment("GenerateFullNameConst", "generateFullNameConst") - ); + .AttributeClass(new(GeneratorTypeLibrary.Attributes.TypeRefAttribute), AttributeTargets.Field, bodyWriter => + { + bodyWriter + .XmlSummary("Declares a type library member whose type name matches the member name.") + .XmlParam("namespace", "The namespace of the target type.") + .XmlParam("arity", "The generic arity of the target type, or 0 for a non-generic type.") + .XmlParam( + "includeInGetTypes", + "Whether the member is included in the namespace's generated GetTypes() call." + ) + .XmlParam( + "generateFullNameConst", + "Whether the member generates a full name constant; useful for compile-time usage, such as in Attribute Data Model generation." + ) + .Constructor( + new(GeneratorTypeLibrary.Attributes.TypeRefAttribute, TypeDeclarationAccessibility.Public) + { + Parameters = + [ + new("@namespace", PurviewTypeLibrary.System.String), + new("arity", PurviewTypeLibrary.System.Int32) { DefaultValue = "0" }, + new("includeInGetTypes", PurviewTypeLibrary.System.Boolean) { DefaultValue = "false" }, + new("generateFullNameConst", PurviewTypeLibrary.System.Boolean) + { + DefaultValue = "false", + }, + ], + }, + constructorWriter => + constructorWriter + .Assignment("Namespace", "@namespace") + .Assignment("Arity", "arity") + .Assignment("IncludeInGetTypes", "includeInGetTypes") + .Assignment("GenerateFullNameConst", "generateFullNameConst") + ); - bodyWriter - .XmlSummary("Gets the target type.") - .Property( - "TargetType", - PurviewTypeLibrary.System.Object.MakeNullable(), - TypeDeclarationAccessibility.Public - ); + bodyWriter + .XmlSummary("Declares a type library member with an explicit target type.") + .XmlParam("type", "The target type, supplied as a typeof(...) value or a type-name string.") + .XmlParam("namespace", "The namespace of the target type, or null to infer it from the type.") + .XmlParam( + "arity", + "The generic arity of the target type; -1 infers it from the type when possible." + ) + .XmlParam( + "includeInGetTypes", + "Whether the member is included in the namespace's generated GetTypes() call." + ) + .XmlParam( + "generateFullNameConst", + "Whether the member generates a full name constant; useful for compile-time usage, such as in Attribute Data Model generation." + ) + .Constructor( + new(GeneratorTypeLibrary.Attributes.TypeRefAttribute, TypeDeclarationAccessibility.Public) + { + Parameters = + [ + new("type", PurviewTypeLibrary.System.Object.MakeNullable()), + new("@namespace", PurviewTypeLibrary.System.String.MakeNullable()) + { + DefaultValue = "null", + }, + new("arity", PurviewTypeLibrary.System.Int32) { DefaultValue = "-1" }, + new("includeInGetTypes", PurviewTypeLibrary.System.Boolean) { DefaultValue = "false" }, + new("generateFullNameConst", PurviewTypeLibrary.System.Boolean) + { + DefaultValue = "false", + }, + ], + }, + constructorWriter => + constructorWriter + .Assignment("TargetType", "type") + .Assignment("Namespace", "@namespace") + .Assignment("Arity", "arity") + .Assignment("IncludeInGetTypes", "includeInGetTypes") + .Assignment("GenerateFullNameConst", "generateFullNameConst") + ); - bodyWriter - .XmlSummary("Gets or sets the namespace of the target type.") - .Property( - new( - "Namespace", - PurviewTypeLibrary.System.String.MakeNullable(), - TypeDeclarationAccessibility.Public - ) - { - IsInitOnly = true, - } - ); + bodyWriter + .XmlSummary("Gets the target type.") + .Property( + "TargetType", + PurviewTypeLibrary.System.Object.MakeNullable(), + TypeDeclarationAccessibility.Public + ); - bodyWriter - .XmlSummary( - "Gets or sets the generic arity of the target type; -1 infers it from the type when possible." + bodyWriter + .XmlSummary("Gets or sets the namespace of the target type.") + .Property( + new( + "Namespace", + PurviewTypeLibrary.System.String.MakeNullable(), + TypeDeclarationAccessibility.Public ) - .Property( - new("Arity", PurviewTypeLibrary.System.Int32, TypeDeclarationAccessibility.Public) - { - IsInitOnly = true, - } - ); + { + IsInitOnly = true, + } + ); - bodyWriter - .XmlSummary( - "Gets or sets whether the member is included in the namespace's generated GetTypes() call." - ) - .Property( - new( - "IncludeInGetTypes", - PurviewTypeLibrary.System.Boolean, - TypeDeclarationAccessibility.Public - ) - { - IsInitOnly = true, - } - ); + bodyWriter + .XmlSummary( + "Gets or sets the generic arity of the target type; -1 infers it from the type when possible." + ) + .Property( + new("Arity", PurviewTypeLibrary.System.Int32, TypeDeclarationAccessibility.Public) + { + IsInitOnly = true, + } + ); - bodyWriter - .XmlSummary("Gets or sets whether the member generates a full name constant.") - .XmlRemarks( - "This can be useful for compile-time usage, such as in Attribute Data Model generation." + bodyWriter + .XmlSummary( + "Gets or sets whether the member is included in the namespace's generated GetTypes() call." + ) + .Property( + new("IncludeInGetTypes", PurviewTypeLibrary.System.Boolean, TypeDeclarationAccessibility.Public) + { + IsInitOnly = true, + } + ); + + bodyWriter + .XmlSummary("Gets or sets whether the member generates a full name constant.") + .XmlRemarks( + "This can be useful for compile-time usage, such as in Attribute Data Model generation." + ) + .Property( + new( + "GenerateFullNameConst", + PurviewTypeLibrary.System.Boolean, + TypeDeclarationAccessibility.Public ) - .Property( - new( - "GenerateFullNameConst", - PurviewTypeLibrary.System.Boolean, - TypeDeclarationAccessibility.Public - ) - { - IsInitOnly = true, - } - ); - } - ); + { + IsInitOnly = true, + } + ); + }); } static SourceText EnumValueAttribute() diff --git a/src/src/SourceGeneratorFramework.Generators/Helpers/TypeLibraryModelLibrary.cs b/src/src/SourceGeneratorFramework.Generators/Helpers/TypeLibraryModelLibrary.cs index 9e6b3f9..e92d9f8 100644 --- a/src/src/SourceGeneratorFramework.Generators/Helpers/TypeLibraryModelLibrary.cs +++ b/src/src/SourceGeneratorFramework.Generators/Helpers/TypeLibraryModelLibrary.cs @@ -278,8 +278,7 @@ CancellationToken cancellationToken /// static bool GetIncludeInGetTypes(AttributeData typeRef) { - var named = - GetNamedArgument(typeRef, "IncludeInGetTypes", (bool?)null) + var named = GetNamedArgument(typeRef, "IncludeInGetTypes", (bool?)null) ?? GetNamedArgument(typeRef, "includeInGetTypes", (bool?)null); if (named is not null) return named.Value; @@ -303,8 +302,7 @@ static bool GetIncludeInGetTypes(AttributeData typeRef) /// static bool GetGenerateFullNameConstant(AttributeData typeRef) { - var named = - GetNamedArgument(typeRef, "GenerateFullNameConst", (bool?)null) + var named = GetNamedArgument(typeRef, "GenerateFullNameConst", (bool?)null) ?? GetNamedArgument(typeRef, "generateFullNameConst", (bool?)null); if (named is not null) return named.Value; @@ -1183,8 +1181,9 @@ List diagnostics } #pragma warning restore format - var resolvedNamespace = - namedNamespace ?? GetConstructorArgument(typeRef, 1, (string?)null) ?? inferredNamespace; + var resolvedNamespace = namedNamespace + ?? GetConstructorArgument(typeRef, 1, (string?)null) + ?? inferredNamespace; if (string.IsNullOrWhiteSpace(resolvedNamespace)) { diagnostics.Add( diff --git a/src/src/SourceGeneratorFramework.Generators/TypeLibraryGenerator.cs b/src/src/SourceGeneratorFramework.Generators/TypeLibraryGenerator.cs index 886af21..4524751 100644 --- a/src/src/SourceGeneratorFramework.Generators/TypeLibraryGenerator.cs +++ b/src/src/SourceGeneratorFramework.Generators/TypeLibraryGenerator.cs @@ -25,26 +25,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var outputPipeline = targetPipeline.CombineWithContext(contextPipeline); - context.RegisterSourceOutput( - outputPipeline, - static (spc, outputContext) => - { - var (target, generationContext) = outputContext; + context.RegisterSourceOutput(outputPipeline, static (spc, outputContext) => + { + var (target, generationContext) = outputContext; - if (generationContext.Settings.IsSourceGeneratorDisabled) - { - generationContext.Info("TypeLibraryGenerator is disabled."); - return; - } + if (generationContext.Settings.IsSourceGeneratorDisabled) + { + generationContext.Info("TypeLibraryGenerator is disabled."); + return; + } - // Validation diagnostics (TLB0001-TLB0010) are reported by the analyzers; the generator - // only skips processing targets that carry a blocking error. - if (!target.ShouldProcess) - return; + // Validation diagnostics (TLB0001-TLB0010) are reported by the analyzers; the generator + // only skips processing targets that carry a blocking error. + if (!target.ShouldProcess) + return; - GenerateTypeLibrary(spc, target.Value, generationContext); - } - ); + GenerateTypeLibrary(spc, target.Value, generationContext); + }); } static void GenerateTypeLibrary( diff --git a/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/DiagnosticAssertions.cs b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/DiagnosticAssertions.cs index bd8ab8f..5056f03 100644 --- a/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/DiagnosticAssertions.cs +++ b/src/src/SourceGeneratorFramework.Testing.TUnit/Assertions/DiagnosticAssertions.cs @@ -51,8 +51,7 @@ DiagnosticDescriptor expected if (expected is null) return AssertionResult.Failed($"expected {nameof(DiagnosticDescriptor)} is null"); - var matchingDiagnostic = - diagnostic.DriverResult.Diagnostics.FirstOrDefault(d => d.Id == expected.Id) + var matchingDiagnostic = diagnostic.DriverResult.Diagnostics.FirstOrDefault(d => d.Id == expected.Id) ?? diagnostic.AnalyzerResult?.Diagnostics.FirstOrDefault(d => d.Id == expected.Id); return matchingDiagnostic is null ? (AssertionResult) @@ -111,8 +110,7 @@ public static AssertionResult HasDiagnostic(this DriverRunResult dia if (string.IsNullOrWhiteSpace(expected)) return AssertionResult.Failed($"expected {nameof(DiagnosticDescriptor.Id)} is null/ empty/ whitespace"); - var matchedDiagnotics = - diagnostic.DriverResult.Diagnostics.FirstOrDefault(d => d.Id == expected) + var matchedDiagnotics = diagnostic.DriverResult.Diagnostics.FirstOrDefault(d => d.Id == expected) ?? diagnostic.AnalyzerResult?.Diagnostics.FirstOrDefault(d => d.Id == expected); ; return matchedDiagnotics is null diff --git a/src/src/SourceGeneratorFramework.Testing/AttributeDataFactory.cs b/src/src/SourceGeneratorFramework.Testing/AttributeDataFactory.cs index ba075a2..b41f3da 100644 --- a/src/src/SourceGeneratorFramework.Testing/AttributeDataFactory.cs +++ b/src/src/SourceGeneratorFramework.Testing/AttributeDataFactory.cs @@ -142,8 +142,7 @@ public static ImmutableArray FromSource( var compilation = Compile(source, options ?? SourceGeneratorTestOptions.Default); ThrowOnErrors(compilation, null); - var type = - compilation.GetTypeByMetadataName(typeMetadataName) + var type = compilation.GetTypeByMetadataName(typeMetadataName) ?? throw new InvalidOperationException($"Type '{typeMetadataName}' was not found in the compilation."); if (memberName is null) diff --git a/src/src/SourceGeneratorFramework.Testing/CodeFixTestRunner.cs b/src/src/SourceGeneratorFramework.Testing/CodeFixTestRunner.cs index 40fb100..ba81e11 100644 --- a/src/src/SourceGeneratorFramework.Testing/CodeFixTestRunner.cs +++ b/src/src/SourceGeneratorFramework.Testing/CodeFixTestRunner.cs @@ -24,24 +24,20 @@ public async Task RunAsync( { options ??= new(); using var testProject = CreateProject([source], options, typeof(TAnalyzer).Assembly); - var compilation = - await testProject.Project.GetCompilationAsync(cancellationToken) + var compilation = await testProject.Project.GetCompilationAsync(cancellationToken) ?? throw new InvalidOperationException("Unable to create the test compilation."); var diagnostics = await WithAnalyzers(compilation, [new TAnalyzer()], options) .GetAnalyzerDiagnosticsAsync(cancellationToken); - var diagnostic = - diagnostics.FirstOrDefault(diagnostic => diagnostic.Location.IsInSource) + var diagnostic = diagnostics.FirstOrDefault(diagnostic => diagnostic.Location.IsInSource) ?? throw new InvalidOperationException("The analyzer did not report a source diagnostic."); var document = testProject.Project.Solution.GetDocument(testProject.DocumentIds[0])!; var actions = RegisterActions(document, diagnostic, cancellationToken); var action = SelectAction(actions, options); var operations = await action.GetOperationsAsync(cancellationToken); - var changedSolution = - operations.OfType().SingleOrDefault()?.ChangedSolution + var changedSolution = operations.OfType().SingleOrDefault()?.ChangedSolution ?? throw new InvalidOperationException("The code action did not produce an ApplyChangesOperation."); - var changedDocument = - changedSolution.GetDocument(document.Id) + var changedDocument = changedSolution.GetDocument(document.Id) ?? throw new InvalidOperationException("The code action removed the source document."); var fixedSource = (await changedDocument.GetTextAsync(cancellationToken)).ToString(); @@ -60,8 +56,7 @@ public async Task RunFixAllAsync( { options ??= new(); using var testProject = CreateProject(sources, options, typeof(TAnalyzer).Assembly); - var compilation = - await testProject.Project.GetCompilationAsync(cancellationToken) + var compilation = await testProject.Project.GetCompilationAsync(cancellationToken) ?? throw new InvalidOperationException("Unable to create the test compilation."); var diagnostics = await WithAnalyzers(compilation, [new TAnalyzer()], options) .GetAnalyzerDiagnosticsAsync(cancellationToken); @@ -70,20 +65,22 @@ await testProject.Project.GetCompilationAsync(cancellationToken) throw new InvalidOperationException("The analyzer did not report a source diagnostic."); var firstDiagnostic = sourceDiagnostics[0]; - var document = - await GetDocumentForDiagnosticAsync(testProject, firstDiagnostic, cancellationToken) + var document = await GetDocumentForDiagnosticAsync(testProject, firstDiagnostic, cancellationToken) ?? throw new InvalidOperationException("Unable to locate the document containing the diagnostic."); var actions = RegisterActions(document, firstDiagnostic, cancellationToken); var action = SelectAction(actions, options); TCodeFix codeFixProvider = new(); - var fixAllAction = - await RunFixAllProviderAsync(document, codeFixProvider, action, sourceDiagnostics, cancellationToken) - ?? throw new InvalidOperationException("The FixAllProvider did not produce a code action."); + var fixAllAction = await RunFixAllProviderAsync( + document, + codeFixProvider, + action, + sourceDiagnostics, + cancellationToken + ) ?? throw new InvalidOperationException("The FixAllProvider did not produce a code action."); var operations = await fixAllAction.GetOperationsAsync(cancellationToken); - var changedSolution = - operations.OfType().SingleOrDefault()?.ChangedSolution + var changedSolution = operations.OfType().SingleOrDefault()?.ChangedSolution ?? throw new InvalidOperationException("The fix-all action did not produce an ApplyChangesOperation."); var fixedSources = ImmutableDictionary.CreateBuilder(); @@ -107,8 +104,7 @@ await RunFixAllProviderAsync(document, codeFixProvider, action, sourceDiagnostic CancellationToken cancellationToken ) { - var fixAllProvider = - codeFixProvider.GetFixAllProvider() + var fixAllProvider = codeFixProvider.GetFixAllProvider() ?? throw new InvalidOperationException("The code fix provider has no FixAllProvider."); FixAllContext fixAllContext = new( diff --git a/src/src/SourceGeneratorFramework.Testing/CodeQuery.Declarations.cs b/src/src/SourceGeneratorFramework.Testing/CodeQuery.Declarations.cs index f2f14be..f0ae5cd 100644 --- a/src/src/SourceGeneratorFramework.Testing/CodeQuery.Declarations.cs +++ b/src/src/SourceGeneratorFramework.Testing/CodeQuery.Declarations.cs @@ -516,20 +516,16 @@ public bool HasConstructor(string containingTypeName) => /// Gets a namespace declaration (block or file-scoped) by its dotted name. /// public CodeQueryResult GetNamespace(string name) => - FindByName( - name, - null, - namespaceDeclaration => namespaceDeclaration.Name.ToString() + FindByName(name, null, namespaceDeclaration => + namespaceDeclaration.Name.ToString() ); /// /// Determines whether a namespace declaration with the given dotted name exists. /// public bool HasNamespace(string name) => - HasByName( - name, - null, - namespaceDeclaration => namespaceDeclaration.Name.ToString() + HasByName(name, null, namespaceDeclaration => + namespaceDeclaration.Name.ToString() ); // --------------------------------------------------------------------------------------------- diff --git a/src/src/SourceGeneratorFramework.Testing/DiagnosticAnalyzerTestRunner.cs b/src/src/SourceGeneratorFramework.Testing/DiagnosticAnalyzerTestRunner.cs index c153c42..8c50f70 100644 --- a/src/src/SourceGeneratorFramework.Testing/DiagnosticAnalyzerTestRunner.cs +++ b/src/src/SourceGeneratorFramework.Testing/DiagnosticAnalyzerTestRunner.cs @@ -28,8 +28,7 @@ public async Task RunAsync( { options ??= new(); using var testProject = CreateProject(sources, options, typeof(TAnalyzer).Assembly); - var compilation = - await testProject.Project.GetCompilationAsync(cancellationToken) + var compilation = await testProject.Project.GetCompilationAsync(cancellationToken) ?? throw new InvalidOperationException("Unable to create the test compilation."); var diagnostics = await WithAnalyzers(compilation, [new TAnalyzer()], options) .GetAnalyzerDiagnosticsAsync(cancellationToken); diff --git a/src/src/SourceGeneratorFramework.Testing/DriverRunResultExtensions.cs b/src/src/SourceGeneratorFramework.Testing/DriverRunResultExtensions.cs index 6ee63f7..45f957d 100644 --- a/src/src/SourceGeneratorFramework.Testing/DriverRunResultExtensions.cs +++ b/src/src/SourceGeneratorFramework.Testing/DriverRunResultExtensions.cs @@ -100,8 +100,7 @@ public static string AssertSingleGeneratedSource(this DriverRunResult result) if (result == null) throw new ArgumentNullException(nameof(result)); - var tree = - result.PrimarySyntaxTrees.SingleOrDefault() + var tree = result.PrimarySyntaxTrees.SingleOrDefault() ?? throw new InvalidOperationException("Expected a single generated source but found none."); return tree.GetText().ToString(); diff --git a/src/src/SourceGeneratorFramework.Testing/RefactoringTestRunner.cs b/src/src/SourceGeneratorFramework.Testing/RefactoringTestRunner.cs index d58ec4e..c7ac5de 100644 --- a/src/src/SourceGeneratorFramework.Testing/RefactoringTestRunner.cs +++ b/src/src/SourceGeneratorFramework.Testing/RefactoringTestRunner.cs @@ -32,12 +32,10 @@ public async Task RunAsync( { options ??= new(); using var testProject = CreateProject(sources, options, typeof(TRefactoring).Assembly); - var compilation = - await testProject.Project.GetCompilationAsync(cancellationToken) + var compilation = await testProject.Project.GetCompilationAsync(cancellationToken) ?? throw new InvalidOperationException("Unable to create the test compilation."); - var document = - testProject.Project.Solution.GetDocument(testProject.DocumentIds[0]) + var document = testProject.Project.Solution.GetDocument(testProject.DocumentIds[0]) ?? throw new InvalidOperationException("Unable to locate the test document."); var span = ResolveSpan(options, compilation); @@ -46,16 +44,14 @@ await testProject.Project.GetCompilationAsync(cancellationToken) CodeRefactoringContext context = new(document, span, actions.Add, cancellationToken); await new TRefactoring().ComputeRefactoringsAsync(context); - var action = - ( - options.EquivalenceKey is null - ? actions.ElementAtOrDefault(options.CodeActionIndex) - : actions.FirstOrDefault(candidate => candidate.EquivalenceKey == options.EquivalenceKey) - ) ?? throw new InvalidOperationException("The requested refactoring was not registered."); + var action = ( + options.EquivalenceKey is null + ? actions.ElementAtOrDefault(options.CodeActionIndex) + : actions.FirstOrDefault(candidate => candidate.EquivalenceKey == options.EquivalenceKey) + ) ?? throw new InvalidOperationException("The requested refactoring was not registered."); var operations = await action.GetOperationsAsync(cancellationToken); - var changedSolution = - operations.OfType().SingleOrDefault()?.ChangedSolution + var changedSolution = operations.OfType().SingleOrDefault()?.ChangedSolution ?? throw new InvalidOperationException("The refactoring did not produce an ApplyChangesOperation."); var fixedSources = ImmutableDictionary.CreateBuilder(); diff --git a/src/src/SourceGeneratorFramework.Testing/SourceGeneratorTestRunner.cs b/src/src/SourceGeneratorFramework.Testing/SourceGeneratorTestRunner.cs index 542f337..7ce7385 100644 --- a/src/src/SourceGeneratorFramework.Testing/SourceGeneratorTestRunner.cs +++ b/src/src/SourceGeneratorFramework.Testing/SourceGeneratorTestRunner.cs @@ -417,28 +417,25 @@ static readonly ConcurrentDictionary< static Func, IDisposable>? GetEmbeddedSinkRegistration(Assembly generatorAssembly) { - return EmbeddedSinkRegistrationCache.GetOrAdd( - generatorAssembly, - static assembly => - { - var embeddedLoggingType = assembly.GetType( - "Purview.SourceGeneratorFramework.Logging.SourceGenLogging", - throwOnError: false - ); - if (embeddedLoggingType is null || embeddedLoggingType == typeof(SourceGenLogging)) - return null; + return EmbeddedSinkRegistrationCache.GetOrAdd(generatorAssembly, static assembly => + { + var embeddedLoggingType = assembly.GetType( + "Purview.SourceGeneratorFramework.Logging.SourceGenLogging", + throwOnError: false + ); + if (embeddedLoggingType is null || embeddedLoggingType == typeof(SourceGenLogging)) + return null; - var registerSink = embeddedLoggingType.GetMethod( - "RegisterSinkCore", - BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic - ); + var registerSink = embeddedLoggingType.GetMethod( + "RegisterSinkCore", + BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic + ); - return registerSink is null - ? null - : (Func, IDisposable>) - Delegate.CreateDelegate(typeof(Func, IDisposable>), registerSink); - } - ); + return registerSink is null + ? null + : (Func, IDisposable>) + Delegate.CreateDelegate(typeof(Func, IDisposable>), registerSink); + }); } sealed class LoggingRegistrations(List registrations) : IDisposable diff --git a/src/src/SourceGeneratorFramework/Helpers/EmbeddedResourceHelper.cs b/src/src/SourceGeneratorFramework/Helpers/EmbeddedResourceHelper.cs index 441f923..1d9733b 100644 --- a/src/src/SourceGeneratorFramework/Helpers/EmbeddedResourceHelper.cs +++ b/src/src/SourceGeneratorFramework/Helpers/EmbeddedResourceHelper.cs @@ -27,8 +27,7 @@ public static Stream LoadStream(string resourceName, Assembly? assembly = null) assembly ??= Assembly.GetCallingAssembly(); var resolvedName = ResolveResourceName(resourceName, assembly); - var stream = - assembly.GetManifestResourceStream(resolvedName) + var stream = assembly.GetManifestResourceStream(resolvedName) ?? throw new InvalidOperationException( $"Embedded resource '{resolvedName}' was not found in assembly '{assembly.FullName}'." ); diff --git a/src/src/SourceGeneratorShared/CodeWriter.cs b/src/src/SourceGeneratorShared/CodeWriter.cs index 0faa088..c61b734 100644 --- a/src/src/SourceGeneratorShared/CodeWriter.cs +++ b/src/src/SourceGeneratorShared/CodeWriter.cs @@ -1836,14 +1836,11 @@ public CodeWriter Enum(TypeDeclarationOptions declaration, params EnumFieldDecla for (var index = 0; index < fields.Length; index++) ValidateEnumFieldDeclaration(fields[index]); - return Enum( - declaration, - body => - { - for (var index = 0; index < fields.Length; index++) - body.EnumField(fields[index]); - } - ); + return Enum(declaration, body => + { + for (var index = 0; index < fields.Length; index++) + body.EnumField(fields[index]); + }); } /// @@ -4295,8 +4292,7 @@ or TypeDeclarationKind.RecordClass for (var typeIndex = 0; typeIndex < declaration.GenericTypes.Length; typeIndex++) { - var genericType = - declaration.GenericTypes[typeIndex] + var genericType = declaration.GenericTypes[typeIndex] ?? throw new ArgumentException( "Generic type parameters cannot contain null values.", nameof(declaration) diff --git a/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalGeneratorInitializationContextExtensions.cs b/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalGeneratorInitializationContextExtensions.cs index 430ec08..96ac364 100644 --- a/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalGeneratorInitializationContextExtensions.cs +++ b/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalGeneratorInitializationContextExtensions.cs @@ -96,28 +96,25 @@ public IncrementalGeneratorInitializationContext RegisterSourceOutput (Output: output, Context: ctx)) .WithTrackingName(trackingName ?? $"RegisterSourceOutput_{typeof(TOutput).Name}"); - context.RegisterSourceOutput( - combined, - (spc, item) => - { - if (item.Output.HasDiagnostics) - spc.ReportDiagnostics(item.Output.Diagnostics); + context.RegisterSourceOutput(combined, (spc, item) => + { + if (item.Output.HasDiagnostics) + spc.ReportDiagnostics(item.Output.Diagnostics); - if (!item.Output.ShouldProcess) - return; + if (!item.Output.ShouldProcess) + return; - // Guarded rather than called directly: an exception escaping here is a CS8785 that - // discards every file this generator produced for the compilation, so the consumer sees - // a wall of "type or namespace not found" on top of a stack trace through code they do - // not own. Reported as a diagnostic instead, the rest of the output still arrives. - ComponentGuard.Run( - spc, - ComponentGuard.ResolveComponentType(generate, typeof(TOutput)), - () => generate(spc, item.Output.Value, item.Context), - item.Context.Settings?.FailureOptions - ); - } - ); + // Guarded rather than called directly: an exception escaping here is a CS8785 that + // discards every file this generator produced for the compilation, so the consumer sees + // a wall of "type or namespace not found" on top of a stack trace through code they do + // not own. Reported as a diagnostic instead, the rest of the output still arrives. + ComponentGuard.Run( + spc, + ComponentGuard.ResolveComponentType(generate, typeof(TOutput)), + () => generate(spc, item.Output.Value, item.Context), + item.Context.Settings?.FailureOptions + ); + }); return context; } diff --git a/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalValueProviderExtensions.cs b/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalValueProviderExtensions.cs index 14396f3..ddf8ec0 100644 --- a/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalValueProviderExtensions.cs +++ b/src/src/SourceGeneratorShared/Extensions/Microsoft/CodeAnalysis/IncrementalValueProviderExtensions.cs @@ -126,9 +126,8 @@ IncrementalValueProvider contextProvider ) where TOutput : notnull { - return valuesProvider.CombineWith( - contextProvider, - static (output, generationContext, _) => (output, generationContext) + return valuesProvider.CombineWith(contextProvider, static (output, generationContext, _) => + (output, generationContext) ); } } diff --git a/src/src/SourceGeneratorShared/Helpers/IncrementalPipeline.cs b/src/src/SourceGeneratorShared/Helpers/IncrementalPipeline.cs index c4e534e..b29a8b7 100644 --- a/src/src/SourceGeneratorShared/Helpers/IncrementalPipeline.cs +++ b/src/src/SourceGeneratorShared/Helpers/IncrementalPipeline.cs @@ -105,8 +105,8 @@ public static IncrementalValueProvider< ValidateCodeWriterScopes = configuration.ValidateCodeWriterScopes, IsSourceGeneratorDisabled = configuration.IsSourceGeneratorDisabled, IsLoggingEnabled = logger is not null, - IsNullableContextEnabled = - settings.IsNullableContextEnabled ?? IsNullableContextEnabled(compilation), + IsNullableContextEnabled = settings.IsNullableContextEnabled + ?? IsNullableContextEnabled(compilation), LanguageVersion = configuration.LanguageVersion ?? settings.LanguageVersion, }; diff --git a/src/src/SourceGeneratorShared/Helpers/IncrementalPipelineExtensions.cs b/src/src/SourceGeneratorShared/Helpers/IncrementalPipelineExtensions.cs index f64af17..b0a9b75 100644 --- a/src/src/SourceGeneratorShared/Helpers/IncrementalPipelineExtensions.cs +++ b/src/src/SourceGeneratorShared/Helpers/IncrementalPipelineExtensions.cs @@ -44,10 +44,8 @@ public static IncrementalValueProvider< IncrementalGeneratorInitializationContext context, GenerationSettings settings ) => - IncrementalPipeline.GenerationContextValueProvider( - context, - settings, - static (_, _, _, _) => EmptyCapabilities.Instance + IncrementalPipeline.GenerationContextValueProvider(context, settings, static (_, _, _, _) => + EmptyCapabilities.Instance ); /// diff --git a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/FixtureGenerator.cs b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/FixtureGenerator.cs index ca7e9ad..0fbf64f 100644 --- a/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/FixtureGenerator.cs +++ b/src/tests/Fixtures/Purview.ComponentClosureFixture/Fixture.Generator/FixtureGenerator.cs @@ -16,25 +16,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var disabled = IncrementalPipeline.IsDisabledValueProvider(context, "Fixture_Disable"); - context.RegisterSourceOutput( - disabled, - static (output, isDisabled) => - { - if (isDisabled) - return; + context.RegisterSourceOutput(disabled, static (output, isDisabled) => + { + if (isDisabled) + return; - output.AddSource( - "Fixture.Generator.Marker.g.cs", - "// \n" - + "namespace Fixture.Generator.Generated;\n\n" - + "internal static class Marker\n" - + "{\n" - + "\tinternal const string DiagnosticId = \"" - + FixtureComponentDiagnostics.DiagnosticId - + "\";\n" - + "}\n" - ); - } - ); + output.AddSource( + "Fixture.Generator.Marker.g.cs", + "// \n" + + "namespace Fixture.Generator.Generated;\n\n" + + "internal static class Marker\n" + + "{\n" + + "\tinternal const string DiagnosticId = \"" + + FixtureComponentDiagnostics.DiagnosticId + + "\";\n" + + "}\n" + ); + }); } } diff --git a/src/tests/SourceGeneratorFramework.UnitTests/TestingFrameworkTests.cs b/src/tests/SourceGeneratorFramework.UnitTests/TestingFrameworkTests.cs index 02ab996..7ae2c02 100644 --- a/src/tests/SourceGeneratorFramework.UnitTests/TestingFrameworkTests.cs +++ b/src/tests/SourceGeneratorFramework.UnitTests/TestingFrameworkTests.cs @@ -30,12 +30,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context) (ctx, _) => ctx.TargetSymbol.Name ); - context.RegisterSourceOutput( - provider, - static (spc, name) => - spc.AddSource( - $"{name}.g.cs", - $@" + context.RegisterSourceOutput(provider, static (spc, name) => spc.AddSource( + $"{name}.g.cs", + $@" namespace Test {{ public static class Generated_{name} @@ -44,8 +41,7 @@ public static class Generated_{name} }} }} " - ) - ); + )); } } @@ -90,21 +86,17 @@ out var value } ); - context.RegisterSourceOutput( - validationValue, - static (output, value) => - output.AddSource( - "ScopeValidation.g.cs", - $"internal static class ScopeValidation {{ internal const string Value = \"{value}\"; }}" - ) + context.RegisterSourceOutput(validationValue, static (output, value) => + output.AddSource( + "ScopeValidation.g.cs", + $"internal static class ScopeValidation {{ internal const string Value = \"{value}\"; }}" + ) ); - context.RegisterSourceOutput( - customValue, - static (output, value) => - output.AddSource( - "CustomOption.g.cs", - $"internal static class CustomOption {{ internal const string Value = \"{value}\"; }}" - ) + context.RegisterSourceOutput(customValue, static (output, value) => + output.AddSource( + "CustomOption.g.cs", + $"internal static class CustomOption {{ internal const string Value = \"{value}\"; }}" + ) ); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs b/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs index 266f7c5..7ff5165 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs @@ -1127,9 +1127,8 @@ public async Task Enum_WithEmbeddedAttributeDisabled_OmitsEmbeddedAttribute() { var writer = CodeWriterFactory.ForTests(); - writer.Enum( - new TypeDeclarationOptions("Status") { IncludeEmbeddedAttribute = false }, - body => body.EnumField(new EnumFieldDeclarationOptions("Ready", 1)) + writer.Enum(new TypeDeclarationOptions("Status") { IncludeEmbeddedAttribute = false }, body => + body.EnumField(new EnumFieldDeclarationOptions("Ready", 1)) ); await Assert.That(writer.ToString()).DoesNotContain("[global::Microsoft.CodeAnalysis.Embedded]"); @@ -2128,16 +2127,11 @@ public async Task Block_WithBodyAndCustomSeparators_WritesDelimitedBody() var writer = CodeWriterFactory.ForTests(); // Act - writer.DelimitedBlock( - "Create", - "(", - ");", - body => - { - body.Quote("value").Line(","); - body.Line("EmptyPath"); - } - ); + writer.DelimitedBlock("Create", "(", ");", body => + { + body.Quote("value").Line(","); + body.Line("EmptyPath"); + }); // Assert await Assert.That(writer.ToString()).IsEqualTo("Create\n(\n\t\"value\",\n\tEmptyPath\n);\n"); @@ -2322,16 +2316,13 @@ public async Task Assignment_WithMethodCallChainRootGenericArguments_WritesChain { var writer = CodeWriterFactory.ForTests(); - writer.Assignment( - "var", - "optionsBuilder", - expression => - expression.MethodCallChain( - "builder.Services.AddOptions", - [], - chain => chain.Method("BindConfiguration", ["\"Purview.SectionName\""]), - genericArguments: [Type("Options")] - ) + writer.Assignment("var", "optionsBuilder", expression => + expression.MethodCallChain( + "builder.Services.AddOptions", + [], + chain => chain.Method("BindConfiguration", ["\"Purview.SectionName\""]), + genericArguments: [Type("Options")] + ) ); await Assert @@ -2346,10 +2337,8 @@ public async Task MethodCallChain_WritesChainedInvocations() { var writer = CodeWriterFactory.ForTests(); - writer.MethodCallChain( - "builder.Configuration.GetSection", - ["x.SectionName"], - chain => chain.Method("Get", genericArguments: [Type("Options")]).Postfix(" ?? new()") + writer.MethodCallChain("builder.Configuration.GetSection", ["x.SectionName"], chain => + chain.Method("Get", genericArguments: [Type("Options")]).Postfix(" ?? new()") ); await Assert @@ -2362,14 +2351,10 @@ public async Task MethodCallChain_AsAssignmentValue_WritesDeclarationAndSemicolo { var writer = CodeWriterFactory.ForTests(); - writer.Assignment( - "var value", - value => - value.MethodCallChain( - "builder.Configuration.GetSection", - ["x.SectionName"], - chain => chain.Method("Get", genericArguments: [Type("Options")]).Postfix(" ?? new()") - ) + writer.Assignment("var value", value => + value.MethodCallChain("builder.Configuration.GetSection", ["x.SectionName"], chain => + chain.Method("Get", genericArguments: [Type("Options")]).Postfix(" ?? new()") + ) ); await Assert @@ -2394,10 +2379,8 @@ public async Task MethodCallChain_WithMultipleSegments_WritesEachInvocation() { var writer = CodeWriterFactory.ForTests(); - writer.MethodCallChain( - "items.Where", - ["value => value.Enabled"], - chain => chain.Method("OrderBy", ["value => value.Name"]).Method("ToList") + writer.MethodCallChain("items.Where", ["value => value.Enabled"], chain => + chain.Method("OrderBy", ["value => value.Name"]).Method("ToList") ); await Assert @@ -2897,9 +2880,8 @@ public async Task GeneratorIdentity_GivenNoHeaderArguments_UsesDefaultsAndDecora CodeWriter writer = new(new("HostKitGenerator", "2.3.4"), throwOnUnclosedScopes: false); writer.AutoGeneratedHeader(); - writer.Class( - new TypeDeclarationOptions("GeneratedType"), - body => body.Property(new PropertyDeclarationOptions("Value", TypeIdentity.Create())) + writer.Class(new TypeDeclarationOptions("GeneratedType"), body => + body.Property(new PropertyDeclarationOptions("Value", TypeIdentity.Create())) ); var result = writer.ToString(); @@ -3186,13 +3168,11 @@ public async Task MemberDeclarations_GivenDefaultIncludeGeneratedAttributesFalse { body.Field(new FieldDeclarationOptions("_field", Type("int"))); body.Property(new PropertyDeclarationOptions("Property", Type("int"))); - body.Method( - new MethodDeclarationOptions("Method", Type("void")), - methodBody => methodBody.Line("return;") + body.Method(new MethodDeclarationOptions("Method", Type("void")), methodBody => + methodBody.Line("return;") ); - body.Constructor( - new ConstructorDeclarationOptions("Sample"), - constructorBody => constructorBody.Line("// ctor") + body.Constructor(new ConstructorDeclarationOptions("Sample"), constructorBody => + constructorBody.Line("// ctor") ); } ); @@ -3370,22 +3350,16 @@ public async Task Assignment_WritesDeclarationAndMultilineInitializer() { var writer = CodeWriterFactory.ForTests(); - writer.Assignment( - "var value", - value => + writer.Assignment("var value", value => + { + value.Line("new()"); + value.OpenBlock(null, block => { - value.Line("new()"); - value.OpenBlock( - null, - block => - { - block.Line("X = 1,"); - block.Line("Y = 2,"); - block.Line("Z = 3"); - } - ); - } - ); + block.Line("X = 1,"); + block.Line("Y = 2,"); + block.Line("Z = 3"); + }); + }); await Assert .That(writer.ToString()) @@ -3411,9 +3385,8 @@ public async Task ExpressionMembers_WritesMultilineExpressions() writer.MethodScope( new MethodDeclarationOptions("Load", Type("Value")) { ExpressionBody = "Create()\n.Configure()" } ); - writer.PropertyExpression( - new PropertyDeclarationOptions("Current", Type("Value")), - property => property.Line("GetCurrent()") + writer.PropertyExpression(new PropertyDeclarationOptions("Current", Type("Value")), property => + property.Line("GetCurrent()") ); await Assert @@ -3435,9 +3408,8 @@ public async Task Method_WithPartialDeclarationWithBody_WritesBodyOutsideMethod( writer.DefaultIncludeGeneratedAttributes = false; // Act - writer.Class( - new("Example") { IsPartial = true }, - body => body.Method(new("Apply") { IsPartial = true }, methodBody => methodBody.Return()) + writer.Class(new("Example") { IsPartial = true }, body => + body.Method(new("Apply") { IsPartial = true }, methodBody => methodBody.Return()) ); // Assert @@ -3940,17 +3912,15 @@ public async Task Assignment_WithNewExpressionCallbackAndStructuredArguments_Wri { var writer = CodeWriterFactory.ForTests(); - writer.Assignment( - "var handler", - expression => - expression.New( - "HostKit", - [ - new MethodCallArgumentOptions("onBuilt"), - new MethodCallArgumentOptions("onConfigured") { Name = "configured" }, - new MethodCallArgumentOptions("options", ParameterModifier.In), - ] - ) + writer.Assignment("var handler", expression => + expression.New( + "HostKit", + [ + new MethodCallArgumentOptions("onBuilt"), + new MethodCallArgumentOptions("onConfigured") { Name = "configured" }, + new MethodCallArgumentOptions("options", ParameterModifier.In), + ] + ) ); await Assert @@ -4042,15 +4012,12 @@ public async Task Assignment_WithNewExpressionCallbackAndSeparateLineArguments_W var writer = CodeWriterFactory.ForTests(); writer.Indent(); - writer.Assignment( - "var", - "optionsBuilder", - expression => - expression.New( - "Order", - [new MethodCallArgumentOptions("aParameterNameThatForcesTheArgumentsOntoTheirOwnLine")], - writeArgumentsOnSeparateLines: true - ) + writer.Assignment("var", "optionsBuilder", expression => + expression.New( + "Order", + [new MethodCallArgumentOptions("aParameterNameThatForcesTheArgumentsOntoTheirOwnLine")], + writeArgumentsOnSeparateLines: true + ) ); writer.Unindent(); @@ -4368,14 +4335,12 @@ public async Task StatementFamily_WritesStructuredBlocks() // Act writer.Try(tryBody => - tryBody.Foreach( - "var item in items", - foreachBody => - foreachBody.IfElse( - "item is null", - ifBody => ifBody.Throw(TypeIdentity.Create(), "Null item"), - elseBody => elseBody.MethodCall("Process", "item") - ) + tryBody.Foreach("var item in items", foreachBody => + foreachBody.IfElse( + "item is null", + ifBody => ifBody.Throw(TypeIdentity.Create(), "Null item"), + elseBody => elseBody.MethodCall("Process", "item") + ) ) ); writer.Catch(TypeIdentity.Create(), "ex", catchBody => catchBody.MethodCall("Log", "ex")); @@ -4775,11 +4740,8 @@ public async Task MethodExpressionOverload_GivenCallback_WritesExpressionMethod( var writer = CodeWriterFactory.ForTests(); // Act - writer.MethodExpression( - "Count", - Type("int"), - TypeDeclarationAccessibility.Public, - expression => expression.Write("items.Count") + writer.MethodExpression("Count", Type("int"), TypeDeclarationAccessibility.Public, expression => + expression.Write("items.Count") ); // Assert @@ -4860,11 +4822,12 @@ public async Task PropertyOverload_WithConfigure_WritesConfiguredProperty() var writer = CodeWriterFactory.ForTests(); // Act - writer.Property( - "Name", - Type("string"), - TypeDeclarationAccessibility.Public, - options => options with { HasSetter = true, Initializer = "string.Empty" } + writer.Property("Name", Type("string"), TypeDeclarationAccessibility.Public, options => + options with + { + HasSetter = true, + Initializer = "string.Empty", + } ); // Assert @@ -4909,11 +4872,8 @@ public async Task PropertyExpressionOverload_WritesExpressionProperty() var writer = CodeWriterFactory.ForTests(); // Act - writer.PropertyExpression( - "Count", - Type("int"), - TypeDeclarationAccessibility.Public, - expression => expression.Write("_items.Count") + writer.PropertyExpression("Count", Type("int"), TypeDeclarationAccessibility.Public, expression => + expression.Write("_items.Count") ); // Assert @@ -4927,11 +4887,11 @@ public async Task IndexerOverload_GivenMinimalProperties_WritesIndexer() var writer = CodeWriterFactory.ForTests(); // Act - writer.Indexer( - Type("string"), - TypeDeclarationAccessibility.Public, - [new("index", Type("int"))], - options => options with { HasSetter = true } + writer.Indexer(Type("string"), TypeDeclarationAccessibility.Public, [new("index", Type("int"))], options => + options with + { + HasSetter = true, + } ); // Assert @@ -5007,11 +4967,8 @@ public async Task ConstructorOverload_GivenMinimalProperties_WritesConstructor() var writer = CodeWriterFactory.ForTests(); // Act - writer.Constructor( - "Repository", - TypeDeclarationAccessibility.Public, - null, - body => body.Line("Connection = connection;") + writer.Constructor("Repository", TypeDeclarationAccessibility.Public, null, body => + body.Line("Connection = connection;") ); // Assert @@ -5159,12 +5116,8 @@ public async Task TypeOverload_GivenKindAndBody_WritesType() var writer = CodeWriterFactory.ForTests(); // Act - writer.Type( - TypeDeclarationKind.RecordClass, - "Model", - TypeDeclarationAccessibility.Public, - null, - body => body.Line("// body") + writer.Type(TypeDeclarationKind.RecordClass, "Model", TypeDeclarationAccessibility.Public, null, body => + body.Line("// body") ); // Assert @@ -5436,11 +5389,11 @@ public async Task PropertyAccessors_WithPublicDefaults_StayBare() var writer = CodeWriterFactory.ForTests(); // Act - writer.Property( - "Name", - Type("string"), - TypeDeclarationAccessibility.Public, - options => options with { HasSetter = true } + writer.Property("Name", Type("string"), TypeDeclarationAccessibility.Public, options => + options with + { + HasSetter = true, + } ); // Assert @@ -5455,11 +5408,11 @@ public async Task PropertySetterDefault_MoreRestrictive_WritesModifier() writer.DefaultPropertySetterAccessibility = TypeDeclarationAccessibility.Private; // Act - writer.Property( - "Name", - Type("string"), - TypeDeclarationAccessibility.Public, - options => options with { HasSetter = true } + writer.Property("Name", Type("string"), TypeDeclarationAccessibility.Public, options => + options with + { + HasSetter = true, + } ); // Assert @@ -5476,11 +5429,11 @@ public async Task PropertyAccessorDefault_MorePermissive_IsInherited() writer.DefaultPropertyAccessibility = TypeDeclarationAccessibility.Internal; // Act - writer.Property( - "Name", - Type("string"), - TypeDeclarationAccessibility.Internal, - options => options with { HasSetter = true } + writer.Property("Name", Type("string"), TypeDeclarationAccessibility.Internal, options => + options with + { + HasSetter = true, + } ); // Assert @@ -5563,11 +5516,8 @@ public async Task HashDefines_InsideClass_WritesDirectivesAtColumnZero() var writer = CodeWriterFactory.ForTests(); // Act - writer.Class( - "Sample", - TypeDeclarationAccessibility.Public, - null, - body => body.HashDefines("NET", conditional => conditional.Property("Value", Type("int"))) + writer.Class("Sample", TypeDeclarationAccessibility.Public, null, body => + body.HashDefines("NET", conditional => conditional.Property("Value", Type("int"))) ); // Assert @@ -5655,18 +5605,20 @@ public async Task HashElse_InsideHashDefinesScope_WritesElseDirective() // Act using (writer.HashDefinesScope("NET48_OR_GREATER || PURVIEW_TELEMETRY_NON_NULLABLE")) { - writer.Property( - "name", - Type("string"), - TypeDeclarationAccessibility.Public, - options => options with { HasSetter = true, IncludeGeneratedAttributes = false } + writer.Property("name", Type("string"), TypeDeclarationAccessibility.Public, options => + options with + { + HasSetter = true, + IncludeGeneratedAttributes = false, + } ); writer.HashElse(); - writer.Property( - "name", - Type("string").Nullable(), - TypeDeclarationAccessibility.Public, - options => options with { HasSetter = true, IncludeGeneratedAttributes = false } + writer.Property("name", Type("string").Nullable(), TypeDeclarationAccessibility.Public, options => + options with + { + HasSetter = true, + IncludeGeneratedAttributes = false, + } ); } @@ -5745,9 +5697,8 @@ public async Task FileLevelDirectives_AreSelfSpacingAndColumnZero() // Act writer.AutoGeneratedHeader(nullableDirective: NullableDirectiveMode.Disable); - writer.HashDefines( - "!NET48_OR_GREATER && !PURVIEW_TELEMETRY_NON_NULLABLE", - hashWriter => hashWriter.Line("#nullable enable") + writer.HashDefines("!NET48_OR_GREATER && !PURVIEW_TELEMETRY_NON_NULLABLE", hashWriter => + hashWriter.Line("#nullable enable") ); writer.PragmaDisable("CS8625"); writer.FileScopedNamespace("Purview.Telemetry"); diff --git a/src/tests/SourceGeneratorShared.UnitTests/Extensions/Microsoft/CodeAnalysis/SourceProductionContextExtensionsTests.cs b/src/tests/SourceGeneratorShared.UnitTests/Extensions/Microsoft/CodeAnalysis/SourceProductionContextExtensionsTests.cs index 809543b..2c02853 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/Extensions/Microsoft/CodeAnalysis/SourceProductionContextExtensionsTests.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/Extensions/Microsoft/CodeAnalysis/SourceProductionContextExtensionsTests.cs @@ -27,21 +27,18 @@ sealed class DiagnosticGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { - context.RegisterSourceOutput( - context.CompilationProvider, - static (spc, _) => - { - DiagnosticDescriptor descriptor = new( - "TEST001", - "Test", - "Test message", - "Test", - DiagnosticSeverity.Warning, - true - ); - spc.ReportDiagnostic(ReportableDiagnostic.Create(descriptor, isBlocking: false)); - } - ); + context.RegisterSourceOutput(context.CompilationProvider, static (spc, _) => + { + DiagnosticDescriptor descriptor = new( + "TEST001", + "Test", + "Test message", + "Test", + DiagnosticSeverity.Warning, + true + ); + spc.ReportDiagnostic(ReportableDiagnostic.Create(descriptor, isBlocking: false)); + }); } } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/AlwaysNullableContextTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/AlwaysNullableContextTestGenerator.cs index ce2d3a4..08adfa3 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/AlwaysNullableContextTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/AlwaysNullableContextTestGenerator.cs @@ -23,27 +23,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context) static (_, _, _, _) => EmptyCapabilities.Instance ); - context.RegisterSourceOutput( - generationContext, - static (spc, ctx) => - { - var writer = ctx.CreateCodeWriter(); - writer.AutoGeneratedHeader(); - writer.FileScopedNamespace("Test"); - writer.Class( - new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, - body => - body.Property( - new( - "Name", - TypeIdentity.Create().MakeNullable(writer), - TypeDeclarationAccessibility.Public - ) + context.RegisterSourceOutput(generationContext, static (spc, ctx) => + { + var writer = ctx.CreateCodeWriter(); + writer.AutoGeneratedHeader(); + writer.FileScopedNamespace("Test"); + writer.Class( + new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, + body => + body.Property( + new( + "Name", + TypeIdentity.Create().MakeNullable(writer), + TypeDeclarationAccessibility.Public ) - ); + ) + ); - spc.AddSource("AlwaysNullableContext.g.cs", writer.ToString()); - } - ); + spc.AddSource("AlwaysNullableContext.g.cs", writer.ToString()); + }); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/DiagnosticTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/DiagnosticTestGenerator.cs index e7d329c..2270a56 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/DiagnosticTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/DiagnosticTestGenerator.cs @@ -35,15 +35,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("DiagnosticTestGenerator", "1.0.0") ); - context.RegisterSourceOutput( - targets, - generationContext, - static (spc, target, ctx) => - { - var writer = ctx.CreateCodeWriter(); - writer.Line($"partial class {target.Name} {{ }}"); - spc.AddSource($"{target.Name}.g.cs", writer.ToString()); - } - ); + context.RegisterSourceOutput(targets, generationContext, static (spc, target, ctx) => + { + var writer = ctx.CreateCodeWriter(); + writer.Line($"partial class {target.Name} {{ }}"); + spc.AddSource($"{target.Name}.g.cs", writer.ToString()); + }); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ExplicitNullableContextTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ExplicitNullableContextTestGenerator.cs index a7d5f4c..c7b6b35 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ExplicitNullableContextTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ExplicitNullableContextTestGenerator.cs @@ -17,27 +17,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("ExplicitNullableContextTestGenerator", "1.0.0") { IsNullableContextEnabled = true } ); - context.RegisterSourceOutput( - generationContext, - static (spc, ctx) => - { - var writer = ctx.CreateCodeWriter(); - writer.AutoGeneratedHeader(); - writer.FileScopedNamespace("Test"); - writer.Class( - new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, - body => - body.Property( - new( - "Name", - TypeIdentity.Create().MakeNullable(writer), - TypeDeclarationAccessibility.Public - ) + context.RegisterSourceOutput(generationContext, static (spc, ctx) => + { + var writer = ctx.CreateCodeWriter(); + writer.AutoGeneratedHeader(); + writer.FileScopedNamespace("Test"); + writer.Class( + new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, + body => + body.Property( + new( + "Name", + TypeIdentity.Create().MakeNullable(writer), + TypeDeclarationAccessibility.Public ) - ); + ) + ); - spc.AddSource("ExplicitNullableContext.g.cs", writer.ToString()); - } - ); + spc.AddSource("ExplicitNullableContext.g.cs", writer.ToString()); + }); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/GenerationContextTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/GenerationContextTestGenerator.cs index 10b0d49..5299563 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/GenerationContextTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/GenerationContextTestGenerator.cs @@ -12,9 +12,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("GenerationContextTestGenerator", "1.0.0") ); - context.RegisterSourceOutput( - generationContext, - static (spc, value) => spc.AddSource("Context.g.cs", $"// GenerationContextTestGenerator") + context.RegisterSourceOutput(generationContext, static (spc, value) => + spc.AddSource("Context.g.cs", $"// GenerationContextTestGenerator") ); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/NullableContextTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/NullableContextTestGenerator.cs index 8caa1e4..ec67552 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/NullableContextTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/NullableContextTestGenerator.cs @@ -16,27 +16,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("NullableContextTestGenerator", "1.0.0") ); - context.RegisterSourceOutput( - generationContext, - static (spc, ctx) => - { - var writer = ctx.CreateCodeWriter(); - writer.AutoGeneratedHeader(); - writer.FileScopedNamespace("Test"); - writer.Class( - new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, - body => - body.Property( - new( - "Name", - TypeIdentity.Create().MakeNullable(writer), - TypeDeclarationAccessibility.Public - ) + context.RegisterSourceOutput(generationContext, static (spc, ctx) => + { + var writer = ctx.CreateCodeWriter(); + writer.AutoGeneratedHeader(); + writer.FileScopedNamespace("Test"); + writer.Class( + new TypeDeclarationOptions("Sample") { Accessibility = TypeDeclarationAccessibility.Public }, + body => + body.Property( + new( + "Name", + TypeIdentity.Create().MakeNullable(writer), + TypeDeclarationAccessibility.Public ) - ); + ) + ); - spc.AddSource("NullableContext.g.cs", writer.ToString()); - } - ); + spc.AddSource("NullableContext.g.cs", writer.ToString()); + }); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/OrderedLoggingTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/OrderedLoggingTestGenerator.cs index ff5e5c2..6bc542c 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/OrderedLoggingTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/OrderedLoggingTestGenerator.cs @@ -22,15 +22,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("OrderedLoggingTestGenerator", "1.0.0") ); - context.RegisterSourceOutput( - generationContext, - static (spc, value) => - { - foreach (var message in Messages) - value.Log(SourceGenLogLevel.Info, 0, message); + context.RegisterSourceOutput(generationContext, static (spc, value) => + { + foreach (var message in Messages) + value.Log(SourceGenLogLevel.Info, 0, message); - spc.AddSource("OrderedLogging.g.cs", "// OrderedLoggingTestGenerator"); - } - ); + spc.AddSource("OrderedLogging.g.cs", "// OrderedLoggingTestGenerator"); + }); } } diff --git a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ThrowingTestGenerator.cs b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ThrowingTestGenerator.cs index a392336..932c83c 100644 --- a/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ThrowingTestGenerator.cs +++ b/src/tests/SourceGeneratorShared.UnitTests/TestGenerators/ThrowingTestGenerator.cs @@ -24,10 +24,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) new GenerationSettings("ThrowingTestGenerator", "1.0.0") ); - context.RegisterSourceOutput( - targets, - generationContext, - static (spc, target, ctx) => throw new InvalidOperationException(FailureMessage) + context.RegisterSourceOutput(targets, generationContext, static (spc, target, ctx) => + throw new InvalidOperationException(FailureMessage) ); } } From b594848ec17704755804a22e643f4daee478c6cb Mon Sep 17 00:00:00 2001 From: Kieron Lanning Date: Wed, 11 Nov 2026 10:28:53 +0000 Subject: [PATCH 4/4] chore: bumped nuget versions --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 889ed3a..1bfc27a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,7 +3,7 @@ true 5.9.0 5.9.0 - 1.81.16 + 1.83.0