Skip to content

Commit f7aaf02

Browse files
committed
[SourceKit] Add an optional path and name to refactoring edits
Add two new fields to refactoring edits: - A file path if the edit corresponds to a buffer other than the original file - A buffer name when the edit is actually source of generated buffer Macro expansions allow the former as a macro could expand to member attributes, which may eg. add accessors to each member. The attribute itself is inside the expansion, but the edit is to the member in the original source. The latter will later allow clients to send requests with these names to allow semantic functionality inside synthesized buffers.
1 parent 6b5f449 commit f7aaf02

File tree

9 files changed

+137
-49
lines changed

9 files changed

+137
-49
lines changed

include/swift/IDE/Utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,15 @@ struct NoteRegion {
551551
};
552552

553553
struct Replacement {
554+
/// If the edit is outside of the originally request source file, the path
555+
/// to the file it is editing.
556+
StringRef Path;
557+
/// Range to apply the replacement to, zero-width if making an addition.
554558
CharSourceRange Range;
559+
/// If the edit is actually a file (which could be generated/from an
560+
/// expansion), the name (or path) of that buffer.
561+
StringRef BufferName;
562+
/// The text to replace \c Range with.
555563
StringRef Text;
556564
ArrayRef<NoteRegion> RegionsWorthNote;
557565
};

lib/IDE/Utils.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,8 @@ accept(SourceManager &SM, SourceLoc Loc, StringRef Text,
607607
void swift::ide::SourceEditConsumer::
608608
accept(SourceManager &SM, CharSourceRange Range, StringRef Text,
609609
ArrayRef<NoteRegion> SubRegions) {
610-
accept(SM, RegionType::ActiveCode, {{Range, Text, SubRegions}});
610+
accept(SM, RegionType::ActiveCode,
611+
{{/*Path=*/{}, Range, /*BufferName=*/{}, Text, SubRegions}});
611612
}
612613

613614
void swift::ide::SourceEditConsumer::
@@ -649,15 +650,27 @@ accept(SourceManager &SM, RegionType Type, ArrayRef<Replacement> Replacements) {
649650
void swift::ide::SourceEditTextConsumer::
650651
accept(SourceManager &SM, RegionType Type, ArrayRef<Replacement> Replacements) {
651652
for (const auto &Replacement: Replacements) {
652-
CharSourceRange Range = Replacement.Range;
653-
unsigned BufID = SM.findBufferContainingLoc(Range.getStart());
654-
auto Path(SM.getIdentifierForBuffer(BufID));
655-
auto Start = SM.getLineAndColumnInBuffer(Range.getStart());
656-
auto End = SM.getLineAndColumnInBuffer(Range.getEnd());
653+
OS << "// ";
654+
StringRef Path = Replacement.Path;
655+
if (Path.empty()) {
656+
unsigned BufID = SM.findBufferContainingLoc(Replacement.Range.getStart());
657+
Path = SM.getIdentifierForBuffer(BufID);
658+
} else {
659+
OS << "explicit ";
660+
}
661+
OS << Path.str() << " ";
657662

658-
OS << "// " << Path.str() << " ";
663+
auto Start = SM.getLineAndColumnInBuffer(Replacement.Range.getStart());
664+
auto End = SM.getLineAndColumnInBuffer(Replacement.Range.getEnd());
659665
OS << Start.first << ":" << Start.second << " -> ";
660-
OS << End.first << ":" << End.second << "\n";
666+
OS << End.first << ":" << End.second;
667+
668+
if (Replacement.BufferName.empty()) {
669+
OS << " (" << Replacement.BufferName << ")\n";
670+
} else {
671+
OS << "\n";
672+
}
673+
661674
OS << Replacement.Text << "\n";
662675
}
663676
}

lib/Refactoring/Refactoring.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ class RenameRangeDetailCollector : public Renamer {
477477

478478
class TextReplacementsRenamer : public Renamer {
479479
llvm::StringSet<> &ReplaceTextContext;
480-
std::vector<Replacement> Replacements;
480+
SmallVector<Replacement> Replacements;
481481

482482
public:
483483
const DeclNameViewer New;
@@ -571,7 +571,8 @@ class TextReplacementsRenamer : public Renamer {
571571
StringRef Text =
572572
getReplacementText(ExistingLabel, RangeKind, OldLabel, NewLabel);
573573
if (Text != ExistingLabel)
574-
Replacements.push_back({LabelRange, Text, {}});
574+
Replacements.push_back({/*Path=*/{}, LabelRange, /*BufferName=*/{}, Text,
575+
/*RegionsWorthNote=*/{}});
575576
}
576577

577578
void doRenameLabel(CharSourceRange Label, RefactoringRangeKind RangeKind,
@@ -582,7 +583,9 @@ class TextReplacementsRenamer : public Renamer {
582583

583584
void doRenameBase(CharSourceRange Range, RefactoringRangeKind) override {
584585
if (Old.base() != New.base())
585-
Replacements.push_back({Range, registerText(New.base()), {}});
586+
Replacements.push_back({/*Path=*/{}, Range, /*BufferName=*/{},
587+
registerText(New.base()),
588+
/*RegionsWorthNote=*/{}});
586589
}
587590

588591
public:
@@ -595,9 +598,7 @@ class TextReplacementsRenamer : public Renamer {
595598
assert(Old.partsCount() == New.partsCount());
596599
}
597600

598-
std::vector<Replacement> getReplacements() const {
599-
return std::move(Replacements);
600-
}
601+
ArrayRef<Replacement> getReplacements() const { return Replacements; }
601602
};
602603

603604
static const ValueDecl *getRelatedSystemDecl(const ValueDecl *VD) {
@@ -8688,7 +8689,37 @@ bool RefactoringActionExpandMacro::performChange() {
86888689
rewrittenBuffer = adjustMacroExpansionWhitespace(
86898690
generatedInfo->kind, rewrittenBuffer, scratchBuffer);
86908691

8691-
EditConsumer.accept(SM, originalSourceRange, rewrittenBuffer);
8692+
// `TheFile` is the file of the actual expansion site, where as
8693+
// `OriginalFile` is the possibly enclosing buffer. Concretely:
8694+
// ```
8695+
// // m.swift
8696+
// @AddMemberAttributes
8697+
// struct Foo {
8698+
// // --- expanded from @AddMemberAttributes eg. @_someBufferName ---
8699+
// @AddedAttribute
8700+
// // ---
8701+
// let someMember: Int
8702+
// }
8703+
// ```
8704+
//
8705+
// When expanding `AddedAttribute`, the expansion actually applies to the
8706+
// original source (`m.swift`) rather than the buffer of the expansion
8707+
// site (`@_someBufferName`). Thus, we need to include the path to the
8708+
// original source as well. Note that this path could itself be another
8709+
// expansion.
8710+
SourceFile *originalFile =
8711+
MD->getSourceFileContainingLocation(originalSourceRange.getStart());
8712+
StringRef originalPath;
8713+
if (originalFile->getBufferID().hasValue() &&
8714+
TheFile->getBufferID() != originalFile->getBufferID()) {
8715+
originalPath = SM.getIdentifierForBuffer(*originalFile->getBufferID());
8716+
}
8717+
8718+
EditConsumer.accept(SM, {originalPath,
8719+
originalSourceRange,
8720+
SM.getIdentifierForBuffer(bufferID),
8721+
rewrittenBuffer,
8722+
{}});
86928723

86938724
if (generatedInfo->attachedMacroCustomAttr && !attachedMacroAttr)
86948725
attachedMacroAttr = generatedInfo->attachedMacroCustomAttr;
@@ -8780,7 +8811,8 @@ struct swift::ide::FindRenameRangesAnnotatingConsumer::Implementation {
87808811
if (Range.Index.has_value())
87818812
OS << " index=" << *Range.Index;
87828813
OS << ">" << Range.Range.str() << "</" << Tag << ">";
8783-
pRewriter->accept(SM, {Range.Range, OS.str(), {}});
8814+
pRewriter->accept(SM, {/*Path=*/{}, Range.Range, /*BufferName=*/{},
8815+
OS.str(), /*RegionsWorthNote=*/{}});
87848816
}
87858817
};
87868818

test/SourceKit/Macros/macro_basic.swift

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ struct S3 {
107107
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=4:8 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=EXPAND %s
108108

109109
// EXPAND: source.edit.kind.active:
110-
// EXPAND-NEXT: 4:7-4:24 "(a + b, "a + b")"
110+
// EXPAND-NEXT: 4:7-4:24 (@__swiftmacro_9MacroUser13testStringify1a1bySi_SitF9stringifyfMf_.swift) "(a + b, "a + b")"
111111

112112
//##-- cursor-info at 'myTypeWrapper' position following @. We don't support
113113
// on the @ currently.
@@ -130,46 +130,51 @@ struct S3 {
130130
//##-- Refactoring expanding the attached macro
131131
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=21:2 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ATTACHED_EXPAND %s
132132
// ATTACHED_EXPAND: source.edit.kind.active:
133-
// ATTACHED_EXPAND: 23:3-23:3 "@accessViaStorage "
134-
// ATTACHED_EXPAND: source.edit.kind.active:
135-
// ATTACHED_EXPAND: 24:3-24:3 "@accessViaStorage "
136-
// ATTACHED_EXPAND: source.edit.kind.active:
137-
// ATTACHED_EXPAND: 22:11-22:11 "
138-
// ATTACHED_EXPAND: private var _storage = _Storage()
139-
// ATTACHED_EXPAND: source.edit.kind.active:
140-
// ATTACHED_EXPAND: 21:1-21:15 ""
133+
// ATTACHED_EXPAND-NEXT: 23:3-23:3 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMA_.swift) "@accessViaStorage "
134+
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
135+
// ATTACHED_EXPAND-NEXT: 24:3-24:3 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMA_.swift) "@accessViaStorage "
136+
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
137+
// ATTACHED_EXPAND-NEXT: 22:11-22:11 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMm_.swift) "
138+
// ATTACHED_EXPAND-NEXT: private var _storage = _Storage()
139+
// ATTACHED_EXPAND-NEXT: "
140+
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
141+
// ATTACHED_EXPAND-NEXT: 21:1-21:15 ""
141142

142143
//##-- Refactoring expanding the first accessor macro
143144
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=30:4 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ACCESSOR1_EXPAND %s
144145
// ACCESSOR1_EXPAND: source.edit.kind.active:
145-
// ACCESSOR1_EXPAND: 31:13-31:13 "{
146-
// ACCESSOR1_EXPAND: get { _storage.x }
147-
// ACCESSOR1_EXPAND: set { _storage.x = newValue }
148-
// ACCESSOR1_EXPAND: }"
149-
// ACCESSOR1_EXPAND: source.edit.kind.active:
150-
// ACCESSOR1_EXPAND: 30:3-30:20 ""
146+
// ACCESSOR1_EXPAND-NEXT: 31:13-31:13 (@__swiftmacro_9MacroUser2S2V1xSivp16accessViaStoragefMa_.swift) "{
147+
// ACCESSOR1_EXPAND-NEXT: get { _storage.x }
148+
// ACCESSOR1_EXPAND-EMPTY:
149+
// ACCESSOR1_EXPAND-NEXT: set { _storage.x = newValue }
150+
// ACCESSOR1_EXPAND-NEXT: }"
151+
// ACCESSOR1_EXPAND-NEXT: source.edit.kind.active:
152+
// ACCESSOR1_EXPAND-NEXT: 30:3-30:20 ""
151153

152154
//##-- Refactoring expanding the second accessor macro
153155
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=33:13 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ACCESSOR2_EXPAND %s
154156
// ACCESSOR2_EXPAND: source.edit.kind.active:
155-
// ACCESSOR2_EXPAND: 34:14-34:18 "{
156-
// ACCESSOR2_EXPAND: get { _storage.y }
157-
// ACCESSOR2_EXPAND: set { _storage.y = newValue }
158-
// ACCESSOR2_EXPAND: }"
159-
// ACCESSOR2_EXPAND: source.edit.kind.active:
160-
// ACCESSOR2_EXPAND: 33:3-33:20 ""
157+
// ACCESSOR2_EXPAND-NEXT: 34:14-34:18 (@__swiftmacro_9MacroUser2S2V1ySivp16accessViaStoragefMa_.swift) "{
158+
// ACCESSOR2_EXPAND-NEXT: get { _storage.y }
159+
// ACCESSOR2_EXPAND-EMPTY:
160+
// ACCESSOR2_EXPAND-NEXT: set { _storage.y = newValue }
161+
// ACCESSOR2_EXPAND-NEXT: }"
162+
// ACCESSOR2_EXPAND-NEXT: source.edit.kind.active:
163+
// ACCESSOR2_EXPAND-NEXT: 33:3-33:20 ""
161164

162165
//##-- Refactoring expanding the second accessor macro
163166
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=42:5 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=PEER_EXPAND %s
164167
// PEER_EXPAND: source.edit.kind.active:
165-
// PEER_EXPAND: 45:4-45:4 "
166-
// PEER_EXPAND: func f(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
167-
// PEER_EXPAND: Task {
168-
// PEER_EXPAND: completionHandler(await f(a: a, for: b, value))
169-
// PEER_EXPAND: }
170-
// PEER_EXPAND: }
171-
// PEER_EXPAND: source.edit.kind.active:
172-
// PEER_EXPAND: 42:3-42:24 ""
168+
// PEER_EXPAND-NEXT: 45:4-45:4 (@__swiftmacro_9MacroUser2S3V1f1a3for_SSSi_SSSdtYaF20addCompletionHandlerfMp_.swift) "
169+
// PEER_EXPAND-EMPTY:
170+
// PEER_EXPAND-NEXT: func f(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
171+
// PEER_EXPAND-NEXT: Task {
172+
// PEER_EXPAND-NEXT: completionHandler(await f(a: a, for: b, value))
173+
// PEER_EXPAND-NEXT: }
174+
// PEER_EXPAND-NEXT: }
175+
// PEER_EXPAND-NEXT: "
176+
// PEER_EXPAND-NEXT: source.edit.kind.active:
177+
// PEER_EXPAND-NEXT: 42:3-42:24 ""
173178

174179
//##-- Doc info, mostly just checking we don't crash because of the separate buffers
175180
// RUN: %sourcekitd-test -req=doc-info %s -- ${COMPILER_ARGS_WITHOUT_SOURCE[@]} | %FileCheck -check-prefix=DOCINFO %s

tools/SourceKit/include/SourceKit/Core/LangSupport.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,10 +708,16 @@ struct NoteRegion {
708708
};
709709

710710
struct Edit {
711+
/// If the edit is outside of the originally request source file, the path
712+
/// to the file it is editing.
713+
std::string Path;
711714
unsigned StartLine;
712715
unsigned StartColumn;
713716
unsigned EndLine;
714717
unsigned EndColumn;
718+
/// If the edit is actually a file (which could be generated/from an
719+
/// expansion), the name (or path) of that buffer.
720+
std::string BufferName;
715721
std::string NewText;
716722
SmallVector<NoteRegion, 2> RegionsWithNote;
717723
};

tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,8 +1287,9 @@ class RequestRefactoringEditConsumer::Implementation {
12871287
R.EndColumn,
12881288
R.ArgIndex};
12891289
});
1290-
return {Start.first, Start.second, End.first,
1291-
End.second, R.Text.str(), std::move(SubRanges)};
1290+
return {R.Path.str(), Start.first, Start.second,
1291+
End.first, End.second, R.BufferName.str(),
1292+
R.Text.str(), std::move(SubRanges)};
12921293
});
12931294
unsigned End = AllEdits.size();
12941295
StartEnds.emplace_back(Start, End);

tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,14 +2223,30 @@ static void printSyntacticRenameEdits(sourcekitd_variant_t Info,
22232223
for(unsigned j = 0, je = sourcekitd_variant_array_get_count(Edits);
22242224
j != je; ++j) {
22252225
OS << " "; // indent
2226+
22262227
sourcekitd_variant_t Edit = sourcekitd_variant_array_get_value(Edits, j);
2228+
2229+
StringRef Path(
2230+
sourcekitd_variant_dictionary_get_string(Edit, KeyFilePath));
2231+
if (!Path.empty()) {
2232+
OS << Path << " ";
2233+
}
2234+
22272235
int64_t Line = sourcekitd_variant_dictionary_get_int64(Edit, KeyLine);
22282236
int64_t Column = sourcekitd_variant_dictionary_get_int64(Edit, KeyColumn);
22292237
int64_t EndLine = sourcekitd_variant_dictionary_get_int64(Edit, KeyEndLine);
22302238
int64_t EndColumn = sourcekitd_variant_dictionary_get_int64(Edit, KeyEndColumn);
2231-
OS << Line << ':' << Column << '-' << EndLine << ':' << EndColumn << " \"";
2239+
OS << Line << ':' << Column << '-' << EndLine << ':' << EndColumn << " ";
2240+
2241+
StringRef BufferName(
2242+
sourcekitd_variant_dictionary_get_string(Edit, KeyBufferName));
2243+
if (!BufferName.empty()) {
2244+
OS << "(" << BufferName << ") ";
2245+
}
2246+
22322247
StringRef Text(sourcekitd_variant_dictionary_get_string(Edit, KeyText));
2233-
OS << Text << "\"\n";
2248+
OS << "\"" << Text << "\"\n";
2249+
22342250
sourcekitd_variant_t NoteRanges =
22352251
sourcekitd_variant_dictionary_get_value(Edit, KeyRangesWorthNote);
22362252
if (unsigned e = sourcekitd_variant_array_get_count(NoteRanges)) {

tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,10 +3675,16 @@ createCategorizedEditsResponse(const RequestResult<ArrayRef<CategorizedEdits>> &
36753675
auto Edits = Entry.setArray(KeyEdits);
36763676
for(auto E: TheEdit.Edits) {
36773677
auto Edit = Edits.appendDictionary();
3678+
if (!E.Path.empty()) {
3679+
Edit.set(KeyFilePath, E.Path);
3680+
}
36783681
Edit.set(KeyLine, E.StartLine);
36793682
Edit.set(KeyColumn, E.StartColumn);
36803683
Edit.set(KeyEndLine, E.EndLine);
36813684
Edit.set(KeyEndColumn, E.EndColumn);
3685+
if (!E.BufferName.empty()) {
3686+
Edit.set(KeyBufferName, E.BufferName);
3687+
}
36823688
Edit.set(KeyText, E.NewText);
36833689
if (!E.RegionsWithNote.empty()) {
36843690
auto Notes = Edit.setArray(KeyRangesWorthNote);

utils/gyb_sourcekit_support/UIDs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def __init__(self, internal_name, external_name):
202202
# in this time. For cancellation testing purposes.
203203
KEY('SimulateLongRequest', 'key.simulate_long_request'),
204204
KEY('IsSynthesized', 'key.is_synthesized'),
205+
KEY('BufferName', 'key.buffer_name')
205206
]
206207

207208

0 commit comments

Comments
 (0)