1
+ using System ;
1
2
using System . Collections . Generic ;
3
+ using System . Linq ;
2
4
using Antlr4 . Runtime ;
3
5
using Rubberduck . Common ;
4
6
using Rubberduck . Parsing . Symbols ;
7
+ using Rubberduck . Parsing . VBA ;
5
8
using Rubberduck . UI ;
6
9
using Rubberduck . VBEditor ;
10
+ using Rubberduck . VBEditor . Extensions ;
7
11
8
12
namespace Rubberduck . Inspections
9
13
{
@@ -17,7 +21,7 @@ public IdentifierNotUsedInspectionResult(IInspection inspection, Declaration tar
17
21
{
18
22
_quickFixes = new CodeInspectionQuickFix [ ]
19
23
{
20
- new RemoveUnusedDeclarationQuickFix ( context , QualifiedSelection ) ,
24
+ new RemoveUnusedDeclarationQuickFix ( context , QualifiedSelection , Target ) ,
21
25
new IgnoreOnceQuickFix ( context , QualifiedSelection , Inspection . AnnotationName ) ,
22
26
} ;
23
27
}
@@ -42,32 +46,138 @@ public override NavigateCodeEventArgs GetNavigationArgs()
42
46
/// </summary>
43
47
public class RemoveUnusedDeclarationQuickFix : CodeInspectionQuickFix
44
48
{
45
- public RemoveUnusedDeclarationQuickFix ( ParserRuleContext context , QualifiedSelection selection )
49
+ private readonly Declaration _target ;
50
+
51
+ public RemoveUnusedDeclarationQuickFix ( ParserRuleContext context , QualifiedSelection selection , Declaration target )
46
52
: base ( context , selection , InspectionsUI . RemoveUnusedDeclarationQuickFix )
47
53
{
54
+ _target = target ;
48
55
}
49
56
50
57
public override void Fix ( )
51
58
{
52
- var module = Selection . QualifiedName . Component . CodeModule ;
53
- var selection = Selection . Selection ;
59
+ if ( _target . DeclarationType == DeclarationType . Variable )
60
+ {
61
+ RemoveVariable ( _target ) ;
62
+ }
63
+ else
64
+ {
65
+ var module = Selection . QualifiedName . Component . CodeModule ;
66
+ var selection = Selection . Selection ;
67
+
68
+ var originalCodeLines = module . Lines [ selection . StartLine , selection . LineCount ]
69
+ . Replace ( "\r \n " , " " )
70
+ . Replace ( "_" , string . Empty ) ;
71
+
72
+ var originalInstruction = Context . GetText ( ) ;
73
+ module . DeleteLines ( selection . StartLine , selection . LineCount ) ;
74
+
75
+ var newCodeLines = originalCodeLines . Replace ( originalInstruction , string . Empty ) ;
76
+ if ( ! string . IsNullOrEmpty ( newCodeLines ) )
77
+ {
78
+ module . InsertLines ( selection . StartLine , newCodeLines ) ;
79
+ }
80
+ }
81
+ }
82
+
83
+ private void RemoveVariable ( Declaration target )
84
+ {
85
+ Selection selection ;
86
+ var declarationText = target . Context . GetText ( ) . Replace ( " _" + Environment . NewLine , string . Empty ) ;
87
+ var multipleDeclarations = target . HasMultipleDeclarationsInStatement ( ) ;
88
+
89
+ var variableStmtContext = target . GetVariableStmtContext ( ) ;
90
+
91
+ if ( ! multipleDeclarations )
92
+ {
93
+ declarationText = variableStmtContext . GetText ( ) . Replace ( " _" + Environment . NewLine , string . Empty ) ;
94
+ selection = target . GetVariableStmtContextSelection ( ) ;
95
+ }
96
+ else
97
+ {
98
+ selection = new Selection ( target . Context . Start . Line , target . Context . Start . Column ,
99
+ target . Context . Stop . Line , target . Context . Stop . Column ) ;
100
+ }
54
101
55
- var originalCodeLines = module . get_Lines ( selection . StartLine , selection . LineCount )
56
- . Replace ( "\r \n " , " " )
57
- . Replace ( "_" , string . Empty ) ;
102
+ var codeModule = target . QualifiedName . QualifiedModuleName . Component . CodeModule ;
103
+ var oldLines = codeModule . GetLines ( selection ) ;
58
104
59
- var originalInstruction = Context . GetText ( ) ;
60
- module . DeleteLines ( selection . StartLine , selection . LineCount ) ;
105
+ var newLines = oldLines . Replace ( " _" + Environment . NewLine , string . Empty )
106
+ . Remove ( selection . StartColumn , declarationText . Length ) ;
61
107
62
- var newInstruction = string . Empty ;
63
- var newCodeLines = string . IsNullOrEmpty ( newInstruction )
64
- ? string . Empty
65
- : originalCodeLines . Replace ( originalInstruction , newInstruction ) ;
108
+ if ( multipleDeclarations )
109
+ {
110
+ selection = target . GetVariableStmtContextSelection ( ) ;
111
+ newLines = RemoveExtraComma ( codeModule . GetLines ( selection ) . Replace ( oldLines , newLines ) ,
112
+ target . CountOfDeclarationsInStatement ( ) , target . IndexOfVariableDeclarationInStatement ( ) ) ;
113
+ }
66
114
67
- if ( ! string . IsNullOrEmpty ( newCodeLines ) )
115
+ var newLinesWithoutExcessSpaces = newLines . Split ( new [ ] { Environment . NewLine } , StringSplitOptions . None ) ;
116
+ for ( var i = 0 ; i < newLinesWithoutExcessSpaces . Length ; i ++ )
68
117
{
69
- module . InsertLines ( selection . StartLine , newCodeLines ) ;
118
+ newLinesWithoutExcessSpaces [ i ] = newLinesWithoutExcessSpaces [ i ] . RemoveExtraSpacesLeavingIndentation ( ) ;
70
119
}
120
+
121
+ for ( var i = newLinesWithoutExcessSpaces . Length - 1 ; i >= 0 ; i -- )
122
+ {
123
+ if ( newLinesWithoutExcessSpaces [ i ] . Trim ( ) == string . Empty )
124
+ {
125
+ continue ;
126
+ }
127
+
128
+ if ( newLinesWithoutExcessSpaces [ i ] . EndsWith ( " _" ) )
129
+ {
130
+ newLinesWithoutExcessSpaces [ i ] =
131
+ newLinesWithoutExcessSpaces [ i ] . Remove ( newLinesWithoutExcessSpaces [ i ] . Length - 2 ) ;
132
+ }
133
+ break ;
134
+ }
135
+
136
+ // remove all lines with only whitespace
137
+ newLinesWithoutExcessSpaces = newLinesWithoutExcessSpaces . Where ( str => str . Any ( c => ! char . IsWhiteSpace ( c ) ) ) . ToArray ( ) ;
138
+
139
+ codeModule . DeleteLines ( selection ) ;
140
+ if ( newLinesWithoutExcessSpaces . Any ( ) )
141
+ {
142
+ codeModule . InsertLines ( selection . StartLine ,
143
+ string . Join ( Environment . NewLine , newLinesWithoutExcessSpaces ) ) ;
144
+ }
145
+ }
146
+
147
+ private string RemoveExtraComma ( string str , int numParams , int indexRemoved )
148
+ {
149
+ // Example use cases for this method (fields and variables):
150
+ // Dim fizz as Boolean, dizz as Double
151
+ // Private fizz as Boolean, dizz as Double
152
+ // Public fizz as Boolean, _
153
+ // dizz as Double
154
+ // Private fizz as Boolean _
155
+ // , dizz as Double _
156
+ // , iizz as Integer
157
+
158
+ // Before this method is called, the parameter to be removed has
159
+ // already been removed. This means 'str' will look like:
160
+ // Dim fizz as Boolean,
161
+ // Private , dizz as Double
162
+ // Public fizz as Boolean, _
163
+ //
164
+ // Private _
165
+ // , dizz as Double _
166
+ // , iizz as Integer
167
+
168
+ // This method is responsible for removing the redundant comma
169
+ // and returning a string similar to:
170
+ // Dim fizz as Boolean
171
+ // Private dizz as Double
172
+ // Public fizz as Boolean _
173
+ //
174
+ // Private _
175
+ // dizz as Double _
176
+ // , iizz as Integer
177
+
178
+ var commaToRemove = numParams == indexRemoved ? indexRemoved - 1 : indexRemoved ;
179
+
180
+ return str . Remove ( str . NthIndexOf ( ',' , commaToRemove ) , 1 ) ;
71
181
}
72
182
}
73
183
}
0 commit comments