Skip to content

Commit 7385390

Browse files
committed
Merge pull request #898 from Hosch250/ExtractInterface
Extract interface
2 parents 950c66a + 1821f37 commit 7385390

21 files changed

+1745
-0
lines changed

RetailCoder.VBE/Common/DeclarationExtensions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.Linq;
56
using System.Windows.Media.Imaging;
67
using Microsoft.Vbe.Interop;
78
using Rubberduck.Annotations;
9+
using Rubberduck.Parsing;
810
using Rubberduck.Parsing.Grammar;
911
using Rubberduck.Parsing.Symbols;
1012
using Rubberduck.VBEditor;
@@ -441,5 +443,34 @@ public static Declaration FindVariable(this IEnumerable<Declaration> declaration
441443
}
442444
return null;
443445
}
446+
447+
/// <summary>
448+
/// Returns the interface for a QualifiedSelection contained by a statement similar to "Implements IClass1"
449+
/// </summary>
450+
/// <param name="declarations"></param>
451+
/// <param name="selection"></param>
452+
/// <returns></returns>
453+
[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")]
454+
public static Declaration FindInterface(this IEnumerable<Declaration> declarations, QualifiedSelection selection)
455+
{
456+
foreach (var declaration in declarations.FindInterfaces())
457+
{
458+
foreach (var reference in declaration.References)
459+
{
460+
var implementsStmt = reference.Context.Parent as VBAParser.ImplementsStmtContext;
461+
462+
if (implementsStmt == null) { continue; }
463+
464+
if (reference.QualifiedModuleName == selection.QualifiedName &&
465+
(implementsStmt.GetSelection().Contains(selection.Selection)
466+
|| reference.Selection.Contains(selection.Selection)))
467+
{
468+
return declaration;
469+
}
470+
}
471+
}
472+
473+
return null;
474+
}
444475
}
445476
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Parsing.Grammar;
4+
using Rubberduck.Parsing.Symbols;
5+
using Rubberduck.Parsing.VBA;
6+
using Rubberduck.VBEditor;
7+
8+
namespace Rubberduck.Refactorings.ExtractInterface
9+
{
10+
public class ExtractInterfaceModel
11+
{
12+
private readonly RubberduckParserState _parseResult;
13+
public RubberduckParserState ParseResult { get { return _parseResult; } }
14+
15+
private readonly IEnumerable<Declaration> _declarations;
16+
public IEnumerable<Declaration> Declarations { get { return _declarations; } }
17+
18+
private readonly QualifiedSelection _selection;
19+
public QualifiedSelection Selection { get { return _selection; } }
20+
21+
private readonly Declaration _targetDeclaration;
22+
public Declaration TargetDeclaration { get { return _targetDeclaration; } }
23+
24+
public string InterfaceName { get; set; }
25+
public List<InterfaceMember> Members { get; set; }
26+
27+
private readonly static DeclarationType[] DeclarationTypes =
28+
{
29+
DeclarationType.Class,
30+
DeclarationType.Document,
31+
DeclarationType.UserForm
32+
};
33+
34+
public readonly string[] PrimitiveTypes =
35+
{
36+
Tokens.Boolean,
37+
Tokens.Byte,
38+
Tokens.Date,
39+
Tokens.Decimal,
40+
Tokens.Double,
41+
Tokens.Long,
42+
Tokens.LongLong,
43+
Tokens.LongPtr,
44+
Tokens.Integer,
45+
Tokens.Single,
46+
Tokens.String,
47+
Tokens.StrPtr
48+
};
49+
50+
public ExtractInterfaceModel(RubberduckParserState parseResult, QualifiedSelection selection)
51+
{
52+
_parseResult = parseResult;
53+
_selection = selection;
54+
_declarations = parseResult.AllDeclarations.ToList();
55+
56+
_targetDeclaration =
57+
_declarations.SingleOrDefault(
58+
item =>
59+
!item.IsBuiltIn && DeclarationTypes.Contains(item.DeclarationType)
60+
&& item.Project == selection.QualifiedName.Project
61+
&& item.QualifiedSelection.QualifiedName == selection.QualifiedName);
62+
63+
InterfaceName = "I" + TargetDeclaration.IdentifierName;
64+
65+
Members = _declarations.Where(item => !item.IsBuiltIn &&
66+
item.Project == _targetDeclaration.Project &&
67+
item.ComponentName == _targetDeclaration.ComponentName &&
68+
item.Accessibility == Accessibility.Public &&
69+
item.DeclarationType != DeclarationType.Variable &&
70+
item.DeclarationType != DeclarationType.Event)
71+
.OrderBy(o => o.Selection.StartLine)
72+
.ThenBy(t => t.Selection.StartColumn)
73+
.Select(d => new InterfaceMember(d, _declarations))
74+
.ToList();
75+
}
76+
}
77+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Linq;
2+
using System.Windows.Forms;
3+
using Microsoft.Vbe.Interop;
4+
5+
namespace Rubberduck.Refactorings.ExtractInterface
6+
{
7+
public interface IExtractInterfacePresenter
8+
{
9+
ExtractInterfaceModel Show();
10+
}
11+
12+
public class ExtractInterfacePresenter : IExtractInterfacePresenter
13+
{
14+
private readonly IExtractInterfaceView _view;
15+
private readonly ExtractInterfaceModel _model;
16+
17+
public ExtractInterfacePresenter(IExtractInterfaceView view, ExtractInterfaceModel model)
18+
{
19+
_view = view;
20+
_model = model;
21+
}
22+
23+
public ExtractInterfaceModel Show()
24+
{
25+
if (_model.TargetDeclaration == null) { return null; }
26+
27+
_view.ComponentNames =
28+
_model.TargetDeclaration.Project.VBComponents.Cast<VBComponent>().Select(c => c.Name).ToList();
29+
_view.InterfaceName = _model.InterfaceName;
30+
_view.Members = _model.Members;
31+
32+
if (_view.ShowDialog() != DialogResult.OK)
33+
{
34+
return null;
35+
}
36+
37+
_model.InterfaceName = _view.InterfaceName;
38+
_model.Members = _view.Members;
39+
return _model;
40+
}
41+
}
42+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Rubberduck.Parsing.VBA;
2+
using Rubberduck.VBEditor;
3+
4+
namespace Rubberduck.Refactorings.ExtractInterface
5+
{
6+
public class ExtractInterfacePresenterFactory : IRefactoringPresenterFactory<ExtractInterfacePresenter>
7+
{
8+
private readonly IActiveCodePaneEditor _editor;
9+
private readonly IExtractInterfaceView _view;
10+
private readonly RubberduckParserState _parseResult;
11+
12+
public ExtractInterfacePresenterFactory(RubberduckParserState parseResult, IActiveCodePaneEditor editor, IExtractInterfaceView view)
13+
{
14+
_editor = editor;
15+
_view = view;
16+
_parseResult = parseResult;
17+
}
18+
19+
public ExtractInterfacePresenter Create()
20+
{
21+
var selection = _editor.GetSelection();
22+
if (selection == null)
23+
{
24+
return null;
25+
}
26+
27+
var model = new ExtractInterfaceModel(_parseResult, selection.Value);
28+
return new ExtractInterfacePresenter(_view, model);
29+
}
30+
}
31+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
using System;
2+
using System.Linq;
3+
using Microsoft.Vbe.Interop;
4+
using Rubberduck.Parsing.Symbols;
5+
using Rubberduck.VBEditor;
6+
7+
namespace Rubberduck.Refactorings.ExtractInterface
8+
{
9+
public class ExtractInterfaceRefactoring : IRefactoring
10+
{
11+
private readonly IRefactoringPresenterFactory<ExtractInterfacePresenter> _factory;
12+
private readonly IActiveCodePaneEditor _editor;
13+
private ExtractInterfaceModel _model;
14+
15+
public ExtractInterfaceRefactoring(IRefactoringPresenterFactory<ExtractInterfacePresenter> factory,
16+
IActiveCodePaneEditor editor)
17+
{
18+
_factory = factory;
19+
_editor = editor;
20+
}
21+
22+
public void Refactor()
23+
{
24+
var presenter = _factory.Create();
25+
if (presenter == null)
26+
{
27+
return;
28+
}
29+
30+
_model = presenter.Show();
31+
32+
if (_model == null) { return; }
33+
34+
AddInterface();
35+
}
36+
37+
public void Refactor(QualifiedSelection target)
38+
{
39+
_editor.SetSelection(target);
40+
Refactor();
41+
}
42+
43+
public void Refactor(Declaration target)
44+
{
45+
_editor.SetSelection(target.QualifiedSelection);
46+
Refactor();
47+
}
48+
49+
private void AddInterface()
50+
{
51+
var interfaceComponent = _model.TargetDeclaration.Project.VBComponents.Add(vbext_ComponentType.vbext_ct_ClassModule);
52+
interfaceComponent.Name = _model.InterfaceName;
53+
54+
_editor.InsertLines(1, GetInterface());
55+
56+
var module = _model.TargetDeclaration.QualifiedSelection.QualifiedName.Component.CodeModule;
57+
58+
AddItems(module);
59+
module.InsertLines(module.CountOfDeclarationLines + 1, "Implements " + _model.InterfaceName);
60+
}
61+
62+
private void AddItems(CodeModule module)
63+
{
64+
_model.Members.Reverse();
65+
66+
foreach (var member in _model.Members.Where(m => m.IsSelected))
67+
{
68+
module.InsertLines(module.CountOfDeclarationLines + 1, GetInterfaceMember(member));
69+
}
70+
}
71+
72+
private string GetInterfaceMember(InterfaceMember member)
73+
{
74+
switch (member.MemberType)
75+
{
76+
case "Sub":
77+
return SubStmt(member);
78+
79+
case "Function":
80+
return FunctionStmt(member);
81+
82+
case "Property":
83+
switch (member.PropertyType)
84+
{
85+
case "Get":
86+
return PropertyGetStmt(member);
87+
88+
case "Let":
89+
return PropertyLetStmt(member);
90+
91+
case "Set":
92+
return PropertySetStmt(member);
93+
}
94+
break;
95+
}
96+
97+
return string.Empty;
98+
}
99+
100+
private string SubStmt(InterfaceMember member)
101+
{
102+
var memberSignature = "Public Sub " + _model.InterfaceName + "_" + member.Member.IdentifierName + "(" +
103+
string.Join(", ", member.MemberParams) + ")";
104+
105+
var memberBody = " " + member.Member.IdentifierName + " " +
106+
string.Join(", ", member.MemberParams.Select(p => p.ParamName));
107+
108+
var memberCloseStatement = "End Sub" + Environment.NewLine;
109+
110+
return string.Join(Environment.NewLine, memberSignature, memberBody, memberCloseStatement);
111+
}
112+
113+
private string FunctionStmt(InterfaceMember member)
114+
{
115+
var memberSignature = "Public Function " + _model.InterfaceName + "_" + member.Member.IdentifierName + "(" +
116+
string.Join(", ", member.MemberParams) + ")" + " As " + member.Type;
117+
118+
var memberBody = " " + _model.InterfaceName + "_" + member.Member.IdentifierName + " = " +
119+
member.Member.IdentifierName + "(" +
120+
string.Join(", ", member.MemberParams.Select(p => p.ParamName)) + ")";
121+
122+
var memberCloseStatement = "End Function" + Environment.NewLine;
123+
124+
return string.Join(Environment.NewLine, memberSignature, memberBody, memberCloseStatement);
125+
}
126+
127+
private string PropertyGetStmt(InterfaceMember member)
128+
{
129+
var memberSignature = "Public Property Get " + _model.InterfaceName + "_" + member.Member.IdentifierName +
130+
" As " + member.Type;
131+
132+
var memberBody = _model.PrimitiveTypes.Contains(member.Type) ||
133+
member.Member.DeclarationType == DeclarationType.UserDefinedType
134+
? " "
135+
: " Set ";
136+
137+
memberBody += _model.InterfaceName + "_" + member.Member.IdentifierName + " = " +
138+
member.Member.IdentifierName;
139+
140+
var memberCloseStatement = "End Property" + Environment.NewLine;
141+
142+
return string.Join(Environment.NewLine, memberSignature, memberBody, memberCloseStatement);
143+
}
144+
145+
private string PropertyLetStmt(InterfaceMember member)
146+
{
147+
var memberSignature = "Public Property Let " + _model.InterfaceName + "_" + member.Member.IdentifierName +
148+
"(" + string.Join(", ", member.MemberParams) + ")";
149+
150+
var memberBody = _model.PrimitiveTypes.Contains(member.MemberParams.Last().ParamType) ||
151+
member.Member.DeclarationType == DeclarationType.UserDefinedType
152+
? " "
153+
: " Set ";
154+
155+
memberBody += member.Member.IdentifierName + " = " + member.MemberParams.Last().ParamName;
156+
157+
var memberCloseStatement = "End Property" + Environment.NewLine;
158+
159+
return string.Join(Environment.NewLine, memberSignature, memberBody, memberCloseStatement);
160+
}
161+
162+
private string PropertySetStmt(InterfaceMember member)
163+
{
164+
var memberSignature = "Public Property Set " + _model.InterfaceName + "_" + member.Member.IdentifierName +
165+
"(" + string.Join(", ", member.MemberParams) + ")";
166+
167+
var memberBody = " Set " + member.Member.IdentifierName + " = " + member.MemberParams.Last().ParamName;
168+
169+
var memberCloseStatement = "End Property" + Environment.NewLine;
170+
171+
return string.Join(Environment.NewLine, memberSignature, memberBody, memberCloseStatement);
172+
}
173+
174+
private string GetInterface()
175+
{
176+
return "Option Explicit" + Environment.NewLine + string.Join(Environment.NewLine, _model.Members.Where(m => m.IsSelected));
177+
}
178+
}
179+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Collections.Generic;
2+
using Rubberduck.UI;
3+
4+
namespace Rubberduck.Refactorings.ExtractInterface
5+
{
6+
public interface IExtractInterfaceView : IDialogView
7+
{
8+
string InterfaceName { get; set; }
9+
List<InterfaceMember> Members { get; set; }
10+
List<string> ComponentNames { get; set; }
11+
}
12+
}

0 commit comments

Comments
 (0)