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

Do not load CodeStyle analyzers added by the SDK #75250

Merged
merged 2 commits into from
Sep 27, 2024

Conversation

JoeRobich
Copy link
Member

@JoeRobich JoeRobich commented Sep 26, 2024

To avoid a version mismatch between the version of Roslyn in the IDE and the version of Roslyn CodeStyle analyzers added by the SDK (#72811), we will not load the CodeStyle analyzers added by the SDK. The IDE ships with the same analyzers which are version matched and used during analysis.

The analyzers are still listed in the Solution Explorer but without any associated analyzers.
image

@JoeRobich JoeRobich requested a review from a team as a code owner September 26, 2024 08:15
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Sep 26, 2024
return OneOrMany.Create(fullPath);
}

private static readonly string s_csharpCodeStyleAnalyzerSdkDirectory = Path.Combine("Sdks", "Microsoft.NET.Sdk", "codestyle", "cs") + PathUtilities.DirectorySeparatorStr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PathUtilities.DirectorySeparatorStr

Should this be at the beginning of the string too?


if (Language == LanguageNames.VisualBasic &&
fullPath.LastIndexOf(s_visualBasicCodeStyleAnalyzerSdkDirectory, StringComparison.OrdinalIgnoreCase) + s_visualBasicCodeStyleAnalyzerSdkDirectory.Length - 1 ==
fullPath.LastIndexOf(Path.DirectorySeparatorChar))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this would be a bit easier to read as a separate fn since it's done in 3 places

return OneOrMany.Create(fullPath);
}

private static readonly string s_csharpCodeStyleAnalyzerSdkDirectory = Path.Combine("Sdks", "Microsoft.NET.Sdk", "codestyle", "cs") + PathUtilities.DirectorySeparatorStr;
Copy link
Member

@sharwell sharwell Sep 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Should we just look at the assembly name? With the current approach, if users explicitly reference a version of the code style package instead of using the one in the SDK, they will end up in the same bad IDE state we have today. The other option is to just stop shipping the code style layer as a separate package.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus far we've tried to limit this to when you load the analyzer / generator from the .NET SDK. The idea being that we want to isolate the .NET SDK from being able to negatively influence Visual Studio behavior. But our sample size is one, Razor, and there is no package option for that.

The guidance we're trying to give to 3rd party package is they need to be aware of the VS versions they can be loaded in and multi-target analyze for that.

My recommendation is start with the change as is, let's see if we get negative feedback and we can adjust based on that.

@sharwell
Copy link
Member

Note that this will load the analyzers which ship in the IDE, but it does not correct the error where the wrong options are provided to those analyzers (analyzers in the IDE use values from Tools > Options, but those same analyzers in a build do not).

return OneOrMany.Create(fullPath);
}

private static readonly string s_csharpCodeStyleAnalyzerSdkDirectory = Path.Combine("Sdks", "Microsoft.NET.Sdk", "codestyle", "cs") + PathUtilities.DirectorySeparatorStr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus far we've tried to limit this to when you load the analyzer / generator from the .NET SDK. The idea being that we want to isolate the .NET SDK from being able to negatively influence Visual Studio behavior. But our sample size is one, Razor, and there is no package option for that.

The guidance we're trying to give to 3rd party package is they need to be aware of the VS versions they can be loaded in and multi-target analyze for that.

My recommendation is start with the change as is, let's see if we get negative feedback and we can adjust based on that.

project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.Fixes.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.dll"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all of these DLLs already in box that we're mapping to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably needs VB too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the in box code style analyzers. We are ensuring that they do not get returned as AnalyzerReferences from the Project. Which means they will not be used for analysis.

}

return OneOrMany<string>.Empty;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My one fear is that this is hard to test in a unit test. Do we have an item on the queue to do manual verification of Razor / Code style once this is all merged in?

Have we thought about adding an integration test that verifies we redirected these loads?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be easy enough to write an integration test for this. Will do as a follow up after the snap.

@jasonmalinowski
Copy link
Member

The analyzers are still listed in the Solution Explorer but without any associated analyzers.

Do we have a design-time target somewhere we can add a hack in that removes these at the MSBuild level instead? This is a perfectly fine tactical fix of course, but that'd avoid side effects like this.

Comment on lines +223 to +218
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.Fixes.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.dll"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do resource binaries get added too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe resource binaries are added as AnalyzerReferences to the project. I would expect they are loaded by the AnalyzerAssemblyLoader.

project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.Fixes.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.dll"))
project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.dll"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably needs VB too.


private bool IsSdkCodeStyleAnalyzer(string fullPath)
{
if (Language == LanguageNames.CSharp &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to just match on Sdks\Microsoft.NET.Sdk\codestyle and work for both languages at once?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to make that change. Didn't have a good feel with how specific we wanted to get.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually will keep it as is. The code currently checks for the analyzer path to end with the folder path fragment which is a stronger guarantee than just containing the fragment.

{
// We discard the CodeStyle analyzers added by the SDK when the EnforceCodeStyleInBuild property is set.
// The same analyzers ship in-box as part of the Features layer and are version matched to the compiler.
return OneOrMany<string>.Empty;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to call it out explicitly, doing this here will:

  1. Also apply to VS Code (which might be reasonable since we'll have similar issues there I imagine)
  2. Will not apply to MSBuildWorkspace, which might be bad, or might not be.

The latter we can of course defer for this change (since this has huge dogfooding benefit), but wanted to call out the former.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't love that we're expanding this mechanism, given the work we're doing to allow the SDK to redirect analyzers via #74820

That isn't a reason to block on this, given its not done yet, but could we open an issue to investigate if we could replace this with the new API when it's introduced?

@JoeRobich JoeRobich enabled auto-merge (squash) September 26, 2024 22:28
}

return OneOrMany.Create(fullPath);
}

private static string CreateDirectoryPathFragment(params string[] paths) => Path.Combine([" ", .. paths, " "]).Trim();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

" "

Why did this switch from the directory separator char to a space?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So Path.Combine will add the separator then we trim it off the spaces. Was just trying to put the work onto Path.Combine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is dumb. Happy to revert it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not dumb, just a little too tricky for me to spot without the explanation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to do a follow up that adds an integration test. Will add a comment here as well.

@JoeRobich
Copy link
Member Author

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@KirillOsenkov
Copy link
Member

@JoeRobich quick question: will it work if the paths to analyzers contain ..?

I haven't tried in VS, but some other hosts receive paths like this:
C:\Program Files\dotnet\sdk\9.0.100-rc.1.24452.12\Sdks\Microsoft.NET.Sdk\targets\..\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll, so need to first call Path.GetFullPath() on the reference before calling IsSdk...

I haven't checked whether the VS project system normalizes paths before this codepath is hit.

@JoeRobich
Copy link
Member Author

so need to first call Path.GetFullPath() on the reference before calling IsSdk...

Thanks for checking! We do call Path.GetFullPath() just before.

private OneOrMany<string> GetMappedAnalyzerPaths(string fullPath)
{
fullPath = Path.GetFullPath(fullPath);
if (IsSdkCodeStyleAnalyzer(fullPath))

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

Successfully merging this pull request may close these issues.

9 participants