Skip to content

Commit 277674a

Browse files
authored
Merge pull request #64298 from bnbarham/fix-shorthand-rename
[SourceKit] Merge local refactoring implementations
2 parents b3f54e5 + d2de8ed commit 277674a

File tree

7 files changed

+187
-166
lines changed

7 files changed

+187
-166
lines changed

include/swift/AST/DiagnosticsRefactoring.def

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,19 @@ ERROR(arity_mismatch, none, "the given new name '%0' does not match the arity of
3232

3333
ERROR(name_not_functionlike, none, "the 'call' name usage cannot be used with a non-function-like name '%0'", (StringRef))
3434

35-
ERROR(unresolved_location, none, "cannot resolve location as name", ())
35+
ERROR(unresolved_location, none, "cannot rename due to unresolved location", ())
3636

3737
ERROR(location_module_mismatch, none, "given location does not belong to module '%0'", (StringRef))
3838

39-
ERROR(value_decl_no_loc, none, "value decl '%0' has no declaration location", (DeclName))
39+
ERROR(value_decl_no_loc, none, "cannot rename %0 as it has no declaration location", (DeclName))
40+
41+
ERROR(decl_is_system_symbol, none, "cannot rename system symbol %0", (DeclName))
42+
43+
ERROR(decl_has_no_name, none, "cannot rename as no declaration name was found", ())
44+
45+
ERROR(decl_no_accessibility, none, "cannot rename as accessibility could not be determined", ())
46+
47+
ERROR(decl_from_clang, none, "cannot rename a Clang symbol from its Swift reference", ())
4048

4149
ERROR(value_decl_referenced_out_of_range, none, "value decl '%0' is referenced out of range", (DeclName))
4250

include/swift/Refactoring/Refactoring.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,8 @@ struct RenameRefInfo {
148148
bool IsArgLabel; ///< Whether Loc is on an arg label, rather than base name.
149149
};
150150

151-
void collectRenameAvailabilityInfo(
152-
const ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
153-
llvm::SmallVectorImpl<RenameAvailabilityInfo> &Infos);
151+
Optional<RenameAvailabilityInfo>
152+
renameAvailabilityInfo(const ValueDecl *VD, Optional<RenameRefInfo> RefInfo);
154153

155154
} // namespace ide
156155
} // namespace swift

lib/Refactoring/Refactoring.cpp

Lines changed: 121 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -625,29 +625,54 @@ static const ValueDecl *getRelatedSystemDecl(const ValueDecl *VD) {
625625
return nullptr;
626626
}
627627

628-
static Optional<RefactoringKind>
629-
getAvailableRenameForDecl(const ValueDecl *VD,
630-
Optional<RenameRefInfo> RefInfo) {
631-
SmallVector<RenameAvailabilityInfo, 2> Infos;
632-
collectRenameAvailabilityInfo(VD, RefInfo, Infos);
633-
for (auto &Info : Infos) {
634-
if (Info.AvailableKind == RenameAvailableKind::Available)
635-
return Info.Kind;
628+
struct RenameInfo {
629+
ValueDecl *VD;
630+
RenameAvailabilityInfo Availability;
631+
};
632+
633+
/// Given a cursor, return the decl and its rename availability. \c None if
634+
/// the cursor did not resolve to a decl or it resolved to a decl that we do
635+
/// not allow renaming on.
636+
static Optional<RenameInfo> getRenameInfo(ResolvedCursorInfoPtr cursorInfo) {
637+
auto valueCursor = dyn_cast<ResolvedValueRefCursorInfo>(cursorInfo);
638+
if (!valueCursor)
639+
return None;
640+
641+
ValueDecl *VD = valueCursor->typeOrValue();
642+
if (!VD)
643+
return None;
644+
645+
Optional<RenameRefInfo> refInfo;
646+
if (!valueCursor->getShorthandShadowedDecls().empty()) {
647+
// Find the outermost decl for a shorthand if let/closure capture
648+
VD = valueCursor->getShorthandShadowedDecls().back();
649+
} else if (valueCursor->isRef()) {
650+
refInfo = {valueCursor->getSourceFile(), valueCursor->getLoc(),
651+
valueCursor->isKeywordArgument()};
636652
}
637-
return None;
653+
654+
Optional<RenameAvailabilityInfo> info = renameAvailabilityInfo(VD, refInfo);
655+
if (!info)
656+
return None;
657+
658+
return RenameInfo{VD, *info};
638659
}
639660

640661
class RenameRangeCollector : public IndexDataConsumer {
641662
public:
642663
RenameRangeCollector(StringRef USR, StringRef newName)
643-
: USR(USR.str()), newName(newName.str()) {}
664+
: USR(USR), newName(newName) {}
644665

645666
RenameRangeCollector(const ValueDecl *D, StringRef newName)
646-
: newName(newName.str()) {
647-
llvm::raw_string_ostream OS(USR);
667+
: newName(newName) {
668+
SmallString<64> SS;
669+
llvm::raw_svector_ostream OS(SS);
648670
printValueDeclUSR(D, OS);
671+
USR = stringStorage.copyString(SS.str());
649672
}
650673

674+
RenameRangeCollector(RenameRangeCollector &&collector) = default;
675+
651676
ArrayRef<RenameLoc> results() const { return locations; }
652677

653678
private:
@@ -689,8 +714,8 @@ class RenameRangeCollector : public IndexDataConsumer {
689714
StringRef NewName);
690715

691716
private:
692-
std::string USR;
693-
std::string newName;
717+
StringRef USR;
718+
StringRef newName;
694719
StringScratchSpace stringStorage;
695720
std::vector<RenameLoc> locations;
696721
};
@@ -845,29 +870,14 @@ class RefactoringAction##KIND: public RangeBasedRefactoringAction { \
845870

846871
bool RefactoringActionLocalRename::isApplicable(
847872
ResolvedCursorInfoPtr CursorInfo, DiagnosticEngine &Diag) {
848-
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
849-
if (!ValueRefInfo)
850-
return false;
851-
852-
Optional<RenameRefInfo> RefInfo;
853-
if (ValueRefInfo->isRef())
854-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
855-
ValueRefInfo->isKeywordArgument()};
856-
857-
auto RenameOp = getAvailableRenameForDecl(ValueRefInfo->getValueD(), RefInfo);
858-
return RenameOp.has_value() &&
859-
RenameOp.value() == RefactoringKind::LocalRename;
873+
Optional<RenameInfo> Info = getRenameInfo(CursorInfo);
874+
return Info &&
875+
Info->Availability.AvailableKind == RenameAvailableKind::Available &&
876+
Info->Availability.Kind == RefactoringKind::LocalRename;
860877
}
861878

862-
static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
863-
DiagnosticEngine &Diags,
879+
static void analyzeRenameScope(ValueDecl *VD,
864880
SmallVectorImpl<DeclContext *> &Scopes) {
865-
Scopes.clear();
866-
if (!getAvailableRenameForDecl(VD, RefInfo).has_value()) {
867-
Diags.diagnose(SourceLoc(), diag::value_decl_no_loc, VD->getName());
868-
return;
869-
}
870-
871881
auto *Scope = VD->getDeclContext();
872882
// There may be sibling decls that the renamed symbol is visible from.
873883
switch (Scope->getContextKind()) {
@@ -892,6 +902,53 @@ static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
892902
Scopes.push_back(Scope);
893903
}
894904

905+
static Optional<RenameRangeCollector> localRenames(SourceFile *SF,
906+
SourceLoc startLoc,
907+
StringRef preferredName,
908+
DiagnosticEngine &diags) {
909+
auto cursorInfo =
910+
evaluateOrDefault(SF->getASTContext().evaluator,
911+
CursorInfoRequest{CursorInfoOwner(SF, startLoc)},
912+
new ResolvedCursorInfo());
913+
914+
Optional<RenameInfo> info = getRenameInfo(cursorInfo);
915+
if (!info) {
916+
diags.diagnose(startLoc, diag::unresolved_location);
917+
return None;
918+
}
919+
920+
switch (info->Availability.AvailableKind) {
921+
case RenameAvailableKind::Available:
922+
break;
923+
case RenameAvailableKind::Unavailable_system_symbol:
924+
diags.diagnose(startLoc, diag::decl_is_system_symbol, info->VD->getName());
925+
return None;
926+
case RenameAvailableKind::Unavailable_has_no_location:
927+
diags.diagnose(startLoc, diag::value_decl_no_loc, info->VD->getName());
928+
return None;
929+
case RenameAvailableKind::Unavailable_has_no_name:
930+
diags.diagnose(startLoc, diag::decl_has_no_name);
931+
return None;
932+
case RenameAvailableKind::Unavailable_has_no_accessibility:
933+
diags.diagnose(startLoc, diag::decl_no_accessibility);
934+
return None;
935+
case RenameAvailableKind::Unavailable_decl_from_clang:
936+
diags.diagnose(startLoc, diag::decl_from_clang);
937+
return None;
938+
}
939+
940+
SmallVector<DeclContext *, 8> scopes;
941+
analyzeRenameScope(info->VD, scopes);
942+
if (scopes.empty())
943+
return None;
944+
945+
RenameRangeCollector rangeCollector(info->VD, preferredName);
946+
for (DeclContext *DC : scopes)
947+
indexDeclContext(DC, rangeCollector);
948+
949+
return rangeCollector;
950+
}
951+
895952
bool RefactoringActionLocalRename::performChange() {
896953
if (StartLoc.isInvalid()) {
897954
DiagEngine.diagnose(SourceLoc(), diag::invalid_location);
@@ -906,40 +963,16 @@ bool RefactoringActionLocalRename::performChange() {
906963
MD->getNameStr());
907964
return true;
908965
}
909-
CursorInfo =
910-
evaluateOrDefault(TheFile->getASTContext().evaluator,
911-
CursorInfoRequest{CursorInfoOwner(TheFile, StartLoc)},
912-
new ResolvedCursorInfo());
913-
auto ValueRefCursorInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
914-
if (ValueRefCursorInfo && ValueRefCursorInfo->getValueD()) {
915-
ValueDecl *VD = ValueRefCursorInfo->typeOrValue();
916-
// The index always uses the outermost shadow for references
917-
if (!ValueRefCursorInfo->getShorthandShadowedDecls().empty()) {
918-
VD = ValueRefCursorInfo->getShorthandShadowedDecls().back();
919-
}
920-
921-
SmallVector<DeclContext *, 8> Scopes;
922-
923-
Optional<RenameRefInfo> RefInfo;
924-
if (ValueRefCursorInfo->isRef())
925-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
926-
ValueRefCursorInfo->isKeywordArgument()};
927966

928-
analyzeRenameScope(VD, RefInfo, DiagEngine, Scopes);
929-
if (Scopes.empty())
930-
return true;
931-
RenameRangeCollector rangeCollector(VD, PreferredName);
932-
for (DeclContext *DC : Scopes)
933-
indexDeclContext(DC, rangeCollector);
934-
935-
auto consumers = DiagEngine.takeConsumers();
936-
assert(consumers.size() == 1);
937-
return syntacticRename(TheFile, rangeCollector.results(), EditConsumer,
938-
*consumers[0]);
939-
} else {
940-
DiagEngine.diagnose(StartLoc, diag::unresolved_location);
967+
Optional<RenameRangeCollector> rangeCollector =
968+
localRenames(TheFile, StartLoc, PreferredName, DiagEngine);
969+
if (!rangeCollector)
941970
return true;
942-
}
971+
972+
auto consumers = DiagEngine.takeConsumers();
973+
assert(consumers.size() == 1);
974+
return syntacticRename(TheFile, rangeCollector->results(), EditConsumer,
975+
*consumers[0]);
943976
}
944977

945978
StringRef getDefaultPreferredName(RefactoringKind Kind) {
@@ -8805,9 +8838,9 @@ accept(SourceManager &SM, RegionType RegionType,
88058838
}
88068839
}
88078840

8808-
void swift::ide::collectRenameAvailabilityInfo(
8809-
const ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
8810-
SmallVectorImpl<RenameAvailabilityInfo> &Infos) {
8841+
Optional<RenameAvailabilityInfo>
8842+
swift::ide::renameAvailabilityInfo(const ValueDecl *VD,
8843+
Optional<RenameRefInfo> RefInfo) {
88118844
RenameAvailableKind AvailKind = RenameAvailableKind::Available;
88128845
if (getRelatedSystemDecl(VD)){
88138846
AvailKind = RenameAvailableKind::Unavailable_system_symbol;
@@ -8822,22 +8855,22 @@ void swift::ide::collectRenameAvailabilityInfo(
88228855
if (isa<AbstractFunctionDecl>(VD)) {
88238856
// Disallow renaming accessors.
88248857
if (isa<AccessorDecl>(VD))
8825-
return;
8858+
return None;
88268859

88278860
// Disallow renaming deinit.
88288861
if (isa<DestructorDecl>(VD))
8829-
return;
8862+
return None;
88308863

88318864
// Disallow renaming init with no arguments.
88328865
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
88338866
if (!CD->getParameters()->size())
8834-
return;
8867+
return None;
88358868

88368869
if (RefInfo && !RefInfo->IsArgLabel) {
88378870
NameMatcher Matcher(*(RefInfo->SF));
88388871
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88398872
if (Resolved.LabelRanges.empty())
8840-
return;
8873+
return None;
88418874
}
88428875
}
88438876

@@ -8847,30 +8880,27 @@ void swift::ide::collectRenameAvailabilityInfo(
88478880
// whether it's an instance method, so we do the same here for now.
88488881
if (FD->getBaseIdentifier() == FD->getASTContext().Id_callAsFunction) {
88498882
if (!FD->getParameters()->size())
8850-
return;
8883+
return None;
88518884

88528885
if (RefInfo && !RefInfo->IsArgLabel) {
88538886
NameMatcher Matcher(*(RefInfo->SF));
88548887
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88558888
if (Resolved.LabelRanges.empty())
8856-
return;
8889+
return None;
88578890
}
88588891
}
88598892
}
88608893
}
88618894

88628895
// Always return local rename for parameters.
88638896
// FIXME: if the cursor is on the argument, we should return global rename.
8864-
if (isa<ParamDecl>(VD)) {
8865-
Infos.emplace_back(RefactoringKind::LocalRename, AvailKind);
8866-
return;
8867-
}
8897+
if (isa<ParamDecl>(VD))
8898+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
88688899

88698900
// If the indexer considers VD a global symbol, then we apply global rename.
88708901
if (index::isLocalSymbol(VD))
8871-
Infos.emplace_back(RefactoringKind::LocalRename, AvailKind);
8872-
else
8873-
Infos.emplace_back(RefactoringKind::GlobalRename, AvailKind);
8902+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
8903+
return RenameAvailabilityInfo{RefactoringKind::GlobalRename, AvailKind};
88748904
}
88758905

88768906
void swift::ide::collectAvailableRefactorings(
@@ -8880,27 +8910,10 @@ void swift::ide::collectAvailableRefactorings(
88808910
CursorInfo->getSourceFile()->getASTContext().SourceMgr);
88818911

88828912
if (!ExcludeRename) {
8883-
if (RefactoringActionLocalRename::isApplicable(CursorInfo, DiagEngine))
8884-
Kinds.push_back(RefactoringKind::LocalRename);
8885-
8886-
switch (CursorInfo->getKind()) {
8887-
case CursorInfoKind::ModuleRef:
8888-
case CursorInfoKind::Invalid:
8889-
case CursorInfoKind::StmtStart:
8890-
case CursorInfoKind::ExprStart:
8891-
break;
8892-
case CursorInfoKind::ValueRef: {
8893-
auto ValueRefInfo = cast<ResolvedValueRefCursorInfo>(CursorInfo);
8894-
Optional<RenameRefInfo> RefInfo;
8895-
if (ValueRefInfo->isRef())
8896-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
8897-
ValueRefInfo->isKeywordArgument()};
8898-
auto RenameOp =
8899-
getAvailableRenameForDecl(ValueRefInfo->getValueD(), RefInfo);
8900-
if (RenameOp.has_value() &&
8901-
RenameOp.value() == RefactoringKind::GlobalRename)
8902-
Kinds.push_back(RenameOp.value());
8903-
}
8913+
if (auto Info = getRenameInfo(CursorInfo)) {
8914+
if (Info->Availability.AvailableKind == RenameAvailableKind::Available) {
8915+
Kinds.push_back(Info->Availability.Kind);
8916+
}
89048917
}
89058918
}
89068919

@@ -9106,29 +9119,11 @@ int swift::ide::findLocalRenameRanges(
91069119
Diags.addConsumer(DiagConsumer);
91079120

91089121
auto StartLoc = Lexer::getLocForStartOfToken(SM, Range.getStart(SM));
9109-
ResolvedCursorInfoPtr CursorInfo =
9110-
evaluateOrDefault(SF->getASTContext().evaluator,
9111-
CursorInfoRequest{CursorInfoOwner(SF, StartLoc)},
9112-
new ResolvedCursorInfo());
9113-
auto ValueRefCursorInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
9114-
if (!ValueRefCursorInfo || !ValueRefCursorInfo->getValueD()) {
9115-
Diags.diagnose(StartLoc, diag::unresolved_location);
9116-
return true;
9117-
}
9118-
ValueDecl *VD = ValueRefCursorInfo->typeOrValue();
9119-
Optional<RenameRefInfo> RefInfo;
9120-
if (ValueRefCursorInfo->isRef())
9121-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
9122-
ValueRefCursorInfo->isKeywordArgument()};
9123-
9124-
llvm::SmallVector<DeclContext *, 8> Scopes;
9125-
analyzeRenameScope(VD, RefInfo, Diags, Scopes);
9126-
if (Scopes.empty())
9122+
Optional<RenameRangeCollector> RangeCollector =
9123+
localRenames(SF, StartLoc, StringRef(), Diags);
9124+
if (!RangeCollector)
91279125
return true;
9128-
RenameRangeCollector RangeCollector(VD, StringRef());
9129-
for (DeclContext *DC : Scopes)
9130-
indexDeclContext(DC, RangeCollector);
91319126

9132-
return findSyntacticRenameRanges(SF, RangeCollector.results(), RenameConsumer,
9133-
DiagConsumer);
9127+
return findSyntacticRenameRanges(SF, RangeCollector->results(),
9128+
RenameConsumer, DiagConsumer);
91349129
}

0 commit comments

Comments
 (0)