33using System . Collections . ObjectModel ;
44using System . Linq ;
55using Antlr4 . Runtime ;
6+ using Rubberduck . Parsing ;
67using Rubberduck . Parsing . Grammar ;
78using Rubberduck . Parsing . Symbols ;
8- using Rubberduck . VBEditor ;
99using Rubberduck . Parsing . VBA ;
1010using Rubberduck . SmartIndenter ;
11+ using Rubberduck . VBEditor ;
1112using Rubberduck . VBEditor . Extensions ;
13+ using Rubberduck . Refactorings . Exceptions ;
1214using Rubberduck . Refactorings . Exceptions . ExtractMethod ;
13- using Rubberduck . Parsing ;
14- using System . Text . RegularExpressions ;
1515
1616namespace Rubberduck . Refactorings . ExtractMethod
1717{
@@ -28,9 +28,8 @@ public class ExtractMethodModel : IRefactoringModel
2828 public IEnumerable < string > ComponentNames =>
2929 _declarationFinderProvider . DeclarationFinder . UserDeclarations ( DeclarationType . Member ) . Where ( d => d . ComponentName == QualifiedSelection . QualifiedName . ComponentName )
3030 . Select ( d => d . IdentifierName ) ;
31- public string SourceMethodName { get ; private set ; }
31+ public string SourceMethodName { get => TargetMethod . IdentifierName ; }
3232 public Declaration TargetMethod { get ; set ; }
33- //public IEnumerable<Declaration> SourceVariables { get; private set; }
3433 public string NewMethodName
3534 {
3635 get => extractedMethod . MethodName ;
@@ -61,47 +60,27 @@ public ExtractMethodModel(IDeclarationFinderProvider declarationFinderProvider,
6160
6261 private void Setup ( )
6362 {
64- //if (string.IsNullOrWhiteSpace(NewMethodName))
65- //{
66- // NewMethodName = RefactoringsUI.ExtractMethod_DefaultNewMethodName; //Check for conflicts - see other document for example code
67- //}
63+ var functionReturnValueAssignments = TargetMethod . References
64+ . Where ( r => QualifiedSelection . Selection . Contains ( r . Selection ) &&
65+ ( r . IsAssignment || r . IsSetAssignment ) ) ;
66+ if ( functionReturnValueAssignments . Count ( ) != 0 )
67+ {
68+ var firstSelection = functionReturnValueAssignments . FirstOrDefault ( ) . QualifiedSelection ;
69+ var message = "Selection modifies the return value of the enclosing function" ; //TODO - get from resx
70+ throw new InvalidTargetSelectionException ( firstSelection , message ) ;
71+ }
6872
6973 SelectedCode = string . Join ( Environment . NewLine , SelectedContexts . Select ( c => c . GetText ( ) ) ) ;
7074
71- //SourceVariables = _declarationFinderProvider.DeclarationFinder.UserDeclarations(DeclarationType.Variable)
72- // .Where(d => (Selection.Selection.Contains(d.Selection) &&
73- // d.QualifiedName.QualifiedModuleName == Selection.QualifiedName) ||
74- // d.References.Any(r =>
75- // r.QualifiedModuleName.ComponentName == Selection.QualifiedName.ComponentName
76- // && r.QualifiedModuleName.ComponentName ==
77- // d.QualifiedName.QualifiedModuleName.ComponentName
78- // && Selection.Selection.Contains(r.Selection)))
79- // .OrderBy(d => d.Selection.StartLine)
80- // .ThenBy(d => d.Selection.StartColumn);
81-
82- var declarationsInSelection = _declarationFinderProvider . DeclarationFinder . UserDeclarations ( DeclarationType . Variable )
83- . Where ( d => QualifiedSelection . Selection . Contains ( d . Selection ) &&
84- d . QualifiedName . QualifiedModuleName == QualifiedSelection . QualifiedName )
85- . OrderBy ( d => d . Selection . StartLine )
86- . ThenBy ( d => d . Selection . StartColumn ) ;
87- var referencesOfDeclarationsInSelection = ( from dec in declarationsInSelection select dec . References ) . ToArray ( ) ; //debug purposes
75+ var declarationsInSelection = GetDeclarationsInSelection ( QualifiedSelection ) ;
8876
8977 var sourceMethodParameters = ( ( IParameterizedDeclaration ) TargetMethod ) . Parameters ;
9078 var sourceMethodSelection = new QualifiedSelection ( QualifiedSelection . QualifiedName ,
9179 new Selection ( TargetMethod . Context . Start . Line , TargetMethod . Context . Start . Column , TargetMethod . Context . Stop . Line , TargetMethod . Context . Stop . Column ) ) ;
9280
93- //TODO - refactor below and declarationsInSelection to generic declarations in selection method if stay consistent
94- var declarationsInParentMethod = _declarationFinderProvider . DeclarationFinder . UserDeclarations ( DeclarationType . Variable )
95- . Where ( d => sourceMethodSelection . Selection . Contains ( d . Selection ) &&
96- d . QualifiedName . QualifiedModuleName == sourceMethodSelection . QualifiedName )
97- . OrderBy ( d => d . Selection . StartLine )
98- . ThenBy ( d => d . Selection . StartColumn ) ;
81+ var declarationsInParentMethod = GetDeclarationsInSelection ( sourceMethodSelection ) ;
9982
10083 //List of "inbound" variables. Parent procedure parameters + explicit dims which get referenced inside the selection.
101- //Ideally excluding those declared but not assigned before the selection. Refinement to change this later
102- //No need to check if reference is outside of method because just dealing with local parameters and declarations
103- //Add function reference if it is a function?
104- //Would ideally identify variables assigned before the selection, not just declared. Could assume any reference before the selection is an assignment?
10584 //TODO - add case where reference earlier in the same line as where the selection starts (unusual but could exist if using colons to separate multiple statements)
10685 var inboundParameters = sourceMethodParameters . Where ( d => d . References . Any ( r => QualifiedSelection . Selection . Contains ( r . Selection ) ) ) ;
10786 var inboundLocalVariables = declarationsInParentMethod . Where ( d => d . References . Any ( r => QualifiedSelection . Selection . Contains ( r . Selection ) ) &&
@@ -112,7 +91,33 @@ private void Setup()
11291 var outboundVariables = sourceMethodParameters . Concat ( declarationsInParentMethod )
11392 . Where ( d => d . References . Any ( r => QualifiedSelection . Selection . Contains ( r . Selection ) ) && d . References . Any ( r => r . Selection . StartLine > QualifiedSelection . Selection . EndLine ) ) ;
11493
115- //Set up parameters
94+ SetUpParameters ( inboundVariables , outboundVariables ) ;
95+
96+ //Variables to have declarations moved out of the selection
97+ // - where declaration is in the selection and it is a ByRef variable i.e. intersection of declarations in selection and outbound
98+ _declarationsToMoveOut = declarationsInSelection . Intersect ( outboundVariables )
99+ . OrderByDescending ( d => d . Selection . StartLine )
100+ . ThenByDescending ( d => d . Selection . StartColumn ) ;
101+
102+ //Variables to have declarations moved into the selection
103+ // - where declaration is before the selection but only references are inside the selection
104+ _declarationsToMoveIn = declarationsInParentMethod . Except ( declarationsInSelection )
105+ . Where ( d => d . References . Any ( r => QualifiedSelection . Selection . Contains ( r . Selection ) ) &&
106+ ! d . References . Any ( r => r . Selection . EndLine < QualifiedSelection . Selection . StartLine ) &&
107+ ! d . References . Any ( r => r . Selection . StartLine > QualifiedSelection . Selection . EndLine ) ) ;
108+ }
109+
110+ private IOrderedEnumerable < Declaration > GetDeclarationsInSelection ( QualifiedSelection qualifiedSelection )
111+ {
112+ return _declarationFinderProvider . DeclarationFinder . UserDeclarations ( DeclarationType . Variable )
113+ . Where ( d => qualifiedSelection . Selection . Contains ( d . Selection ) &&
114+ d . QualifiedName . QualifiedModuleName == qualifiedSelection . QualifiedName )
115+ . OrderBy ( d => d . Selection . StartLine )
116+ . ThenBy ( d => d . Selection . StartColumn ) ;
117+ }
118+
119+ private void SetUpParameters ( IEnumerable < Declaration > inboundVariables , IEnumerable < Declaration > outboundVariables )
120+ {
116121 Parameters = new ObservableCollection < ExtractMethodParameter > ( ) ;
117122
118123 foreach ( var declaration in inboundVariables . Union ( outboundVariables ) )
@@ -149,24 +154,6 @@ private void Setup()
149154 paramType , declaration . IdentifierName ,
150155 declaration . IsArray , declaration . IsObject , canReturn ) ) ;
151156 }
152-
153- //Variables to have declarations moved out of the selection
154- // - where declaration is in the selection and it is a ByRef variable i.e. intersection of declarations in selection and outbound
155- _declarationsToMoveOut = declarationsInSelection . Intersect ( outboundVariables )
156- . OrderByDescending ( d => d . Selection . StartLine )
157- . ThenByDescending ( d => d . Selection . StartColumn ) ;
158-
159- //Variables to have declarations moved into the selection
160- // - where declaration is before the selection but only references are inside the selection
161- _declarationsToMoveIn = declarationsInParentMethod . Except ( declarationsInSelection )
162- . Where ( d => d . References . Any ( r => QualifiedSelection . Selection . Contains ( r . Selection ) ) &&
163- ! d . References . Any ( r => r . Selection . EndLine < QualifiedSelection . Selection . StartLine ) &&
164- ! d . References . Any ( r => r . Selection . StartLine > QualifiedSelection . Selection . EndLine ) ) ;
165-
166- //List of neither "inbound" or "outbound" (need the declaration copied inside the selection OR moved if careful but can leave inspections to pick up unnecessary declarations)
167- //Only applies if the list of inbound variables excludes those declared but not assigned before the selection
168- //????
169-
170157 }
171158
172159 public string SelectedCode { get ; private set ; }
@@ -213,7 +200,7 @@ public string SelectedCodeToExtract
213200 //1) Go up to Block ancester
214201 //2) Find BlockStmt enclosing the declaration
215202 //3) Check if preceding or following BlockStmts (if exist) are on the same line (preceding.Stop or following.Start)
216- //4) Throw error or rebuild line
203+ //4) preceding blocks seem okay except for indentation. following blocks
217204
218205
219206 //Remove declaration range from selected code
@@ -333,6 +320,7 @@ public string NewMethodCode
333320
334321 private string FrontPadding ( VBAParser . BlockStmtContext context )
335322 {
323+ //TODO - starts from block statement but that could be following another statement e.g. a = 1 : b = 2, so better to find whole line
336324 var paddingChars = context . Start . Column ;
337325 if ( paddingChars > 0 )
338326 {
0 commit comments