Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup>
<ItemGroup Condition="'$(MSBuildProjectName)' == 'Light.GuardClauses.InternalRoslynAnalyzers'">
<PackageVersion Update="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" />
<!--
The compiler-loaded analyzer assembly (Light.GuardClauses.InternalRoslynAnalyzers) and its
matching CodeFixes assembly must be built against Roslyn 4.11.0 to match the Roslyn version
shipped with the pinned .NET SDK 8.0.400 (see global.json). A compiler-loaded extension must
not reference a newer Microsoft.CodeAnalysis than the SDK's compiler. The analyzer is the only
consumer of Microsoft.CodeAnalysis.CSharp, so it is pinned centrally here. The CodeFixes project
overrides Microsoft.CodeAnalysis.CSharp.Workspaces to 4.11.0 via VersionOverride so its Roslyn
version matches the analyzer; the central Workspaces version stays 4.13.0 for the source-export
tooling, which runs on the installed SDK and is not a compiler extension.
-->
<ItemGroup>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
</ItemGroup>
</Project>
7 changes: 7 additions & 0 deletions Light.GuardClauses.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Light.GuardClauses.Performa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Light.GuardClauses.InternalRoslynAnalyzers", "tools\analyzers\Light.GuardClauses.InternalRoslynAnalyzers\Light.GuardClauses.InternalRoslynAnalyzers.csproj", "{DB4A3982-5312-4923-9C79-C39D18A5899C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes", "tools\analyzers\Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes\Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes.csproj", "{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Light.GuardClauses.InternalRoslynAnalyzers.Tests", "tests\Light.GuardClauses.InternalRoslynAnalyzers.Tests\Light.GuardClauses.InternalRoslynAnalyzers.Tests.csproj", "{2FE2D52E-21B8-4C51-9983-9C1812BDEBA0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Light.GuardClauses.SourceCodeTransformation", "tools\source-export\Light.GuardClauses.SourceCodeTransformation\Light.GuardClauses.SourceCodeTransformation.csproj", "{ECE42390-E3B5-49D4-9452-3B0CC04C633A}"
Expand Down Expand Up @@ -66,6 +68,10 @@ Global
{DB4A3982-5312-4923-9C79-C39D18A5899C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB4A3982-5312-4923-9C79-C39D18A5899C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB4A3982-5312-4923-9C79-C39D18A5899C}.Release|Any CPU.Build.0 = Release|Any CPU
{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1}.Release|Any CPU.Build.0 = Release|Any CPU
{2FE2D52E-21B8-4C51-9983-9C1812BDEBA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2FE2D52E-21B8-4C51-9983-9C1812BDEBA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2FE2D52E-21B8-4C51-9983-9C1812BDEBA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -93,6 +99,7 @@ Global
{A2067796-F167-47BE-B367-191152DCE230} = {22B02CC1-06EC-4A20-8964-B7E941FAEB49}
{F4EE1A0F-60E0-4077-BFC4-82387535352A} = {33B02CC1-06EC-4A20-8964-B7E941FAEB49}
{DB4A3982-5312-4923-9C79-C39D18A5899C} = {55B02CC1-06EC-4A20-8964-B7E941FAEB49}
{0D6B435A-E59C-48EB-A13D-69FDB5B6F4A1} = {55B02CC1-06EC-4A20-8964-B7E941FAEB49}
{ECE42390-E3B5-49D4-9452-3B0CC04C633A} = {66B02CC1-06EC-4A20-8964-B7E941FAEB49}
{B546B7B7-9CA5-456C-96CD-15C21E64B7DF} = {66B02CC1-06EC-4A20-8964-B7E941FAEB49}
{55B02CC1-06EC-4A20-8964-B7E941FAEB49} = {44B02CC1-06EC-4A20-8964-B7E941FAEB49}
Expand Down
38 changes: 38 additions & 0 deletions ai-plans/0139-roslyn-RS1038-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Resolve RS1038 by Splitting the Internal Roslyn Analyzers Assembly

## Rationale

Building the solution produces warning RS1038 because `Light.GuardClauses.InternalRoslynAnalyzers` contains a `DiagnosticAnalyzer` — an extension loaded by the compiler during every command-line build of the product — while also referencing `Microsoft.CodeAnalysis.CSharp.Workspaces`, which the compiler does not provide. The build only works today because the analyzer's executed code paths never touch a Workspaces type; any future change that makes one reachable would cause the analyzer to fail loading (CS8032), silently disabling it and breaking Release builds via `TreatWarningsAsErrors`.

Split the assembly following the standard Roslyn pattern: the compiler-loaded analyzer must reference only compiler-layer Roslyn assemblies, while the IDE-only code fix providers move to a separate assembly that may reference Workspaces.

## Acceptance Criteria

- [x] Building the complete solution in Release configuration produces no RS1038 warning and no new warnings.
- [x] The `Light.GuardClauses.InternalRoslynAnalyzers` assembly references only compiler-layer Roslyn packages and contains no code fix providers; the two code fix providers reside in a new `Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes` assembly.
- [x] The product project receives both assemblies as analyzer references, so command-line builds still run the XML-comment analyzer and IDEs can still load the code fixes.
- [x] Introducing a non-default `parameterName` or `message` XML comment on a standard exception assertion in the product project still produces the corresponding `LightGuardClauses_*` diagnostic during a command-line build.
- [x] The existing analyzer and code-fix tests pass against the split assemblies, and the complete solution's tests all pass.
- [x] `Directory.Packages.props` contains no project-name-conditional version override; the Roslyn version constraint for compiler-loaded assemblies is documented where the version is pinned.
- [x] The new project appears in `Light.GuardClauses.sln` under the `tools/analyzers` solution folder hierarchy.

## Technical Details

Create `tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes/` and move `MessageXmlCommentFix.cs` and `ParameterNameXmlCommentFix.cs` into it, keeping the existing `Light.GuardClauses.InternalRoslynAnalyzers` namespace to avoid churn. The shared types (`Descriptors`, `ParameterNameConstants`, `MessageConstants`) are already public and stay in the analyzer project; the CodeFixes project references it via a regular `ProjectReference`. Both projects target `netstandard2.0` and reference `Microsoft.CodeAnalysis.Analyzers` with `PrivateAssets="all"`; only the analyzer project keeps `EnforceExtendedAnalyzerRules`.

The analyzer project replaces its `Microsoft.CodeAnalysis.CSharp.Workspaces` reference with `Microsoft.CodeAnalysis.CSharp`; the CodeFixes project references `Microsoft.CodeAnalysis.CSharp.Workspaces`. Both must stay at 4.11.0: a compiler-loaded extension must not be built against a newer Microsoft.CodeAnalysis than the Roslyn version shipped with the pinned .NET SDK 8.0.400 (Roslyn 4.11), and the code fixes must match the analyzer's Roslyn version. Express this via a central `Microsoft.CodeAnalysis.CSharp` entry at 4.11.0 (the analyzer is its only consumer) and a `VersionOverride="4.11.0"` on the Workspaces reference in the CodeFixes project, removing the existing `MSBuildProjectName`-conditional `PackageVersion Update` group. Record the SDK constraint as a comment next to the pinned versions. The central `Microsoft.CodeAnalysis.CSharp.Workspaces` version remains 4.13.0 for the source-export tooling.

The product project adds a second analyzer reference alongside the existing one (illustrative — mirrors the existing reference):

```xml
<ProjectReference
Include="../../tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
```

The compiler finds no analyzer types in the CodeFixes assembly and ignores it; IDEs load the fix providers from it with Workspaces available at runtime. This is the same layout analyzer NuGet packages such as StyleCop.Analyzers use.

`Light.GuardClauses.InternalRoslynAnalyzers.Tests` currently references only the analyzer project but tests both the analyzer and the fixes, and its helpers use Workspaces types that today arrive transitively through the analyzer. Repoint it to reference the CodeFixes project (the analyzer project arrives transitively); no test logic changes are expected.

Behavior does not change; the existing test suite covering the analyzer and both code fixes constitutes the required coverage.
4 changes: 4 additions & 0 deletions src/Light.GuardClauses/Light.GuardClauses.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
Include="../../tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers/Light.GuardClauses.InternalRoslynAnalyzers.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
<ProjectReference
Include="../../tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../../tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers/Light.GuardClauses.InternalRoslynAnalyzers.csproj" />
<ProjectReference Include="../../tools/analyzers/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes/Light.GuardClauses.InternalRoslynAnalyzers.CodeFixes.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" VersionOverride="4.11.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../Light.GuardClauses.InternalRoslynAnalyzers/Light.GuardClauses.InternalRoslynAnalyzers.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
</ItemGroup>

</Project>
Loading