@@ -118,8 +118,7 @@ class Renamer {
118
118
size_t Index = 0 ;
119
119
for (const auto &LabelRange : LabelRanges) {
120
120
assert (LabelRange.isValid ());
121
-
122
- if (!labelRangeMatches (LabelRange, OldLabels[Index]))
121
+ if (!labelRangeMatches (LabelRange, RangeType, OldLabels[Index]))
123
122
return true ;
124
123
splitAndRenameLabel (LabelRange, RangeType, Index++);
125
124
}
@@ -135,7 +134,9 @@ class Renamer {
135
134
case LabelRangeType::CallArg:
136
135
return splitAndRenameCallArg (Range, NameIndex);
137
136
case LabelRangeType::Param:
138
- return splitAndRenameParamLabel (Range, NameIndex);
137
+ return splitAndRenameParamLabel (Range, NameIndex, /* IsCollapsible=*/ true );
138
+ case LabelRangeType::NoncollapsibleParam:
139
+ return splitAndRenameParamLabel (Range, NameIndex, /* IsCollapsible=*/ false );
139
140
case LabelRangeType::Selector:
140
141
return doRenameLabel (
141
142
Range, RefactoringRangeKind::SelectorArgumentLabel, NameIndex);
@@ -144,28 +145,47 @@ class Renamer {
144
145
}
145
146
}
146
147
147
- void splitAndRenameParamLabel (CharSourceRange Range, size_t NameIndex) {
148
+ void splitAndRenameParamLabel (CharSourceRange Range, size_t NameIndex, bool IsCollapsible ) {
148
149
// Split parameter range foo([a b]: Int) into decl argument label [a] and
149
- // parameter name [b]. If we have only foo([a]: Int), then we add an empty
150
- // range for the local name.
150
+ // parameter name [b] or noncollapsible parameter name [b] if IsCollapsible
151
+ // is false (as for subscript decls). If we have only foo([a]: Int), then we
152
+ // add an empty range for the local name, or for the decl argument label if
153
+ // IsCollapsible is false.
151
154
StringRef Content = Range.str ();
152
155
size_t ExternalNameEnd = Content.find_first_of (" \t\n\v\f\r /" );
153
- ExternalNameEnd =
154
- ExternalNameEnd == StringRef::npos ? Content.size () : ExternalNameEnd;
155
-
156
- CharSourceRange Ext{Range.getStart (), unsigned (ExternalNameEnd)};
157
- doRenameLabel (Ext, RefactoringRangeKind::DeclArgumentLabel, NameIndex);
158
156
159
- size_t LocalNameStart = Content.find_last_of (" \t\n\v\f\r /" );
160
- LocalNameStart =
161
- LocalNameStart == StringRef::npos ? ExternalNameEnd : LocalNameStart;
162
- // Note: we consider the leading whitespace part of the parameter name since
163
- // when the parameter is removed we want to remove the whitespace too.
164
- // FIXME: handle comments foo(a /*...*/b: Int).
165
- auto LocalLoc = Range.getStart ().getAdvancedLocOrInvalid (LocalNameStart);
166
- assert (LocalLoc.isValid ());
167
- CharSourceRange Local{LocalLoc, unsigned (Content.size () - LocalNameStart)};
168
- doRenameLabel (Local, RefactoringRangeKind::ParameterName, NameIndex);
157
+ if (ExternalNameEnd == StringRef::npos) { // foo([a]: Int)
158
+ if (IsCollapsible) {
159
+ doRenameLabel (Range, RefactoringRangeKind::DeclArgumentLabel, NameIndex);
160
+ doRenameLabel (CharSourceRange{Range.getEnd (), 0 },
161
+ RefactoringRangeKind::ParameterName, NameIndex);
162
+ } else {
163
+ doRenameLabel (CharSourceRange{Range.getStart (), 0 },
164
+ RefactoringRangeKind::DeclArgumentLabel, NameIndex);
165
+ doRenameLabel (Range, RefactoringRangeKind::NoncollapsibleParameterName,
166
+ NameIndex);
167
+ }
168
+ } else { // foo([a b]: Int)
169
+ CharSourceRange Ext{Range.getStart (), unsigned (ExternalNameEnd)};
170
+
171
+ // Note: we consider the leading whitespace part of the parameter name
172
+ // if the parameter is collapsible, since if the parameter is collapsed
173
+ // into a matching argument label, we want to remove the whitespace too.
174
+ // FIXME: handle comments foo(a /*...*/b: Int).
175
+ size_t LocalNameStart = Content.find_last_of (" \t\n\v\f\r /" );
176
+ assert (LocalNameStart != StringRef::npos);
177
+ if (!IsCollapsible)
178
+ ++LocalNameStart;
179
+ auto LocalLoc = Range.getStart ().getAdvancedLocOrInvalid (LocalNameStart);
180
+ CharSourceRange Local{LocalLoc, unsigned (Content.size () - LocalNameStart)};
181
+
182
+ doRenameLabel (Ext, RefactoringRangeKind::DeclArgumentLabel, NameIndex);
183
+ if (IsCollapsible) {
184
+ doRenameLabel (Local, RefactoringRangeKind::ParameterName, NameIndex);
185
+ } else {
186
+ doRenameLabel (Local, RefactoringRangeKind::NoncollapsibleParameterName, NameIndex);
187
+ }
188
+ }
169
189
}
170
190
171
191
void splitAndRenameCallArg (CharSourceRange Range, size_t NameIndex) {
@@ -192,14 +212,24 @@ class Renamer {
192
212
doRenameLabel (Rest, RefactoringRangeKind::CallArgumentColon, NameIndex);
193
213
}
194
214
195
- bool labelRangeMatches (CharSourceRange Range, StringRef Expected) {
215
+ bool labelRangeMatches (CharSourceRange Range, LabelRangeType RangeType, StringRef Expected) {
196
216
if (Range.getByteLength ()) {
197
- StringRef ExistingLabel = Lexer::getCharSourceRangeFromSourceRange (SM,
198
- Range.getStart ()).str ();
199
- if (!Expected.empty ())
200
- return Expected == ExistingLabel;
201
- else
202
- return ExistingLabel == " _" ;
217
+ CharSourceRange ExistingLabelRange =
218
+ Lexer::getCharSourceRangeFromSourceRange (SM, Range.getStart ());
219
+ StringRef ExistingLabel = ExistingLabelRange.str ();
220
+
221
+ switch (RangeType) {
222
+ case LabelRangeType::NoncollapsibleParam:
223
+ if (ExistingLabelRange == Range && Expected.empty ()) // subscript([x]: Int)
224
+ return true ;
225
+ LLVM_FALLTHROUGH;
226
+ case LabelRangeType::CallArg:
227
+ case LabelRangeType::Param:
228
+ case LabelRangeType::Selector:
229
+ return ExistingLabel == (Expected.empty () ? " _" : Expected);
230
+ case LabelRangeType::None:
231
+ llvm_unreachable (" Unhandled label range type" );
232
+ }
203
233
}
204
234
return Expected.empty ();
205
235
}
@@ -238,7 +268,7 @@ class Renamer {
238
268
if (NameIndex >= OldNames.size ())
239
269
return true ;
240
270
241
- while (!labelRangeMatches (Label, OldNames[NameIndex])) {
271
+ while (!labelRangeMatches (Label, RangeType, OldNames[NameIndex])) {
242
272
if (++NameIndex >= OldNames.size ())
243
273
return true ;
244
274
};
@@ -279,13 +309,16 @@ class Renamer {
279
309
280
310
assert (Config.Usage != NameUsage::Call || Config.IsFunctionLike );
281
311
282
- bool isKeywordBase = Old.base () == " init" || Old.base () == " subscript" ;
312
+ // FIXME: handle escaped keyword names `init`
313
+ bool IsSubscript = Old.base () == " subscript" && Config.IsFunctionLike ;
314
+ bool IsInit = Old.base () == " init" && Config.IsFunctionLike ;
315
+ bool IsKeywordBase = IsInit || IsSubscript;
283
316
284
- if (!Config.IsFunctionLike || !isKeywordBase ) {
317
+ if (!Config.IsFunctionLike || !IsKeywordBase ) {
285
318
if (renameBase (Resolved.Range , RefactoringRangeKind::BaseName))
286
319
return RegionType::Mismatch;
287
320
288
- } else if (isKeywordBase && Config.Usage == NameUsage::Definition) {
321
+ } else if (IsKeywordBase && Config.Usage == NameUsage::Definition) {
289
322
if (renameBase (Resolved.Range , RefactoringRangeKind::KeywordBaseName))
290
323
return RegionType::Mismatch;
291
324
}
@@ -300,7 +333,7 @@ class Renamer {
300
333
HandleLabels = true ;
301
334
break ;
302
335
case NameUsage::Reference:
303
- HandleLabels = Resolved.LabelType == LabelRangeType::Selector;
336
+ HandleLabels = Resolved.LabelType == LabelRangeType::Selector || IsSubscript ;
304
337
break ;
305
338
case NameUsage::Unknown:
306
339
HandleLabels = Resolved.LabelType != LabelRangeType::None;
@@ -315,7 +348,7 @@ class Renamer {
315
348
316
349
if (HandleLabels) {
317
350
bool isCallSite = Config.Usage != NameUsage::Definition &&
318
- Config.Usage != NameUsage::Reference &&
351
+ ( Config.Usage != NameUsage::Reference || IsSubscript) &&
319
352
Resolved.LabelType == LabelRangeType::CallArg;
320
353
321
354
if (renameLabels (Resolved.LabelRanges , Resolved.LabelType , isCallSite))
@@ -395,6 +428,17 @@ class TextReplacementsRenamer : public Renamer {
395
428
return registerText (OldParam);
396
429
}
397
430
431
+ StringRef getDeclArgumentLabelReplacement (StringRef OldLabelRange,
432
+ StringRef NewArgLabel) {
433
+ // OldLabelRange is subscript([]a: Int), foo([a]: Int) or foo([a] b: Int)
434
+ if (NewArgLabel.empty ())
435
+ return OldLabelRange.empty () ? " " : " _" ;
436
+
437
+ if (OldLabelRange.empty ())
438
+ return registerText ((llvm::Twine (NewArgLabel) + " " ).str ());
439
+ return registerText (NewArgLabel);
440
+ }
441
+
398
442
StringRef getReplacementText (StringRef LabelRange,
399
443
RefactoringRangeKind RangeKind,
400
444
StringRef OldLabel, StringRef NewLabel) {
@@ -407,9 +451,12 @@ class TextReplacementsRenamer : public Renamer {
407
451
return getCallArgCombinedReplacement (LabelRange, NewLabel);
408
452
case RefactoringRangeKind::ParameterName:
409
453
return getParamNameReplacement (LabelRange, OldLabel, NewLabel);
454
+ case RefactoringRangeKind::NoncollapsibleParameterName:
455
+ return LabelRange;
410
456
case RefactoringRangeKind::DeclArgumentLabel:
457
+ return getDeclArgumentLabelReplacement (LabelRange, NewLabel);
411
458
case RefactoringRangeKind::SelectorArgumentLabel:
412
- return registerText ( NewLabel.empty () ? " _" : NewLabel);
459
+ return NewLabel.empty () ? " _" : registerText ( NewLabel);
413
460
default :
414
461
llvm_unreachable (" label range type is none but there are labels" );
415
462
}
@@ -2404,6 +2451,8 @@ struct swift::ide::FindRenameRangesAnnotatingConsumer::Implementation {
2404
2451
return " keywordBase" ;
2405
2452
case RefactoringRangeKind::ParameterName:
2406
2453
return " param" ;
2454
+ case RefactoringRangeKind::NoncollapsibleParameterName:
2455
+ return " noncollapsibleparam" ;
2407
2456
case RefactoringRangeKind::DeclArgumentLabel:
2408
2457
return " arglabel" ;
2409
2458
case RefactoringRangeKind::CallArgumentLabel:
0 commit comments