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,148 @@ 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 || _target . DeclarationType == DeclarationType . Constant )
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
+
70
+ var originalInstruction = Context . GetText ( ) ;
71
+ module . DeleteLines ( selection . StartLine , selection . LineCount ) ;
72
+
73
+ var newCodeLines = originalCodeLines . Replace ( originalInstruction , string . Empty ) ;
74
+ if ( ! string . IsNullOrEmpty ( newCodeLines ) )
75
+ {
76
+ module . InsertLines ( selection . StartLine , newCodeLines ) ;
77
+ }
78
+ }
79
+ }
80
+
81
+ private void RemoveVariable ( Declaration target )
82
+ {
83
+ Selection selection ;
84
+ var declarationText = target . Context . GetText ( ) . Replace ( " _" + Environment . NewLine , string . Empty ) ;
85
+ var multipleDeclarations = target . DeclarationType == DeclarationType . Variable && target . HasMultipleDeclarationsInStatement ( ) ;
86
+
87
+ if ( ! multipleDeclarations )
88
+ {
89
+ declarationText = GetStmtContext ( target ) . GetText ( ) . Replace ( " _" + Environment . NewLine , string . Empty ) ;
90
+ selection = GetStmtContextSelection ( target ) ;
91
+ }
92
+ else
93
+ {
94
+ selection = new Selection ( target . Context . Start . Line , target . Context . Start . Column ,
95
+ target . Context . Stop . Line , target . Context . Stop . Column ) ;
96
+ }
54
97
55
- var originalCodeLines = module . get_Lines ( selection . StartLine , selection . LineCount )
56
- . Replace ( "\r \n " , " " )
57
- . Replace ( "_" , string . Empty ) ;
98
+ var codeModule = target . QualifiedName . QualifiedModuleName . Component . CodeModule ;
99
+ var oldLines = codeModule . GetLines ( selection ) ;
58
100
59
- var originalInstruction = Context . GetText ( ) ;
60
- module . DeleteLines ( selection . StartLine , selection . LineCount ) ;
101
+ var newLines = oldLines . Replace ( " _" + Environment . NewLine , string . Empty )
102
+ . Remove ( selection . StartColumn , declarationText . Length ) ;
61
103
62
- var newInstruction = string . Empty ;
63
- var newCodeLines = string . IsNullOrEmpty ( newInstruction )
64
- ? string . Empty
65
- : originalCodeLines . Replace ( originalInstruction , newInstruction ) ;
104
+ if ( multipleDeclarations )
105
+ {
106
+ selection = GetStmtContextSelection ( target ) ;
107
+ newLines = RemoveExtraComma ( codeModule . GetLines ( selection ) . Replace ( oldLines , newLines ) ,
108
+ target . CountOfDeclarationsInStatement ( ) , target . IndexOfVariableDeclarationInStatement ( ) ) ;
109
+ }
66
110
67
- if ( ! string . IsNullOrEmpty ( newCodeLines ) )
111
+ var newLinesWithoutExcessSpaces = newLines . Split ( new [ ] { Environment . NewLine } , StringSplitOptions . None ) ;
112
+ for ( var i = 0 ; i < newLinesWithoutExcessSpaces . Length ; i ++ )
68
113
{
69
- module . InsertLines ( selection . StartLine , newCodeLines ) ;
114
+ newLinesWithoutExcessSpaces [ i ] = newLinesWithoutExcessSpaces [ i ] . RemoveExtraSpacesLeavingIndentation ( ) ;
70
115
}
116
+
117
+ for ( var i = newLinesWithoutExcessSpaces . Length - 1 ; i >= 0 ; i -- )
118
+ {
119
+ if ( newLinesWithoutExcessSpaces [ i ] . Trim ( ) == string . Empty )
120
+ {
121
+ continue ;
122
+ }
123
+
124
+ if ( newLinesWithoutExcessSpaces [ i ] . EndsWith ( " _" ) )
125
+ {
126
+ newLinesWithoutExcessSpaces [ i ] =
127
+ newLinesWithoutExcessSpaces [ i ] . Remove ( newLinesWithoutExcessSpaces [ i ] . Length - 2 ) ;
128
+ }
129
+ break ;
130
+ }
131
+
132
+ // remove all lines with only whitespace
133
+ newLinesWithoutExcessSpaces = newLinesWithoutExcessSpaces . Where ( str => str . Any ( c => ! char . IsWhiteSpace ( c ) ) ) . ToArray ( ) ;
134
+
135
+ codeModule . DeleteLines ( selection ) ;
136
+ if ( newLinesWithoutExcessSpaces . Any ( ) )
137
+ {
138
+ codeModule . InsertLines ( selection . StartLine ,
139
+ string . Join ( Environment . NewLine , newLinesWithoutExcessSpaces ) ) ;
140
+ }
141
+ }
142
+
143
+ private Selection GetStmtContextSelection ( Declaration target )
144
+ {
145
+ return target . DeclarationType == DeclarationType . Variable
146
+ ? target . GetVariableStmtContextSelection ( )
147
+ : target . GetConstStmtContextSelection ( ) ;
148
+ }
149
+
150
+ private ParserRuleContext GetStmtContext ( Declaration target )
151
+ {
152
+ return target . DeclarationType == DeclarationType . Variable
153
+ ? ( ParserRuleContext ) target . GetVariableStmtContext ( )
154
+ : ( ParserRuleContext ) target . GetConstStmtContext ( ) ;
155
+ }
156
+
157
+ private string RemoveExtraComma ( string str , int numParams , int indexRemoved )
158
+ {
159
+ // Example use cases for this method (fields and variables):
160
+ // Dim fizz as Boolean, dizz as Double
161
+ // Private fizz as Boolean, dizz as Double
162
+ // Public fizz as Boolean, _
163
+ // dizz as Double
164
+ // Private fizz as Boolean _
165
+ // , dizz as Double _
166
+ // , iizz as Integer
167
+
168
+ // Before this method is called, the parameter to be removed has
169
+ // already been removed. This means 'str' will look like:
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
+ // This method is responsible for removing the redundant comma
179
+ // and returning a string similar to:
180
+ // Dim fizz as Boolean
181
+ // Private dizz as Double
182
+ // Public fizz as Boolean _
183
+ //
184
+ // Private _
185
+ // dizz as Double _
186
+ // , iizz as Integer
187
+
188
+ var commaToRemove = numParams == indexRemoved ? indexRemoved - 1 : indexRemoved ;
189
+
190
+ return str . Remove ( str . NthIndexOf ( ',' , commaToRemove ) , 1 ) ;
71
191
}
72
192
}
73
193
}
0 commit comments