12
12
using Rubberduck . VBEditor ;
13
13
using Rubberduck . VBEditor . Extensions ;
14
14
15
- namespace Rubberduck . Refactorings . ExtractMethod
15
+
16
+ public static class IEnumerableExt
16
17
{
18
+ /// <summary>
19
+ /// Yields an Enumeration of selector Type,
20
+ /// by checking for gaps between elements
21
+ /// using the supplied increment function to work out the next value
22
+ /// </summary>
23
+ /// <typeparam name="T"></typeparam>
24
+ /// <typeparam name="U"></typeparam>
25
+ /// <param name="inputs"></param>
26
+ /// <param name="getIncr"></param>
27
+ /// <param name="selector"></param>
28
+ /// <param name="comparisonFunc"></param>
29
+ /// <returns></returns>
30
+ public static IEnumerable < U > GroupByMissing < T , U > ( this IEnumerable < T > inputs , Func < T , T > getIncr , Func < T , T , U > selector , Func < T , T , int > comparisonFunc )
31
+ {
32
+
33
+ var initialized = false ;
34
+ T first = default ( T ) ;
35
+ T last = default ( T ) ;
36
+ T next = default ( T ) ;
37
+ Tuple < T , T > tuple = null ;
17
38
39
+ foreach ( var input in inputs )
40
+ {
41
+ if ( ! initialized )
42
+ {
43
+ first = input ;
44
+ last = input ;
45
+ initialized = true ;
46
+ continue ;
47
+ }
48
+ if ( comparisonFunc ( last , input ) < 0 )
49
+ {
50
+ throw new ArgumentException ( string . Format ( "Values are not monotonically increasing. {0} should be less than {1}" , last , input ) ) ;
51
+ }
52
+ var inc = getIncr ( last ) ;
53
+ if ( ! input . Equals ( inc ) )
54
+ {
55
+ yield return selector ( first , last ) ;
56
+ first = input ;
57
+ }
58
+ last = input ;
59
+ }
60
+ if ( initialized )
61
+ {
62
+ yield return selector ( first , last ) ;
63
+ }
64
+ }
65
+ }
66
+
67
+ namespace Rubberduck . Refactorings . ExtractMethod
68
+ {
18
69
public class ExtractMethodModel : IExtractMethodModel
19
70
{
20
- private const string NEW_METHOD = "NewMethod" ;
71
+ private List < Declaration > _extractDeclarations ;
72
+ private IExtractMethodParameterClassification _paramClassify ;
73
+ private IExtractedMethod _extractedMethod ;
21
74
22
- public ExtractMethodModel ( List < IExtractMethodRule > emRules , IExtractedMethod extractedMethod )
75
+ public ExtractMethodModel ( IExtractedMethod extractedMethod , IExtractMethodParameterClassification paramClassify )
23
76
{
24
- _rules = emRules ;
25
77
_extractedMethod = extractedMethod ;
78
+ _paramClassify = paramClassify ;
26
79
}
27
80
28
-
29
81
public void extract ( IEnumerable < Declaration > declarations , QualifiedSelection selection , string selectedCode )
30
82
{
31
83
var items = declarations . ToList ( ) ;
32
- var sourceMember = items . FindSelectedDeclaration ( selection , DeclarationExtensions . ProcedureTypes , d => ( ( ParserRuleContext ) d . Context . Parent ) . GetSelection ( ) ) ;
84
+ _selection = selection ;
85
+ _selectedCode = selectedCode ;
86
+ _rowsToRemove = new List < Selection > ( ) ;
87
+
88
+ var sourceMember = items . FindSelectedDeclaration (
89
+ selection ,
90
+ DeclarationExtensions . ProcedureTypes ,
91
+ d => ( ( ParserRuleContext ) d . Context . Parent ) . GetSelection ( ) ) ;
92
+
33
93
if ( sourceMember == null )
34
94
{
35
95
throw new InvalidOperationException ( "Invalid selection." ) ;
36
96
}
37
97
38
98
var inScopeDeclarations = items . Where ( item => item . ParentScope == sourceMember . Scope ) . ToList ( ) ;
39
-
40
- _byref = new List < Declaration > ( ) ;
41
- _byval = new List < Declaration > ( ) ;
42
- _declarationsToMove = new List < Declaration > ( ) ;
43
- _extractDeclarations = new List < Tuple < Declaration , bool > > ( ) ;
44
- _extractedMethod = new ExtractedMethod ( ) ;
45
-
46
-
47
- var selectionToRemove = new List < Selection > ( ) ;
48
99
var selectionStartLine = selection . Selection . StartLine ;
49
100
var selectionEndLine = selection . Selection . EndLine ;
50
-
51
101
var methodInsertLine = sourceMember . Context . Stop . Line + 1 ;
102
+
52
103
_positionForNewMethod = new Selection ( methodInsertLine , 1 , methodInsertLine , 1 ) ;
53
104
54
- // https://github.com/rubberduck-vba/Rubberduck/wiki/Extract-Method-Refactoring-%3A-Workings---Determining-what-params-to-move
55
105
foreach ( var item in inScopeDeclarations )
56
106
{
57
- var flags = new Byte ( ) ;
58
-
59
- foreach ( var oRef in item . References )
60
- {
61
- foreach ( var rule in _rules )
62
- {
63
- rule . setValidFlag ( ref flags , oRef , selection . Selection ) ;
64
- }
65
- }
66
-
67
- //TODO: extract this to seperate class.
68
- if ( flags < 4 ) { /*ignore the variable*/ }
69
- else if ( flags < 12 )
70
- _byref . Add ( item ) ;
71
- else if ( flags == 12 )
72
- _declarationsToMove . Add ( item ) ;
73
- else if ( flags > 12 )
74
- _byval . Add ( item ) ;
75
-
76
- if ( flags >= 18 )
77
- {
78
- _extractDeclarations . Add ( Tuple . Create ( item , true ) ) ;
79
- }
80
-
107
+ _paramClassify . classifyDeclarations ( selection , item ) ;
81
108
}
109
+ _declarationsToMove = _paramClassify . DeclarationsToMove . ToList ( ) ;
82
110
111
+ _rowsToRemove = splitSelection ( selection . Selection , _declarationsToMove ) . ToList ( ) ;
83
112
84
- _declarationsToMove . ForEach ( d => selectionToRemove . Add ( d . Selection ) ) ;
85
- selectionToRemove . Add ( selection . Selection ) ;
86
-
87
- var methodCallPositionStartLine = selectionStartLine - selectionToRemove . Count ( s => s . StartLine < selectionStartLine ) ;
113
+ var methodCallPositionStartLine = selectionStartLine - _declarationsToMove . Count ( d => d . Selection . StartLine < selectionStartLine ) ;
88
114
_positionForMethodCall = new Selection ( methodCallPositionStartLine , 1 , methodCallPositionStartLine , 1 ) ;
89
-
90
- var methodParams = _byref . Select ( dec => new ExtractedParameter ( dec . AsTypeName , ExtractedParameter . PassedBy . ByRef , dec . IdentifierName ) )
91
- . Union ( _byval . Select ( dec => new ExtractedParameter ( dec . AsTypeName , ExtractedParameter . PassedBy . ByVal , dec . IdentifierName ) ) ) ;
92
-
93
- // iterate until we have a non-clashing method name.
94
- var newMethodName = NEW_METHOD ;
95
-
96
- var newMethodInc = 0 ;
97
- while ( declarations . FirstOrDefault ( d =>
98
- DeclarationExtensions . ProcedureTypes . Contains ( d . DeclarationType )
99
- && d . IdentifierName . Equals ( newMethodName ) ) != null )
100
- {
101
- newMethodInc ++ ;
102
- newMethodName = NEW_METHOD + newMethodInc ;
103
- }
104
-
105
- _extractedMethod . MethodName = newMethodName ;
106
115
_extractedMethod . ReturnValue = null ;
107
116
_extractedMethod . Accessibility = Accessibility . Private ;
108
117
_extractedMethod . SetReturnValue = false ;
109
- _extractedMethod . Parameters = methodParams . ToList ( ) ;
110
-
111
- _selection = selection ;
112
- _selectedCode = selectedCode ;
113
- _selectionToRemove = selectionToRemove . ToList ( ) ;
118
+ _extractedMethod . Parameters = _paramClassify . ExtractedParameters . ToList ( ) ;
114
119
115
120
}
116
121
117
- private List < Declaration > _byref ;
118
- private List < Declaration > _byval ;
119
- private List < Declaration > _moveIn ;
122
+ public IEnumerable < Selection > splitSelection ( Selection selection , IEnumerable < Declaration > declarations )
123
+ {
124
+ var tupleList = new List < Tuple < int , int > > ( ) ;
125
+ var declarationRows = declarations
126
+ . Where ( decl =>
127
+ selection . StartLine <= decl . Selection . StartLine &&
128
+ decl . Selection . StartLine <= selection . EndLine )
129
+ . Select ( decl => decl . Selection . StartLine )
130
+ . OrderBy ( x => x )
131
+ . ToList ( ) ;
132
+
133
+ var gappedSelectionRows = Enumerable . Range ( selection . StartLine , selection . EndLine - selection . StartLine + 1 ) . Except ( declarationRows ) . ToList ( ) ;
134
+ var returnList = gappedSelectionRows . GroupByMissing ( x => ( x + 1 ) , ( x , y ) => new Selection ( x , 1 , y , 1 ) , ( x , y ) => y - x ) ;
135
+ return returnList ;
136
+ }
120
137
121
138
private Declaration _sourceMember ;
122
139
public Declaration SourceMember { get { return _sourceMember ; } }
@@ -132,34 +149,33 @@ public void extract(IEnumerable<Declaration> declarations, QualifiedSelection se
132
149
133
150
private IEnumerable < ExtractedParameter > _input ;
134
151
public IEnumerable < ExtractedParameter > Inputs { get { return _input ; } }
135
-
136
152
private IEnumerable < ExtractedParameter > _output ;
137
153
public IEnumerable < ExtractedParameter > Outputs { get { return _output ; } }
138
154
139
155
private List < Declaration > _declarationsToMove ;
140
156
public IEnumerable < Declaration > DeclarationsToMove { get { return _declarationsToMove ; } }
141
157
142
- private IExtractedMethod _extractedMethod ;
143
-
144
- private IEnumerable < IExtractMethodRule > _rules ;
145
-
146
158
public IExtractedMethod Method { get { return _extractedMethod ; } }
147
159
148
-
149
160
private Selection _positionForMethodCall ;
150
161
public Selection PositionForMethodCall { get { return _positionForMethodCall ; } }
151
162
152
163
public string NewMethodCall { get { return _extractedMethod . NewMethodCall ( ) ; } }
153
164
154
165
private Selection _positionForNewMethod ;
155
166
public Selection PositionForNewMethod { get { return _positionForNewMethod ; } }
156
- IEnumerable < Selection > _selectionToRemove ;
157
- private List < IExtractMethodRule > emRules ;
158
-
159
- public IEnumerable < Selection > SelectionToRemove { get { return _selectionToRemove ; } }
160
-
161
- private List < Tuple < Declaration , bool > > _extractDeclarations ;
162
- public IEnumerable < Tuple < Declaration , bool > > ExtractDeclarations { get { return _extractDeclarations ; } }
167
+ IList < Selection > _rowsToRemove ;
168
+ public IEnumerable < Selection > RowsToRemove
169
+ {
170
+ // we need to split selectionToRemove around any declarations that
171
+ // are within the selection.
172
+ get { return _declarationsToMove . Select ( decl => decl . Selection ) . Union ( _rowsToRemove )
173
+ . Select ( x => new Selection ( x . StartLine , 1 , x . EndLine , 1 ) ) ; }
174
+ }
163
175
176
+ public IEnumerable < Declaration > DeclarationsToExtract
177
+ {
178
+ get { return _extractDeclarations ; }
179
+ }
164
180
}
165
181
}
0 commit comments