mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[refactoring] Upstreaming the implementation for Swift local refactoring (#11568)
[refactoring] Upstreaming the implementation for Swift local refactoring
This commit is contained in:
committed by
GitHub
parent
9edef031e4
commit
60a91bb736
@@ -27,6 +27,7 @@
|
||||
#include "swift/IDE/CommentConversion.h"
|
||||
#include "swift/IDE/ModuleInterfacePrinting.h"
|
||||
#include "swift/IDE/Utils.h"
|
||||
#include "swift/IDE/Refactoring.h"
|
||||
#include "swift/Markup/XMLUtils.h"
|
||||
#include "swift/Sema/IDETypeChecking.h"
|
||||
|
||||
@@ -614,6 +615,51 @@ static bool passCursorInfoForModule(ModuleEntity Mod,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
collectAvailableRenameInfo(const ValueDecl *VD,
|
||||
std::vector<UIdent> &RefactoringIds,
|
||||
DelayedStringRetriever &RefactroingNameOS,
|
||||
DelayedStringRetriever &RefactoringReasonOS) {
|
||||
std::vector<ide::RenameAvailabiliyInfo> Scratch;
|
||||
for (auto Info : ide::collectRenameAvailabilityInfo(VD, Scratch)) {
|
||||
RefactoringIds.push_back(SwiftLangSupport::
|
||||
getUIDForRefactoringKind(Info.Kind));
|
||||
RefactroingNameOS.startPiece();
|
||||
RefactroingNameOS << ide::getDescriptiveRefactoringKindName(Info.Kind);
|
||||
RefactroingNameOS.endPiece();
|
||||
RefactoringReasonOS.startPiece();
|
||||
RefactoringReasonOS << ide::getDescriptiveRenameUnavailableReason(Info.
|
||||
AvailableKind);
|
||||
RefactoringReasonOS.endPiece();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
serializeRefactoringKinds(ArrayRef<RefactoringKind> AllKinds,
|
||||
std::vector<UIdent> &RefactoringIds,
|
||||
DelayedStringRetriever &RefactroingNameOS,
|
||||
DelayedStringRetriever &RefactoringReasonOS) {
|
||||
for (auto Kind : AllKinds) {
|
||||
RefactoringIds.push_back(SwiftLangSupport::getUIDForRefactoringKind(Kind));
|
||||
RefactroingNameOS.startPiece();
|
||||
RefactroingNameOS << ide::getDescriptiveRefactoringKindName(Kind);
|
||||
RefactroingNameOS.endPiece();
|
||||
RefactoringReasonOS.startPiece();
|
||||
RefactoringReasonOS.endPiece();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
collectAvailableRefactoringsOtherThanRename(SourceFile *SF, SemaToken Tok,
|
||||
std::vector<UIdent> &RefactoringIds,
|
||||
DelayedStringRetriever &RefactroingNameOS,
|
||||
DelayedStringRetriever &RefactoringReasonOS) {
|
||||
std::vector<RefactoringKind> Scratch;
|
||||
serializeRefactoringKinds(collectAvailableRefactorings(SF, Tok, Scratch,
|
||||
/*ExcludeRename*/true), RefactoringIds, RefactroingNameOS,
|
||||
RefactoringReasonOS);
|
||||
}
|
||||
|
||||
static Optional<unsigned>
|
||||
getParamParentNameOffset(const ValueDecl *VD, SourceLoc Cursor) {
|
||||
if (Cursor.isInvalid())
|
||||
@@ -644,13 +690,17 @@ getParamParentNameOffset(const ValueDecl *VD, SourceLoc Cursor) {
|
||||
}
|
||||
|
||||
/// Returns true for failure to resolve.
|
||||
static bool passCursorInfoForDecl(const ValueDecl *VD,
|
||||
static bool passCursorInfoForDecl(SourceFile* SF,
|
||||
const ValueDecl *VD,
|
||||
const ModuleDecl *MainModule,
|
||||
const Type Ty,
|
||||
const Type ContainerTy,
|
||||
bool IsRef,
|
||||
bool RetrieveRefactoring,
|
||||
SemaToken TheTok,
|
||||
Optional<unsigned> OrigBufferID,
|
||||
SourceLoc CursorLoc,
|
||||
ArrayRef<RefactoringInfo> KownRefactoringInfoFromRange,
|
||||
SwiftLangSupport &Lang,
|
||||
const CompilerInvocation &Invok,
|
||||
ArrayRef<ImmutableTextSnapshotRef> PreviousASTSnaps,
|
||||
@@ -756,6 +806,16 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
|
||||
}
|
||||
unsigned LocalizationEnd = SS.size();
|
||||
|
||||
std::vector<UIdent> RefactoringIds;
|
||||
DelayedStringRetriever RefactoringNameOS(SS);
|
||||
DelayedStringRetriever RefactoringReasonOS(SS);
|
||||
if (RetrieveRefactoring) {
|
||||
collectAvailableRenameInfo(VD, RefactoringIds, RefactoringNameOS,
|
||||
RefactoringReasonOS);
|
||||
collectAvailableRefactoringsOtherThanRename(SF, TheTok, RefactoringIds,
|
||||
RefactoringNameOS, RefactoringReasonOS);
|
||||
}
|
||||
|
||||
DelayedStringRetriever OverUSRsStream(SS);
|
||||
|
||||
ide::walkOverriddenDecls(VD,
|
||||
@@ -861,6 +921,17 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
|
||||
SmallVector<StringRef, 4> AnnotatedRelatedDecls;
|
||||
RelDeclsStream.retrieve([&](StringRef S) { AnnotatedRelatedDecls.push_back(S); });
|
||||
|
||||
SmallVector<RefactoringInfo, 4> RefactoringInfoBuffer;
|
||||
for (unsigned I = 0, N = RefactoringIds.size(); I < N; I ++) {
|
||||
RefactoringInfoBuffer.push_back({RefactoringIds[I], RefactoringNameOS[I],
|
||||
RefactoringReasonOS[I]});
|
||||
}
|
||||
|
||||
// Add available refactoring inheritted from range.
|
||||
RefactoringInfoBuffer.insert(RefactoringInfoBuffer.end(),
|
||||
KownRefactoringInfoFromRange.begin(),
|
||||
KownRefactoringInfoFromRange.end());
|
||||
|
||||
bool IsSystem = VD->getModuleContext()->isSystemModule();
|
||||
std::string TypeInterface;
|
||||
|
||||
@@ -884,6 +955,7 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
|
||||
Info.LocalizationKey = LocalizationKey;
|
||||
Info.IsSystem = IsSystem;
|
||||
Info.TypeInterface = StringRef();
|
||||
Info.AvailableActions = llvm::makeArrayRef(RefactoringInfoBuffer);
|
||||
Info.ParentNameOffset = getParamParentNameOffset(VD, CursorLoc);
|
||||
Receiver(Info);
|
||||
return false;
|
||||
@@ -1139,10 +1211,10 @@ static void resolveCursor(SwiftLangSupport &Lang,
|
||||
void handlePrimaryAST(ASTUnitRef AstUnit) override {
|
||||
auto &CompIns = AstUnit->getCompilerInstance();
|
||||
ModuleDecl *MainModule = CompIns.getMainModule();
|
||||
|
||||
SourceManager &SM = CompIns.getSourceMgr();
|
||||
unsigned BufferID = AstUnit->getPrimarySourceFile().getBufferID().getValue();
|
||||
SourceLoc Loc =
|
||||
Lexer::getLocForStartOfToken(CompIns.getSourceMgr(), BufferID, Offset);
|
||||
Lexer::getLocForStartOfToken(SM, BufferID, Offset);
|
||||
if (Loc.isInvalid()) {
|
||||
Receiver({});
|
||||
return;
|
||||
@@ -1157,13 +1229,59 @@ static void resolveCursor(SwiftLangSupport &Lang,
|
||||
{std::make_pair("Offset", std::to_string(Offset))});
|
||||
}
|
||||
|
||||
// Sanitize length.
|
||||
if (Length) {
|
||||
SourceLoc TokEnd = Lexer::getLocForEndOfToken(SM, Loc);
|
||||
SourceLoc EndLoc = SM.getLocForOffset(BufferID, Offset + Length);
|
||||
|
||||
// If TokEnd is not before the given EndLoc, the EndLoc contains no
|
||||
// more stuff than this token, so set the length to 0.
|
||||
if (SM.isBeforeInBuffer(EndLoc, TokEnd) || TokEnd == EndLoc)
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
// Retrive relevant actions on the code under selection.
|
||||
std::vector<RefactoringInfo> AvailableRefactorings;
|
||||
if (Actionables && Length) {
|
||||
std::vector<RefactoringKind> Scratch;
|
||||
RangeConfig Range;
|
||||
Range.BufferId = BufferID;
|
||||
auto Pair = SM.getLineAndColumn(Loc);
|
||||
Range.Line = Pair.first;
|
||||
Range.Column = Pair.second;
|
||||
Range.Length = Length;
|
||||
bool RangeStartMayNeedRename = false;
|
||||
for (RefactoringKind Kind :
|
||||
collectAvailableRefactorings(&AstUnit->getPrimarySourceFile(),
|
||||
Range, RangeStartMayNeedRename, Scratch, {})) {
|
||||
AvailableRefactorings.push_back({
|
||||
SwiftLangSupport::getUIDForRefactoringKind(Kind),
|
||||
getDescriptiveRefactoringKindName(Kind),
|
||||
/*UnavailableReason*/ StringRef()
|
||||
});
|
||||
}
|
||||
if (!RangeStartMayNeedRename) {
|
||||
CursorInfo Info;
|
||||
|
||||
// FIXME: This Kind does not mean anything.
|
||||
Info.Kind = SwiftLangSupport::getUIDForModuleRef();
|
||||
Info.AvailableActions = llvm::makeArrayRef(AvailableRefactorings);
|
||||
|
||||
// If Length is given, then the cursor-info request should only about
|
||||
// collecting available refactorings for the range.
|
||||
Receiver(Info);
|
||||
return;
|
||||
}
|
||||
// If the range start may need rename, we fall back to a regular cursor
|
||||
// info request to get the available rename kinds.
|
||||
}
|
||||
|
||||
SemaLocResolver Resolver(AstUnit->getPrimarySourceFile());
|
||||
SemaToken SemaTok = Resolver.resolve(Loc);
|
||||
if (SemaTok.isInvalid()) {
|
||||
Receiver({});
|
||||
return;
|
||||
}
|
||||
|
||||
CompilerInvocation CompInvok;
|
||||
ASTInvok->applyTo(CompInvok);
|
||||
|
||||
@@ -1174,11 +1292,15 @@ static void resolveCursor(SwiftLangSupport &Lang,
|
||||
return;
|
||||
case SemaTokenKind::ValueRef: {
|
||||
ValueDecl *VD = SemaTok.CtorTyRef ? SemaTok.CtorTyRef : SemaTok.ValueD;
|
||||
bool Failed = passCursorInfoForDecl(VD, MainModule,
|
||||
bool Failed = passCursorInfoForDecl(&AstUnit->getPrimarySourceFile(),
|
||||
VD, MainModule,
|
||||
SemaTok.ContainerType,
|
||||
SemaTok.ContainerType,
|
||||
SemaTok.IsRef, BufferID, Loc, Lang,
|
||||
CompInvok, getPreviousASTSnaps(),
|
||||
SemaTok.IsRef, Actionables, SemaTok,
|
||||
BufferID, Loc,
|
||||
AvailableRefactorings,
|
||||
Lang, CompInvok,
|
||||
getPreviousASTSnaps(),
|
||||
Receiver);
|
||||
if (Failed) {
|
||||
if (!getPreviousASTSnaps().empty()) {
|
||||
@@ -1194,6 +1316,29 @@ static void resolveCursor(SwiftLangSupport &Lang,
|
||||
}
|
||||
case SemaTokenKind::ExprStart:
|
||||
case SemaTokenKind::StmtStart: {
|
||||
if (Actionables) {
|
||||
SmallString<64> SS;
|
||||
std::vector<UIdent> RefactoringIds;
|
||||
DelayedStringRetriever NameRetriever(SS);
|
||||
DelayedStringRetriever ReasonRetriever(SS);
|
||||
collectAvailableRefactoringsOtherThanRename(
|
||||
&AstUnit->getPrimarySourceFile(), SemaTok, RefactoringIds,
|
||||
NameRetriever, ReasonRetriever);
|
||||
if (auto Size = RefactoringIds.size()) {
|
||||
CursorInfo Info;
|
||||
|
||||
// FIXME: This Kind does not mean anything.
|
||||
Info.Kind = SwiftLangSupport::getUIDForModuleRef();
|
||||
for (unsigned I = 0; I < Size; I ++) {
|
||||
AvailableRefactorings.push_back({RefactoringIds[I],
|
||||
NameRetriever[I], ReasonRetriever[I]});
|
||||
}
|
||||
Info.AvailableActions = llvm::makeArrayRef(AvailableRefactorings);
|
||||
Receiver(Info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Receiver({});
|
||||
return;
|
||||
}
|
||||
@@ -1426,7 +1571,7 @@ void SwiftLangSupport::getCursorInfo(
|
||||
SwiftArgs, OpArgs);
|
||||
}
|
||||
|
||||
IFaceGenRef->accessASTAsync([this, IFaceGenRef, Offset, Receiver] {
|
||||
IFaceGenRef->accessASTAsync([this, IFaceGenRef, Offset, Actionables, Receiver] {
|
||||
SwiftInterfaceGenContext::ResolvedEntity Entity;
|
||||
Entity = IFaceGenRef->resolveEntityForOffset(Offset);
|
||||
if (Entity.isResolved()) {
|
||||
@@ -1439,8 +1584,10 @@ void SwiftLangSupport::getCursorInfo(
|
||||
// FIXME: Should pass the main module for the interface but currently
|
||||
// it's not necessary.
|
||||
passCursorInfoForDecl(
|
||||
Entity.Dcl, /*MainModule*/ nullptr, Type(), Type(), Entity.IsRef,
|
||||
/*OrigBufferID=*/None, SourceLoc(), *this, Invok, {}, Receiver);
|
||||
/*SourceFile*/nullptr, Entity.Dcl, /*MainModule*/ nullptr, Type(),
|
||||
Type(), Entity.IsRef, Actionables, SemaToken(),
|
||||
/*OrigBufferID=*/None, SourceLoc(),
|
||||
{}, *this, Invok, {}, Receiver);
|
||||
}
|
||||
} else {
|
||||
Receiver({});
|
||||
@@ -1627,9 +1774,10 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
|
||||
selfTy = VD->getInnermostDeclContext()->mapTypeIntoContext(selfTy);
|
||||
}
|
||||
bool Failed =
|
||||
passCursorInfoForDecl(VD, MainModule, selfTy, Type(),
|
||||
/*IsRef=*/false, BufferID, SourceLoc(), Lang,
|
||||
CompInvok, PreviousASTSnaps, Receiver);
|
||||
passCursorInfoForDecl(/*SourceFile*/nullptr, VD, MainModule, selfTy,
|
||||
Type(), /*IsRef=*/false, false, SemaToken(),
|
||||
BufferID, SourceLoc(), {}, Lang, CompInvok,
|
||||
PreviousASTSnaps, Receiver);
|
||||
if (Failed) {
|
||||
if (!PreviousASTSnaps.empty()) {
|
||||
// Attempt again using the up-to-date AST.
|
||||
@@ -1854,3 +2002,70 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
|
||||
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
|
||||
ASTMgr->processASTAsync(Invok, std::move(Consumer), Once);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SwiftLangSupport::semanticRefactoring
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static RefactoringKind getIDERefactoringKind(SemanticRefactoringInfo Info) {
|
||||
switch(Info.Kind) {
|
||||
case SemanticRefactoringKind::None: return RefactoringKind::None;
|
||||
#define SEMANTIC_REFACTORING(KIND, NAME, ID) \
|
||||
case SemanticRefactoringKind::KIND: return RefactoringKind::KIND;
|
||||
#include "swift/IDE/RefactoringKinds.def"
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftLangSupport::
|
||||
semanticRefactoring(StringRef Filename, SemanticRefactoringInfo Info,
|
||||
ArrayRef<const char*> Args,
|
||||
CategorizedEditsReceiver Receiver) {
|
||||
std::string Error;
|
||||
SwiftInvocationRef Invok = ASTMgr->getInvocation(Args, Filename, Error);
|
||||
if (!Invok) {
|
||||
// FIXME: Report it as failed request.
|
||||
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
|
||||
Receiver({}, Error);
|
||||
return;
|
||||
}
|
||||
assert(Invok);
|
||||
|
||||
class SemaRefactoringConsumer : public SwiftASTConsumer {
|
||||
SemanticRefactoringInfo Info;
|
||||
CategorizedEditsReceiver Receiver;
|
||||
|
||||
public:
|
||||
SemaRefactoringConsumer(SemanticRefactoringInfo Info,
|
||||
CategorizedEditsReceiver Receiver) : Info(Info),
|
||||
Receiver(std::move(Receiver)) {}
|
||||
|
||||
void handlePrimaryAST(ASTUnitRef AstUnit) override {
|
||||
auto &CompIns = AstUnit->getCompilerInstance();
|
||||
ModuleDecl *MainModule = CompIns.getMainModule();
|
||||
RefactoringOptions Opts(getIDERefactoringKind(Info));
|
||||
Opts.Range.BufferId = AstUnit->getPrimarySourceFile().getBufferID().
|
||||
getValue();
|
||||
Opts.Range.Line = Info.Line;
|
||||
Opts.Range.Column = Info.Column;
|
||||
Opts.Range.Length = Info.Length;
|
||||
Opts.PreferredName = Info.PreferredName;
|
||||
|
||||
RequestRefactoringEditConsumer EditConsumer(Receiver);
|
||||
refactorSwiftModule(MainModule, Opts, EditConsumer, EditConsumer);
|
||||
}
|
||||
|
||||
void cancelled() override {
|
||||
Receiver({}, "The refactoring is canceled.");
|
||||
}
|
||||
|
||||
void failed(StringRef Error) override {
|
||||
Receiver({}, Error);
|
||||
}
|
||||
};
|
||||
|
||||
auto Consumer = std::make_shared<SemaRefactoringConsumer>(Info, Receiver);
|
||||
/// FIXME: When request cancellation is implemented and Xcode adopts it,
|
||||
/// don't use 'OncePerASTToken'.
|
||||
static const char OncePerASTToken = 0;
|
||||
getASTManager().processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user