roslyn: Generators - analyzer using references causing problems CS8785

I have an idea for an analyzer I’d like to add, reusing functionality that is already packaged in a netstandard2.0 package.

Repro is here: https://github.com/protobuf-net/protobuf-net.Grpc/pull/85/ - the interesting projects are:

  • src/generators/protobuf-net.Generator (not the Grpc one!!!)
  • toys/PlayContracts

In my analyzer csproj I have the two expected refs, plus a commented out one for the tool I want to use:

<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.6.0-3.20207.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0-beta2.final" PrivateAssets="all" />
<!--<PackageReference Include="protobuf-net.Reflection" Version="3.0.0-alpha.143" PrivateAssets="all" />-->

The analyzer currently just lists the additional files (I have a <AdditionalFiles Include="test.proto" />). With the above reference commented out, everything kinda works; however, if I uncomment the <PackageReference> and do nothing else, it stops working completely, citing:

Severity Code Description Project File Line Suppression State Warning CS8785 Generator ‘Protogen’ failed to generate source. It will not contribute to the output and compilation errors may occur as a result. PlayContracts (netstandard2.0) C:\Code\protobuf-net.Grpc\toys\PlayContracts\CSC 1 Active

(the actual “do the thing” code is there but commented out)

This may simply be a packaging thing, but… it isn’t obvious how to fix this; I’ve tried numerous things - with/without the PrivateAssets hint, with <Analyzer> dll references vs project references to the analyzer, etc. It could be as simple as a dll version conflict, but I can’t find any way of getting the info out to tell me what exploded.

Any guidance @chsienki ?

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 10
  • Comments: 36 (19 by maintainers)

Most upvoted comments

Was about to submit a repro for this because it seems counter-intuitive that you can’t simply reference some other otherwise uncontroversial netstandard2.0 assembly in your source generator library, without it failing with an obscure warning.

I guess the least horrible thing to do here would be to post-build copy the package references to the analyzer build folder?

Currently working on a design to resolve this. Agree it needs to be solved

@jmarolf I’m not entirely sure what that means in practice as either an author or consumer. When you say nuget doesn’t know… so: how does one most correctly ship an analyzer? Is this:

  1. don’t have non-inbuilt dependencies, they won’t work; inline everything into one assembly
  2. If it can resolve one level; write your own nuspec by hand that ships everything rather than using transitive trees
  3. Some exotic csproj flag I haven’t used when packaging
  4. Something else I haven’t thought of?

Or am I misunderstanding the problem?

<ItemGroup>
    <!-- Take a private dependency on Newtonsoft.Json (PrivateAssets=all) Consumers of this generator will not reference it.
         Set GeneratePathProperty=true so we can reference the binaries via the PKGNewtonsoft_Json property -->
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" PrivateAssets="all" GeneratePathProperty="true" />

    <!-- Package the generator in the analyzer directory of the nuget package -->
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />

    <!-- Package the Newtonsoft.Json dependency alongside the generator assembly -->
    <None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
  </ItemGroup>

using VS 2022 v 17.0.4 with this no longer works:

2>CSC : warning CS8785: Generator 'IncrementalGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'FileNotFoundException' with message 'Could not load file or assembly 'Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified.'

@sharwell The dependency conflicts issue is a deal breaker. Not only would it be annoying and fragile to manually add and maintain the recursive dependencies of a library like NSwag, but even if it works for me, I can’t guarantee that another user of my generator will not have a conflict with some other analyzer. As currently designed, I don’t see non-trivial source generators ever being practical.

And trying to ILMerge that single dependency quickly descended into madness:

<ItemGroup>
    <PackageReference Include="System.Text.Json" Version="5.0.0-preview.3.20214.6" PrivateAssets="All" GeneratePathProperty="true" />
    <PackageReference Include="System.Memory" Version="4.5.4" GeneratePathProperty="true" />
    <PackageReference Include="System.Buffers" Version="4.5.1" GeneratePathProperty="true" />
    <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-preview.3.20214.6" GeneratePathProperty="true" />
    <PackageReference Include="System.Text.Encodings.Web" Version="5.0.0-preview.3.20214.6" GeneratePathProperty="true"  />
    <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" GeneratePathProperty="true" />
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.1.1"  GeneratePathProperty="true" />
</ItemGroup>
<Target Name="ILMerge" AfterTargets="Build">
    <Exec Command="$(ILMergeConsolePath) /out:$(AssemblyName).dll ^
          /lib:$(NuGetPackageRoot)NETStandard.Library\2.0.1\build\netstandard2.0\ref ^
          /lib:$(PkgSystem_Runtime_CompilerServices_Unsafe)\lib\$(TargetFramework) ^
          /lib:$(PkgSystem_Buffers)\lib\$(TargetFramework) ^
          /lib:$(PkgSystem_Memory)\lib\$(TargetFramework) ^
          /lib:$(PkgSystem_Text_Encodings_Web)\lib\$(TargetFramework) ^
          /lib:$(PkgSystem_Threading_Tasks_Extensions)\lib\$(TargetFramework) ^
          $(PkgSystem_Text_Json)\lib\$(TargetFramework)\System.Text.Json.dll ^
          $(PkgMicrosoft_Bcl_AsyncInterfaces)\lib\$(TargetFramework)\Microsoft.Bcl.AsyncInterfaces.dll ^
          "/>
</Target>

I think the only sane solution is for Roslyn to run analyzers and code generators on .NET Core only.

Sounds like @jmarolf can guess what the error is. We have work to do to actually surface the errors, for now they’re just swallowed unless you have a debugger on it.

Current ‘best guidance’ (very loosely speaking) is to Debugger.Launch() in your initialize method. Then you can attach and see what’s actually failing during a compilation.