Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler server fails to load analyzers properly on second and third rebuilds of the same project #52171

Closed
jnm2 opened this issue Mar 26, 2021 · 5 comments
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead

Comments

@jnm2
Copy link
Contributor

jnm2 commented Mar 26, 2021

Version Used: SDK 5.0.201

The current state of things is unfortunate. The workaround is poorly documented, the repro is intermittent, and there's a great likelihood of regressing the main branch of a repository because the build always succeeds the first time.

It is really hard to get a reliable repro. It's 100% reliable in a mid-sized solution. The smaller and faster the build is, the less frequently this happens. It was happening around 1 out of every 3 tries when it was just a .csproj and a .cs file underneath a .sln that referenced that project and many more. When the .sln file was gone, it was happening around 1 out of every 15 tries.

for ($i = 0; $i -lt 10; $i++) { dotnet build /t:rebuild }

The problem is a flood of warnings, 37 of these even for a repro that doesn't have that many lines in it:

CSC : error AD0001: Analyzer 'PropertyChangedAnalyzers.ClassDeclarationAnalyzer' threw an exception of type 'System.IO.FileLoadException' with message 'Could not load file or assembly 'Gu.Roslyn.Extensions, Version=0.15.7.0, Culture=neutral, PublicKeyToken=4b04740f2fd5868f'. Could not find or load a specific file. (0x80131621)'.

The build always works fine the first time, and the build always seems to work fine every time with the workaround of adding <UseSharedCompilation>false</UseSharedCompilation> in Directory.Build.props so that people can just type dotnet build without running up against this issue.

PropertyChangedAnalyzers is not doing anything strange or unusual, as far as I can tell. It's doing something that any analyzer might naturally do by packaging an additional .dll file that it needs.

I'm filing this work item against Roslyn because Roslyn defines and consumes UseSharedCompilation, and I'm guessing this repo contains the compiler server implementation:
https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets#L49
https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets#L140

This is the exact csproj used for the repro:

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

  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="PropertyChangedAnalyzers" Version="3.2.2" PrivateAssets="all" />
  </ItemGroup>

</Project>

I'm not pasting the .cs file because I spent more than an hour trying to get something self-contained that would repro reliably, but I have not succeeded. The smaller the project, the faster the build, and the faster the build, the less likely to see the repro. I can keep trying if this is not enough information for you. I can also capture a binlog if that helps, but it would need to be shared privately or I will need to figure out a way to make the repro smaller without losing it due to the timing changing.

By the way, UseSharedCompilation is a very hard thing to learn about. It's not mentioned in dotnet build docs pages or even dotnet build-server docs pages. I knew such a thing must exist, but it took me a while to dig up dotnet/sdk#9487 (comment) where I learned about it.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Mar 26, 2021
@jnm2
Copy link
Contributor Author

jnm2 commented Mar 26, 2021

Ah, I think I know why I failed to repro outside the folder structure beyond just being smaller (though that effect was still there, inside the folder structure). There's a .props that I missed. I'll attempt a minimal repro again.

@jnm2
Copy link
Contributor Author

jnm2 commented Mar 26, 2021

Confirmed, the repro disappears without https://www.nuget.org/packages/ReflectionAnalyzers/0.1.22-dev which was referenced in the .props. I wonder if this due to parallel building, since it has always worked with msbuild and is failing so regularly with dotnet build.

/p:BuildInParallel=false seems to have fixed it, but it doesn't work in .props which is unfortunate because it means that typing dotnet build will still fail.

@jnm2
Copy link
Contributor Author

jnm2 commented Mar 26, 2021

At last! This repro is 100% consistent on one machine and happens every two or three tries on another machine.

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="PropertyChangedAnalyzers" Version="3.2.1" PrivateAssets="all" />
    <PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" />
  </ItemGroup>

</Project>
using System.ComponentModel;
using System.Runtime.CompilerServices;

public sealed class C : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string property1;
    public string Property1 { get => property1; set => Set(ref property1, value); }

    private bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (RuntimeHelpers.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Run:

for ($i = 0; $i -lt 10; $i++) { dotnet build /t:rebuild }

Look for a bunch of AD0001 warnings to show up.

Again, the only workaround I have at the moment is to put /p:BuildInParallel=false in the dotnet build line which is not great because I want people to be able to walk up and type dotnet build multiple times. <BuildInParallel>false</BuildInParallel> didn't seem to have any effect on the repro.

@jnm2
Copy link
Contributor Author

jnm2 commented Mar 26, 2021

I'm reproing fairly steadily now with dotnet build /t:rebuild /p:UseSharedCompilation=false, so the whole shared compilation thing was a red herring. It would be less complex probably to close and open a new issue.

@jnm2 jnm2 closed this as completed Mar 26, 2021
@jnm2
Copy link
Contributor Author

jnm2 commented Mar 26, 2021

Moved to #52177.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

No branches or pull requests

1 participant