Sdk: Analyzers flow from dependency into referencing project

Created on 9 Mar 2017  路  9Comments  路  Source: dotnet/sdk

If you have a project set up as follows

- Sln
  |-- ProjectA
  |-- ProjectB

And add an analyzer to ProjectA, and then reference ProjectA in ProjectB, ProjectB also ends up having the analyzer run. Is this expected? Is there a way to turn this off for solutions where ProjectB does not want the analyzer to be run?

Most helpful comment

@sharwell observed that PrivateAssets="all" does actually work around the issue in many cases. So I took a deeper look, and it turns out that is a reasonable workaround for a common case where the analyzers come from a package with no other assets that you need to flow to consumers.

Consider the Project Caller -> Project Callee -> Package Analyzers

If Callee.csproj has:

    <PackageReference Include="Analyzers" Version="1.2.3" PrivateAssets="All" />

Then Analyzers will not be picked up by project B.

However, if a package has a mix of of both analyzers and API, then you cannot block the analyzers without also blocking the API from flowing. The reason for this is that when PrivateAssets="All", then NuGet will not write out the package and its list of "files" in the "libraries" section of Caller's project.assets.json. However, if PrivateAssets is anything else, then it will write them. For non-analyzer assets, these "files" don't matter, it is the "compile", "runtime" lists under "targets" that do. But there is no such section for "analyzers" under "targets" (NuGet/Home#6279) and so the SDK uses "files" under "libraries", which leads to this behavior.

The irony remains that the default value of PrivateAssets is "contentfiles;analyzers;build", but analyzers do flow by default unlike contentfiles and build.

All 9 comments

ProjectA can use PrivateAssets metadata on the analyzer reference. See https://github.com/NuGet/Home/wiki/PackageReference-Specification

Hmm, PrivateAssets including analyzers is supposed to be the default. @emgarten

Analyzers are read directly by the project system and not from the assets file where the flags are applied. We need to change that behavior to allow NuGet to do this filtering. The existing flags were done to begin this change.

So that means right now, the behavior I described is expected? If so, is there a workaround to disable it for specific projects?

@jinujoseph

Moving this to the backlog to matching NuGet's blocking issue.

@sharwell observed that PrivateAssets="all" does actually work around the issue in many cases. So I took a deeper look, and it turns out that is a reasonable workaround for a common case where the analyzers come from a package with no other assets that you need to flow to consumers.

Consider the Project Caller -> Project Callee -> Package Analyzers

If Callee.csproj has:

    <PackageReference Include="Analyzers" Version="1.2.3" PrivateAssets="All" />

Then Analyzers will not be picked up by project B.

However, if a package has a mix of of both analyzers and API, then you cannot block the analyzers without also blocking the API from flowing. The reason for this is that when PrivateAssets="All", then NuGet will not write out the package and its list of "files" in the "libraries" section of Caller's project.assets.json. However, if PrivateAssets is anything else, then it will write them. For non-analyzer assets, these "files" don't matter, it is the "compile", "runtime" lists under "targets" that do. But there is no such section for "analyzers" under "targets" (NuGet/Home#6279) and so the SDK uses "files" under "libraries", which leads to this behavior.

The irony remains that the default value of PrivateAssets is "contentfiles;analyzers;build", but analyzers do flow by default unlike contentfiles and build.

@nguerrera Thanks for that workaround. Got me out of a pickle.

What's the status of a proper fix? Is this something for which contributions would be welcome?

Was this page helpful?
0 / 5 - 0 ratings