Skip to content

Commit 39ce242

Browse files
committed
Notify the user about failures to apply a quickfix
In case the a module was stale, this is mentioned as part of the message.
1 parent be1a022 commit 39ce242

File tree

8 files changed

+161
-13
lines changed

8 files changed

+161
-13
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Rubberduck.Parsing.Rewriter;
2+
3+
namespace Rubberduck.Inspections.QuickFixes
4+
{
5+
public interface IQuickFixFailureNotifier
6+
{
7+
void NotifyQuickFixExecutionFailure(RewriteSessionState sessionState);
8+
}
9+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using Rubberduck.Interaction;
3+
using Rubberduck.Parsing.Rewriter;
4+
5+
namespace Rubberduck.Inspections.QuickFixes
6+
{
7+
public class QuickFixFailureNotifier : IQuickFixFailureNotifier
8+
{
9+
private readonly IMessageBox _messageBox;
10+
11+
public QuickFixFailureNotifier(IMessageBox messageBox)
12+
{
13+
_messageBox = messageBox;
14+
}
15+
16+
public void NotifyQuickFixExecutionFailure(RewriteSessionState sessionState)
17+
{
18+
var message = FailureMessage(sessionState);
19+
var caption = Resources.Inspections.QuickFixes.ApplyQuickFixFailedCaption;
20+
21+
_messageBox.NotifyWarn(message, caption);
22+
}
23+
24+
private static string FailureMessage(RewriteSessionState sessionState)
25+
{
26+
var baseFailureMessage = Resources.Inspections.QuickFixes.ApplyQuickFixesFailedMessage;
27+
var failureReasonMessage = FailureReasonMessage(sessionState);
28+
var message = string.IsNullOrEmpty(failureReasonMessage)
29+
? baseFailureMessage
30+
: $"{baseFailureMessage}{Environment.NewLine}{Environment.NewLine}{failureReasonMessage}";
31+
return message;
32+
}
33+
34+
private static string FailureReasonMessage(RewriteSessionState sessionState)
35+
{
36+
switch (sessionState)
37+
{
38+
case RewriteSessionState.StaleParseTree:
39+
return Resources.Inspections.QuickFixes.StaleModuleFailureReason;
40+
default:
41+
return string.Empty;
42+
}
43+
}
44+
}
45+
}

Rubberduck.CodeAnalysis/QuickFixes/QuickFixProvider.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Microsoft.CSharp.RuntimeBinder;
66
using Rubberduck.Parsing.Inspections.Abstract;
77
using Rubberduck.Parsing.Rewriter;
8-
using Rubberduck.Parsing.VBA;
98
using Rubberduck.Parsing.VBA.Parsing;
109
using Rubberduck.VBEditor;
1110

@@ -14,11 +13,13 @@ namespace Rubberduck.Inspections.QuickFixes
1413
public class QuickFixProvider : IQuickFixProvider
1514
{
1615
private readonly IRewritingManager _rewritingManager;
16+
private readonly IQuickFixFailureNotifier _failureNotifier;
1717
private readonly Dictionary<Type, HashSet<IQuickFix>> _quickFixes = new Dictionary<Type, HashSet<IQuickFix>>();
1818

19-
public QuickFixProvider(IRewritingManager rewritingManager, IEnumerable<IQuickFix> quickFixes)
19+
public QuickFixProvider(IRewritingManager rewritingManager, IQuickFixFailureNotifier failureNotifier, IEnumerable<IQuickFix> quickFixes)
2020
{
2121
_rewritingManager = rewritingManager;
22+
_failureNotifier = failureNotifier;
2223
foreach (var quickFix in quickFixes)
2324
{
2425
foreach (var supportedInspection in quickFix.SupportedInspections)
@@ -78,7 +79,15 @@ public void Fix(IQuickFix fix, IInspectionResult result)
7879

7980
var rewriteSession = RewriteSession(fix.TargetCodeKind);
8081
fix.Fix(result, rewriteSession);
81-
rewriteSession.TryRewrite();
82+
Apply(rewriteSession);
83+
}
84+
85+
private void Apply(IRewriteSession rewriteSession)
86+
{
87+
if (!rewriteSession.TryRewrite())
88+
{
89+
_failureNotifier.NotifyQuickFixExecutionFailure(rewriteSession.Status);
90+
}
8291
}
8392

8493
private IRewriteSession RewriteSession(CodeKind targetCodeKind)
@@ -115,7 +124,7 @@ public void FixInProcedure(IQuickFix fix, QualifiedMemberName? qualifiedMember,
115124

116125
fix.Fix(result, rewriteSession);
117126
}
118-
rewriteSession.TryRewrite();
127+
Apply(rewriteSession);
119128
}
120129

121130
public void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> results)
@@ -137,7 +146,7 @@ public void FixInModule(IQuickFix fix, QualifiedSelection selection, Type inspec
137146

138147
fix.Fix(result, rewriteSession);
139148
}
140-
rewriteSession.TryRewrite();
149+
Apply(rewriteSession);
141150
}
142151

143152
public void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspectionType, IEnumerable<IInspectionResult> results)
@@ -159,7 +168,7 @@ public void FixInProject(IQuickFix fix, QualifiedSelection selection, Type inspe
159168

160169
fix.Fix(result, rewriteSession);
161170
}
162-
rewriteSession.TryRewrite();
171+
Apply(rewriteSession);
163172
}
164173

165174
public void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionResult> results)
@@ -181,7 +190,7 @@ public void FixAll(IQuickFix fix, Type inspectionType, IEnumerable<IInspectionRe
181190

182191
fix.Fix(result, rewriteSession);
183192
}
184-
rewriteSession.TryRewrite();
193+
Apply(rewriteSession);
185194
}
186195

187196
public bool HasQuickFixes(IInspectionResult inspectionResult)

Rubberduck.Interaction/Input/IMessageBox.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using Forms = System.Windows.Forms;
1+
using Forms = System.Windows.Forms;
32

43
namespace Rubberduck.Interaction
54
{

Rubberduck.Resources/Inspections/QuickFixes.Designer.cs

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Resources/Inspections/QuickFixes.de.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,13 @@
279279
<data name="AddAttributeAnnotationQuickFix" xml:space="preserve">
280280
<value>Attributannotation hinzufügen</value>
281281
</data>
282+
<data name="ApplyQuickFixesFailedMessage" xml:space="preserve">
283+
<value>Die Ausführen des Quickfixes ist fehlgeschlagen. </value>
284+
</data>
285+
<data name="StaleModuleFailureReason" xml:space="preserve">
286+
<value>Ein betroffenes Module wurde seit dem letzten Parse modifiziert.</value>
287+
</data>
288+
<data name="ApplyQuickFixFailedCaption" xml:space="preserve">
289+
<value>Quickfixausführung fehlgeschlagen</value>
290+
</data>
282291
</root>

Rubberduck.Resources/Inspections/QuickFixes.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,13 @@
279279
<data name="AddAttributeAnnotationQuickFix" xml:space="preserve">
280280
<value>Add attribute annotation</value>
281281
</data>
282+
<data name="ApplyQuickFixesFailedMessage" xml:space="preserve">
283+
<value>Failed to apply the quick fix.</value>
284+
</data>
285+
<data name="StaleModuleFailureReason" xml:space="preserve">
286+
<value>An affected module has been modified since the last parse.</value>
287+
</data>
288+
<data name="ApplyQuickFixFailedCaption" xml:space="preserve">
289+
<value>Quick Fix Application Failure</value>
290+
</data>
282291
</root>

RubberduckTests/QuickFixes/QuickFixProviderTests.cs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System.Linq;
22
using System.Threading;
3+
using Moq;
34
using NUnit.Framework;
45
using Rubberduck.Inspections.Concrete;
56
using Rubberduck.Inspections.QuickFixes;
67
using Rubberduck.Parsing.Inspections.Abstract;
8+
using Rubberduck.Parsing.Rewriter;
79
using RubberduckTests.Mocks;
810
using RubberduckTests.Inspections;
911

@@ -29,7 +31,8 @@ public void ProviderDoesNotKnowAboutInspection()
2931
var inspection = new ConstantNotUsedInspection(state);
3032
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
3133

32-
var quickFixProvider = new QuickFixProvider(rewritingManager, new IQuickFix[] { });
34+
var failureNotifier = new Mock<IQuickFixFailureNotifier>().Object;
35+
var quickFixProvider = new QuickFixProvider(rewritingManager, failureNotifier, new IQuickFix[] { });
3336
Assert.AreEqual(0, quickFixProvider.QuickFixes(inspectionResults.First()).Count());
3437
}
3538
}
@@ -53,7 +56,8 @@ Dim str As String
5356
var inspector = InspectionsHelper.GetInspector(inspection);
5457
var inspectionResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
5558

56-
var quickFixProvider = new QuickFixProvider(rewritingManager, new IQuickFix[] { new ReplaceEmptyStringLiteralStatementQuickFix() });
59+
var failureNotifier = new Mock<IQuickFixFailureNotifier>().Object;
60+
var quickFixProvider = new QuickFixProvider(rewritingManager, failureNotifier, new IQuickFix[] { new ReplaceEmptyStringLiteralStatementQuickFix() });
5761
Assert.AreEqual(1, quickFixProvider.QuickFixes(inspectionResults.First()).Count());
5862
}
5963
}
@@ -75,13 +79,47 @@ public void ResultDisablesFix()
7579
var inspection = new ConstantNotUsedInspection(state);
7680
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
7781

78-
var quickFixProvider = new QuickFixProvider(rewritingManager, new IQuickFix[] { new RemoveUnusedDeclarationQuickFix() });
82+
var failureNotifier = new Mock<IQuickFixFailureNotifier>().Object;
83+
var quickFixProvider = new QuickFixProvider(rewritingManager, failureNotifier, new IQuickFix[] { new RemoveUnusedDeclarationQuickFix() });
7984

8085
var result = inspectionResults.First();
8186
result.Properties.DisableFixes = nameof(RemoveUnusedDeclarationQuickFix);
8287

8388
Assert.AreEqual(0, quickFixProvider.QuickFixes(result).Count());
8489
}
8590
}
91+
92+
[Test]
93+
[Category("QuickFixes")]
94+
public void ProviderCallsNotifierOnFailureToRewrite()
95+
{
96+
const string inputCode =
97+
@"Public Sub Foo()
98+
Dim str As String
99+
str = """"
100+
End Sub";
101+
102+
var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out var component);
103+
var (state, rewritingManager) = MockParser.CreateAndParseWithRewritingManager(vbe.Object);
104+
using (state)
105+
{
106+
107+
var inspection = new EmptyStringLiteralInspection(state);
108+
var inspector = InspectionsHelper.GetInspector(inspection);
109+
var inspectionResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
110+
var inspectionResult = inspectionResults.First();
111+
112+
var failureNotifierMock = new Mock<IQuickFixFailureNotifier>();
113+
var quickFixProvider = new QuickFixProvider(rewritingManager, failureNotifierMock.Object, new IQuickFix[] { new ReplaceEmptyStringLiteralStatementQuickFix() });
114+
var quickFix = quickFixProvider.QuickFixes(inspectionResult).First();
115+
116+
//Make rewrite fail.
117+
component.CodeModule.InsertLines(1, "'afejfaofef");
118+
119+
quickFixProvider.Fix(quickFix, inspectionResult);
120+
121+
failureNotifierMock.Verify(m => m.NotifyQuickFixExecutionFailure(RewriteSessionState.StaleParseTree));
122+
}
123+
}
86124
}
87125
}

0 commit comments

Comments
 (0)