Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@ internal sealed partial class DependenciesTreeProvider : ProjectTreeProviderBase
private readonly OrderPrecedenceImportCollection<IProjectTreeActionHandler> _removalActionHandlers;

private readonly DependenciesSnapshotProvider _dependenciesSnapshotProvider;
private readonly IActiveConfiguredValue<IConfiguredProjectExports> _activeConfiguredProjectExports;
private readonly CancellationSeries _treeUpdateCancellationSeries;
private readonly IProjectAccessor _projectAccessor;
private readonly ITaskDelayScheduler _debounce;
private readonly TaskDelayScheduler _debounce;

// NOTE we use a property import here as importing this via the constructor creates a loop between
// DependenciesTreeProvider and DependenciesTreeBuilder. A property import allows MEF to break that
// circular dependency.
[Import]
private DependenciesTreeBuilder TreeBuilder { get; set; } = null!;

Expand All @@ -68,11 +72,13 @@ public DependenciesTreeProvider(
IProjectThreadingService threadingService,
IUnconfiguredProjectTasksService tasksService,
IProjectAccessor projectAccessor,
DependenciesSnapshotProvider dependenciesSnapshotProvider)
DependenciesSnapshotProvider dependenciesSnapshotProvider,
IActiveConfiguredValue<IConfiguredProjectExports> activeConfiguredProjectExports)
: base(threadingService, unconfiguredProject)
{
_dependenciesSnapshotProvider = dependenciesSnapshotProvider;
_projectAccessor = projectAccessor;
_activeConfiguredProjectExports = activeConfiguredProjectExports;

_removalActionHandlers = new OrderPrecedenceImportCollection<IProjectTreeActionHandler>(
ImportOrderPrecedenceComparer.PreferenceOrder.PreferredComesFirst,
Expand Down Expand Up @@ -377,7 +383,7 @@ await _projectAccessor.OpenProjectForWriteAsync(ActiveConfiguredProject, project

protected override ConfiguredProjectExports GetActiveConfiguredProjectExports(ConfiguredProject newActiveConfiguredProject)
{
return GetActiveConfiguredProjectExports<MyConfiguredProjectExports>(newActiveConfiguredProject);
return (ConfiguredProjectExports)_activeConfiguredProjectExports.Value;
}

#region ITreeConstruction
Expand Down Expand Up @@ -479,29 +485,25 @@ IProjectItemTree2 IProjectTreeOperations.NewTree(string caption, IProjectPropert
/// <summary>
/// Describes services collected from the active configured project.
/// </summary>
[Export]
private sealed class MyConfiguredProjectExports : ConfiguredProjectExports
[Export(typeof(IConfiguredProjectExports))]
[method: ImportingConstructor]
private sealed class MyConfiguredProjectExports(ConfiguredProject configuredProject)
: ConfiguredProjectExports(configuredProject),
IConfiguredProjectExports
{
[ImportingConstructor]
public MyConfiguredProjectExports(ConfiguredProject configuredProject)
: base(configuredProject)
{
}
}

/// <summary>
/// A private implementation of <see cref="IProjectTreeActionHandlerContext"/> for use with
/// <see cref="IProjectTreeActionHandler"/> exports.
/// </summary>
private sealed class ProjectDependencyTreeRemovalActionHandlerContext : IProjectTreeActionHandlerContext
private sealed class ProjectDependencyTreeRemovalActionHandlerContext(IProjectTreeProvider treeProvider) : IProjectTreeActionHandlerContext
{
public IProjectTreeProvider TreeProvider { get; }
public IProjectTreeProvider TreeProvider { get; } = treeProvider;

public IProjectTreeActionHandler SuccessorHandlerDelegator => throw new NotImplementedException();

public ProjectDependencyTreeRemovalActionHandlerContext(IProjectTreeProvider treeProvider)
{
TreeProvider = treeProvider;
}
}

// NOTE this interface is needed to work around accessiblity issues when making MyConfiguredProjectExports non-private
Copy link
Member

Choose a reason for hiding this comment

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

could you be more specific in this comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

Honestly this one had me stumped. The compiler claimed there was a visibility issue (CS0060), and the issue couldn't be suppressed. Something to do with the base type being protected internal yet in a different assembly, maybe. I was confused enough to even view (and edit) the docs for that diagnostic. So, I don't have much more context to add here. If you remove the interface and try to export the concrete type, you'll see the issue.

internal interface IConfiguredProjectExports { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal sealed class ImportTreeProvider : ProjectTreeProviderBase, IProjectTree
private readonly UnconfiguredProject _project;
private readonly IActiveConfiguredProjectSubscriptionService _projectSubscriptionService;
private readonly IUnconfiguredProjectTasksService _unconfiguredProjectTasksService;
private readonly IActiveConfiguredValue<IConfiguredProjectExports> _activeConfiguredProjectExports;

private DisposableBag? _subscriptions;
private bool _showAllFiles;
Expand All @@ -54,12 +55,14 @@ internal ImportTreeProvider(
IProjectThreadingService threadingService,
UnconfiguredProject project,
IActiveConfiguredProjectSubscriptionService projectSubscriptionService,
IUnconfiguredProjectTasksService unconfiguredProjectTasksService)
IUnconfiguredProjectTasksService unconfiguredProjectTasksService,
IActiveConfiguredValue<IConfiguredProjectExports> activeConfiguredProjectExports)
: base(threadingService, project, useDisplayOrdering: true)
{
_project = project;
_projectSubscriptionService = projectSubscriptionService;
_unconfiguredProjectTasksService = unconfiguredProjectTasksService;
_activeConfiguredProjectExports = activeConfiguredProjectExports;
}

public override string? GetPath(IProjectTree node)
Expand Down Expand Up @@ -346,9 +349,7 @@ void TearDownTree()

protected override ConfiguredProjectExports GetActiveConfiguredProjectExports(ConfiguredProject newActiveConfiguredProject)
{
Requires.NotNull(newActiveConfiguredProject);

return GetActiveConfiguredProjectExports<MyConfiguredProjectExports>(newActiveConfiguredProject);
return (ConfiguredProjectExports)_activeConfiguredProjectExports.Value;
}

protected override void Dispose(bool disposing)
Expand All @@ -361,13 +362,14 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

[Export]
private sealed class MyConfiguredProjectExports : ConfiguredProjectExports
[Export(typeof(IConfiguredProjectExports))]
[method: ImportingConstructor]
private sealed class MyConfiguredProjectExports(ConfiguredProject configuredProject)
: ConfiguredProjectExports(configuredProject),
IConfiguredProjectExports
{
[ImportingConstructor]
public MyConfiguredProjectExports(ConfiguredProject configuredProject)
: base(configuredProject)
{
}
}

// NOTE this interface is needed to work around accessiblity issues when making MyConfiguredProjectExports non-private
internal interface IConfiguredProjectExports { }
}