2
2
using Rubberduck . Inspections . Abstract ;
3
3
using Rubberduck . Inspections . Resources ;
4
4
using Rubberduck . Parsing . Grammar ;
5
+ using Rubberduck . Parsing . Symbols ;
5
6
using Rubberduck . VBEditor ;
7
+ using System ;
8
+ using System . Collections . Generic ;
6
9
using System . Text . RegularExpressions ;
7
10
using static Rubberduck . Parsing . Grammar . VBAParser ;
8
11
@@ -13,33 +16,117 @@ namespace Rubberduck.Inspections.QuickFixes
13
16
/// </summary>
14
17
public class PassParameterByReferenceQuickFix : QuickFixBase
15
18
{
16
- public PassParameterByReferenceQuickFix ( ParserRuleContext context , QualifiedSelection selection )
17
- : base ( context , selection , InspectionsUI . PassParameterByReferenceQuickFix )
19
+ private Declaration _target ;
20
+ private int _byValTokenProcLine ;
21
+ private int _byValIdentifierNameProcLine ;
22
+
23
+ public PassParameterByReferenceQuickFix ( Declaration target , QualifiedSelection selection )
24
+ : base ( target . Context , selection , InspectionsUI . PassParameterByReferenceQuickFix )
18
25
{
26
+ _target = target ;
27
+ _byValTokenProcLine = 0 ;
28
+ _byValIdentifierNameProcLine = 0 ;
19
29
}
20
30
21
31
public override void Fix ( )
22
32
{
23
- var byValParameter = Context . GetText ( ) ;
33
+ string byValTargetString ;
34
+ string byValTokenReplacementString ;
35
+ string replacementString ;
24
36
25
- var byRefParameter = BuildByRefParameter ( byValParameter ) ;
37
+ var procLines = RetrieveProcedureLines ( ) ;
26
38
27
- ReplaceByValParameterInModule ( byValParameter , byRefParameter ) ;
28
- }
39
+ SetMemberLineValues ( procLines ) ;
40
+
41
+ string moduleLineWithByValToken = procLines [ _byValTokenProcLine - 1 ] ;
42
+
43
+ if ( _byValTokenProcLine == _byValIdentifierNameProcLine )
44
+ {
45
+ //The replacement is based on the (e.g. "ByVal identifierName")
46
+ byValTargetString = Tokens . ByVal + " " + _target . IdentifierName ;
47
+ byValTokenReplacementString = BuildByRefParameter ( byValTargetString ) ;
48
+ replacementString = moduleLineWithByValToken . Replace ( byValTargetString , byValTokenReplacementString ) ;
49
+ }
50
+ else
51
+ {
52
+ //if the token and identifier are on different lines, then the target
53
+ //string consists of the ByVal token and the LineContinuation token.
54
+ //(e.g. the replacement is based on "ByVal _". Spaces between tokens can vary)
55
+ byValTargetString = GetUniqueTargetStringForByValAtEndOfLine ( moduleLineWithByValToken ) ;
56
+ byValTokenReplacementString = BuildByRefParameter ( byValTargetString ) ;
57
+
58
+ //avoid updating possible cases of ByVal followed by underscore-prefixed identifiers
59
+ var index = moduleLineWithByValToken . LastIndexOf ( byValTargetString ) ;
60
+ var firstPart = moduleLineWithByValToken . Substring ( 0 , index ) ;
61
+ replacementString = firstPart + byValTokenReplacementString ;
62
+ }
29
63
64
+ var module = Selection . QualifiedName . Component . CodeModule ;
65
+ module . ReplaceLine ( RetrieveTheProcedureStartLine ( ) + _byValTokenProcLine - 1 , replacementString ) ;
66
+ }
67
+ private string [ ] RetrieveProcedureLines ( )
68
+ {
69
+ var moduleContent = Context . Start . InputStream . ToString ( ) ;
70
+ string [ ] newLine = { "\r \n " } ;
71
+ var moduleLines = moduleContent . Split ( newLine , StringSplitOptions . None ) ;
72
+ var procLines = new List < string > ( ) ;
73
+ var startIndex = RetrieveTheProcedureStartLine ( ) ;
74
+ var endIndex = RetrieveTheProcedureEndLine ( ) ;
75
+ for ( int idx = startIndex - 1 ; idx < endIndex ; idx ++ )
76
+ {
77
+ procLines . Add ( moduleLines [ idx ] ) ;
78
+ }
79
+ return procLines . ToArray ( ) ;
80
+ }
81
+ private int RetrieveTheProcedureStartLine ( )
82
+ {
83
+ var parserRuleCtxt = ( ParserRuleContext ) Context . Parent . Parent ;
84
+ return parserRuleCtxt . Start . Line ;
85
+ }
86
+ private int RetrieveTheProcedureEndLine ( )
87
+ {
88
+ var parserRuleCtxt = ( ParserRuleContext ) Context . Parent . Parent ;
89
+ return parserRuleCtxt . Stop . Line ;
90
+ }
30
91
private string BuildByRefParameter ( string originalParameter )
31
92
{
32
93
var everythingAfterTheByValToken = originalParameter . Substring ( Tokens . ByVal . Length ) ;
33
94
return Tokens . ByRef + everythingAfterTheByValToken ;
34
95
}
35
- private void ReplaceByValParameterInModule ( string byValParameter , string byRefParameter )
96
+ private string GetUniqueTargetStringForByValAtEndOfLine ( string procLineWithByValToken )
36
97
{
37
- var selection = Selection . Selection ;
38
- var module = Selection . QualifiedName . Component . CodeModule ;
98
+ System . Diagnostics . Debug . Assert ( procLineWithByValToken . Contains ( Tokens . LineContinuation ) ) ;
99
+
100
+ var positionOfLineContinuation = procLineWithByValToken . LastIndexOf ( Tokens . LineContinuation ) ;
101
+ var positionOfLastByValToken = procLineWithByValToken . LastIndexOf ( Tokens . ByVal ) ;
102
+ return procLineWithByValToken . Substring ( positionOfLastByValToken , positionOfLineContinuation - positionOfLastByValToken + 2 ) ;
103
+ }
104
+ private void SetMemberLineValues ( string [ ] procedureLines )
105
+ {
106
+ string line ;
107
+ bool byValTokenFound = false ;
108
+ bool byValIdentifierNameFound = false ;
109
+ for ( int zbIndexByValLine = 0 ; ! byValIdentifierNameFound && zbIndexByValLine < procedureLines . Length ; zbIndexByValLine ++ )
110
+ {
111
+ line = procedureLines [ zbIndexByValLine ] ;
112
+ if ( line . Contains ( Tokens . ByVal ) )
113
+ {
114
+ _byValTokenProcLine = zbIndexByValLine + 1 ;
115
+ byValTokenFound = true ;
116
+ }
117
+ if ( byValTokenFound )
118
+ {
119
+ if ( line . Contains ( _target . IdentifierName ) )
120
+ {
121
+ _byValIdentifierNameProcLine = zbIndexByValLine + 1 ;
122
+ byValIdentifierNameFound = true ;
123
+ }
124
+ }
125
+ }
39
126
40
- var lines = module . GetLines ( selection . StartLine , selection . LineCount ) ;
41
- var result = lines . Replace ( byValParameter , byRefParameter ) ;
42
- module . ReplaceLine ( selection . StartLine , result ) ;
127
+ System . Diagnostics . Debug . Assert ( _byValTokenProcLine > 0 ) ;
128
+ System . Diagnostics . Debug . Assert ( _byValIdentifierNameProcLine > 0 ) ;
129
+ return ;
43
130
}
44
131
}
45
132
}
0 commit comments