Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5578 from BZngr/EF_SplitRefactoring
EncapsulateFieldRefactoring - Split Refactoring
- Loading branch information
Showing
87 changed files
with
6,043 additions
and
2,933 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
324 changes: 324 additions & 0 deletions
324
Rubberduck.Refactorings/EncapsulateField/ConflictDetection/EncapsulateFieldConflictFinder.cs
Large diffs are not rendered by default.
Oops, something went wrong.
65 changes: 65 additions & 0 deletions
65
Rubberduck.Refactorings/EncapsulateField/EncapsulateFieldCandidateSetsProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using Rubberduck.Parsing.Symbols; | ||
using Rubberduck.Parsing.VBA; | ||
using Rubberduck.VBEditor; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Rubberduck.Refactorings.EncapsulateField | ||
{ | ||
public interface IEncapsulateFieldCandidateSetsProviderFactory | ||
{ | ||
IEncapsulateFieldCandidateSetsProvider Create(IDeclarationFinderProvider declarationFinderProvider, | ||
IEncapsulateFieldCandidateFactory encapsulateFieldCandidateFactory, | ||
QualifiedModuleName qualifiedModuleName); | ||
} | ||
|
||
public interface IEncapsulateFieldCandidateSetsProvider | ||
{ | ||
IReadOnlyCollection<IEncapsulateFieldCandidate> EncapsulateFieldUseBackingFieldCandidates { get; } | ||
IReadOnlyCollection<IEncapsulateFieldAsUDTMemberCandidate> EncapsulateFieldUseBackingUDTMemberCandidates { get; } | ||
IReadOnlyCollection<IObjectStateUDT> ObjectStateFieldCandidates { get; } | ||
} | ||
|
||
/// <summary> | ||
/// EncapsulateFieldCandidateSetsProvider provides access to a sets of | ||
/// EncapsulateField candidate instances to be shared among EncapsulateFieldRefactoringActions. | ||
/// </summary> | ||
public class EncapsulateFieldCandidateSetsProvider : IEncapsulateFieldCandidateSetsProvider | ||
{ | ||
public EncapsulateFieldCandidateSetsProvider(IDeclarationFinderProvider declarationFinderProvider, | ||
IEncapsulateFieldCandidateFactory encapsulateFieldCandidateFactory, | ||
QualifiedModuleName qualifiedModuleName) | ||
{ | ||
EncapsulateFieldUseBackingFieldCandidates = declarationFinderProvider.DeclarationFinder.Members(qualifiedModuleName, DeclarationType.Variable) | ||
.Where(v => v.ParentDeclaration is ModuleDeclaration | ||
&& !v.IsWithEvents) | ||
.Select(f => encapsulateFieldCandidateFactory.CreateFieldCandidate(f)) | ||
.ToList(); | ||
|
||
var objectStateUDTCandidates = EncapsulateFieldUseBackingFieldCandidates | ||
.OfType<IUserDefinedTypeCandidate>() | ||
.Where(fc => fc.Declaration.Accessibility == Accessibility.Private | ||
&& fc.Declaration.AsTypeDeclaration.Accessibility == Accessibility.Private) | ||
.Select(udtc => encapsulateFieldCandidateFactory.CreateObjectStateField(udtc)) | ||
//If multiple fields of the same UserDefinedType exist, they are all disqualified as candidates to host a module's state. | ||
.ToLookup(objectStateUDTCandidate => objectStateUDTCandidate.Declaration.AsTypeDeclaration.IdentifierName) | ||
.Where(osc => osc.Count() == 1) | ||
.SelectMany(osc => osc) | ||
.ToList(); | ||
|
||
var defaultObjectStateUDT = encapsulateFieldCandidateFactory.CreateDefaultObjectStateField(qualifiedModuleName); | ||
objectStateUDTCandidates.Add(defaultObjectStateUDT); | ||
ObjectStateFieldCandidates = objectStateUDTCandidates; | ||
|
||
EncapsulateFieldUseBackingUDTMemberCandidates = EncapsulateFieldUseBackingFieldCandidates | ||
.Select(fc => encapsulateFieldCandidateFactory.CreateUDTMemberCandidate(fc, defaultObjectStateUDT)) | ||
.ToList(); | ||
} | ||
|
||
public IReadOnlyCollection<IEncapsulateFieldCandidate> EncapsulateFieldUseBackingFieldCandidates { get; } | ||
|
||
public IReadOnlyCollection<IEncapsulateFieldAsUDTMemberCandidate> EncapsulateFieldUseBackingUDTMemberCandidates { get; } | ||
|
||
public IReadOnlyCollection<IObjectStateUDT> ObjectStateFieldCandidates { get; } | ||
} | ||
} |
162 changes: 0 additions & 162 deletions
162
Rubberduck.Refactorings/EncapsulateField/EncapsulateFieldElementsBuilder.cs
This file was deleted.
Oops, something went wrong.
95 changes: 95 additions & 0 deletions
95
...efactorings/EncapsulateField/EncapsulateFieldInsertNewCode/EncapsulateFieldCodeBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using Rubberduck.Parsing.Grammar; | ||
using Rubberduck.Parsing.Symbols; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Rubberduck.Refactorings.EncapsulateField | ||
{ | ||
public interface IEncapsulateFieldCodeBuilder | ||
{ | ||
(string Get, string Let, string Set) BuildPropertyBlocks(PropertyAttributeSet propertyAttributeSet); | ||
string BuildUserDefinedTypeDeclaration(IObjectStateUDT objectStateUDT, IEnumerable<IEncapsulateFieldCandidate> candidates); | ||
string BuildObjectStateFieldDeclaration(IObjectStateUDT objectStateUDT); | ||
string BuildFieldDeclaration(Declaration target, string identifier); | ||
} | ||
|
||
/// <summary> | ||
/// EncapsulateFieldCodeBuilder wraps an ICodeBuilder instance to extend it for the | ||
/// specific needs of an EncapsulateField refactoring action. | ||
/// </summary> | ||
public class EncapsulateFieldCodeBuilder : IEncapsulateFieldCodeBuilder | ||
{ | ||
private readonly ICodeBuilder _codeBuilder; | ||
|
||
public EncapsulateFieldCodeBuilder(ICodeBuilder codeBuilder) | ||
{ | ||
_codeBuilder = codeBuilder; | ||
} | ||
|
||
public (string Get, string Let, string Set) BuildPropertyBlocks(PropertyAttributeSet propertyAttributes) | ||
{ | ||
if (!(propertyAttributes.Declaration.DeclarationType.HasFlag(DeclarationType.Variable) | ||
|| propertyAttributes.Declaration.DeclarationType.HasFlag(DeclarationType.UserDefinedTypeMember))) | ||
{ | ||
throw new ArgumentException("Invalid prototype DeclarationType", nameof(propertyAttributes)); | ||
} | ||
|
||
(string Get, string Let, string Set) blocks = (string.Empty, string.Empty, string.Empty); | ||
|
||
var mutatorBody = $"{propertyAttributes.BackingField} = {propertyAttributes.RHSParameterIdentifier}"; | ||
|
||
if (propertyAttributes.GeneratePropertyLet) | ||
{ | ||
_codeBuilder.TryBuildPropertyLetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Let, content: mutatorBody); | ||
} | ||
|
||
if (propertyAttributes.GeneratePropertySet) | ||
{ | ||
_codeBuilder.TryBuildPropertySetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Set, content: $"{Tokens.Set} {mutatorBody}"); | ||
} | ||
|
||
var propertyGetBody = propertyAttributes.UsesSetAssignment | ||
? $"{Tokens.Set} {propertyAttributes.PropertyName} = {propertyAttributes.BackingField}" | ||
: $"{propertyAttributes.PropertyName} = {propertyAttributes.BackingField}"; | ||
|
||
if (propertyAttributes.AsTypeName.Equals(Tokens.Variant) && !propertyAttributes.Declaration.IsArray) | ||
{ | ||
propertyGetBody = string.Join( | ||
$"{Tokens.If} IsObject({propertyAttributes.BackingField}) {Tokens.Then}", | ||
$"{Tokens.Set} {propertyAttributes.PropertyName} = {propertyAttributes.BackingField}", | ||
Tokens.Else, | ||
$"{propertyAttributes.PropertyName} = {propertyAttributes.BackingField}", | ||
$"{Tokens.End} {Tokens.If}"); | ||
} | ||
|
||
_codeBuilder.TryBuildPropertyGetCodeBlock(propertyAttributes.Declaration, propertyAttributes.PropertyName, out blocks.Get, content: propertyGetBody); | ||
|
||
return (blocks.Get, blocks.Let, blocks.Set); | ||
} | ||
|
||
public string BuildUserDefinedTypeDeclaration(IObjectStateUDT objectStateUDT, IEnumerable<IEncapsulateFieldCandidate> candidates) | ||
{ | ||
var newUDTMembers = candidates.Where(c => c.EncapsulateFlag) | ||
.Select(m => (m.Declaration, m.BackingIdentifier)); | ||
|
||
if (_codeBuilder.TryBuildUserDefinedTypeDeclaration(objectStateUDT.AsTypeName, newUDTMembers, out var declaration)) | ||
{ | ||
return declaration; | ||
} | ||
|
||
return string.Empty; | ||
} | ||
|
||
public string BuildObjectStateFieldDeclaration(IObjectStateUDT objectStateUDT) | ||
=> $"{Accessibility.Private} {objectStateUDT.IdentifierName} {Tokens.As} {objectStateUDT.AsTypeName}"; | ||
|
||
public string BuildFieldDeclaration(Declaration target, string identifier) | ||
{ | ||
var identifierExpressionSansVisibility = target.Context.GetText().Replace(target.IdentifierName, identifier); | ||
return target.IsTypeSpecified | ||
? $"{Tokens.Private} {identifierExpressionSansVisibility}" | ||
: $"{Tokens.Private} {identifierExpressionSansVisibility} {Tokens.As} {target.AsTypeName}"; | ||
} | ||
} | ||
} |
Oops, something went wrong.