Roslyn Analyser backwards compatibility

Written on May 28, 2020

I recently created a Roslyn Code Analyzer project in Visual Studio 2019 16.6, but discovered that the package references used by the template aren’t suitable if you need the analyzer to run against older projects.

Using the latest template might result in an error like this:

error NU1202: Package Microsoft.CodeAnalysis.CSharp.Workspaces 3.3.1 is not compatible with net45 (.NETFramework,Version=v4.5). Package Microsoft.CodeAnalysis.CSharp.Workspaces 3.3.1 supports: netstandard2.0 (.NETStandard,Version=v2.0)

So I spun up an instance of Visual Studio 2017 (on an Azure VM) to compare the projects.

Here’s the analyzer csproj (after I did minor package updates)

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
  </PropertyGroup>

  <PropertyGroup>
    <PackageId>Analyzer2</PackageId>
    <PackageVersion>1.0.0.0</PackageVersion>
    <Authors>dgardiner</Authors>
    <PackageLicenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</PackageLicenseUrl>
    <PackageProjectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</PackageProjectUrl>
    <PackageIconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</PackageIconUrl>
    <RepositoryUrl>http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE</RepositoryUrl>
    <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
    <Description>Analyzer2</Description>
    <PackageReleaseNotes>Summary of changes made in this release of the package.</PackageReleaseNotes>
    <Copyright>Copyright</Copyright>
    <PackageTags>Analyzer2, analyzers</PackageTags>
    <NoPackageAnalysis>true</NoPackageAnalysis>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.6.1" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.9.0" PrivateAssets="all" />
    <PackageReference Update="NETStandard.Library" PrivateAssets="all" />
  </ItemGroup>

  <ItemGroup>
    <Compile Update="Resources.Designer.cs" DesignTime="True" AutoGen="True" DependentUpon="Resources.resx" />
    <EmbeddedResource Update="Resources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Resources.Designer.cs" />
  </ItemGroup>

  <ItemGroup>
    <None Update="tools\*.ps1" CopyToOutputDirectory="Always" Pack="true" PackagePath="" />
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
  </ItemGroup>

</Project>

and the test csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.6.1" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.9.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.2" />
    <PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
    <PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Analyzer2\Analyzer2.csproj" />
  </ItemGroup>

</Project>

The older test project also contains helper and verifier classes (the equivalent of these have moved to Nuget packages in 2019 templates).

The older projects still compile and work in 2019. Obviously if you’re using a newer C# language / SDK version then using the newer template is preferred.

If you’re looking for a nice overview of analyzers, you might want to check out the recording of Jason Bock’s presentation ‘Using the Compiler API in Real World Scenarios’

Categories: .NET