Skip to content

Conversation

@jjonescz jjonescz marked this pull request as ready for review November 5, 2025 13:24
@jjonescz jjonescz requested a review from a team as a code owner November 5, 2025 13:24
@jjonescz jjonescz requested review from 333fred and JoeRobich November 5, 2025 13:25
@jjonescz
Copy link
Member Author

jjonescz commented Dec 2, 2025

@jasonmalinowski for another look, thanks

Comment on lines 53 to 54
var enable = Environment.GetEnvironmentVariable("DOTNET_ANALYZER_REDIRECTING");
_enabled = !"0".Equals(enable, StringComparison.OrdinalIgnoreCase) && !"false".Equals(enable, StringComparison.OrdinalIgnoreCase);
Copy link
Member

Choose a reason for hiding this comment

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

Should this be using VS feature flags or a user setting or something else? We don't usually use enviornment variables much if we can since we have other mechanisms.

Copy link
Member

Choose a reason for hiding this comment

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

It's also a bit weird that setting these environment variables would break tests. If we were going to keep it, I'd expect that was read at the non-unit derived type.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, I'm not familiar with VS feature flags, I guess that's a bit complicated to add one? Is there an example or docs how to add new one? I just wanted a way to opt out if necessary, but originally I didn't even have that and I think that might be fine too.

Copy link
Member

Choose a reason for hiding this comment

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

Feature flags would be for if you wanted to support a rollback more generally, or you were trying to A/B test this or something. If you just wanted a setting, then this could be a user setting. You'd add that setting to our unified settings registration (maybe there's a way to hide it though?) and follow what #81503 added.

Comment on lines 92 to 95
if (!analyzerPath.StartsWith(topLevelDirectory, StringComparison.OrdinalIgnoreCase))
{
continue;
}
Copy link
Member

Choose a reason for hiding this comment

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

How would this happen? Or just a paranoia check?

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 guess the latter, I will add an assert.

Copy link
Member

Choose a reason for hiding this comment

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

Use Debug.Fail() here, so you can add a message or something. And add a comment. We normally don't use asserts much on the IDE side, but given a throw here might really break things (i.e. no analyzers added for you!), it's probably appropriate here.

}

var subsetName = Path.GetFileName(topLevelDirectory);
if (!versions.TryGetValue(subsetName, out var version))
Copy link
Member

Choose a reason for hiding this comment

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

It'd be nice if there was a comment what the versions JSON is or looks like. There's not a file I can look at right now so I'm guessing, but I would have assumed versioning was related to the individual DLL which is odd since this path isn't depending on that yet....

Copy link
Member Author

Choose a reason for hiding this comment

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

There is an example in the doc (which is linked in the doc comment of SdkAnalyzerAssemblyRedirector): https://github.com/dotnet/sdk/blob/main/documentation/general/analyzer-redirecting.md

Copy link
Member

Choose a reason for hiding this comment

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

Ah that's really helpful. How does versioning work in this design them? If we needed to have redirected versions for a 9.0 and 10.0, then there'd be two top level folders in the JSON with different names?

Copy link
Member Author

@jjonescz jjonescz Dec 22, 2025

Choose a reason for hiding this comment

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

If we needed to have redirected versions for a 9.0 and 10.0

That's intentionally unsupported. There is always only one SDK version inserted into VS anyway.

then there'd be two top level folders in the JSON with different names?

I guess that would technically work. I will add a test. But that won't happen in the way we currently generate the payload in the sdk repo.

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Looks good. Wouldn't mind a few more tests around "very" unexpected path cases just to make sure we don't trip up on those. For example, you have lots of tests for when the paths look "about right", but would the path mapping code get messed up where the suffix does match, but that's the root of the drive? Or just C:\AnalyzerName.dll? We've had bugs like that in the past.

Comment on lines 92 to 95
if (!analyzerPath.StartsWith(topLevelDirectory, StringComparison.OrdinalIgnoreCase))
{
continue;
}
Copy link
Member

Choose a reason for hiding this comment

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

Use Debug.Fail() here, so you can add a message or something. And add a comment. We normally don't use asserts much on the IDE side, but given a throw here might really break things (i.e. no analyzers added for you!), it's probably appropriate here.

}

var subsetName = Path.GetFileName(topLevelDirectory);
if (!versions.TryGetValue(subsetName, out var version))
Copy link
Member

Choose a reason for hiding this comment

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

Ah that's really helpful. How does versioning work in this design them? If we needed to have redirected versions for a 9.0 and 10.0, then there'd be two top level folders in the JSON with different names?

var enable = Environment.GetEnvironmentVariable("DOTNET_ANALYZER_REDIRECTING");
if (!"0".Equals(enable, StringComparison.OrdinalIgnoreCase) && !"false".Equals(enable, StringComparison.OrdinalIgnoreCase))
{
return Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CommonExtensions\Microsoft\DotNet"));
Copy link
Member

Choose a reason for hiding this comment

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

Should this check if the folder is present first? Or we're trusting that nothing will try to use it before the File.Exists check doesn't find the metadata.json?

Copy link
Member Author

@jjonescz jjonescz Dec 22, 2025

Choose a reason for hiding this comment

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

we're trusting that nothing will try to use it before the File.Exists check doesn't find the metadata.json

Yes, in the current implementation, the directory path is not even stored anywhere else, so that File.Exists check should be enough I think.

return false;
}

var directoryPathVersion = Path.GetFileName(Path.GetDirectoryName(directoryPath.Substring(0, index)));
Copy link
Member

Choose a reason for hiding this comment

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

Make sure there's a test if somebody were to add a reference to Z:\analyzers\dotnet\Foo.dll or wherever, where the suffix does match but there is no parent directory.

Copy link
Member Author

@jjonescz jjonescz Dec 22, 2025

Choose a reason for hiding this comment

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

If the suffix matches, that's enough and it will be redirected, there is no need for it to have a parent directory. But I can add a test for it, thanks.

// ~~~~~~~~~~~~~~~~~~~~~~~ = topLevelDirectory
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ = analyzerPath

foreach (var topLevelDirectory in Directory.EnumerateDirectories(insertedAnalyzersDirectory))
Copy link
Member

Choose a reason for hiding this comment

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

Is there a way we can produce a file that produces all this up front so we don't need to search for binaries that ship in the product? This is having the user pay a cost for things we can absolutely determine because we insert these binaries.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, sounds doable, I will look into that, thanks.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done in 64ed67b with SDK counterpart in dotnet/sdk#52326.

@jjonescz
Copy link
Member Author

jjonescz commented Jan 9, 2026

@jasonmalinowski can you please take another look? I made some changes since your last sign off. Thanks.

@jjonescz
Copy link
Member Author

/pr-val

@github-actions
Copy link
Contributor

View PR Validation Run triggered by @jjonescz

Parameters
  • Validation Type: pr-val
  • Pipeline ID: 8972
  • Pipeline Version: main
  • PR Number: 80969
  • Commit SHA: 9a8b74832021739c44150a5cdfe255016d3f8e59
  • Source Branch: analyzer-redirecting
  • Target Branch: main
  • Build ID: 13078718

@jjonescz jjonescz merged commit bba5b13 into dotnet:main Jan 13, 2026
26 checks passed
@jjonescz jjonescz deleted the analyzer-redirecting branch January 13, 2026 09:32
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants