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

Communicate with OOP process to determine if an AnalyzerReference has analyzers or source generators. #74810

Merged
merged 19 commits into from
Aug 20, 2024

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Aug 19, 2024

Fixes #43008

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Aug 19, 2024
@CyrusNajmabadi CyrusNajmabadi changed the title WIP: OOP analyzer references Communicate with OOP process to determine if an AnalyzerReference has analyzers or source generators. Aug 19, 2024
@@ -2,19 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.
Copy link
Member Author

Choose a reason for hiding this comment

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

View with whitespace off.

@@ -2,237 +2,174 @@
// The .NET Foundation licenses this file to you under the MIT license.
Copy link
Member Author

Choose a reason for hiding this comment

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

this is effectively a rewrite. I recommend SxS diff view.

Copy link
Member Author

Choose a reason for hiding this comment

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

This was rewritten in the style of #74444 and #74448


public bool HasItems => true;

public IEnumerable Items => _folderItems;

public object SourceItem => _projectHierarchyItem;

internal void Update()
Copy link
Member Author

Choose a reason for hiding this comment

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

this was only called in the constructor. so it could be inlined. once inlined, it meant that almost all state held int his type went away.

/// equal to <paramref name="analyzerReferenceFullPath"/> has any analyzers or source generators.
/// </summary>
ValueTask<bool> HasAnalyzersOrSourceGeneratorsAsync(
Checksum solutionChecksum, ProjectId projectId, string analyzerReferenceFullPath, CancellationToken cancellationToken);
Copy link
Member Author

Choose a reason for hiding this comment

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

this was the core goal of hte PR. The VS SolutionExplroer side should defer to it to answer this question, instead of loading analyzers/generators in proc (which doesn't work with reloading with .Net Framework).

@@ -143,10 +143,25 @@ public ValueTask<ImmutableArray<SourceGeneratorIdentity>> GetSourceGeneratorIden
{
var project = solution.GetRequiredProject(projectId);
var analyzerReference = project.AnalyzerReferences
.OfType<AnalyzerFileReference>()
Copy link
Member Author

Choose a reason for hiding this comment

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

this was a mistake. And will not work once #74780 goes in. In that PR we no longer have AnalyzerFileReference as the outermost type in the OOP side. Instead, we have a wrapper AnalyzerReference type that ensures that we track if analyzers/generators are asked for.

{
// The set of AnalyzerItems hasn't been realized yet. Just signal that HasItems
// may have changed.
private readonly BulkObservableCollection<AnalyzerItem> _items = [];
Copy link
Member Author

Choose a reason for hiding this comment

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

instead of a collection we overwrite, we now just use a BOC as that can be mutated in place while handling notification to appropriate listeners.

{
_analyzerReferences = project.AnalyzerReferences;
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly AsyncBatchingWorkQueue _workQueue;
Copy link
Member Author

Choose a reason for hiding this comment

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

switched to a work queue model. We listen to workspace vents, which then just pulse the queue.

}
*/
}
var client = await RemoteHostClient.TryGetClientAsync(this.Workspace, cancellationToken).ConfigureAwait(false);
Copy link
Member Author

Choose a reason for hiding this comment

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

we now call to oop if possible to figure out this information.

using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.Internal.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Imaging;
using Microsoft.VisualStudio.Imaging.Interop;

namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer;

internal partial class AnalyzerItem(
internal sealed partial class AnalyzerItem(
Copy link
Member Author

Choose a reason for hiding this comment

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

just cleanup. No other changes.

}
}
=> analyzerReference is UnresolvedAnalyzerReference unresolvedAnalyzerReference
? unresolvedAnalyzerReference.FullPath
Copy link
Member Author

Choose a reason for hiding this comment

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

this prevents an NRT warning by accessing FullPath through teh derived type.

protected override IAttachedCollectionSource? CreateCollectionSource(AnalyzersFolderItem analyzersFolder, string relationshipName)
=> relationshipName == KnownRelationships.Contains
? new AnalyzerItemSource(analyzersFolder, commandHandler, listenerProvider)
: null;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

just cleanup. No other changes.

VisualStudioWorkspace workspace,
[Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler)
: AttachedCollectionSourceProvider<IVsHierarchyItem>
{
private readonly IThreadingContext _threadingContext = threadingContext;
private readonly Workspace _workspace = workspace;
Copy link
Member Author

Choose a reason for hiding this comment

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

passing along IThreadingContext so we update the UI on the UI thread.

.First(r => r.FullPath == analyzerReferenceFullPath);

return ValueTaskFactory.FromResult(analyzerReference.HasAnalyzersOrSourceGenerators(project.Language));
}, cancellationToken);
Copy link
Member Author

Choose a reason for hiding this comment

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

same pattern as the above method.

@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review August 19, 2024 20:47
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner August 19, 2024 20:47
@CyrusNajmabadi
Copy link
Member Author

@ToddGrun @jasonmalinowski ptal.

var referencesToAdd = GetFilteredAnalyzers(_analyzerReferences, project)
.Where(r => !_analyzerItems.Any(item => item.AnalyzerReference == r))
.ToArray();
_workQueue = new AsyncBatchingWorkQueue(
Copy link
Contributor

Choose a reason for hiding this comment

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

AsyncBatchingWorkQueue

ABWQ to the rescue again!!! Will there be a user-facing change here due to the delay between the Workspace event and the collection update?

Copy link
Member Author

Choose a reason for hiding this comment

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

Technically yes. But so minor is unnoticible


_analyzerItems.EndBulkOperation();
// Defer actual determination and computation of the items until later.
public bool HasItems => !_cancellationTokenSource.IsCancellationRequested;
Copy link
Contributor

Choose a reason for hiding this comment

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

HasItems

Is this used in solution explorer to determine if it is expandable?

Copy link
Member Author

Choose a reason for hiding this comment

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

correct. This matches what many of our SE nodes do though, which is to guess that they have children while computing asynchronously.

Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

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

:shipit:

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.

Move logic that populates Solution Explorer Analyzer node OOP
3 participants