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

When replacing CodeStyle analyzers do not provide Features analyzers fallback options #75534

Merged
merged 7 commits into from
Oct 24, 2024

Conversation

JoeRobich
Copy link
Member

@JoeRobich JoeRobich commented Oct 16, 2024

This PR adds a ProjectAttribute to track whether the Project uses the SDK CodeStyle analyzers. This attribute is populated by the ProjectSystemProject which has access to the unmapped set of AnalyzerReferences. This attribute is then used when creating the HostAnalyzerStateSets to determine whether the Features analyzers should be treated as Project analyzers or not. It is also used by the DiagnosticComputer when building the Host and Project CompilationWithAnalyzers to ensure they mirror the statesets.

Suggest to review a commit at a time.

Also plumbs through updating the attribute throughout the various Solution and *State classes.
Use the unmapped references to update the HasSdkCodeStyleAnalyzer ProjectAttribute.
When Features analyzers are being used to replace SDK CodeStyle analyzer we need to treat them as project analyzers and not provide them with the Host's fallback options.
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 16, 2024
…analyzers.

In particular we will treat Features analyzers as project analyzers when a project is using SDK CodeStyle analyzers. This mirrors the change that redirects Features analyzers in the HostStateSets. This is necessary to keep the CompilationsWithAnalyzers in sync with the statesets.
@JoeRobich JoeRobich marked this pull request as ready for review October 22, 2024 06:49
@JoeRobich JoeRobich requested a review from a team as a code owner October 22, 2024 06:49
@@ -1061,6 +1093,14 @@ private OneOrMany<string> GetMappedAnalyzerPaths(string fullPath)
_ => false,
};

private void UpdateHasSdkCodeStyleAnalyzers()
Copy link
Member

Choose a reason for hiding this comment

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

Is this used?

_unmappedProjectAnalyzerPaths.Add(fullPath);

// Determine if we started using SDK CodeStyle analyzers while access to _unmappedProjectAnalyzerPaths is gated.
containsSdkCodeStyleAnalyzers = _unmappedProjectAnalyzerPaths.Any(IsSdkCodeStyleAnalyzer);
Copy link
Member

Choose a reason for hiding this comment

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

Can we do containsSdkCodeStyleAnalyzers = _hasSdkCodeStyleAnalyzers | IsSdkCodeStyleAnalyzer(fullPath) instead of enumerating all the paths each time?

Copy link
Member

Choose a reason for hiding this comment

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

agree on tweaking this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changing this to only track the codestyle analyzer paths instead of tracking all analyzer paths. Only one call to IsSdkCodeStyleAnalyzer when adding or removing.

@@ -58,6 +58,11 @@ internal sealed partial class ProjectSystemProject
/// </summary>
private readonly HashSet<string> _projectAnalyzerPaths = [];

/// <summary>
Copy link
Member

Choose a reason for hiding this comment

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

Add explanation of what mapping of analyzer references means.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changing this field name to _sdkCodeStyleAnalyzerPaths which I think is self explanatory.

var hostAnalyzerCollection = new List<ImmutableArray<DiagnosticAnalyzer>>();
var projectAnalyzerCollection = new List<ImmutableArray<DiagnosticAnalyzer>>();

foreach (var kvp in analyzersPerReference)
Copy link
Member

@tmat tmat Oct 23, 2024

Choose a reason for hiding this comment

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

Deconstruct: foreach (var (referenceId, analyzers) in analyzersPerReference)

"Microsoft.CodeAnalysis.VisualBasic.Features.dll",
}.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase);

private static ImmutableSegmentedDictionary<string, bool> s_analyzerFullPathToIsFeatureAnalyzer = ImmutableSegmentedDictionary<string, bool>.Empty;
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to cache this? It's just simple comparison of 3 strings.

Copy link
Member

@tmat tmat Oct 23, 2024

Choose a reason for hiding this comment

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

You can simplify to:

bool IsFeaturesAnalyzer(this AnalyzerReference reference)
{
  var fileNameSpan = reference.FullPath.AsSpan(FileNameUtilities.IndexOfFileName(reference.FullPath));
  return 
    fileNameSpan.Equals("Microsoft.CodeAnalysis.Features.dll", StringComparison.OrdinalIgnoreCase) ||
    fileNameSpan.Equals("Microsoft.CodeAnalysis.CSharp.Features.dll", StringComparison.OrdinalIgnoreCase) ||
    fileNameSpan.Equals("Microsoft.CodeAnalysis.VisualBasic.Features.dll", 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.

agreed. dictionaries fo rthis seem unnecessary.

@tmat
Copy link
Member

tmat commented Oct 23, 2024

Reviewed up to commit 5.

_unmappedProjectAnalyzerPaths.Add(fullPath);

// Determine if we started using SDK CodeStyle analyzers while access to _unmappedProjectAnalyzerPaths is gated.
containsSdkCodeStyleAnalyzers = _unmappedProjectAnalyzerPaths.Any(IsSdkCodeStyleAnalyzer);
Copy link
Member

Choose a reason for hiding this comment

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

❓ What about

containsSdkCdoeStyleAnalyzers = HasSdkCodeStyleAnalyzers || IsSdkCodeStyleAnalyzer(fullPath);

_unmappedProjectAnalyzerPaths.Remove(fullPath);

// Determine if we are still using SDK CodeStyle analyzers while access to _unmappedProjectAnalyzerPaths is gated.
containsSdkCodeStyleAnalyzers = _unmappedProjectAnalyzerPaths.Any(IsSdkCodeStyleAnalyzer);
Copy link
Member

Choose a reason for hiding this comment

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

💡 Can also simplify this one:

containsSdkCodeStyleAnalyzers = IsSdkCodeStyleAnalyzer(fullPath)
    ? _unmappedProjectAnalyzerPaths.Any(IsSdkCodeStyleAnalyzer)
    : HasSdkCodeStyleAnalyzers;


return new HostAnalyzerStateSets(analyzerMap);
}

static (IEnumerable<ImmutableArray<DiagnosticAnalyzer>> HostAnalyzerCollection, IEnumerable<ImmutableArray<DiagnosticAnalyzer>> ProjectAnalyzerCollection) GetAnalyzerCollections(
Copy link
Member

Choose a reason for hiding this comment

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

def don't like returning these as lazy enumerbles. can you make both an ImmutableArray<ImmutableArray<...

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 could but then we have to do something about the common case where we aren't redirecting and are returning analyzersPerReference.Values which is an IEnumerable<ImmutableArray<DiagnosticAnalyzer>>. The use of these IEnumerable's is also piped into StateManager.CreateStateSetMap. This might be cleanup for a follow up PR.

Copy link
Member

Choose a reason for hiding this comment

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

which is an IEnumerable<ImmutableArray>

Ick :) Can that one change?

Copy link
Member

Choose a reason for hiding this comment

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

at the very least, don't return mutable lists. return an immutable array here. that way we don't have to worry about it changing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated to use ArrayBuilder instead of List.

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.

5 participants