Skip to content

Commit eb66ed9

Browse files
committed
Replace fix and context menu in inspection results with two step menu
The new menu starts with a selection of all quick fixes applicable to the currently (main) selected result. Each one has a sub menu that allows to choose the scope of the application of the quick fix.
1 parent 97bdd9a commit eb66ed9

File tree

10 files changed

+250
-226
lines changed

10 files changed

+250
-226
lines changed

Rubberduck.CodeAnalysis/QuickFixes/Abstract/QuickFixBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,7 @@ public void RemoveInspections(params Type[] inspections)
6060
public abstract bool CanFixInProcedure { get; }
6161
public abstract bool CanFixInModule { get; }
6262
public abstract bool CanFixInProject { get; }
63+
64+
public virtual bool CanFixAll => CanFixInProject;
6365
}
6466
}

Rubberduck.CodeAnalysis/QuickFixes/IQuickFix.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public interface IQuickFix
1414
bool CanFixInProcedure { get; }
1515
bool CanFixInModule { get; }
1616
bool CanFixInProject { get; }
17+
bool CanFixAll { get; }
1718

1819
IReadOnlyCollection<Type> SupportedInspections { get; }
1920
CodeKind TargetCodeKind { get; }

Rubberduck.CodeAnalysis/QuickFixes/IQuickFixProvider.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ public interface IQuickFixProvider
1616

1717
void Fix(IQuickFix fix, IInspectionResult result);
1818

19-
void FixInProcedure(IQuickFix fix, QualifiedMemberName? selection, Type inspectionType,
20-
IEnumerable<IInspectionResult> results);
19+
void Fix(IQuickFix fix, IEnumerable<IInspectionResult> resultsToFix);
2120

22-
void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspectionType,
23-
IEnumerable<IInspectionResult> results);
21+
void FixInProcedure(IQuickFix fix, QualifiedMemberName? selection, Type inspectionType, IEnumerable<IInspectionResult> allResults);
2422

25-
void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspectionType,
26-
IEnumerable<IInspectionResult> results);
23+
void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> allResults);
2724

28-
void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionResult> results);
25+
void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> allResults);
26+
27+
void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionResult> allResults);
2928

3029
bool HasQuickFixes(IInspectionResult inspectionResult);
30+
31+
bool CanFix(IQuickFix fix, IInspectionResult result);
3132
}
3233
}

Rubberduck.CodeAnalysis/QuickFixes/Logistics/QuickFixProvider.cs

Lines changed: 46 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ public IEnumerable<IQuickFix> QuickFixes(IInspectionResult result)
5353
.OrderBy(fix => fix.SupportedInspections.Count); // most specific fixes first; keeps "ignore once" last
5454
}
5555

56-
private bool CanFix(IQuickFix fix, IInspectionResult result)
56+
public bool CanFix(IQuickFix fix, IInspectionResult result)
5757
{
58-
return QuickFixes(result).Contains(fix);
58+
return fix.SupportedInspections.Contains(result.Inspection.GetType())
59+
&& !result.DisabledQuickFixes.Contains(fix.GetType().Name);
5960
}
6061

6162
public void Fix(IQuickFix fix, IInspectionResult result)
@@ -77,40 +78,17 @@ public void Fix(IQuickFix fix, IInspectionResult result)
7778
Apply(rewriteSession);
7879
}
7980

80-
private void Apply(IExecutableRewriteSession rewriteSession)
81-
{
82-
if (!rewriteSession.TryRewrite())
83-
{
84-
_failureNotifier.NotifyQuickFixExecutionFailure(rewriteSession.Status);
85-
}
86-
}
87-
88-
private IExecutableRewriteSession RewriteSession(CodeKind targetCodeKind)
89-
{
90-
switch (targetCodeKind)
91-
{
92-
case CodeKind.CodePaneCode:
93-
return _rewritingManager.CheckOutCodePaneSession();
94-
case CodeKind.AttributesCode:
95-
return _rewritingManager.CheckOutAttributesSession();
96-
default:
97-
throw new NotSupportedException(nameof(targetCodeKind));
98-
}
99-
}
100-
101-
public void FixInProcedure(IQuickFix fix, QualifiedMemberName? qualifiedMember, Type inspectionType, IEnumerable<IInspectionResult> results)
81+
public void Fix(IQuickFix fix, IEnumerable<IInspectionResult> resultsToFix)
10282
{
103-
Debug.Assert(qualifiedMember.HasValue, "Null qualified member.");
83+
var results = resultsToFix.ToList();
10484

105-
var filteredResults = results.Where(result => result.Inspection.GetType() == inspectionType && result.QualifiedMemberName == qualifiedMember).ToList();
106-
107-
if (!filteredResults.Any())
85+
if (!results.Any())
10886
{
10987
return;
11088
}
11189

11290
var rewriteSession = RewriteSession(fix.TargetCodeKind);
113-
foreach (var result in filteredResults)
91+
foreach (var result in results)
11492
{
11593
if (!CanFix(fix, result))
11694
{
@@ -122,70 +100,63 @@ public void FixInProcedure(IQuickFix fix, QualifiedMemberName? qualifiedMember,
122100
Apply(rewriteSession);
123101
}
124102

125-
public void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> results)
103+
private void Apply(IExecutableRewriteSession rewriteSession)
126104
{
127-
var filteredResults = results.Where(result => result.Inspection.GetType() == inspectionType && result.QualifiedSelection.QualifiedName == selection.QualifiedName).ToList();
128-
129-
if (!filteredResults.Any())
105+
if (!rewriteSession.TryRewrite())
130106
{
131-
return;
107+
_failureNotifier.NotifyQuickFixExecutionFailure(rewriteSession.Status);
132108
}
109+
}
133110

134-
var rewriteSession = RewriteSession(fix.TargetCodeKind);
135-
foreach (var result in filteredResults)
111+
private IExecutableRewriteSession RewriteSession(CodeKind targetCodeKind)
112+
{
113+
switch (targetCodeKind)
136114
{
137-
if (!CanFix(fix, result))
138-
{
139-
continue;
140-
}
141-
142-
fix.Fix(result, rewriteSession);
115+
case CodeKind.CodePaneCode:
116+
return _rewritingManager.CheckOutCodePaneSession();
117+
case CodeKind.AttributesCode:
118+
return _rewritingManager.CheckOutAttributesSession();
119+
default:
120+
throw new NotSupportedException(nameof(targetCodeKind));
143121
}
144-
Apply(rewriteSession);
145122
}
146123

147-
public void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> results)
124+
public void FixInProcedure(IQuickFix fix, QualifiedMemberName? qualifiedMember, Type inspectionType, IEnumerable<IInspectionResult> allResults)
148125
{
149-
var filteredResults = results.Where(result => result.Inspection.GetType() == inspectionType && result.QualifiedSelection.QualifiedName.ProjectId == selection.QualifiedName.ProjectId).ToList();
126+
Debug.Assert(qualifiedMember.HasValue, "Null qualified member.");
150127

151-
if (!filteredResults.Any())
152-
{
153-
return;
154-
}
128+
var filteredResults = allResults
129+
.Where(result => result.Inspection.GetType() == inspectionType
130+
&& result.QualifiedMemberName == qualifiedMember);
155131

156-
var rewriteSession = RewriteSession(fix.TargetCodeKind);
157-
foreach (var result in filteredResults)
158-
{
159-
if (!CanFix(fix, result))
160-
{
161-
continue;
162-
}
132+
Fix(fix, filteredResults);
133+
}
163134

164-
fix.Fix(result, rewriteSession);
165-
}
166-
Apply(rewriteSession);
135+
public void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> allResults)
136+
{
137+
var filteredResults = allResults
138+
.Where(result => result.Inspection.GetType() == inspectionType
139+
&& result.QualifiedSelection.QualifiedName == selection.QualifiedName);
140+
141+
Fix(fix, filteredResults);
167142
}
168143

169-
public void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionResult> results)
144+
public void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> allResults)
170145
{
171-
var filteredResults = results.Where(result => result.Inspection.GetType() == inspectionType).ToArray();
146+
var filteredResults = allResults
147+
.Where(result => result.Inspection.GetType() == inspectionType
148+
&& result.QualifiedSelection.QualifiedName.ProjectId == selection.QualifiedName.ProjectId)
149+
.ToList();
172150

173-
if (!filteredResults.Any())
174-
{
175-
return;
176-
}
151+
Fix(fix, filteredResults);
152+
}
177153

178-
var rewriteSession = RewriteSession(fix.TargetCodeKind);
179-
foreach (var result in filteredResults)
180-
{
181-
if (!CanFix(fix, result))
182-
{
183-
continue;
184-
}
154+
public void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionResult> allResults)
155+
{
156+
var filteredResults = allResults
157+
.Where(result => result.Inspection.GetType() == inspectionType);
185158

186-
fix.Fix(result, rewriteSession);
187-
}
188-
Apply(rewriteSession);
159+
Fix(fix, filteredResults);
189160
}
190161

191162
public bool HasQuickFixes(IInspectionResult inspectionResult)

Rubberduck.Core/UI/Inspections/InspectionResultsControl.xaml

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<UserControl x:Class="Rubberduck.UI.Inspections.InspectionResultsControl"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4-
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:codeInspections="clr-namespace:Rubberduck.UI.Inspections"
77
xmlns:controls="clr-namespace:Rubberduck.UI.Controls"
@@ -21,6 +21,24 @@
2121
<codeInspections:InspectionSeverityImageSourceConverter x:Key="SeverityIconConverter" />
2222
<codeInspections:InspectionImageSourceConverter x:Key="InspectionIconConverter" />
2323
<codeInspections:QuickFixImageSourceConverter x:Key="QuickFixIconConverter" />
24+
<codeInspections:InspectionsUIResourceKeyConverter x:Key="InspectionsUIResourceConverter" />
25+
26+
<Style TargetType="MenuItem" x:Key="QuickFixCommandStyle">
27+
<Setter Property="Header" Value="{Binding Key, Converter={StaticResource InspectionsUIResourceConverter}}" />
28+
<Setter Property="Command" Value="{Binding Command}"/>
29+
<Setter Property="CommandParameter" Value="{Binding Fix}"/>
30+
</Style>
31+
32+
<Style TargetType="MenuItem" x:Key="QuickFixItemStyle">
33+
<Setter Property="Header" Value="{Binding Description}"/>
34+
<Setter Property="Icon">
35+
<Setter.Value>
36+
<Image Source="{Binding Fix, Converter={StaticResource QuickFixIconConverter}}" />
37+
</Setter.Value>
38+
</Setter>
39+
<Setter Property="ItemsSource" Value="{Binding Commands}" />
40+
<Setter Property="ItemContainerStyle" Value="{StaticResource QuickFixCommandStyle}" />
41+
</Style>
2442

2543
<Style x:Key="IconMargin" TargetType="Image">
2644
<Setter Property="Margin" Value="4" />
@@ -78,26 +96,15 @@
7896
<Menu Background="Transparent">
7997
<MenuItem VerticalAlignment="Center"
8098
HeaderTemplate="{StaticResource MenuItemHeaderDropdownIndicatorTemplate}"
81-
ItemsSource="{Binding QuickFixes}" Background="Transparent">
99+
ItemsSource="{Binding QuickFixes}"
100+
Background="Transparent"
101+
ItemContainerStyle="{StaticResource QuickFixItemStyle}">
82102
<MenuItem.Icon>
83103
<Image Source="{StaticResource FixImage}" />
84104
</MenuItem.Icon>
85105
<MenuItem.Header>
86106
<TextBlock Text="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=Fix}" />
87107
</MenuItem.Header>
88-
<MenuItem.ItemContainerStyle>
89-
<Style TargetType="{x:Type MenuItem}">
90-
<Setter Property="Icon">
91-
<Setter.Value>
92-
<Image Source="{Binding Fix, Converter={StaticResource QuickFixIconConverter}}" />
93-
</Setter.Value>
94-
</Setter>
95-
<Setter Property="Command" Value="{Binding Command}" />
96-
<Setter Property="CommandParameter" Value="{Binding Fix}" />
97-
<Setter Property="Header" Value="{Binding Description}" />
98-
<Setter Property="Background" Value="Transparent"></Setter>
99-
</Style>
100-
</MenuItem.ItemContainerStyle>
101108
</MenuItem>
102109
</Menu>
103110

@@ -224,21 +231,8 @@
224231
<DataGridTextColumn Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=CodeInspectionResults_Location}" Binding="{Binding QualifiedSelection.QualifiedName, Mode=OneTime, Converter={StaticResource GroupingGridLocationConverter}}" />
225232
</DataGrid.Columns>
226233
<DataGrid.ContextMenu>
227-
<ContextMenu ItemsSource="{Binding PlacementTarget.DataContext.QuickFixes, RelativeSource={RelativeSource Self}}">
228-
<ContextMenu.Resources>
229-
<Style TargetType="{x:Type MenuItem}">
230-
<Setter Property="Icon">
231-
<Setter.Value>
232-
<Image Source="{Binding Fix, Converter={StaticResource QuickFixIconConverter}}" />
233-
</Setter.Value>
234-
</Setter>
235-
<Setter Property="Command" Value="{Binding Command}" />
236-
<Setter Property="CommandParameter" Value="{Binding Fix}" />
237-
<Setter Property="Header" Value="{Binding Description}" />
238-
<Setter Property="Background" Value="Transparent" />
239-
</Style>
240-
</ContextMenu.Resources>
241-
</ContextMenu>
234+
<ContextMenu ItemsSource="{Binding PlacementTarget.DataContext.QuickFixes, RelativeSource={RelativeSource Self}}"
235+
ItemContainerStyle="{StaticResource QuickFixItemStyle}" />
242236
</DataGrid.ContextMenu>
243237
<i:Interaction.Behaviors>
244238
<controls:GroupItemExpandedBehavior ExpandedState="{Binding ExpandedState, Mode=TwoWay}" />
@@ -268,28 +262,10 @@
268262
<TextBlock Margin="4" Text="{Binding SelectedInspection.Meta}" FontSize="10" TextWrapping="WrapWithOverflow"/>
269263
<TextBlock Margin="8" Text="{Binding SelectedInspection.QualifiedSelection}" FontSize="10" TextWrapping="WrapWithOverflow" />
270264

271-
<WrapPanel>
272-
<controls:LinkButton Margin="4"
273-
Visibility="{Binding CanExecuteQuickFixInProcedure, Converter={StaticResource BoolToVisibility}}"
274-
Command="{Binding QuickFixInProcedureCommand}"
275-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_ThisProcedure}" />
276-
<controls:LinkButton Margin="4"
277-
Visibility="{Binding CanExecuteQuickFixInModule, Converter={StaticResource BoolToVisibility}}"
278-
Command="{Binding QuickFixInModuleCommand}"
279-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_ThisModule}" />
280-
<controls:LinkButton Margin="4"
281-
Visibility="{Binding CanExecuteQuickFixInProject, Converter={StaticResource BoolToVisibility}}"
282-
Command="{Binding QuickFixInProjectCommand}"
283-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_ThisProject}" />
284-
<controls:LinkButton Margin="4"
285-
Visibility="{Binding CanExecuteQuickFixInProject, Converter={StaticResource BoolToVisibility}}"
286-
Command="{Binding QuickFixInAllProjectsCommand}"
287-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_All}" />
288-
<controls:LinkButton Margin="4"
289-
Visibility="{Binding CanDisableInspection, Converter={StaticResource BoolToVisibility}}"
290-
Command="{Binding DisableInspectionCommand}"
291-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=DisableThisInspection}" />
292-
</WrapPanel>
265+
<controls:LinkButton Margin="4"
266+
Visibility="{Binding CanDisableInspection, Converter={StaticResource BoolToVisibility}}"
267+
Command="{Binding DisableInspectionCommand}"
268+
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=DisableThisInspection}" />
293269
</StackPanel>
294270
</ScrollViewer>
295271
</Border>

0 commit comments

Comments
 (0)