Skip to content

Commit 3c10fca

Browse files
authored
Merge pull request #5578 from BZngr/EF_SplitRefactoring
EncapsulateFieldRefactoring - Split Refactoring
2 parents 136889f + 9db29d9 commit 3c10fca

File tree

87 files changed

+6043
-2933
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+6043
-2933
lines changed

Rubberduck.Main/Root/RubberduckIoCInstaller.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,14 @@ private void RegisterSpecialFactories(IWindsorContainer container)
380380
container.Register(Component.For<IAnnotationArgumentViewModelFactory>()
381381
.ImplementedBy<AnnotationArgumentViewModelFactory>()
382382
.LifestyleSingleton());
383+
384+
container.Register(Component.For<IReplacePrivateUDTMemberReferencesModelFactory>()
385+
.ImplementedBy<ReplacePrivateUDTMemberReferencesModelFactory>()
386+
.LifestyleSingleton());
387+
383388
RegisterUnreachableCaseFactories(container);
389+
390+
RegisterEncapsulateFieldRefactoringFactories(container);
384391
}
385392

386393
private void RegisterUnreachableCaseFactories(IWindsorContainer container)
@@ -390,6 +397,21 @@ private void RegisterUnreachableCaseFactories(IWindsorContainer container)
390397
.LifestyleSingleton());
391398
}
392399

400+
private void RegisterEncapsulateFieldRefactoringFactories(IWindsorContainer container)
401+
{
402+
container.Register(Component.For<IEncapsulateFieldCandidateFactory>()
403+
.ImplementedBy<EncapsulateFieldCandidateFactory>()
404+
.LifestyleSingleton());
405+
container.Register(Component.For<IEncapsulateFieldUseBackingUDTMemberModelFactory>()
406+
.ImplementedBy<EncapsulateFieldUseBackingUDTMemberModelFactory>()
407+
.LifestyleSingleton());
408+
container.Register(Component.For<IEncapsulateFieldUseBackingFieldModelFactory>()
409+
.ImplementedBy<EncapsulateFieldUseBackingFieldModelFactory>()
410+
.LifestyleSingleton());
411+
container.Register(Component.For<IEncapsulateFieldModelFactory>()
412+
.ImplementedBy<EncapsulateFieldModelFactory>()
413+
.LifestyleSingleton());
414+
}
393415

394416
private void RegisterQuickFixes(IWindsorContainer container, Assembly[] assembliesToRegister)
395417
{

Rubberduck.Refactorings/Abstract/RefactoringPreviewProviderWrapperBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ protected RefactoringPreviewProviderWrapperBase(
2020

2121
protected abstract QualifiedModuleName ComponentToShow(TModel model);
2222

23-
public string Preview(TModel model)
23+
public virtual string Preview(TModel model)
2424
{
2525
var rewriteSession = RewriteSession(RewriteSessionCodeKind);
2626
_refactoringAction.Refactor(model, rewriteSession);

Rubberduck.Refactorings/Common/CodeBuilder.cs

Lines changed: 165 additions & 94 deletions
Large diffs are not rendered by default.

Rubberduck.Refactorings/EncapsulateField/ConflictDetection/EncapsulateFieldConflictFinder.cs

Lines changed: 324 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using Rubberduck.Parsing.Symbols;
2+
using Rubberduck.Parsing.VBA;
3+
using Rubberduck.VBEditor;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Rubberduck.Refactorings.EncapsulateField
8+
{
9+
public interface IEncapsulateFieldCandidateSetsProviderFactory
10+
{
11+
IEncapsulateFieldCandidateSetsProvider Create(IDeclarationFinderProvider declarationFinderProvider,
12+
IEncapsulateFieldCandidateFactory encapsulateFieldCandidateFactory,
13+
QualifiedModuleName qualifiedModuleName);
14+
}
15+
16+
public interface IEncapsulateFieldCandidateSetsProvider
17+
{
18+
IReadOnlyCollection<IEncapsulateFieldCandidate> EncapsulateFieldUseBackingFieldCandidates { get; }
19+
IReadOnlyCollection<IEncapsulateFieldAsUDTMemberCandidate> EncapsulateFieldUseBackingUDTMemberCandidates { get; }
20+
IReadOnlyCollection<IObjectStateUDT> ObjectStateFieldCandidates { get; }
21+
}
22+
23+
/// <summary>
24+
/// EncapsulateFieldCandidateSetsProvider provides access to a sets of
25+
/// EncapsulateField candidate instances to be shared among EncapsulateFieldRefactoringActions.
26+
/// </summary>
27+
public class EncapsulateFieldCandidateSetsProvider : IEncapsulateFieldCandidateSetsProvider
28+
{
29+
public EncapsulateFieldCandidateSetsProvider(IDeclarationFinderProvider declarationFinderProvider,
30+
IEncapsulateFieldCandidateFactory encapsulateFieldCandidateFactory,
31+
QualifiedModuleName qualifiedModuleName)
32+
{
33+
EncapsulateFieldUseBackingFieldCandidates = declarationFinderProvider.DeclarationFinder.Members(qualifiedModuleName, DeclarationType.Variable)
34+
.Where(v => v.ParentDeclaration is ModuleDeclaration
35+
&& !v.IsWithEvents)
36+
.Select(f => encapsulateFieldCandidateFactory.CreateFieldCandidate(f))
37+
.ToList();
38+
39+
var objectStateUDTCandidates = EncapsulateFieldUseBackingFieldCandidates
40+
.OfType<IUserDefinedTypeCandidate>()
41+
.Where(fc => fc.Declaration.Accessibility == Accessibility.Private
42+
&& fc.Declaration.AsTypeDeclaration.Accessibility == Accessibility.Private)
43+
.Select(udtc => encapsulateFieldCandidateFactory.CreateObjectStateField(udtc))
44+
//If multiple fields of the same UserDefinedType exist, they are all disqualified as candidates to host a module's state.
45+
.ToLookup(objectStateUDTCandidate => objectStateUDTCandidate.Declaration.AsTypeDeclaration.IdentifierName)
46+
.Where(osc => osc.Count() == 1)
47+
.SelectMany(osc => osc)
48+
.ToList();
49+
50+
var defaultObjectStateUDT = encapsulateFieldCandidateFactory.CreateDefaultObjectStateField(qualifiedModuleName);
51+
objectStateUDTCandidates.Add(defaultObjectStateUDT);
52+
ObjectStateFieldCandidates = objectStateUDTCandidates;
53+
54+
EncapsulateFieldUseBackingUDTMemberCandidates = EncapsulateFieldUseBackingFieldCandidates
55+
.Select(fc => encapsulateFieldCandidateFactory.CreateUDTMemberCandidate(fc, defaultObjectStateUDT))
56+
.ToList();
57+
}
58+
59+
public IReadOnlyCollection<IEncapsulateFieldCandidate> EncapsulateFieldUseBackingFieldCandidates { get; }
60+
61+
public IReadOnlyCollection<IEncapsulateFieldAsUDTMemberCandidate> EncapsulateFieldUseBackingUDTMemberCandidates { get; }
62+
63+
public IReadOnlyCollection<IObjectStateUDT> ObjectStateFieldCandidates { get; }
64+
}
65+
}

Rubberduck.Refactorings/EncapsulateField/EncapsulateFieldElementsBuilder.cs

Lines changed: 0 additions & 162 deletions
This file was deleted.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using Rubberduck.Parsing.Grammar;
2+
using Rubberduck.Parsing.Symbols;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Rubberduck.Refactorings.EncapsulateField
8+
{
9+
public interface IEncapsulateFieldCodeBuilder
10+
{
11+
(string Get, string Let, string Set) BuildPropertyBlocks(PropertyAttributeSet propertyAttributeSet);
12+
string BuildUserDefinedTypeDeclaration(IObjectStateUDT objectStateUDT, IEnumerable<IEncapsulateFieldCandidate> candidates);
13+
string BuildObjectStateFieldDeclaration(IObjectStateUDT objectStateUDT);
14+
string BuildFieldDeclaration(Declaration target, string identifier);
15+
}
16+
17+
/// <summary>
18+
/// EncapsulateFieldCodeBuilder wraps an ICodeBuilder instance to extend it for the
19+
/// specific needs of an EncapsulateField refactoring action.
20+
/// </summary>
21+
public class EncapsulateFieldCodeBuilder : IEncapsulateFieldCodeBuilder
22+
{
23+
private readonly ICodeBuilder _codeBuilder;
24+
25+
public EncapsulateFieldCodeBuilder(ICodeBuilder codeBuilder)
26+
{
27+
_codeBuilder = codeBuilder;
28+
}
29+
30+
public (string Get, string Let, string Set) BuildPropertyBlocks(PropertyAttributeSet propertyAttributes)
31+
{
32+
if (!(propertyAttributes.Declaration.DeclarationType.HasFlag(DeclarationType.Variable)
33+
|| propertyAttributes.Declaration.DeclarationType.HasFlag(DeclarationType.UserDefinedTypeMember)))
34+
{
35+
throw new ArgumentException("Invalid prototype DeclarationType", nameof(propertyAttributes));
36+
}
37+
38+
(string Get, string Let, string Set) blocks = (string.Empty, string.Empty, string.Empty);
39+
40+
var mutatorBody = $"{propertyAttributes.BackingField} = {propertyAttributes.RHSParameterIdentifier}";
41+
42+
if (propertyAttributes.GeneratePropertyLet)
43+
{
44+
_codeBuilder.TryBuildPropertyLetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Let, content: mutatorBody);
45+
}
46+
47+
if (propertyAttributes.GeneratePropertySet)
48+
{
49+
_codeBuilder.TryBuildPropertySetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Set, content: $"{Tokens.Set} {mutatorBody}");
50+
}
51+
52+
var propertyGetBody = propertyAttributes.UsesSetAssignment
53+
? $"{Tokens.Set} {propertyAttributes.PropertyName} = {propertyAttributes.BackingField}"
54+
: $"{propertyAttributes.PropertyName} = {propertyAttributes.BackingField}";
55+
56+
if (propertyAttributes.AsTypeName.Equals(Tokens.Variant) && !propertyAttributes.Declaration.IsArray)
57+
{
58+
propertyGetBody = string.Join(
59+
$"{Tokens.If} IsObject({propertyAttributes.BackingField}) {Tokens.Then}",
60+
$"{Tokens.Set} {propertyAttributes.PropertyName} = {propertyAttributes.BackingField}",
61+
Tokens.Else,
62+
$"{propertyAttributes.PropertyName} = {propertyAttributes.BackingField}",
63+
$"{Tokens.End} {Tokens.If}");
64+
}
65+
66+
_codeBuilder.TryBuildPropertyGetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Get, content: propertyGetBody);
67+
68+
return (blocks.Get, blocks.Let, blocks.Set);
69+
}
70+
71+
public string BuildUserDefinedTypeDeclaration(IObjectStateUDT objectStateUDT, IEnumerable<IEncapsulateFieldCandidate> candidates)
72+
{
73+
var newUDTMembers = candidates.Where(c => c.EncapsulateFlag)
74+
.Select(m => (m.Declaration, m.BackingIdentifier));
75+
76+
if (_codeBuilder.TryBuildUserDefinedTypeDeclaration(objectStateUDT.AsTypeName, newUDTMembers, out var declaration))
77+
{
78+
return declaration;
79+
}
80+
81+
return string.Empty;
82+
}
83+
84+
public string BuildObjectStateFieldDeclaration(IObjectStateUDT objectStateUDT)
85+
=> $"{Accessibility.Private} {objectStateUDT.IdentifierName} {Tokens.As} {objectStateUDT.AsTypeName}";
86+
87+
public string BuildFieldDeclaration(Declaration target, string identifier)
88+
{
89+
var identifierExpressionSansVisibility = target.Context.GetText().Replace(target.IdentifierName, identifier);
90+
return target.IsTypeSpecified
91+
? $"{Tokens.Private} {identifierExpressionSansVisibility}"
92+
: $"{Tokens.Private} {identifierExpressionSansVisibility} {Tokens.As} {target.AsTypeName}";
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)