99// THE SOFTWARE.
1010
1111using System ;
12+ using System . Linq ;
1213using System . Collections . Generic ;
1314#if ! CORECLR
1415using System . ComponentModel . Composition ;
@@ -138,26 +139,55 @@ private List<CorrectionExtent> GetCorrections(
138139 var filePath = funcDefnAst . Extent . File ;
139140 var correctionExtents = new List < CorrectionExtent > ( ) ;
140141
141- // replace whatif/confirm extent starting with the first character ending with the first character of
142+ // TODO Handle case where only one param is left after correction and there is a
143+ // comma left after the param.
144+
145+ var editableText = new EditableText ( funcDefnAst . Extent . Text ) ;
146+ // replace whatif/confirm extent starting with the last character of the previous parameter and ending with the last character of the whatif/confirm/parameter. This will take care of the trailing comma.
142147 // the next parameter
148+ // TODO Do not incrementally correct the text as it may lead to a situation in which a following
149+ // edits might try to modify edits that have already taken place.
150+ // A better approach is to gather all the edits and give them to the text edit class to handle.
143151 if ( whatIfIndex != - 1 )
144152 {
145153 correctionExtents . Add ( GetCorrectionExtent ( whatIfIndex , parameterAsts ) ) ;
154+ var shiftedCorrectionExtent = Normalize ( funcDefnAst . Extent , correctionExtents . Last ( ) ) ;
155+ editableText = editableText . ApplyEdit ( shiftedCorrectionExtent ) ;
146156 }
147157
148158 if ( confirmIndex != - 1 )
149159 {
150160 correctionExtents . Add ( GetCorrectionExtent ( confirmIndex , parameterAsts ) ) ;
161+ var shiftedCorrectionExtent = Normalize ( funcDefnAst . Extent , correctionExtents . Last ( ) ) ;
162+ editableText = editableText . ApplyEdit ( shiftedCorrectionExtent ) ;
151163 }
152164
153165 if ( paramBlockAst != null )
154166 {
155-
167+ AttributeAst attributeAst ;
168+ // check if it has cmdletbinding attribute
169+ if ( TryGetCmdletBindingAttribute ( paramBlockAst , out attributeAst ) )
170+ {
171+ if ( ! attributeAst . NamedArguments . Any (
172+ x => x . ArgumentName . Equals ( "supportsshouldprocess" ,
173+ StringComparison . OrdinalIgnoreCase ) ) )
174+ {
175+ // add supportsshouldprocess to the attribute
176+ correctionExtents . Add ( GetCorrectionExtent ( attributeAst ) ) ;
177+ }
178+ }
179+ else
180+ {
181+ // has no cmdletbinding attribute
182+ // add the attribute and supportsshouldprocess argument
183+ }
156184 }
157185 else
158186 {
159187 // function doesn't have param block
160- // replace
188+ // remove the parameter list
189+ // and create an equivalent param block
190+ // add cmdletbinding attribute and add supportsshouldprocess to it.
161191 }
162192
163193 // This is how we handle multiple edits.
@@ -167,6 +197,66 @@ private List<CorrectionExtent> GetCorrections(
167197 return correctionExtents ;
168198 }
169199
200+ // doesn't seem right. The arguments should be of same type.
201+ private CorrectionExtent Normalize ( IScriptExtent referenceExtent , CorrectionExtent cextent )
202+ {
203+ // TODO Add ToRange extension methods for this conversion
204+ var refRange = new Range (
205+ referenceExtent . StartLineNumber ,
206+ referenceExtent . StartColumnNumber ,
207+ referenceExtent . EndLineNumber ,
208+ referenceExtent . EndColumnNumber ) ;
209+
210+ var range = new Range (
211+ cextent . StartLineNumber ,
212+ cextent . StartColumnNumber ,
213+ cextent . EndLineNumber ,
214+ cextent . EndColumnNumber ) ;
215+
216+ var shiftedRange = Range . Normalize ( refRange , range ) ;
217+
218+ // TODO Add a method to TextEdit class that takes in range and text
219+ // TODO Add a method to CorrectionExtent that takes in range and all other stuff
220+ return new CorrectionExtent (
221+ shiftedRange . Start . Line ,
222+ shiftedRange . End . Line ,
223+ shiftedRange . Start . Column ,
224+ shiftedRange . End . Column ,
225+ cextent . Text ,
226+ cextent . File ,
227+ cextent . Description ) ;
228+ }
229+ private static bool TryGetCmdletBindingAttribute (
230+ ParamBlockAst paramBlockAst ,
231+ out AttributeAst attributeAst )
232+ {
233+ attributeAst = paramBlockAst . Attributes . FirstOrDefault ( attr =>
234+ {
235+ return attr . TypeName . Name . Equals ( "cmdletbinding" , StringComparison . OrdinalIgnoreCase ) ;
236+ } ) ;
237+
238+ return attributeAst != null ;
239+ }
240+
241+
242+ private static CorrectionExtent GetCorrectionExtent ( AttributeAst cmdletBindingAttributeAst )
243+ {
244+ // 1 for 1 based offset and 1 for the next position.
245+ var startColumnNumber = cmdletBindingAttributeAst . Extent . Text . IndexOf ( "(" ) + 2 ;
246+ var extent = cmdletBindingAttributeAst . Extent ;
247+ var suffix = cmdletBindingAttributeAst . NamedArguments . Count > 0
248+ || cmdletBindingAttributeAst . PositionalArguments . Count > 0
249+ ? ", "
250+ : "" ;
251+ return new CorrectionExtent (
252+ extent . StartLineNumber ,
253+ extent . StartLineNumber ,
254+ startColumnNumber ,
255+ startColumnNumber ,
256+ "SupportsShouldProcess" + suffix ,
257+ extent . File ) ;
258+ }
259+
170260 private static CorrectionExtent GetCorrectionExtent (
171261 int paramIndex ,
172262 ParameterAst [ ] parameterAsts )
0 commit comments