Skip to content

Commit f36df0d

Browse files
committed
Add ModifyUserDefinedTypeRefactoringAction
Replaces CreateUDTMemberRefactoringAction. Leverages ICodeBuilder and IIndenter to rewrite the entire UDT declaration after adding (or removing) UDT Members.
1 parent 51ce8a7 commit f36df0d

File tree

9 files changed

+366
-360
lines changed

9 files changed

+366
-360
lines changed

Rubberduck.Refactorings/CreateUDTMember/CreateUDTMemberModel.cs

Lines changed: 0 additions & 67 deletions
This file was deleted.

Rubberduck.Refactorings/CreateUDTMember/CreateUDTMemberRefactoringAction.cs

Lines changed: 0 additions & 81 deletions
This file was deleted.

Rubberduck.Refactorings/EncapsulateField/EncapsulateFieldRefactoringActionsProvider.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using Rubberduck.Refactorings.CreateUDTMember;
2-
using Rubberduck.Refactorings.ReplaceDeclarationIdentifier;
1+
using Rubberduck.Refactorings.ReplaceDeclarationIdentifier;
32
using Rubberduck.Refactorings.ReplaceReferences;
43
using Rubberduck.Refactorings.ReplacePrivateUDTMemberReferences;
54
using Rubberduck.Refactorings.EncapsulateFieldInsertNewCode;
5+
using Rubberduck.Refactorings.ModifyUserDefinedType;
66

77
namespace Rubberduck.Refactorings.EncapsulateField
88
{
@@ -11,33 +11,33 @@ public interface IEncapsulateFieldRefactoringActionsProvider
1111
ICodeOnlyRefactoringAction<ReplaceReferencesModel> ReplaceReferences { get; }
1212
ICodeOnlyRefactoringAction<ReplacePrivateUDTMemberReferencesModel> ReplaceUDTMemberReferences { get; }
1313
ICodeOnlyRefactoringAction<ReplaceDeclarationIdentifierModel> ReplaceDeclarationIdentifiers { get; }
14-
ICodeOnlyRefactoringAction<CreateUDTMemberModel> CreateUDTMember { get; }
14+
ICodeOnlyRefactoringAction<ModifyUserDefinedTypeModel> ModifyUserDefinedType { get; }
1515
ICodeOnlyRefactoringAction<EncapsulateFieldInsertNewCodeModel> EncapsulateFieldInsertNewCode { get; }
1616
}
1717

1818
/// <summary>
1919
/// EncapsulateFieldRefactoringActionsProvider reduces the number of EncapsulateField refactoring action
20-
/// constructor parameters providing refactoring actions common to the aggregated EncapsulateFieldRefactoringActions
20+
/// constructor parameters. It provides Refactoring Actions common to the EncapsulateFieldRefactoringActions
2121
/// </summary>
2222
public class EncapsulateFieldRefactoringActionsProvider : IEncapsulateFieldRefactoringActionsProvider
2323
{
2424
private readonly ReplaceReferencesRefactoringAction _replaceReferences;
2525
private readonly ReplaceDeclarationIdentifierRefactoringAction _replaceDeclarationIdentifiers;
2626
private readonly ReplacePrivateUDTMemberReferencesRefactoringAction _replaceUDTMemberReferencesRefactoringAction;
27-
private readonly CreateUDTMemberRefactoringAction _createUDTMemberRefactoringAction;
27+
private readonly ModifyUserDefinedTypeRefactoringAction _modifyUDTRefactoringAction;
2828
private readonly EncapsulateFieldInsertNewCodeRefactoringAction _encapsulateFieldInsertNewCodeRefactoringAction;
2929

3030
public EncapsulateFieldRefactoringActionsProvider(
3131
ReplaceReferencesRefactoringAction replaceReferencesRefactoringAction,
3232
ReplacePrivateUDTMemberReferencesRefactoringAction replaceUDTMemberReferencesRefactoringAction,
3333
ReplaceDeclarationIdentifierRefactoringAction replaceDeclarationIdentifierRefactoringAction,
34-
CreateUDTMemberRefactoringAction createUDTMemberRefactoringActionRefactoringAction,
34+
ModifyUserDefinedTypeRefactoringAction modifyUserDefinedTypeRefactoringAction,
3535
EncapsulateFieldInsertNewCodeRefactoringAction encapsulateFieldInsertNewCodeRefactoringAction)
3636
{
3737
_replaceReferences = replaceReferencesRefactoringAction;
3838
_replaceUDTMemberReferencesRefactoringAction = replaceUDTMemberReferencesRefactoringAction;
3939
_replaceDeclarationIdentifiers = replaceDeclarationIdentifierRefactoringAction;
40-
_createUDTMemberRefactoringAction = createUDTMemberRefactoringActionRefactoringAction;
40+
_modifyUDTRefactoringAction = modifyUserDefinedTypeRefactoringAction;
4141
_encapsulateFieldInsertNewCodeRefactoringAction = encapsulateFieldInsertNewCodeRefactoringAction;
4242
}
4343

@@ -50,8 +50,8 @@ public ICodeOnlyRefactoringAction<ReplaceDeclarationIdentifierModel> ReplaceDecl
5050
public ICodeOnlyRefactoringAction<ReplacePrivateUDTMemberReferencesModel> ReplaceUDTMemberReferences
5151
=> _replaceUDTMemberReferencesRefactoringAction;
5252

53-
public ICodeOnlyRefactoringAction<CreateUDTMemberModel> CreateUDTMember
54-
=> _createUDTMemberRefactoringAction;
53+
public ICodeOnlyRefactoringAction<ModifyUserDefinedTypeModel> ModifyUserDefinedType
54+
=> _modifyUDTRefactoringAction;
5555

5656
public ICodeOnlyRefactoringAction<EncapsulateFieldInsertNewCodeModel> EncapsulateFieldInsertNewCode
5757
=> _encapsulateFieldInsertNewCodeRefactoringAction;

Rubberduck.Refactorings/EncapsulateField/EncapsulateFieldUseBackingUDTMember/EncapsulateFieldUseBackingUDTMemberRefactoringAction.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
using Rubberduck.Parsing.Rewriter;
22
using Rubberduck.Parsing.Symbols;
33
using Rubberduck.Refactorings.Common;
4-
using Rubberduck.Refactorings.CreateUDTMember;
54
using Rubberduck.Refactorings.ReplaceReferences;
65
using Rubberduck.Refactorings.ReplacePrivateUDTMemberReferences;
76
using System.Linq;
87
using Rubberduck.Refactorings.EncapsulateField;
98
using Rubberduck.Refactorings.EncapsulateFieldInsertNewCode;
109
using System.Collections.Generic;
10+
using Rubberduck.Refactorings.ModifyUserDefinedType;
1111

1212
namespace Rubberduck.Refactorings.EncapsulateFieldUseBackingUDTMember
1313
{
1414
public class EncapsulateFieldUseBackingUDTMemberRefactoringAction : CodeOnlyRefactoringActionBase<EncapsulateFieldUseBackingUDTMemberModel>
1515
{
16-
private readonly ICodeOnlyRefactoringAction<CreateUDTMemberModel> _createUDTMemberRefactoringAction;
16+
private readonly ICodeOnlyRefactoringAction<ModifyUserDefinedTypeModel> _modifyUDTRefactoringAction;
1717
private readonly ICodeOnlyRefactoringAction<ReplacePrivateUDTMemberReferencesModel> _replacePrivateUDTMemberReferencesRefactoringAction;
1818
private readonly ICodeOnlyRefactoringAction<ReplaceReferencesModel> _replaceReferencesRefactoringAction;
1919
private readonly ICodeOnlyRefactoringAction<EncapsulateFieldInsertNewCodeModel> _encapsulateFieldInsertNewCodeRefactoringAction;
@@ -29,7 +29,7 @@ public EncapsulateFieldUseBackingUDTMemberRefactoringAction(
2929
IEncapsulateFieldCodeBuilderFactory encapsulateFieldCodeBuilderFactory)
3030
: base(rewritingManager)
3131
{
32-
_createUDTMemberRefactoringAction = refactoringActionsProvider.CreateUDTMember;
32+
_modifyUDTRefactoringAction = refactoringActionsProvider.ModifyUserDefinedType;
3333
_replacePrivateUDTMemberReferencesRefactoringAction = refactoringActionsProvider.ReplaceUDTMemberReferences;
3434
_replaceReferencesRefactoringAction = refactoringActionsProvider.ReplaceReferences;
3535
_encapsulateFieldInsertNewCodeRefactoringAction = refactoringActionsProvider.EncapsulateFieldInsertNewCode;
@@ -58,11 +58,14 @@ private void ModifyFields(EncapsulateFieldUseBackingUDTMemberModel encapsulateFi
5858

5959
if (encapsulateFieldModel.ObjectStateUDTField.IsExistingDeclaration)
6060
{
61-
var conversionPairs = encapsulateFieldModel.SelectedFieldCandidates
62-
.Select(c => (c.Declaration, c.BackingIdentifier));
61+
var model = new ModifyUserDefinedTypeModel(encapsulateFieldModel.ObjectStateUDTField.AsTypeDeclaration);
6362

64-
var model = new CreateUDTMemberModel(encapsulateFieldModel.ObjectStateUDTField.AsTypeDeclaration, conversionPairs);
65-
_createUDTMemberRefactoringAction.Refactor(model, rewriteSession);
63+
foreach (var candidate in encapsulateFieldModel.SelectedFieldCandidates)
64+
{
65+
model.AddNewMemberPrototype(candidate.Declaration, candidate.BackingIdentifier);
66+
}
67+
68+
_modifyUDTRefactoringAction.Refactor(model,rewriteSession);
6669
}
6770

6871
rewriter.RemoveVariables(encapsulateFieldModel.SelectedFieldCandidates.Select(f => f.Declaration)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Rubberduck.Parsing.Grammar;
2+
using Rubberduck.Parsing.Symbols;
3+
using System;
4+
using System.Collections.Generic;
5+
6+
namespace Rubberduck.Refactorings.ModifyUserDefinedType
7+
{
8+
public class ModifyUserDefinedTypeModel : IRefactoringModel
9+
{
10+
private List<(Declaration, string)> _newMembers;
11+
private List<Declaration> _membersToRemove;
12+
13+
public ModifyUserDefinedTypeModel(Declaration target)
14+
{
15+
if (!target.DeclarationType.HasFlag(DeclarationType.UserDefinedType))
16+
{
17+
throw new ArgumentException();
18+
}
19+
20+
Target = target;
21+
_newMembers = new List<(Declaration, string)>();
22+
_membersToRemove = new List<Declaration>();
23+
InsertionIndex = (Target.Context as VBAParser.UdtDeclarationContext).END_TYPE().Symbol.TokenIndex - 1;
24+
}
25+
26+
public Declaration Target { get; }
27+
28+
public int InsertionIndex { get; }
29+
30+
public void AddNewMemberPrototype(Declaration prototype, string memberIdentifier)
31+
{
32+
if (!IsValidPrototypeDeclarationType(prototype.DeclarationType))
33+
{
34+
throw new ArgumentException("Invalid prototype DeclarationType");
35+
}
36+
_newMembers.Add((prototype, memberIdentifier));
37+
}
38+
39+
public void RemoveMember(Declaration member)
40+
{
41+
if (!member.DeclarationType.HasFlag(DeclarationType.UserDefinedTypeMember))
42+
{
43+
throw new ArgumentException();
44+
}
45+
_membersToRemove.Add(member);
46+
}
47+
48+
public IEnumerable<(Declaration, string)> MembersToAdd => _newMembers;
49+
50+
public IEnumerable<Declaration> MembersToRemove => _membersToRemove;
51+
52+
private static bool IsValidPrototypeDeclarationType(DeclarationType declarationType)
53+
{
54+
return declarationType.HasFlag(DeclarationType.Variable)
55+
|| declarationType.HasFlag(DeclarationType.UserDefinedTypeMember)
56+
|| declarationType.HasFlag(DeclarationType.Constant)
57+
|| declarationType.HasFlag(DeclarationType.Function);
58+
}
59+
}
60+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using Rubberduck.Parsing;
2+
using Rubberduck.Parsing.Grammar;
3+
using Rubberduck.Parsing.Rewriter;
4+
using Rubberduck.Parsing.Symbols;
5+
using Rubberduck.Parsing.VBA;
6+
using Rubberduck.SmartIndenter;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
11+
namespace Rubberduck.Refactorings.ModifyUserDefinedType
12+
{
13+
public class ModifyUserDefinedTypeRefactoringAction : CodeOnlyRefactoringActionBase<ModifyUserDefinedTypeModel>
14+
{
15+
private readonly IDeclarationFinderProvider _declarationFinderProvider;
16+
private readonly IRewritingManager _rewritingManager;
17+
private readonly ICodeBuilder _codeBuilder;
18+
19+
/// <summary>
20+
/// Removes or adds UserDefinedTypeMember declarations to an existing UserDefinedType.
21+
/// Adding a UDTMember is based on a Declaration prototype (typically a variable declaration but can a UserDefinedTypeMember, Constant, or Function).
22+
/// </summary>
23+
/// <remarks>
24+
/// The refactoring actions does not modify the prototype declaration or its references.
25+
/// The refactoring actions does not modify references for removed UDTMembers.
26+
/// The refactoring action does not provide any identifier validation or conflictAnalysis
27+
/// </remarks>
28+
public ModifyUserDefinedTypeRefactoringAction(IDeclarationFinderProvider declarationFinderProvider, IRewritingManager rewritingManager, ICodeBuilder codeBuilder)
29+
:base(rewritingManager)
30+
{
31+
_declarationFinderProvider = declarationFinderProvider;
32+
_rewritingManager = rewritingManager;
33+
_codeBuilder = codeBuilder;
34+
}
35+
36+
public override void Refactor(ModifyUserDefinedTypeModel model, IRewriteSession rewriteSession)
37+
{
38+
var newMembers = new List<string>();
39+
foreach ((Declaration Prototype, string Identifier) in model.MembersToAdd)
40+
{
41+
_codeBuilder.TryBuildUDTMemberDeclaration(Prototype, Identifier, out var udtMemberDeclaration);
42+
newMembers.Add(udtMemberDeclaration);
43+
}
44+
45+
var scratchPad = _rewritingManager.CheckOutCodePaneSession().CheckOutModuleRewriter(model.Target.QualifiedModuleName);
46+
scratchPad.InsertBefore(model.InsertionIndex, $"{Environment.NewLine}{string.Join(Environment.NewLine, newMembers)}");
47+
48+
foreach (var member in model.MembersToRemove)
49+
{
50+
scratchPad.Remove(member);
51+
}
52+
53+
var udtDeclarationContext = model.Target.Context as VBAParser.UdtDeclarationContext;
54+
var newBlock = scratchPad.GetText(udtDeclarationContext.Start.TokenIndex, udtDeclarationContext.Stop.TokenIndex);
55+
var udtLines = newBlock.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
56+
.Where(ul => !string.IsNullOrEmpty(ul.Trim()));
57+
58+
var rewriter = rewriteSession.CheckOutModuleRewriter(model.Target.QualifiedModuleName);
59+
rewriter.Replace(udtDeclarationContext, string.Join(Environment.NewLine, _codeBuilder.Indenter.Indent(udtLines)));
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)