dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.04k stars 4.03k forks source link

Version Microsoft.CodeAnalysis 4.2.0 doesn't work #61333

Open KondzioSSJ4 opened 2 years ago

KondzioSSJ4 commented 2 years ago

Version Used: 4.2.0

Steps to Reproduce:

Create 2 projects: generator with code like:

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

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

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis" Version="4.2.0"/>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

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

</Project>

and project that use that generator project like:

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

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
        <ProjectReference Include="..\ExampleSourceGenerators\ExampleSourceGenerators.csproj"
                          PrivateAssets="all"
                          OutputItemType="Analyzer"/>
    </ItemGroup>

    <ItemGroup>
        <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
    </ItemGroup>
</Project>

And try to build then you will get warning like:

 warning CS8032: An instance of analyzer ExampleSourceGenerators.SomeGenerator cannot be created from ...\bin\Debug\netstandard2.0\ExampleSourceGenerators.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies

what for me is an error, because the generator generates other files that are required for the code to work

Expected Behavior: It works like it does for 4.1.0 version or when using Microsoft.CodeAnalysis.CSharp.Workspaces in version 4.1.0 that also works

but for some reason, I can't make a working version with 4.2.0

Actual Behavior: Generator can't find file, so generator isn't run

svick commented 2 years ago

The problem is that the version of Roslyn used by your source generator has to be supported by the .Net SDK that you're using.

Experimentally, I get the same error as you when I use .Net SDK 6.0.203 or older, but it works fine on .Net SDK 6.0.300. So, you should either upgrade the version of the .Net SDK, or downgrade the version of Roslyn, so that you're in a supported combination.

Unfortunately, AFAICT, this is not well-documented. I think it would help a lot if the documentation for source generators explained the issue, and included a table listing which versions of Roslyn are supported by which SDK.

huoyaoyuan commented 2 years ago

In practice, generators and analyzers should targets the lowest compiler&SDK version you would use. For example when targeting .net 6, it's safe to reference 4.0.

PawelGerr commented 2 years ago

Alas, the SDK 6.0.300 seems to be not backwards-compatible with Microsoft.CodeAnalysis v4.0.1 nor v4.1.0. In both cases I get

Exception was of type 'MissingMethodException' with message 'Method not found: 'Microsoft.CodeAnalysis.IncrementalValueProvider`1<Microsoft.CodeAnalysis.MetadataReference> Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.get_MetadataReferencesProvider()'.'

I had no issue with Microsoft.CodeAnalysis v4.1.0 and SDK 6.0.203.

The following run in github actions fails with MissingMethodException when trying to build the commit 97bb5c39abc5f58016923a5e600157bee646dabb with SDK 6.0.300. The same exception is thrown when I build the solution locally on my win10 machine and on azure devops (linux-based agent).

Do you have some recommendations?

svick commented 2 years ago

@PawelGerr

I believe that's caused by https://github.com/dotnet/roslyn/pull/58059, which says:

This is technically a breaking change, but the only thing it breaks is invalid code, so I think we should take the fix.

Though I don't know much about incremental generators, so I can't tell you why your usage of MetadataReferencesProvider would be invalid.

cc: @chsienki

PawelGerr commented 2 years ago

@svick Thx for the hint! Based on that I created a workaround. Now, the source generator works with different versions of Microsoft.CodeAnalysis and different SDKs:

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;

namespace Thinktecture;

public static class IncrementalGeneratorInitializationContextExtensions
{
   public static IncrementalValuesProvider<MetadataReference> GetMetadataReferencesProvider(this IncrementalGeneratorInitializationContext context)
   {
      var metadataProviderProperty = context.GetType().GetProperty(nameof(context.MetadataReferencesProvider))
                                     ?? throw new Exception($"The property '{nameof(context.MetadataReferencesProvider)}' not found");

      var metadataProvider = metadataProviderProperty.GetValue(context);

      if (metadataProvider is IncrementalValuesProvider<MetadataReference> metadataValuesProvider)
         return metadataValuesProvider;

      if (metadataProvider is IncrementalValueProvider<MetadataReference> metadataValueProvider)
         return metadataValueProvider.SelectMany(static (reference, _) => ImmutableArray.Create(reference));

      throw new Exception($"The '{nameof(context.MetadataReferencesProvider)}' is neither an 'IncrementalValuesProvider<{nameof(MetadataReference)}>' nor an 'IncrementalValueProvider<{nameof(MetadataReference)}>.'");
   }
}
chsienki commented 2 years ago

@PawelGerr We changed the metadata references provider, as it was incorrectly marked as returning a single item, when in reality it returns multiple items. If you try and combine against the single-valued version it can crash the generator runtime, which is why we opted to take a hard break.

PawelGerr commented 2 years ago

@chsienki Do you expect any issues with my workaround?

chsienki commented 2 years ago

No, I think the workaround looks good.

NuclearFishin commented 2 years ago

Hi all, I just ran into this issue when taking my first steps towards creating a Roslyn analyser. I am running SDK version 6.0.201 and ran into the issue exactly as-described by @KondzioSSJ4 in the original comment.

In my case, downgrading my package reference for Microsoft.CodeAnalysis.CSharp.Workspaces to 4.1.0 solved the issue regarding:

...Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.2.0.0...

I'm sure upgrading my SDK would also solve the issue. It's nice that this works, but I don't really have any idea what's going on there?

So I guess my main question is, could you please give some more info as to how we could figure out this versioning conflict in future? I'm not sure what it means for a library to be "supported" by an SDK, likewise I couldn't see anything obvious on the NuGet Package Definition for Microsoft.CodeAnalysis that would suggest which versions of the SDK are supported. If there is another update to the SDK or Microsoft.CodeAnalysis package this triggers this error again, it would be great to be able to dig in and figure out what to update. Thanks very much!

erichiller commented 2 years ago

Hopefully this helps someone else, because it took me a little bit to track down:

My issue was as posted above my SDK version was too old for Microsoft.CodeAnalysis.

I am on Ubuntu 22.04 and am using the microsoft-prod repo. I discovered that despite having "upgraded" dotnet-* recently, I was only at version 6.0.108 using dotnet sdk check. Apparently, at some point the version format for microsoft-prod began to differ from the ubuntu repo. Ubuntu is naming packages like 6.0.108-0ubuntu1~22.04.1 while the microsoft versions were in the format 6.0.8-1 (and 108 is greater than 8).

The solution is to set the priority for a package source. Create a preferences file, eg. /etc/apt/preferences.d/99microsoft-prod

# Give microsoft repo priority
Package: *
Pin: origin packages.microsoft.com
Pin-Priority: 1000
byme8 commented 1 year ago

I got a similar issue. My source generator was failing silently during a build. As a result, some required stuff was not appropriately bootstrapped at runtime, and the app failed. I fixed it by downgrading Microsoft.CodeAnalysis.CSharp NuGet package in the project with the source generator.

I suppose, from Roslyn's perspective, if it finds unsupported assembly, it should emit an error and stop compilation. At the moment, it is not clear what went wrong.

More info about the initial issue you can find here. The solution described in this comment