Skip to content

Commit d2de8ed

Browse files
committed
[SourceKit] Merge local refactoring implementations
Retrieving local rename ranges and the local rename refactoring both had almost identical methods, except for the addition of retrieving the outermost shadowed decl that was added a couple months back. Merge them. Resolves rdar://106529370.
1 parent 5f8338f commit d2de8ed

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
@@ -616,29 +616,54 @@ static const ValueDecl *getRelatedSystemDecl(const ValueDecl *VD) {
616616
return nullptr;
617617
}
618618

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

631652
class RenameRangeCollector : public IndexDataConsumer {
632653
public:
633654
RenameRangeCollector(StringRef USR, StringRef newName)
634-
: USR(USR.str()), newName(newName.str()) {}
655+
: USR(USR), newName(newName) {}
635656

636657
RenameRangeCollector(const ValueDecl *D, StringRef newName)
637-
: newName(newName.str()) {
638-
llvm::raw_string_ostream OS(USR);
658+
: newName(newName) {
659+
SmallString<64> SS;
660+
llvm::raw_svector_ostream OS(SS);
639661
printValueDeclUSR(D, OS);
662+
USR = stringStorage.copyString(SS.str());
640663
}
641664

665+
RenameRangeCollector(RenameRangeCollector &&collector) = default;
666+
642667
ArrayRef<RenameLoc> results() const { return locations; }
643668

644669
private:
@@ -680,8 +705,8 @@ class RenameRangeCollector : public IndexDataConsumer {
680705
StringRef NewName);
681706

682707
private:
683-
std::string USR;
684-
std::string newName;
708+
StringRef USR;
709+
StringRef newName;
685710
StringScratchSpace stringStorage;
686711
std::vector<RenameLoc> locations;
687712
};
@@ -836,29 +861,14 @@ class RefactoringAction##KIND: public RangeBasedRefactoringAction { \
836861

837862
bool RefactoringActionLocalRename::isApplicable(
838863
ResolvedCursorInfoPtr CursorInfo, DiagnosticEngine &Diag) {
839-
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
840-
if (!ValueRefInfo)
841-
return false;
842-
843-
Optional<RenameRefInfo> RefInfo;
844-
if (ValueRefInfo->isRef())
845-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
846-
ValueRefInfo->isKeywordArgument()};
847-
848-
auto RenameOp = getAvailableRenameForDecl(ValueRefInfo->getValueD(), RefInfo);
849-
return RenameOp.has_value() &&
850-
RenameOp.value() == RefactoringKind::LocalRename;
864+
Optional<RenameInfo> Info = getRenameInfo(CursorInfo);
865+
return Info &&
866+
Info->Availability.AvailableKind == RenameAvailableKind::Available &&
867+
Info->Availability.Kind == RefactoringKind::LocalRename;
851868
}
852869

853-
static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
854-
DiagnosticEngine &Diags,
870+
static void analyzeRenameScope(ValueDecl *VD,
855871
SmallVectorImpl<DeclContext *> &Scopes) {
856-
Scopes.clear();
857-
if (!getAvailableRenameForDecl(VD, RefInfo).has_value()) {
858-
Diags.diagnose(SourceLoc(), diag::value_decl_no_loc, VD->getName());
859-
return;
860-
}
861-
862872
auto *Scope = VD->getDeclContext();
863873
// There may be sibling decls that the renamed symbol is visible from.
864874
switch (Scope->getContextKind()) {
@@ -883,6 +893,53 @@ static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
883893
Scopes.push_back(Scope);
884894
}
885895

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

919-
analyzeRenameScope(VD, RefInfo, DiagEngine, Scopes);
920-
if (Scopes.empty())
921-
return true;
922-
RenameRangeCollector rangeCollector(VD, PreferredName);
923-
for (DeclContext *DC : Scopes)
924-
indexDeclContext(DC, rangeCollector);
925-
926-
auto consumers = DiagEngine.takeConsumers();
927-
assert(consumers.size() == 1);
928-
return syntacticRename(TheFile, rangeCollector.results(), EditConsumer,
929-
*consumers[0]);
930-
} else {
931-
DiagEngine.diagnose(StartLoc, diag::unresolved_location);
958+
Optional<RenameRangeCollector> rangeCollector =
959+
localRenames(TheFile, StartLoc, PreferredName, DiagEngine);
960+
if (!rangeCollector)
932961
return true;
933-
}
962+
963+
auto consumers = DiagEngine.takeConsumers();
964+
assert(consumers.size() == 1);
965+
return syntacticRename(TheFile, rangeCollector->results(), EditConsumer,
966+
*consumers[0]);
934967
}
935968

936969
StringRef getDefaultPreferredName(RefactoringKind Kind) {
@@ -8783,9 +8816,9 @@ accept(SourceManager &SM, RegionType RegionType,
87838816
}
87848817
}
87858818

8786-
void swift::ide::collectRenameAvailabilityInfo(
8787-
const ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
8788-
SmallVectorImpl<RenameAvailabilityInfo> &Infos) {
8819+
Optional<RenameAvailabilityInfo>
8820+
swift::ide::renameAvailabilityInfo(const ValueDecl *VD,
8821+
Optional<RenameRefInfo> RefInfo) {
87898822
RenameAvailableKind AvailKind = RenameAvailableKind::Available;
87908823
if (getRelatedSystemDecl(VD)){
87918824
AvailKind = RenameAvailableKind::Unavailable_system_symbol;
@@ -8800,22 +8833,22 @@ void swift::ide::collectRenameAvailabilityInfo(
88008833
if (isa<AbstractFunctionDecl>(VD)) {
88018834
// Disallow renaming accessors.
88028835
if (isa<AccessorDecl>(VD))
8803-
return;
8836+
return None;
88048837

88058838
// Disallow renaming deinit.
88068839
if (isa<DestructorDecl>(VD))
8807-
return;
8840+
return None;
88088841

88098842
// Disallow renaming init with no arguments.
88108843
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
88118844
if (!CD->getParameters()->size())
8812-
return;
8845+
return None;
88138846

88148847
if (RefInfo && !RefInfo->IsArgLabel) {
88158848
NameMatcher Matcher(*(RefInfo->SF));
88168849
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88178850
if (Resolved.LabelRanges.empty())
8818-
return;
8851+
return None;
88198852
}
88208853
}
88218854

@@ -8825,30 +8858,27 @@ void swift::ide::collectRenameAvailabilityInfo(
88258858
// whether it's an instance method, so we do the same here for now.
88268859
if (FD->getBaseIdentifier() == FD->getASTContext().Id_callAsFunction) {
88278860
if (!FD->getParameters()->size())
8828-
return;
8861+
return None;
88298862

88308863
if (RefInfo && !RefInfo->IsArgLabel) {
88318864
NameMatcher Matcher(*(RefInfo->SF));
88328865
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88338866
if (Resolved.LabelRanges.empty())
8834-
return;
8867+
return None;
88358868
}
88368869
}
88378870
}
88388871
}
88398872

88408873
// Always return local rename for parameters.
88418874
// FIXME: if the cursor is on the argument, we should return global rename.
8842-
if (isa<ParamDecl>(VD)) {
8843-
Infos.emplace_back(RefactoringKind::LocalRename, AvailKind);
8844-
return;
8845-
}
8875+
if (isa<ParamDecl>(VD))
8876+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
88468877

88478878
// If the indexer considers VD a global symbol, then we apply global rename.
88488879
if (index::isLocalSymbol(VD))
8849-
Infos.emplace_back(RefactoringKind::LocalRename, AvailKind);
8850-
else
8851-
Infos.emplace_back(RefactoringKind::GlobalRename, AvailKind);
8880+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
8881+
return RenameAvailabilityInfo{RefactoringKind::GlobalRename, AvailKind};
88528882
}
88538883

88548884
void swift::ide::collectAvailableRefactorings(
@@ -8858,27 +8888,10 @@ void swift::ide::collectAvailableRefactorings(
88588888
CursorInfo->getSourceFile()->getASTContext().SourceMgr);
88598889

88608890
if (!ExcludeRename) {
8861-
if (RefactoringActionLocalRename::isApplicable(CursorInfo, DiagEngine))
8862-
Kinds.push_back(RefactoringKind::LocalRename);
8863-
8864-
switch (CursorInfo->getKind()) {
8865-
case CursorInfoKind::ModuleRef:
8866-
case CursorInfoKind::Invalid:
8867-
case CursorInfoKind::StmtStart:
8868-
case CursorInfoKind::ExprStart:
8869-
break;
8870-
case CursorInfoKind::ValueRef: {
8871-
auto ValueRefInfo = cast<ResolvedValueRefCursorInfo>(CursorInfo);
8872-
Optional<RenameRefInfo> RefInfo;
8873-
if (ValueRefInfo->isRef())
8874-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
8875-
ValueRefInfo->isKeywordArgument()};
8876-
auto RenameOp =
8877-
getAvailableRenameForDecl(ValueRefInfo->getValueD(), RefInfo);
8878-
if (RenameOp.has_value() &&
8879-
RenameOp.value() == RefactoringKind::GlobalRename)
8880-
Kinds.push_back(RenameOp.value());
8881-
}
8891+
if (auto Info = getRenameInfo(CursorInfo)) {
8892+
if (Info->Availability.AvailableKind == RenameAvailableKind::Available) {
8893+
Kinds.push_back(Info->Availability.Kind);
8894+
}
88828895
}
88838896
}
88848897

@@ -9084,29 +9097,11 @@ int swift::ide::findLocalRenameRanges(
90849097
Diags.addConsumer(DiagConsumer);
90859098

90869099
auto StartLoc = Lexer::getLocForStartOfToken(SM, Range.getStart(SM));
9087-
ResolvedCursorInfoPtr CursorInfo =
9088-
evaluateOrDefault(SF->getASTContext().evaluator,
9089-
CursorInfoRequest{CursorInfoOwner(SF, StartLoc)},
9090-
new ResolvedCursorInfo());
9091-
auto ValueRefCursorInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
9092-
if (!ValueRefCursorInfo || !ValueRefCursorInfo->getValueD()) {
9093-
Diags.diagnose(StartLoc, diag::unresolved_location);
9094-
return true;
9095-
}
9096-
ValueDecl *VD = ValueRefCursorInfo->typeOrValue();
9097-
Optional<RenameRefInfo> RefInfo;
9098-
if (ValueRefCursorInfo->isRef())
9099-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
9100-
ValueRefCursorInfo->isKeywordArgument()};
9101-
9102-
llvm::SmallVector<DeclContext *, 8> Scopes;
9103-
analyzeRenameScope(VD, RefInfo, Diags, Scopes);
9104-
if (Scopes.empty())
9100+
Optional<RenameRangeCollector> RangeCollector =
9101+
localRenames(SF, StartLoc, StringRef(), Diags);
9102+
if (!RangeCollector)
91059103
return true;
9106-
RenameRangeCollector RangeCollector(VD, StringRef());
9107-
for (DeclContext *DC : Scopes)
9108-
indexDeclContext(DC, RangeCollector);
91099104

9110-
return findSyntacticRenameRanges(SF, RangeCollector.results(), RenameConsumer,
9111-
DiagConsumer);
9105+
return findSyntacticRenameRanges(SF, RangeCollector->results(),
9106+
RenameConsumer, DiagConsumer);
91129107
}

0 commit comments

Comments
 (0)