Skip to content

Commit b2d883a

Browse files
committed
Override special default members on expansion
1 parent 6521b35 commit b2d883a

File tree

4 files changed

+191
-9
lines changed

4 files changed

+191
-9
lines changed

Rubberduck.CodeAnalysis/QuickFixes/ExpandBangNotationQuickFix.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
using System.Linq;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using Antlr4.Runtime;
34
using Rubberduck.Inspections.Abstract;
45
using Rubberduck.Inspections.Concrete;
56
using Rubberduck.Parsing.Grammar;
67
using Rubberduck.Parsing.Inspections.Abstract;
78
using Rubberduck.Parsing.Rewriter;
9+
using Rubberduck.Parsing.Symbols;
810
using Rubberduck.Parsing.VBA;
911
using Rubberduck.Parsing.VBA.DeclarationCaching;
1012
using Rubberduck.VBEditor;
@@ -60,23 +62,33 @@ private string DefaultMemberAccessCode(QualifiedSelection selection, Declaration
6062
{
6163
var defaultMemberAccesses = finder.IdentifierReferences(selection);
6264
var defaultMemberNames = defaultMemberAccesses
63-
.Select(reference => reference.Declaration.IdentifierName)
65+
.Select(DefaultMemberName)
6466
.Select(declarationName => IsNotLegalIdentifierName(declarationName)
6567
? $"[{declarationName}]"
6668
: declarationName);
6769
return $".{string.Join("().", defaultMemberNames)}";
6870
}
6971

72+
private static string DefaultMemberName(IdentifierReference defaultMemberReference)
73+
{
74+
var defaultMemberMemberName = defaultMemberReference.Declaration.QualifiedName;
75+
var fullDefaultMemberName = $"{defaultMemberMemberName.QualifiedModuleName.ProjectName}.{defaultMemberMemberName.QualifiedModuleName.ComponentName}.{defaultMemberMemberName.MemberName}";
76+
77+
if (DefaultMemberOverrides.TryGetValue(fullDefaultMemberName, out var defaultMemberOverride))
78+
{
79+
return defaultMemberOverride;
80+
}
81+
82+
return defaultMemberMemberName.MemberName;
83+
}
84+
7085
private bool IsNotLegalIdentifierName(string declarationName)
7186
{
7287
return string.IsNullOrEmpty(declarationName)
7388
|| NonIdentifierCharacters.Any(character => declarationName.Contains(character))
7489
|| AdditionalNonFirstIdentifierCharacters.Contains(declarationName[0]); ;
7590
}
7691

77-
private string NonIdentifierCharacters = "[](){}\r\n\t.,'\"\\ |!@#$%^&*-+:=; ";
78-
private string AdditionalNonFirstIdentifierCharacters = "0123456789_";
79-
8092
public override string Description(IInspectionResult result)
8193
{
8294
return Resources.Inspections.QuickFixes.ExpandBangNotationQuickFix;
@@ -85,5 +97,14 @@ public override string Description(IInspectionResult result)
8597
public override bool CanFixInProcedure => true;
8698
public override bool CanFixInModule => true;
8799
public override bool CanFixInProject => true;
100+
101+
private string NonIdentifierCharacters = "[](){}\r\n\t.,'\"\\ |!@#$%^&*-+:=; ";
102+
private string AdditionalNonFirstIdentifierCharacters = "0123456789_";
103+
104+
private static readonly Dictionary<string, string> DefaultMemberOverrides = new Dictionary<string, string>
105+
{
106+
["Excel.Range._Default"] = "Item"
107+
};
108+
88109
}
89110
}

Rubberduck.CodeAnalysis/QuickFixes/ExpandDefaultMemberQuickFix.cs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
using System.Linq;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using Antlr4.Runtime;
34
using Rubberduck.Inspections.Abstract;
45
using Rubberduck.Inspections.Concrete;
6+
using Rubberduck.Parsing.Grammar;
57
using Rubberduck.Parsing.Inspections.Abstract;
68
using Rubberduck.Parsing.Rewriter;
79
using Rubberduck.Parsing.Symbols;
@@ -54,7 +56,7 @@ private void InsertDefaultMember(ParserRuleContext lExpressionContext, Qualified
5456
private string DefaultMemberAccessCode(QualifiedSelection selection, DeclarationFinder finder)
5557
{
5658
var defaultMemberAccesses = finder.IdentifierReferences(selection).Where(reference => reference.DefaultMemberRecursionDepth > 0);
57-
var defaultMemberNames = defaultMemberAccesses.Select(reference => reference.Declaration.IdentifierName)
59+
var defaultMemberNames = defaultMemberAccesses.Select(DefaultMemberName)
5860
.Select(declarationName => IsNotLegalIdentifierName(declarationName)
5961
? $"[{declarationName}]"
6062
: declarationName);
@@ -68,8 +70,59 @@ private bool IsNotLegalIdentifierName(string declarationName)
6870
|| AdditionalNonFirstIdentifierCharacters.Contains(declarationName[0]); ;
6971
}
7072

71-
private string NonIdentifierCharacters = "[](){}\r\n\t.,'\"\\ |!@#$%^&*-+:=; ";
72-
private string AdditionalNonFirstIdentifierCharacters = "0123456789_";
73+
private static string DefaultMemberName(IdentifierReference defaultMemberReference)
74+
{
75+
var defaultMemberMemberName = defaultMemberReference.Declaration.QualifiedName;
76+
var fullDefaultMemberName = $"{defaultMemberMemberName.QualifiedModuleName.ProjectName}.{defaultMemberMemberName.QualifiedModuleName.ComponentName}.{defaultMemberMemberName.MemberName}";
77+
78+
if (DefaultMemberBaseOverrides.TryGetValue(fullDefaultMemberName, out var baseOverride))
79+
{
80+
if (DefaultMemberArgumentNumberOverrides.TryGetValue(fullDefaultMemberName, out var argumentNumberOverrides))
81+
{
82+
var numberOfArguments = NumberOfArguments(defaultMemberReference);
83+
if (argumentNumberOverrides.TryGetValue(numberOfArguments, out var numberOfArgumentsOverride))
84+
{
85+
return numberOfArgumentsOverride;
86+
}
87+
}
88+
89+
return baseOverride;
90+
}
91+
92+
return defaultMemberMemberName.MemberName;
93+
}
94+
95+
private static int NumberOfArguments(IdentifierReference defaultMemberReference)
96+
{
97+
if (defaultMemberReference.IsNonIndexedDefaultMemberAccess)
98+
{
99+
return 0;
100+
}
101+
102+
var argumentList = ArgumentList(defaultMemberReference);
103+
if (argumentList == null)
104+
{
105+
return -1;
106+
}
107+
108+
var arguments = argumentList.argument();
109+
110+
return arguments?.Length ?? 0;
111+
}
112+
113+
private static VBAParser.ArgumentListContext ArgumentList(IdentifierReference indexedDefaultMemberReference)
114+
{
115+
var defaultMemberReferenceContextWithArguments = indexedDefaultMemberReference.Context.Parent;
116+
switch (defaultMemberReferenceContextWithArguments)
117+
{
118+
case VBAParser.IndexExprContext indexExpression:
119+
return indexExpression.argumentList();
120+
case VBAParser.WhitespaceIndexExprContext whiteSpaceIndexExpression:
121+
return whiteSpaceIndexExpression.argumentList();
122+
default:
123+
return null;
124+
}
125+
}
73126

74127
public override string Description(IInspectionResult result)
75128
{
@@ -79,5 +132,18 @@ public override string Description(IInspectionResult result)
79132
public override bool CanFixInProcedure => true;
80133
public override bool CanFixInModule => true;
81134
public override bool CanFixInProject => true;
135+
136+
private string NonIdentifierCharacters = "[](){}\r\n\t.,'\"\\ |!@#$%^&*-+:=; ";
137+
private string AdditionalNonFirstIdentifierCharacters = "0123456789_";
138+
139+
private static readonly Dictionary<string, string> DefaultMemberBaseOverrides = new Dictionary<string, string>
140+
{
141+
["Excel.Range._Default"] = "Item"
142+
};
143+
144+
private static readonly Dictionary<string, Dictionary<int, string>> DefaultMemberArgumentNumberOverrides = new Dictionary<string, Dictionary<int, string>>
145+
{
146+
["Excel.Range._Default"] = new Dictionary<int, string>{[0] = "Value"}
147+
};
82148
}
83149
}

RubberduckTests/QuickFixes/ExpandBangNotationQuickFixTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,37 @@ End Sub
201201
Assert.AreEqual(expectedModuleCode, actualModuleCode);
202202
}
203203

204+
[Test]
205+
[Category("QuickFixes")]
206+
public void SpecialDefaultMembersAreReplacedBasedOnName()
207+
{
208+
var moduleCode = @"
209+
Private Sub Foo()
210+
Dim baz As Excel.Range
211+
Dim bar As Variant
212+
Set bar = baz.Columns!A
213+
End Sub
214+
";
215+
216+
var expectedModuleCode = @"
217+
Private Sub Foo()
218+
Dim baz As Excel.Range
219+
Dim bar As Variant
220+
Set bar = baz.Columns.Item(""A"")
221+
End Sub
222+
";
223+
224+
var vbe = new MockVbeBuilder()
225+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
226+
.AddComponent("Module1", ComponentType.StandardModule, moduleCode)
227+
.AddReference("Excel", MockVbeBuilder.LibraryPathMsExcel, 1, 8, true)
228+
.AddProjectToVbeBuilder()
229+
.Build();
230+
231+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new UseOfBangNotationInspection(state));
232+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
233+
}
234+
204235
protected override IQuickFix QuickFix(RubberduckParserState state)
205236
{
206237
return new ExpandBangNotationQuickFix(state);

RubberduckTests/QuickFixes/ExpandDefaultMemberQuickFixTests.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,70 @@ End Sub
675675
Assert.AreEqual(expectedModuleCode, actualModuleCode);
676676
}
677677

678+
[Test]
679+
[Category("QuickFixes")]
680+
public void SpecialDefaultMembersAreReplacedBasedOnName()
681+
{
682+
var moduleCode = @"
683+
Private Sub Foo()
684+
Dim baz As Excel.Range
685+
Dim bar As Variant
686+
Set bar = baz.Columns(""A"")
687+
Set bar = baz.Cells(1,1)
688+
End Sub
689+
";
690+
691+
var expectedModuleCode = @"
692+
Private Sub Foo()
693+
Dim baz As Excel.Range
694+
Dim bar As Variant
695+
Set bar = baz.Columns.Item(""A"")
696+
Set bar = baz.Cells.Item(1,1)
697+
End Sub
698+
";
699+
700+
var vbe = new MockVbeBuilder()
701+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
702+
.AddComponent("Module1", ComponentType.StandardModule, moduleCode)
703+
.AddReference("Excel", MockVbeBuilder.LibraryPathMsExcel, 1, 8, true)
704+
.AddProjectToVbeBuilder()
705+
.Build();
706+
707+
var actualModuleCode = ApplyQuickFixToAllInspectionResults(vbe.Object, "Module1", state => new IndexedDefaultMemberAccessInspection(state));
708+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
709+
}
710+
711+
[Test]
712+
[Category("QuickFixes")]
713+
public void SpecialDefaultMembersAreReplacedBasedOnNameAndArgumentNumber()
714+
{
715+
var moduleCode = @"
716+
Private Sub Foo()
717+
Dim baz As Excel.Range
718+
Dim bar As Variant
719+
bar = baz
720+
End Sub
721+
";
722+
723+
var expectedModuleCode = @"
724+
Private Sub Foo()
725+
Dim baz As Excel.Range
726+
Dim bar As Variant
727+
bar = baz.Value
728+
End Sub
729+
";
730+
731+
var vbe = new MockVbeBuilder()
732+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
733+
.AddComponent("Module1", ComponentType.StandardModule, moduleCode)
734+
.AddReference("Excel", MockVbeBuilder.LibraryPathMsExcel, 1, 8, true)
735+
.AddProjectToVbeBuilder()
736+
.Build();
737+
738+
var actualModuleCode = ApplyQuickFixToFirstInspectionResult(vbe.Object, "Module1", state => new ImplicitDefaultMemberAccessInspection(state));
739+
Assert.AreEqual(expectedModuleCode, actualModuleCode);
740+
}
741+
678742
protected override IQuickFix QuickFix(RubberduckParserState state)
679743
{
680744
return new ExpandDefaultMemberQuickFix(state);

0 commit comments

Comments
 (0)