Skip to content

Commit def1ce6

Browse files
authored
Merge pull request rubberduck-vba#2896 from Hosch250/Issue2884
Rewrite Encapsulate Field
2 parents 11b3caf + c947235 commit def1ce6

File tree

9 files changed

+73
-60
lines changed

9 files changed

+73
-60
lines changed

RetailCoder.VBE/Inspections/Abstract/InspectionBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ protected bool IsIgnoringInspectionResultFor(IVBComponent component, int line)
104104
}
105105

106106
// VBE 1-based indexing
107-
for (var i = line - 1; i >= 1; i--)
107+
for (var i = line; i >= 1; i--)
108108
{
109109
var annotation = annotations.SingleOrDefault(a => a.QualifiedSelection.Selection.StartLine == i) as IgnoreAnnotation;
110110
if (annotation != null && annotation.InspectionNames.Contains(AnnotationName))

RetailCoder.VBE/Inspections/QuickFixes/AssignedByValParameterMakeLocalCopyQuickFix.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private void InsertLocalVariableDeclarationAndAssignment(IModuleRewriter rewrite
103103
+ (_target.AsTypeDeclaration is ClassModuleDeclaration ? Tokens.Set + " " : string.Empty)
104104
+ localIdentifier + " = " + _target.IdentifierName;
105105

106-
rewriter.Insert(((ParserRuleContext)_target.Context.Parent).Stop.TokenIndex + 1, "\r\n" + content);
106+
rewriter.InsertBefore(((ParserRuleContext)_target.Context.Parent).Stop.TokenIndex + 1, "\r\n" + content);
107107
}
108108
}
109109
}

RetailCoder.VBE/Refactorings/EncapsulateField/EncapsulateFieldRefactoring.cs

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using Rubberduck.Parsing.PostProcessing;
45
using Rubberduck.Parsing.Symbols;
@@ -15,6 +16,8 @@ public class EncapsulateFieldRefactoring : IRefactoring
1516
private readonly IRefactoringPresenterFactory<IEncapsulateFieldPresenter> _factory;
1617
private EncapsulateFieldModel _model;
1718

19+
private readonly HashSet<IModuleRewriter> _referenceRewriters = new HashSet<IModuleRewriter>();
20+
1821
public EncapsulateFieldRefactoring(IVBE vbe, IIndenter indenter, IRefactoringPresenterFactory<IEncapsulateFieldPresenter> factory)
1922
{
2023
_vbe = vbe;
@@ -35,6 +38,10 @@ public void Refactor()
3538
AddProperty(rewriter);
3639

3740
rewriter.Rewrite();
41+
foreach (var referenceRewriter in _referenceRewriters)
42+
{
43+
referenceRewriter.Rewrite();
44+
}
3845
}
3946

4047
public void Refactor(QualifiedSelection target)
@@ -58,46 +65,54 @@ private void AddProperty(IModuleRewriter rewriter)
5865

5966
var members = _model.State.DeclarationFinder
6067
.Members(_model.TargetDeclaration.QualifiedName.QualifiedModuleName)
61-
.OrderBy(declaration => declaration.QualifiedSelection)
62-
.ToArray();
68+
.OrderBy(declaration => declaration.QualifiedSelection);
6369

64-
var property = Environment.NewLine + Environment.NewLine + GetPropertyText() + Environment.NewLine;
70+
var fields = members.Where(d => d.DeclarationType == DeclarationType.Variable && !d.ParentScopeDeclaration.DeclarationType.HasFlag(DeclarationType.Member)).ToList();
6571

66-
var lastMember = members.LastOrDefault(m => m.DeclarationType.HasFlag(DeclarationType.Member));
67-
if (lastMember == null)
72+
var property = Environment.NewLine + Environment.NewLine + GetPropertyText();
73+
if (members.Any(m => m.DeclarationType.HasFlag(DeclarationType.Member)))
6874
{
69-
rewriter.Insert(1, property);
75+
property += Environment.NewLine;
76+
}
77+
78+
if (_model.TargetDeclaration.Accessibility != Accessibility.Private)
79+
{
80+
var newField = "Private " + _model.TargetDeclaration.IdentifierName + " As " + _model.TargetDeclaration.AsTypeName;
81+
if (fields.Count > 1)
82+
{
83+
newField = Environment.NewLine + newField;
84+
}
85+
86+
property = newField + property;
87+
}
88+
89+
if (_model.TargetDeclaration.Accessibility == Accessibility.Private || fields.Count > 1)
90+
{
91+
rewriter.InsertAfter(fields.Last().Context.Stop.TokenIndex, property);
7092
}
7193
else
7294
{
73-
rewriter.Insert(lastMember.Context.Stop.TokenIndex, property);
95+
rewriter.InsertBefore(0, property);
7496
}
7597
}
7698

7799
private void UpdateReferences()
78100
{
79101
foreach (var reference in _model.TargetDeclaration.References)
80102
{
81-
var module = reference.QualifiedModuleName.Component.CodeModule;
82-
var oldLine = module.GetLines(reference.Selection.StartLine, 1);
83-
oldLine = oldLine.Remove(reference.Selection.StartColumn - 1, reference.Selection.EndColumn - reference.Selection.StartColumn);
84-
var newLine = oldLine.Insert(reference.Selection.StartColumn - 1, _model.PropertyName);
103+
var rewriter = _model.State.GetRewriter(reference.QualifiedModuleName);
104+
rewriter.Replace(reference.Context, _model.PropertyName);
85105

86-
module.ReplaceLine(reference.Selection.StartLine, newLine);
106+
_referenceRewriters.Add(rewriter);
87107
}
88108
}
89109

90110
private void SetFieldToPrivate(IModuleRewriter rewriter)
91111
{
92-
var target = _model.TargetDeclaration;
93-
if (target.Accessibility == Accessibility.Private)
112+
if (_model.TargetDeclaration.Accessibility != Accessibility.Private)
94113
{
95-
return;
114+
rewriter.Remove(_model.TargetDeclaration);
96115
}
97-
98-
var newField = "Private " + _model.TargetDeclaration.IdentifierName + " As " + _model.TargetDeclaration.AsTypeName + Environment.NewLine;
99-
100-
rewriter.Replace(target, newField);
101116
}
102117

103118
private string GetPropertyText()

RetailCoder.VBE/Refactorings/IntroduceField/IntroduceFieldRefactoring.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ private void PromoteVariable(IModuleRewriter rewriter, Declaration target)
9595
pane.Selection = oldSelection.Value.Selection;
9696
}
9797
}
98+
99+
rewriter.Rewrite();
98100
}
99101

100102
private void AddField(IModuleRewriter rewriter, Declaration target)
@@ -105,7 +107,7 @@ private void AddField(IModuleRewriter rewriter, Declaration target)
105107
.OrderByDescending(item => item.Selection);
106108

107109
var firstMember = members.FirstOrDefault();
108-
rewriter.Insert(firstMember?.Context.Start.TokenIndex ?? 0, content);
110+
rewriter.InsertBefore(firstMember?.Context.Start.TokenIndex ?? 0, content);
109111
}
110112
}
111113
}

RetailCoder.VBE/Refactorings/IntroduceParameter/IntroduceParameterRefactoring.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Windows.Forms;
44
using Rubberduck.Common;
55
using Rubberduck.Parsing.Grammar;
6+
using Rubberduck.Parsing.PostProcessing;
67
using Rubberduck.Parsing.Symbols;
78
using Rubberduck.Parsing.VBA;
89
using Rubberduck.UI;
@@ -18,6 +19,8 @@ public class IntroduceParameterRefactoring : IRefactoring
1819
private readonly IList<Declaration> _declarations;
1920
private readonly IMessageBox _messageBox;
2021

22+
private readonly HashSet<IModuleRewriter> _rewriters = new HashSet<IModuleRewriter>();
23+
2124
private static readonly DeclarationType[] ValidDeclarationTypes =
2225
{
2326
DeclarationType.Function,
@@ -94,6 +97,7 @@ private void PromoteVariable(Declaration target)
9497
}
9598

9699
var rewriter = _state.GetRewriter(target);
100+
_rewriters.Add(rewriter);
97101

98102
QualifiedSelection? oldSelection = null;
99103
var pane = _vbe.ActiveCodePane;
@@ -110,6 +114,11 @@ private void PromoteVariable(Declaration target)
110114
{
111115
pane.Selection = oldSelection.Value.Selection;
112116
}
117+
118+
foreach (var tokenRewriter in _rewriters)
119+
{
120+
tokenRewriter.Rewrite();
121+
}
113122
}
114123

115124
private bool PromptIfMethodImplementsInterface(Declaration targetVariable)
@@ -188,23 +197,24 @@ private void UpdateSignature(Declaration targetMethod, Declaration targetVariabl
188197
private void AddParameter(Declaration targetMethod, Declaration targetVariable, VBAParser.ArgListContext paramList)
189198
{
190199
var rewriter = _state.GetRewriter(targetMethod);
200+
_rewriters.Add(rewriter);
191201

192202
var argList = paramList.arg();
193203
var newParameter = Tokens.ByVal + " " + targetVariable.IdentifierName + " "+ Tokens.As + " " + targetVariable.AsTypeName;
194204

195205
if (!argList.Any())
196206
{
197-
rewriter.Insert(paramList.RPAREN().Symbol.TokenIndex, newParameter);
207+
rewriter.InsertBefore(paramList.RPAREN().Symbol.TokenIndex, newParameter);
198208
}
199209
else if (targetMethod.DeclarationType != DeclarationType.PropertyLet &&
200210
targetMethod.DeclarationType != DeclarationType.PropertySet)
201211
{
202-
rewriter.Insert(paramList.RPAREN().Symbol.TokenIndex, $", {newParameter}");
212+
rewriter.InsertBefore(paramList.RPAREN().Symbol.TokenIndex, $", {newParameter}");
203213
}
204214
else
205215
{
206216
var lastParam = argList.Last();
207-
rewriter.Insert(lastParam.Start.TokenIndex, $"{newParameter}, ");
217+
rewriter.InsertBefore(lastParam.Start.TokenIndex, $"{newParameter}, ");
208218
}
209219
}
210220

Rubberduck.Parsing/PostProcessing/IModuleRewriter.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,18 @@ public interface IModuleRewriter
5050
void Replace(IToken token, string content);
5151

5252
/// <summary>
53-
/// Inserts specified content at the specified token index in the module. Use <see cref="Rewrite"/> method to apply changes.
53+
/// Inserts specified content before the specified token index in the module. Use <see cref="Rewrite"/> method to apply changes.
5454
/// </summary>
5555
/// <param name="tokenIndex">The index of the insertion point in the module's lexer token stream.</param>
5656
/// <param name="content">The literal content to insert.</param>
57-
void Insert(int tokenIndex, string content);
57+
void InsertBefore(int tokenIndex, string content);
58+
59+
/// <summary>
60+
/// Inserts specified content after the specified token index in the module. Use <see cref="Rewrite"/> method to apply changes.
61+
/// </summary>
62+
/// <param name="tokenIndex">The index of the insertion point in the module's lexer token stream.</param>
63+
/// <param name="content">The literal content to insert.</param>
64+
void InsertAfter(int tokenIndex, string content);
5865

5966
/// <summary>
6067
/// Gets the text between specified token positions (inclusive).
@@ -67,5 +74,7 @@ public interface IModuleRewriter
6774
/// </summary>
6875
/// <returns></returns>
6976
string GetText();
77+
78+
ITokenStream TokenStream { get; }
7079
}
7180
}

Rubberduck.Parsing/PostProcessing/ModuleRewriter.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public class ModuleRewriter : IModuleRewriter
1212
private readonly ICodeModule _module;
1313
private readonly TokenStreamRewriter _rewriter;
1414

15+
public ITokenStream TokenStream => _rewriter.TokenStream;
16+
1517
public ModuleRewriter(ICodeModule module, TokenStreamRewriter rewriter)
1618
{
1719
_module = module;
@@ -69,11 +71,16 @@ public void Replace(IToken token, string content)
6971
_rewriter.Replace(token, content);
7072
}
7173

72-
public void Insert(int tokenIndex, string content)
74+
public void InsertBefore(int tokenIndex, string content)
7375
{
7476
_rewriter.InsertBefore(tokenIndex, content);
7577
}
7678

79+
public void InsertAfter(int tokenIndex, string content)
80+
{
81+
_rewriter.InsertAfter(tokenIndex, content);
82+
}
83+
7784
public string GetText(int startTokenIndex, int stopTokenIndex)
7885
{
7986
return _rewriter.GetText(Interval.Of(startTokenIndex, stopTokenIndex));

Rubberduck.Parsing/Symbols/DeclarationType.cs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,34 @@ namespace Rubberduck.Parsing.Symbols
77
[Flags]
88
public enum DeclarationType
99
{
10-
[DebuggerDisplay("Project")]
1110
Project = 1 << 0,
12-
[DebuggerDisplay("Module")]
1311
Module = 1 << 1,
14-
[DebuggerDisplay("ProceduralModule")]
1512
ProceduralModule = 1 << 2 | Module,
16-
[DebuggerDisplay("ClassModule")]
1713
ClassModule = 1 << 3 | Module,
18-
[DebuggerDisplay("UserForm")]
1914
UserForm = 1 << 4 | ClassModule,
20-
[DebuggerDisplay("Document")]
2115
Document = 1 << 5 | ClassModule,
22-
[DebuggerDisplay("ModuleOption")]
2316
ModuleOption = 1 << 6,
24-
[DebuggerDisplay("Member")]
2517
Member = 1 << 7,
26-
[DebuggerDisplay("Procedure")]
2718
Procedure = 1 << 8 | Member,
28-
[DebuggerDisplay("Function")]
2919
Function = 1 << 9 | Member,
30-
[DebuggerDisplay("Property")]
3120
Property = 1 << 10 | Member,
32-
[DebuggerDisplay("PropertyGet")]
3321
PropertyGet = 1 << 11 | Property | Function,
34-
[DebuggerDisplay("PropertyLet")]
3522
PropertyLet = 1 << 12 | Property | Procedure,
36-
[DebuggerDisplay("PropertySet")]
3723
PropertySet = 1 << 13 | Property | Procedure,
38-
[DebuggerDisplay("Parameter")]
3924
Parameter = 1 << 14,
40-
[DebuggerDisplay("Variable")]
4125
Variable = 1 << 15,
42-
[DebuggerDisplay("Control")]
4326
Control = 1 << 16 | Variable,
44-
[DebuggerDisplay("Constant")]
4527
Constant = 1 << 17,
46-
[DebuggerDisplay("Enumeration")]
4728
Enumeration = 1 << 18,
48-
[DebuggerDisplay("EnumerationMember")]
4929
EnumerationMember = 1 << 19,
50-
[DebuggerDisplay("Event")]
5130
Event = 1 << 20,
52-
[DebuggerDisplay("UserDefinedType")]
5331
UserDefinedType = 1 << 21,
54-
[DebuggerDisplay("UserDefinedTypeMember")]
5532
UserDefinedTypeMember = 1 << 22,
56-
[DebuggerDisplay("LibraryFunction")]
5733
LibraryFunction = 1 << 23 | Function,
58-
[DebuggerDisplay("LibraryProcedure")]
5934
LibraryProcedure = 1 << 24 | Procedure,
60-
[DebuggerDisplay("LineLabel")]
6135
LineLabel = 1 << 25,
62-
[DebuggerDisplay("UnresolvedMember")]
6336
UnresolvedMember = 1 << 26,
64-
[DebuggerDisplay("BracketedExpression")]
6537
BracketedExpression = 1 << 27,
66-
[DebuggerDisplay("ComAlias")]
6738
ComAlias = 1 << 28
6839
}
6940

RubberduckTests/Refactoring/EncapsulateFieldTests.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ public void EncapsulatePublicField_FieldDeclarationHasMultipleFields_MoveLast()
493493
//Expectation
494494
const string expectedCode =
495495
@"Public fizz, _
496-
buzz As Boolean
496+
buzz As Boolean
497497
Private bazz As Date
498498
499499
Public Property Get Name() As Date
@@ -571,7 +571,6 @@ End Property
571571

572572
var refactoring = new EncapsulateFieldRefactoring(vbe.Object, CreateIndenter(vbe.Object), factory.Object);
573573
refactoring.Refactor(qualifiedSelection);
574-
refactoring.Refactor(qualifiedSelection);
575574

576575
var rewriter = state.GetRewriter(model.TargetDeclaration);
577576
Assert.AreEqual(expectedCode, rewriter.GetText());
@@ -726,7 +725,7 @@ Sub Bar(ByVal v As Integer)
726725
Assert.AreEqual(expectedCode1, rewriter1.GetText());
727726

728727
var rewriter2 = state.GetRewriter(module2.Parent);
729-
Assert.AreEqual(expectedCode1, rewriter2.GetText());
728+
Assert.AreEqual(expectedCode2, rewriter2.GetText());
730729
}
731730

732731
[TestMethod]

0 commit comments

Comments
 (0)