1
- using Antlr4 . Runtime ;
1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using Antlr4 . Runtime ;
5
+ using Rubberduck . Parsing ;
2
6
using Rubberduck . Parsing . Symbols ;
7
+ using Rubberduck . Parsing . VBA ;
8
+ using Rubberduck . VBEditor ;
3
9
using Rubberduck . VBEditor . SafeComWrappers . Abstract ;
4
10
5
11
namespace Rubberduck . Common
6
12
{
7
13
public static class CodeModuleExtensions
8
14
{
15
+ /// <summary>
16
+ /// Removes a <see cref="Declaration"/> and its <see cref="Declaration.References"/>.
17
+ /// </summary>
18
+ /// <param name="module">The <see cref="ICodeModule"/> to modify.</param>
19
+ /// <param name="target"></param>
20
+ public static void Remove ( this ICodeModule module , Declaration target )
21
+ {
22
+ var multipleDeclarations = target . DeclarationType == DeclarationType . Variable && target . HasMultipleDeclarationsInStatement ( ) ;
23
+ var context = GetStmtContext ( target ) ;
24
+ var declarationText = context . GetText ( ) . Replace ( " _" + Environment . NewLine , string . Empty ) ;
25
+ var selection = GetStmtContextSelection ( target ) ;
26
+
27
+ var oldLines = module . GetLines ( selection ) ;
28
+
29
+ var newLines = oldLines . Replace ( " _" + Environment . NewLine , string . Empty )
30
+ . Remove ( selection . StartColumn - 1 , declarationText . Length ) ;
31
+
32
+ if ( multipleDeclarations )
33
+ {
34
+ selection = GetStmtContextSelection ( target ) ;
35
+ newLines = RemoveExtraComma ( module . GetLines ( selection ) . Replace ( oldLines , newLines ) ,
36
+ target . CountOfDeclarationsInStatement ( ) , target . IndexOfVariableDeclarationInStatement ( ) ) ;
37
+ }
38
+
39
+ var newLinesWithoutExcessSpaces = newLines . Split ( new [ ] { Environment . NewLine } , StringSplitOptions . None ) ;
40
+ for ( var i = 0 ; i < newLinesWithoutExcessSpaces . Length ; i ++ )
41
+ {
42
+ newLinesWithoutExcessSpaces [ i ] = newLinesWithoutExcessSpaces [ i ] . RemoveExtraSpacesLeavingIndentation ( ) ;
43
+ }
44
+
45
+ for ( var i = newLinesWithoutExcessSpaces . Length - 1 ; i >= 0 ; i -- )
46
+ {
47
+ if ( newLinesWithoutExcessSpaces [ i ] . Trim ( ) == string . Empty )
48
+ {
49
+ continue ;
50
+ }
51
+
52
+ if ( newLinesWithoutExcessSpaces [ i ] . EndsWith ( " _" ) )
53
+ {
54
+ newLinesWithoutExcessSpaces [ i ] =
55
+ newLinesWithoutExcessSpaces [ i ] . Remove ( newLinesWithoutExcessSpaces [ i ] . Length - 2 ) ;
56
+ }
57
+ break ;
58
+ }
59
+
60
+ // remove all lines with only whitespace
61
+ newLinesWithoutExcessSpaces = newLinesWithoutExcessSpaces . Where ( str => str . Any ( c => ! char . IsWhiteSpace ( c ) ) ) . ToArray ( ) ;
62
+
63
+ module . DeleteLines ( selection ) ;
64
+ if ( newLinesWithoutExcessSpaces . Any ( ) )
65
+ {
66
+ module . InsertLines ( selection . StartLine , string . Join ( Environment . NewLine , newLinesWithoutExcessSpaces ) ) ;
67
+ }
68
+ }
69
+
70
+ private static Selection GetStmtContextSelection ( Declaration target )
71
+ {
72
+ switch ( target . DeclarationType )
73
+ {
74
+ case DeclarationType . Variable :
75
+ return target . GetVariableStmtContextSelection ( ) ;
76
+ case DeclarationType . Constant :
77
+ return target . GetConstStmtContextSelection ( ) ;
78
+ default :
79
+ return target . Context . GetSelection ( ) ;
80
+ }
81
+ }
82
+
83
+ private static ParserRuleContext GetStmtContext ( Declaration target )
84
+ {
85
+ switch ( target . DeclarationType )
86
+ {
87
+ case DeclarationType . Variable :
88
+ return target . GetVariableStmtContext ( ) ;
89
+ case DeclarationType . Constant :
90
+ return target . GetConstStmtContext ( ) ;
91
+ default :
92
+ return target . Context ;
93
+ }
94
+ }
95
+
96
+ private static string RemoveExtraComma ( string str , int numParams , int indexRemoved )
97
+ {
98
+ #region usage example
99
+ // Example use cases for this method (fields and variables):
100
+ // Dim fizz as Boolean, dizz as Double
101
+ // Private fizz as Boolean, dizz as Double
102
+ // Public fizz as Boolean, _
103
+ // dizz as Double
104
+ // Private fizz as Boolean _
105
+ // , dizz as Double _
106
+ // , iizz as Integer
107
+
108
+ // Before this method is called, the parameter to be removed has
109
+ // already been removed. This means 'str' will look like:
110
+ // Dim fizz as Boolean,
111
+ // Private , dizz as Double
112
+ // Public fizz as Boolean, _
113
+ //
114
+ // Private _
115
+ // , dizz as Double _
116
+ // , iizz as Integer
117
+
118
+ // This method is responsible for removing the redundant comma
119
+ // and returning a string similar to:
120
+ // Dim fizz as Boolean
121
+ // Private dizz as Double
122
+ // Public fizz as Boolean _
123
+ //
124
+ // Private _
125
+ // dizz as Double _
126
+ // , iizz as Integer
127
+ #endregion
128
+ var commaToRemove = numParams == indexRemoved ? indexRemoved - 1 : indexRemoved ;
129
+ return str . Remove ( str . NthIndexOf ( ',' , commaToRemove ) , 1 ) ;
130
+ }
131
+
132
+ public static void Remove ( this ICodeModule module , ConstantDeclaration target )
133
+ {
134
+
135
+ }
136
+
137
+ public static void Remove ( this ICodeModule module , IdentifierReference target )
138
+ {
139
+ var parent = target . Context . Parent as ParserRuleContext ;
140
+ module . Remove ( parent . GetSelection ( ) , parent ) ;
141
+ }
142
+
143
+ public static void Remove ( this ICodeModule module , IEnumerable < IdentifierReference > targets )
144
+ {
145
+ foreach ( var target in targets . OrderByDescending ( e => e . Selection ) )
146
+ {
147
+ module . Remove ( target ) ;
148
+ }
149
+ }
150
+
151
+ public static void Remove ( this ICodeModule module , Selection selection , ParserRuleContext instruction )
152
+ {
153
+ var originalCodeLines = module . GetLines ( selection . StartLine , selection . LineCount ) ;
154
+ var originalInstruction = instruction . GetText ( ) ;
155
+ module . DeleteLines ( selection . StartLine , selection . LineCount ) ;
156
+
157
+ var newCodeLines = originalCodeLines . Replace ( originalInstruction , string . Empty ) ;
158
+ if ( ! string . IsNullOrEmpty ( newCodeLines ) )
159
+ {
160
+ module . InsertLines ( selection . StartLine , newCodeLines ) ;
161
+ }
162
+ }
163
+
9
164
public static void ReplaceToken ( this ICodeModule module , IToken token , string replacement )
10
165
{
11
166
var original = module . GetLines ( token . Line , 1 ) ;
@@ -22,13 +177,14 @@ public static void ReplaceIdentifierReferenceName(this ICodeModule module, Ident
22
177
23
178
public static void InsertLines ( this ICodeModule module , int startLine , string [ ] lines )
24
179
{
25
- int lineNumber = startLine ;
26
- for ( int idx = 0 ; idx < lines . Length ; idx ++ )
180
+ var lineNumber = startLine ;
181
+ for ( var idx = 0 ; idx < lines . Length ; idx ++ )
27
182
{
28
183
module . InsertLines ( lineNumber , lines [ idx ] ) ;
29
184
lineNumber ++ ;
30
185
}
31
186
}
187
+
32
188
private static string ReplaceStringAtIndex ( string original , string toReplace , string replacement , int startIndex )
33
189
{
34
190
var modifiedContent = original . Remove ( startIndex , toReplace . Length ) ;
0 commit comments