1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using Rubberduck . Common ;
5
+ using Rubberduck . Parsing . Grammar ;
6
+ using Rubberduck . Parsing . Symbols ;
7
+ using Rubberduck . Parsing . VBA ;
8
+ using Rubberduck . UI ;
9
+ using Rubberduck . VBEditor ;
10
+
11
+ namespace Rubberduck . Refactorings . ImplementInterface
12
+ {
13
+ public class ImplementInterfaceRefactoring : IRefactoring
14
+ {
15
+ private readonly List < Declaration > _declarations ;
16
+ private readonly IActiveCodePaneEditor _editor ;
17
+ private Declaration _targetInterface ;
18
+ private Declaration _targetClass ;
19
+ private readonly IMessageBox _messageBox ;
20
+
21
+ const string MemberBody = " Err.Raise 5" ;
22
+
23
+ public ImplementInterfaceRefactoring ( RubberduckParserState state , IActiveCodePaneEditor editor , IMessageBox messageBox )
24
+ {
25
+ _declarations = state . AllDeclarations . ToList ( ) ;
26
+ _editor = editor ;
27
+ _messageBox = messageBox ;
28
+ }
29
+
30
+ public void Refactor ( )
31
+ {
32
+ var selection = _editor . GetSelection ( ) ;
33
+
34
+ if ( ! selection . HasValue )
35
+ {
36
+ _messageBox . Show ( "Invalid selection." , "Rubberduck - Implement Interface" ,
37
+ System . Windows . Forms . MessageBoxButtons . OK , System . Windows . Forms . MessageBoxIcon . Exclamation ) ;
38
+ return ;
39
+ }
40
+
41
+ Refactor ( selection . Value ) ;
42
+ }
43
+
44
+ public void Refactor ( QualifiedSelection selection )
45
+ {
46
+ _targetInterface = _declarations . FindInterface ( selection ) ;
47
+
48
+ _targetClass =
49
+ _declarations . SingleOrDefault (
50
+ d =>
51
+ ! d . IsBuiltIn && d . DeclarationType == DeclarationType . Class &&
52
+ d . QualifiedSelection . QualifiedName == selection . QualifiedName ) ;
53
+
54
+ if ( _targetClass == null || _targetInterface == null )
55
+ {
56
+ return ;
57
+ }
58
+
59
+ ImplementMissingMembers ( ) ;
60
+ }
61
+
62
+ public void Refactor ( Declaration target )
63
+ {
64
+ throw new NotImplementedException ( ) ;
65
+ }
66
+
67
+ private void ImplementMissingMembers ( )
68
+ {
69
+ var interfaceMembers = GetInterfaceMembers ( ) ;
70
+ var implementedMembers = GetImplementedMembers ( ) ;
71
+
72
+ var nonImplementedMembers =
73
+ interfaceMembers . Where (
74
+ d =>
75
+ ! implementedMembers . Select ( s => s . IdentifierName )
76
+ . Contains ( _targetInterface . ComponentName + "_" + d . IdentifierName ) ) . ToList ( ) ;
77
+
78
+ AddItems ( nonImplementedMembers ) ;
79
+ }
80
+
81
+ private void AddItems ( List < Declaration > members )
82
+ {
83
+ var module = _targetClass . QualifiedSelection . QualifiedName . Component . CodeModule ;
84
+
85
+ members . Reverse ( ) ;
86
+
87
+ foreach ( var member in members )
88
+ {
89
+ module . InsertLines ( module . CountOfDeclarationLines + 1 , GetInterfaceMember ( member ) ) ;
90
+ }
91
+ }
92
+
93
+ private string GetInterfaceMember ( Declaration member )
94
+ {
95
+ switch ( GetMemberType ( member ) )
96
+ {
97
+ case "Sub" :
98
+ return SubStmt ( member ) ;
99
+
100
+ case "Function" :
101
+ return FunctionStmt ( member ) ;
102
+
103
+ case "Property Get" :
104
+ return PropertyGetStmt ( member ) ;
105
+
106
+ case "Property Let" :
107
+ return PropertyLetStmt ( member ) ;
108
+
109
+ case "Property Set" :
110
+ return PropertySetStmt ( member ) ;
111
+ }
112
+
113
+ return string . Empty ;
114
+ }
115
+
116
+ private string SubStmt ( Declaration member )
117
+ {
118
+ var memberParams = GetParameters ( member ) ;
119
+
120
+ var memberSignature = "Public Sub " + _targetInterface . IdentifierName + "_" + member . IdentifierName + "(" +
121
+ string . Join ( ", " , memberParams ) + ")" ;
122
+
123
+ var memberCloseStatement = "End Sub" + Environment . NewLine ;
124
+
125
+ return string . Join ( Environment . NewLine , memberSignature , MemberBody , memberCloseStatement ) ;
126
+ }
127
+
128
+ private string FunctionStmt ( Declaration member )
129
+ {
130
+ var memberParams = GetParameters ( member ) ;
131
+
132
+ var memberSignature = "Public Function " + _targetInterface . IdentifierName + "_" + member . IdentifierName + "(" +
133
+ string . Join ( ", " , memberParams ) + ")" + " As " + member . AsTypeName ;
134
+
135
+ var memberCloseStatement = "End Function" + Environment . NewLine ;
136
+
137
+ return string . Join ( Environment . NewLine , memberSignature , MemberBody , memberCloseStatement ) ;
138
+ }
139
+
140
+ private string PropertyGetStmt ( Declaration member )
141
+ {
142
+ var memberParams = GetParameters ( member ) ;
143
+
144
+ var memberSignature = "Public Property Get " + _targetInterface . IdentifierName + "_" + member . IdentifierName + "(" +
145
+ string . Join ( ", " , memberParams ) + ")" + " As " + member . AsTypeName ;
146
+
147
+ var memberCloseStatement = "End Property" + Environment . NewLine ;
148
+
149
+ return string . Join ( Environment . NewLine , memberSignature , MemberBody , memberCloseStatement ) ;
150
+ }
151
+
152
+ private string PropertyLetStmt ( Declaration member )
153
+ {
154
+ var memberParams = GetParameters ( member ) ;
155
+
156
+ var memberSignature = "Public Property Let " + _targetInterface . IdentifierName + "_" + member . IdentifierName +
157
+ "(" + string . Join ( ", " , memberParams ) + ")" ;
158
+
159
+ var memberCloseStatement = "End Property" + Environment . NewLine ;
160
+
161
+ return string . Join ( Environment . NewLine , memberSignature , MemberBody , memberCloseStatement ) ;
162
+ }
163
+
164
+ private string PropertySetStmt ( Declaration member )
165
+ {
166
+ var memberParams = GetParameters ( member ) ;
167
+
168
+ var memberSignature = "Public Property Set " + _targetInterface . IdentifierName + "_" + member . IdentifierName +
169
+ "(" + string . Join ( ", " , memberParams ) + ")" ;
170
+
171
+ var memberCloseStatement = "End Property" + Environment . NewLine ;
172
+
173
+ return string . Join ( Environment . NewLine , memberSignature , MemberBody , memberCloseStatement ) ;
174
+ }
175
+
176
+ private List < Parameter > GetParameters ( Declaration member )
177
+ {
178
+ var parameters = _declarations . Where ( item => item . DeclarationType == DeclarationType . Parameter &&
179
+ item . ParentScope == member . Scope )
180
+ . OrderBy ( o => o . Selection . StartLine )
181
+ . ThenBy ( t => t . Selection . StartColumn )
182
+ . Select ( p => new Parameter
183
+ {
184
+ ParamAccessibility = ( ( VBAParser . ArgContext ) p . Context ) . BYREF ( ) == null ? Tokens . ByVal : Tokens . ByRef ,
185
+ ParamName = p . IdentifierName ,
186
+ ParamType = p . AsTypeName
187
+ } )
188
+ . ToList ( ) ;
189
+
190
+ if ( member . DeclarationType == DeclarationType . PropertyGet )
191
+ {
192
+ parameters . Remove ( parameters . Last ( ) ) ;
193
+ }
194
+
195
+ return parameters ;
196
+ }
197
+
198
+ private IEnumerable < Declaration > GetInterfaceMembers ( )
199
+ {
200
+ return _declarations . FindInterfaceMembers ( )
201
+ . Where ( d => d . ComponentName == _targetInterface . IdentifierName )
202
+ . OrderBy ( d => d . Selection . StartLine )
203
+ . ThenBy ( d => d . Selection . StartColumn ) ;
204
+ }
205
+
206
+ private IEnumerable < Declaration > GetImplementedMembers ( )
207
+ {
208
+ return _declarations . FindInterfaceImplementationMembers ( )
209
+ . Where ( item => item . Project . Equals ( _targetInterface . Project )
210
+ && item . ComponentName == _targetClass . IdentifierName
211
+ && item . IdentifierName . StartsWith ( _targetInterface . ComponentName + "_" )
212
+ && ! item . Equals ( _targetClass ) )
213
+ . OrderBy ( d => d . Selection . StartLine )
214
+ . ThenBy ( d => d . Selection . StartColumn ) ;
215
+ }
216
+
217
+ private string GetMemberType ( Declaration member )
218
+ {
219
+ var context = member . Context ;
220
+
221
+ var subStmtContext = context as VBAParser . SubStmtContext ;
222
+ if ( subStmtContext != null )
223
+ {
224
+ return Tokens . Sub ;
225
+ }
226
+
227
+ var functionStmtContext = context as VBAParser . FunctionStmtContext ;
228
+ if ( functionStmtContext != null )
229
+ {
230
+ return Tokens . Function ;
231
+ }
232
+
233
+ var propertyGetStmtContext = context as VBAParser . PropertyGetStmtContext ;
234
+ if ( propertyGetStmtContext != null )
235
+ {
236
+ return Tokens . Property + " " + Tokens . Get ;
237
+ }
238
+
239
+ var propertyLetStmtContext = context as VBAParser . PropertyLetStmtContext ;
240
+ if ( propertyLetStmtContext != null )
241
+ {
242
+ return Tokens . Property + " " + Tokens . Let ;
243
+ }
244
+
245
+ var propertySetStmtContext = context as VBAParser . PropertySetStmtContext ;
246
+ if ( propertySetStmtContext != null )
247
+ {
248
+ return Tokens . Property + " " + Tokens . Set ;
249
+ }
250
+
251
+ return string . Empty ;
252
+ }
253
+ }
254
+ }
0 commit comments