From e3c1dfcc7ec3e2c8960041f04fab73484e01b335 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 10 Jul 2025 18:21:50 +0100 Subject: [PATCH] [Refactoring] Handle argument count mismatches in `renameLabelsLenient` Make sure we bail if we don't have enough labels in the old name when matching against a found reference. rdar://155549979 --- .../SyntacticRenameRangeDetails.cpp | 11 +- .../SourceKit/Refactoring/rdar155549979.swift | 105 ++++++++++++++++++ 2 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 test/SourceKit/Refactoring/rdar155549979.swift diff --git a/lib/Refactoring/SyntacticRenameRangeDetails.cpp b/lib/Refactoring/SyntacticRenameRangeDetails.cpp index 6236956236c1b..efd1ed71ee27b 100644 --- a/lib/Refactoring/SyntacticRenameRangeDetails.cpp +++ b/lib/Refactoring/SyntacticRenameRangeDetails.cpp @@ -283,12 +283,12 @@ bool RenameRangeDetailCollector::renameLabelsLenient( LabelRanges = LabelRanges.take_front(*FirstTrailingLabel); for (auto LabelIndex : llvm::reverse(indices(TrailingLabels))) { + if (OldNames.empty()) + return true; + CharSourceRange Label = TrailingLabels[LabelIndex]; if (Label.getByteLength()) { - if (OldNames.empty()) - return true; - while (!labelRangeMatches(Label, LabelRangeType::CompoundName, OldNames.back())) { if ((OldNames = OldNames.drop_back()).empty()) @@ -302,9 +302,6 @@ bool RenameRangeDetailCollector::renameLabelsLenient( // empty labelled trailing closure label if (LabelIndex) { - if (OldNames.empty()) - return true; - while (!OldNames.back().empty()) { if ((OldNames = OldNames.drop_back()).empty()) return true; @@ -330,6 +327,8 @@ bool RenameRangeDetailCollector::renameLabelsLenient( // first name pos if (!NameIndex) { + if (NameIndex >= OldNames.size()) + return true; while (!OldNames[NameIndex].empty()) { if (++NameIndex >= OldNames.size()) return true; diff --git a/test/SourceKit/Refactoring/rdar155549979.swift b/test/SourceKit/Refactoring/rdar155549979.swift new file mode 100644 index 0000000000000..c5102d4e9b2b3 --- /dev/null +++ b/test/SourceKit/Refactoring/rdar155549979.swift @@ -0,0 +1,105 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %sourcekitd-test -req=find-rename-ranges -rename-spec %t/spec.json %t/main.swift | %FileCheck %s + +// REQUIRES: swift_swift_parser + +//--- main.swift +func foo() {} + +// Make sure we don't crash on the unrelated comment refs: +// foo() +// foo(0) +// foo(a: 0) +// foo {} +// foo {} a: {} + +// Nor when written in code: +foo() +foo(0) +foo(a: 0) +foo {} +foo {} a: {} + +// CHECK: source.edit.kind.active: +// CHECK-NEXT: 1:6-1:9 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.comment: +// CHECK-NEXT: 4:4-4:7 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.unknown: +// CHECK-NEXT: 5:4-5:7 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.unknown: +// CHECK-NEXT: 6:4-6:7 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.unknown: +// CHECK-NEXT: 7:4-7:7 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.unknown: +// CHECK-NEXT: 8:4-8:7 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.active: +// CHECK-NEXT: 11:1-11:4 source.refactoring.range.kind.basename +// CHECK-NEXT: source.edit.kind.mismatch: +// CHECK-NEXT: source.edit.kind.mismatch: +// CHECK-NEXT: source.edit.kind.mismatch: +// CHECK-NEXT: source.edit.kind.mismatch: + +//--- spec.json +[ + { + "key.name": "foo()", + "key.locations": [ + { + "key.line": 1, + "key.column": 6, + "key.nametype": source.syntacticrename.definition + }, + { + "key.line": 4, + "key.column": 4, + "key.nametype": source.syntacticrename.unknown + }, + { + "key.line": 5, + "key.column": 4, + "key.nametype": source.syntacticrename.unknown + }, + { + "key.line": 6, + "key.column": 4, + "key.nametype": source.syntacticrename.unknown + }, + { + "key.line": 7, + "key.column": 4, + "key.nametype": source.syntacticrename.unknown + }, + { + "key.line": 8, + "key.column": 4, + "key.nametype": source.syntacticrename.unknown + }, + { + "key.line": 11, + "key.column": 1, + "key.nametype": source.syntacticrename.call + }, + { + "key.line": 12, + "key.column": 1, + "key.nametype": source.syntacticrename.call + }, + { + "key.line": 13, + "key.column": 1, + "key.nametype": source.syntacticrename.call + }, + { + "key.line": 14, + "key.column": 1, + "key.nametype": source.syntacticrename.call + }, + { + "key.line": 15, + "key.column": 1, + "key.nametype": source.syntacticrename.call + }, + ] + } +]