[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.
This commit is contained in:
Ben Barham
2023-02-17 18:48:33 -08:00
parent 6b5f4494d8
commit f7aaf02065
9 changed files with 137 additions and 49 deletions

View File

@@ -477,7 +477,7 @@ public:
class TextReplacementsRenamer : public Renamer {
llvm::StringSet<> &ReplaceTextContext;
std::vector<Replacement> Replacements;
SmallVector<Replacement> Replacements;
public:
const DeclNameViewer New;
@@ -571,7 +571,8 @@ private:
StringRef Text =
getReplacementText(ExistingLabel, RangeKind, OldLabel, NewLabel);
if (Text != ExistingLabel)
Replacements.push_back({LabelRange, Text, {}});
Replacements.push_back({/*Path=*/{}, LabelRange, /*BufferName=*/{}, Text,
/*RegionsWorthNote=*/{}});
}
void doRenameLabel(CharSourceRange Label, RefactoringRangeKind RangeKind,
@@ -582,7 +583,9 @@ private:
void doRenameBase(CharSourceRange Range, RefactoringRangeKind) override {
if (Old.base() != New.base())
Replacements.push_back({Range, registerText(New.base()), {}});
Replacements.push_back({/*Path=*/{}, Range, /*BufferName=*/{},
registerText(New.base()),
/*RegionsWorthNote=*/{}});
}
public:
@@ -595,9 +598,7 @@ public:
assert(Old.partsCount() == New.partsCount());
}
std::vector<Replacement> getReplacements() const {
return std::move(Replacements);
}
ArrayRef<Replacement> getReplacements() const { return Replacements; }
};
static const ValueDecl *getRelatedSystemDecl(const ValueDecl *VD) {
@@ -8688,7 +8689,37 @@ bool RefactoringActionExpandMacro::performChange() {
rewrittenBuffer = adjustMacroExpansionWhitespace(
generatedInfo->kind, rewrittenBuffer, scratchBuffer);
EditConsumer.accept(SM, originalSourceRange, rewrittenBuffer);
// `TheFile` is the file of the actual expansion site, where as
// `OriginalFile` is the possibly enclosing buffer. Concretely:
// ```
// // m.swift
// @AddMemberAttributes
// struct Foo {
// // --- expanded from @AddMemberAttributes eg. @_someBufferName ---
// @AddedAttribute
// // ---
// let someMember: Int
// }
// ```
//
// When expanding `AddedAttribute`, the expansion actually applies to the
// original source (`m.swift`) rather than the buffer of the expansion
// site (`@_someBufferName`). Thus, we need to include the path to the
// original source as well. Note that this path could itself be another
// expansion.
SourceFile *originalFile =
MD->getSourceFileContainingLocation(originalSourceRange.getStart());
StringRef originalPath;
if (originalFile->getBufferID().hasValue() &&
TheFile->getBufferID() != originalFile->getBufferID()) {
originalPath = SM.getIdentifierForBuffer(*originalFile->getBufferID());
}
EditConsumer.accept(SM, {originalPath,
originalSourceRange,
SM.getIdentifierForBuffer(bufferID),
rewrittenBuffer,
{}});
if (generatedInfo->attachedMacroCustomAttr && !attachedMacroAttr)
attachedMacroAttr = generatedInfo->attachedMacroCustomAttr;
@@ -8780,7 +8811,8 @@ struct swift::ide::FindRenameRangesAnnotatingConsumer::Implementation {
if (Range.Index.has_value())
OS << " index=" << *Range.Index;
OS << ">" << Range.Range.str() << "</" << Tag << ">";
pRewriter->accept(SM, {Range.Range, OS.str(), {}});
pRewriter->accept(SM, {/*Path=*/{}, Range.Range, /*BufferName=*/{},
OS.str(), /*RegionsWorthNote=*/{}});
}
};