44using System . Collections . Immutable ;
55using System . ComponentModel . Composition ;
66using System . IO ;
7+ using System . Linq ;
78using System . Threading ;
89using System . Threading . Tasks ;
910using Microsoft . CodeAnalysis ;
@@ -70,34 +71,34 @@ private async Task<bool> FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h
7071 return await FixSolutionAsync ( _workspace . CurrentSolution , context ) . ConfigureAwait ( true ) ;
7172 }
7273
73- var itemId = hierarchyContent . ItemId ;
74- if ( itemId == ( uint ) VSConstants . VSITEMID . Root )
74+ // Map the hierarchy to a ProjectId. For hierarchies mapping to multitargeted projects, we first try to
75+ // get the project in the most recent active context, but fall back to the first target framework if no
76+ // active context is available.
77+ var hierarchyToProjectMap = _workspace . Services . GetRequiredService < IHierarchyItemToProjectIdMap > ( ) ;
78+
79+ await _threadingContext . JoinableTaskFactory . SwitchToMainThreadAsync ( context . OperationContext . UserCancellationToken ) ;
80+ context . OperationContext . UserCancellationToken . ThrowIfCancellationRequested ( ) ;
81+
82+ ProjectId projectId = null ;
83+ if ( ErrorHandler . Succeeded ( hierarchy . GetProperty ( ( uint ) VSConstants . VSITEMID . Root , ( int ) __VSHPROPID8 . VSHPROPID_ActiveIntellisenseProjectContext , out var contextProjectNameObject ) )
84+ && contextProjectNameObject is string contextProjectName
85+ && hierarchy . TryGetProjectGuid ( out var projectGuid ) )
7586 {
76- // Map the hierarchy to a ProjectId. For hierarchies mapping to multitargeted projects, we first try to
77- // get the project in the most recent active context, but fall back to the first target framework if no
78- // active context is available.
79- var hierarchyToProjectMap = _workspace . Services . GetRequiredService < IHierarchyItemToProjectIdMap > ( ) ;
80-
81- await _threadingContext . JoinableTaskFactory . SwitchToMainThreadAsync ( context . OperationContext . UserCancellationToken ) ;
82- context . OperationContext . UserCancellationToken . ThrowIfCancellationRequested ( ) ;
83-
84- ProjectId projectId = null ;
85- if ( ErrorHandler . Succeeded ( hierarchy . GetProperty ( ( uint ) VSConstants . VSITEMID . Root , ( int ) __VSHPROPID8 . VSHPROPID_ActiveIntellisenseProjectContext , out var contextProjectNameObject ) )
86- && contextProjectNameObject is string contextProjectName
87- && hierarchy . TryGetProjectGuid ( out var projectGuid ) )
88- {
89- projectId = _workspace . GetProjectWithGuidAndName ( projectGuid , contextProjectName ) ? . Id ;
90- }
87+ projectId = _workspace . GetProjectWithGuidAndName ( projectGuid , contextProjectName ) ? . Id ;
88+ }
9189
92- if ( projectId is null )
90+ if ( projectId is null )
91+ {
92+ var projectHierarchyItem = _vsHierarchyItemManager . GetHierarchyItem ( hierarchyContent . Hierarchy , ( uint ) VSConstants . VSITEMID . Root ) ;
93+ if ( ! hierarchyToProjectMap . TryGetProjectId ( projectHierarchyItem , targetFrameworkMoniker : null , out projectId ) )
9394 {
94- var projectHierarchyItem = _vsHierarchyItemManager . GetHierarchyItem ( hierarchyContent . Hierarchy , itemId ) ;
95- if ( ! hierarchyToProjectMap . TryGetProjectId ( projectHierarchyItem , targetFrameworkMoniker : null , out projectId ) )
96- {
97- return false ;
98- }
95+ return false ;
9996 }
97+ }
10098
99+ var itemId = hierarchyContent . ItemId ;
100+ if ( itemId == ( uint ) VSConstants . VSITEMID . Root )
101+ {
101102 await TaskScheduler . Default ;
102103
103104 var project = _workspace . CurrentSolution . GetProject ( projectId ) ;
@@ -119,9 +120,18 @@ private async Task<bool> FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h
119120 }
120121 else
121122 {
122- // document
123- // TODO: this one will be implemented later
124- // https://github.com/dotnet/roslyn/issues/30165
123+ // Handle code cleanup for a single document
124+ await TaskScheduler . Default ;
125+
126+ var solution = _workspace . CurrentSolution ;
127+ var documentIds = solution . GetDocumentIdsWithFilePath ( path ) ;
128+ var documentId = documentIds . FirstOrDefault ( id => id . ProjectId == projectId ) ;
129+ if ( documentId is null )
130+ {
131+ return false ;
132+ }
133+
134+ return await FixDocumentAsync ( solution . GetDocument ( documentId ) , context ) . ConfigureAwait ( true ) ;
125135 }
126136 }
127137
@@ -152,6 +162,18 @@ async Task<Solution> ApplyFixAsync(ProgressTracker progressTracker, Cancellation
152162 }
153163 }
154164
165+ private Task < bool > FixDocumentAsync ( Document document , ICodeCleanUpExecutionContext context )
166+ {
167+ return FixAsync ( document . Project . Solution . Workspace , ApplyFixAsync , context , document . Name ) ;
168+
169+ // Local function
170+ async Task < Solution > ApplyFixAsync ( ProgressTracker progressTracker , CancellationToken cancellationToken )
171+ {
172+ var newDocument = await FixDocumentAsync ( document , context . EnabledFixIds , progressTracker , cancellationToken ) . ConfigureAwait ( true ) ;
173+ return newDocument . Project . Solution ;
174+ }
175+ }
176+
155177 private Task < bool > FixTextBufferAsync ( TextBufferCodeCleanUpScope textBufferScope , ICodeCleanUpExecutionContext context )
156178 {
157179 var buffer = textBufferScope . SubjectBuffer ;
0 commit comments