Skip to content

Commit 6ca5b84

Browse files
committed
Add ExpandDefaultMemberQuickFix
1 parent 2ce14ae commit 6ca5b84

File tree

6 files changed

+254
-0
lines changed

6 files changed

+254
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Linq;
2+
using Antlr4.Runtime;
3+
using Rubberduck.Inspections.Abstract;
4+
using Rubberduck.Inspections.Concrete;
5+
using Rubberduck.Parsing.Inspections.Abstract;
6+
using Rubberduck.Parsing.Rewriter;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Parsing.VBA.DeclarationCaching;
9+
using Rubberduck.VBEditor;
10+
11+
namespace Rubberduck.CodeAnalysis.QuickFixes
12+
{
13+
public class ExpandDefaultMemberQuickFix : QuickFixBase
14+
{
15+
private readonly IDeclarationFinderProvider _declarationFinderProvider;
16+
17+
public ExpandDefaultMemberQuickFix(IDeclarationFinderProvider declarationFinderProvider)
18+
: base(typeof(ObjectWhereProcedureIsRequiredInspection))
19+
{
20+
_declarationFinderProvider = declarationFinderProvider;
21+
}
22+
23+
public override void Fix(IInspectionResult result, IRewriteSession rewriteSession)
24+
{
25+
var rewriter = rewriteSession.CheckOutModuleRewriter(result.QualifiedSelection.QualifiedName);
26+
var finder = _declarationFinderProvider.DeclarationFinder;
27+
28+
var lExpressionContext = result.Context;
29+
var selection = result.QualifiedSelection;
30+
InsertDefaultMember(lExpressionContext, selection, finder, rewriter);
31+
}
32+
33+
private void InsertDefaultMember(ParserRuleContext lExpressionContext, QualifiedSelection selection, DeclarationFinder finder, IModuleRewriter rewriter)
34+
{
35+
var defaultMemberAccessCode = DefaultMemberAccessCode(selection, finder);
36+
rewriter.InsertAfter(lExpressionContext.Stop.TokenIndex, defaultMemberAccessCode);
37+
}
38+
39+
private string DefaultMemberAccessCode(QualifiedSelection selection, DeclarationFinder finder)
40+
{
41+
var defaultMemberAccesses = finder.IdentifierReferences(selection).Where(reference => reference.DefaultMemberRecursionDepth > 0);
42+
var defaultMemberNames = defaultMemberAccesses.Select(reference => reference.Declaration.IdentifierName);
43+
return $".{string.Join("().", defaultMemberNames)}";
44+
}
45+
46+
public override string Description(IInspectionResult result)
47+
{
48+
return Resources.Inspections.QuickFixes.ExpandDefaultMemberQuickFix;
49+
}
50+
51+
public override bool CanFixInProcedure => true;
52+
public override bool CanFixInModule => true;
53+
public override bool CanFixInProject => true;
54+
}
55+
}

Rubberduck.Resources/Inspections/QuickFixes.Designer.cs

Lines changed: 9 additions & 0 deletions
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,7 @@
294294
<data name="ExpandBangNotationQuickFix" xml:space="preserve">
295295
<value>Ersetze die Ausrufezeichennotation durch einen expliziten Aufruf</value>
296296
</data>
297+
<data name="ExpandDefaultMemberQuickFix" xml:space="preserve">
298+
<value>Füge einen expliziten Zugriff auf den Standardmember ein</value>
299+
</data>
297300
</root>

Rubberduck.Resources/Inspections/QuickFixes.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,7 @@
294294
<data name="ExpandBangNotationQuickFix" xml:space="preserve">
295295
<value>Replace bang notation with explicit access</value>
296296
</data>
297+
<data name="ExpandDefaultMemberQuickFix" xml:space="preserve">
298+
<value>Make default member access explicit</value>
299+
</data>
297300
</root>

RubberduckTests/QuickFixes/ExpandBangNotationQuickFixTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ End Function
4949
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new UseOfBangNotationInspection(state), CodeKind.AttributesCode);
5050
Assert.AreEqual(expectedModuleCode, actualModuleCode);
5151
}
52+
5253
[Test]
5354
[Category("QuickFixes")]
5455
public void RecursiveDictionaryAccessExpression_QuickFixWorks()
@@ -87,6 +88,7 @@ End Function
8788
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new UseOfRecursiveBangNotationInspection(state), CodeKind.AttributesCode);
8889
Assert.AreEqual(expectedModuleCode, actualModuleCode);
8990
}
91+
9092
[Test]
9193
[Category("QuickFixes")]
9294
public void WithDictionaryAccessExpression_QuickFixWorks()
@@ -127,6 +129,7 @@ End Function
127129
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new UseOfBangNotationInspection(state), CodeKind.AttributesCode);
128130
Assert.AreEqual(expectedModuleCode, actualModuleCode);
129131
}
132+
130133
[Test]
131134
[Category("QuickFixes")]
132135
public void RecursiveWithDictionaryAccessExpression_QuickFixWorks()
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
using Rubberduck.CodeAnalysis.QuickFixes;
4+
using Rubberduck.Inspections.Concrete;
5+
using Rubberduck.Parsing.Inspections.Abstract;
6+
using Rubberduck.Parsing.VBA;
7+
using Rubberduck.Parsing.VBA.Parsing;
8+
using Rubberduck.VBEditor.SafeComWrappers;
9+
using RubberduckTests.Mocks;
10+
11+
namespace RubberduckTests.QuickFixes
12+
{
13+
[TestFixture]
14+
public class ExpandDefaultMemberQuickFixTests : QuickFixTestBase
15+
{
16+
[Test]
17+
[Category("QuickFixes")]
18+
public void DictionaryAccessExpression_QuickFixWorks()
19+
{
20+
var class1Code = @"
21+
Public Sub Foo()
22+
Attribute Foo.VB_UserMemId = 0
23+
End Sub
24+
";
25+
26+
var class2Code = @"
27+
Public Function Baz() As Class1
28+
Attribute Baz.VB_UserMemId = 0
29+
Set Baz = New Class1
30+
End Function
31+
";
32+
33+
var moduleCode = $@"
34+
Private Function Foo() As Variant
35+
Dim cls As New Class2
36+
cls
37+
End Function
38+
";
39+
40+
var expectedModuleCode = $@"
41+
Private Function Foo() As Variant
42+
Dim cls As New Class2
43+
cls.Baz
44+
End Function
45+
";
46+
47+
var vbe = MockVbeBuilder.BuildFromModules(
48+
("Class1", class1Code, ComponentType.ClassModule),
49+
("Class2", class2Code, ComponentType.ClassModule),
50+
("Module1", moduleCode, ComponentType.StandardModule));
51+
52+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new ObjectWhereProcedureIsRequiredInspection(state), CodeKind.AttributesCode);
53+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
54+
}
55+
56+
[Test]
57+
[Category("QuickFixes")]
58+
public void NonParameterizedProcedureCoercion_ExplicitCall_QuickFixWorks()
59+
{
60+
var class1Code = @"
61+
Public Sub Foo()
62+
Attribute Foo.VB_UserMemId = 0
63+
End Sub
64+
";
65+
66+
var class2Code = @"
67+
Public Function Baz() As Class1
68+
Attribute Baz.VB_UserMemId = 0
69+
Set Baz = New Class1
70+
End Function
71+
";
72+
73+
var moduleCode = $@"
74+
Private Function Foo() As Variant
75+
Dim cls As New Class2
76+
Call cls
77+
End Function
78+
";
79+
80+
var expectedModuleCode = $@"
81+
Private Function Foo() As Variant
82+
Dim cls As New Class2
83+
Call cls.Baz
84+
End Function
85+
";
86+
87+
var vbe = MockVbeBuilder.BuildFromModules(
88+
("Class1", class1Code, ComponentType.ClassModule),
89+
("Class2", class2Code, ComponentType.ClassModule),
90+
("Module1", moduleCode, ComponentType.StandardModule));
91+
92+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new ObjectWhereProcedureIsRequiredInspection(state), CodeKind.AttributesCode);
93+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
94+
}
95+
96+
[Test]
97+
[Category("QuickFixes")]
98+
public void NonParameterizedProcedureCoercionDefaultMemberAccessOnDefaultMemberArrayAccess_QuickFixWorks()
99+
{
100+
var class1Code = @"
101+
Public Sub Foo()
102+
Attribute Foo.VB_UserMemId = 0
103+
End Sub
104+
";
105+
106+
var class2Code = @"
107+
Public Function Baz() As Class1()
108+
Attribute Baz.VB_UserMemId = 0
109+
Set Baz = New Class1
110+
End Function
111+
";
112+
113+
var moduleCode = $@"
114+
Private Function Foo() As Variant
115+
Dim cls As New Class2
116+
cls(42)
117+
End Function
118+
";
119+
120+
var expectedModuleCode = $@"
121+
Private Function Foo() As Variant
122+
Dim cls As New Class2
123+
cls(42).Foo
124+
End Function
125+
";
126+
127+
var vbe = MockVbeBuilder.BuildFromModules(
128+
("Class1", class1Code, ComponentType.ClassModule),
129+
("Class2", class2Code, ComponentType.ClassModule),
130+
("Module1", moduleCode, ComponentType.StandardModule));
131+
132+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new ObjectWhereProcedureIsRequiredInspection(state), CodeKind.AttributesCode);
133+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
134+
}
135+
136+
[Test]
137+
[Category("QuickFixes")]
138+
public void NonParameterizedProcedureCoercionDefaultMemberAccessOnDefaultMemberArrayAccess_ExplicitCall_QuickFixWorks()
139+
{
140+
var class1Code = @"
141+
Public Sub Foo()
142+
Attribute Foo.VB_UserMemId = 0
143+
End Sub
144+
";
145+
146+
var class2Code = @"
147+
Public Function Baz() As Class1()
148+
Attribute Baz.VB_UserMemId = 0
149+
Set Baz = New Class1
150+
End Function
151+
";
152+
153+
var moduleCode = $@"
154+
Private Function Foo() As Variant
155+
Dim cls As New Class2
156+
Call cls(42)
157+
End Function
158+
";
159+
160+
var expectedModuleCode = $@"
161+
Private Function Foo() As Variant
162+
Dim cls As New Class2
163+
Call cls(42).Foo
164+
End Function
165+
";
166+
167+
var vbe = MockVbeBuilder.BuildFromModules(
168+
("Class1", class1Code, ComponentType.ClassModule),
169+
("Class2", class2Code, ComponentType.ClassModule),
170+
("Module1", moduleCode, ComponentType.StandardModule));
171+
172+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new ObjectWhereProcedureIsRequiredInspection(state), CodeKind.AttributesCode);
173+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
174+
}
175+
176+
protected override IQuickFix QuickFix(RubberduckParserState state)
177+
{
178+
return new ExpandDefaultMemberQuickFix(state);
179+
}
180+
}
181+
}

0 commit comments

Comments
 (0)