Skip to content

Commit c903c88

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 c903c88

File tree

6 files changed

+184
-153
lines changed

6 files changed

+184
-153
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: 118 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -616,29 +616,51 @@ 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 || !valueCursor->typeOrValue())
630+
return None;
631+
632+
ValueDecl *VD = valueCursor->typeOrValue();
633+
Optional<RenameRefInfo> refInfo;
634+
if (!valueCursor->getShorthandShadowedDecls().empty()) {
635+
// Find the outermost decl for a shorthand if let/closure capture
636+
VD = valueCursor->getShorthandShadowedDecls().back();
637+
} else if (valueCursor->isRef()) {
638+
refInfo = {valueCursor->getSourceFile(), valueCursor->getLoc(),
639+
valueCursor->isKeywordArgument()};
627640
}
628-
return None;
641+
642+
Optional<RenameAvailabilityInfo> info = renameAvailabilityInfo(VD, refInfo);
643+
if (!info)
644+
return None;
645+
646+
return RenameInfo{VD, *info};
629647
}
630648

631649
class RenameRangeCollector : public IndexDataConsumer {
632650
public:
633651
RenameRangeCollector(StringRef USR, StringRef newName)
634-
: USR(USR.str()), newName(newName.str()) {}
652+
: USR(USR), newName(newName) {}
635653

636654
RenameRangeCollector(const ValueDecl *D, StringRef newName)
637-
: newName(newName.str()) {
638-
llvm::raw_string_ostream OS(USR);
655+
: newName(newName) {
656+
SmallString<64> SS;
657+
llvm::raw_svector_ostream OS(SS);
639658
printValueDeclUSR(D, OS);
659+
USR = stringStorage.copyString(SS.str());
640660
}
641661

662+
RenameRangeCollector(RenameRangeCollector &&collector) = default;
663+
642664
ArrayRef<RenameLoc> results() const { return locations; }
643665

644666
private:
@@ -680,8 +702,8 @@ class RenameRangeCollector : public IndexDataConsumer {
680702
StringRef NewName);
681703

682704
private:
683-
std::string USR;
684-
std::string newName;
705+
StringRef USR;
706+
StringRef newName;
685707
StringScratchSpace stringStorage;
686708
std::vector<RenameLoc> locations;
687709
};
@@ -836,29 +858,14 @@ class RefactoringAction##KIND: public RangeBasedRefactoringAction { \
836858

837859
bool RefactoringActionLocalRename::isApplicable(
838860
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;
861+
Optional<RenameInfo> Info = getRenameInfo(CursorInfo);
862+
return Info &&
863+
Info->Availability.AvailableKind == RenameAvailableKind::Available &&
864+
Info->Availability.Kind == RefactoringKind::LocalRename;
851865
}
852866

853-
static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
854-
DiagnosticEngine &Diags,
867+
static void analyzeRenameScope(ValueDecl *VD,
855868
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-
862869
auto *Scope = VD->getDeclContext();
863870
// There may be sibling decls that the renamed symbol is visible from.
864871
switch (Scope->getContextKind()) {
@@ -883,6 +890,53 @@ static void analyzeRenameScope(ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
883890
Scopes.push_back(Scope);
884891
}
885892

893+
static Optional<RenameRangeCollector> localRenames(SourceFile *SF,
894+
SourceLoc startLoc,
895+
StringRef preferredName,
896+
DiagnosticEngine &diags) {
897+
auto cursorInfo =
898+
evaluateOrDefault(SF->getASTContext().evaluator,
899+
CursorInfoRequest{CursorInfoOwner(SF, startLoc)},
900+
new ResolvedCursorInfo());
901+
902+
Optional<RenameInfo> info = getRenameInfo(cursorInfo);
903+
if (!info) {
904+
diags.diagnose(startLoc, diag::unresolved_location);
905+
return None;
906+
}
907+
908+
switch (info->Availability.AvailableKind) {
909+
case RenameAvailableKind::Available:
910+
break;
911+
case RenameAvailableKind::Unavailable_system_symbol:
912+
diags.diagnose(startLoc, diag::decl_is_system_symbol, info->VD->getName());
913+
return None;
914+
case RenameAvailableKind::Unavailable_has_no_location:
915+
diags.diagnose(startLoc, diag::value_decl_no_loc, info->VD->getName());
916+
return None;
917+
case RenameAvailableKind::Unavailable_has_no_name:
918+
diags.diagnose(startLoc, diag::decl_has_no_name);
919+
return None;
920+
case RenameAvailableKind::Unavailable_has_no_accessibility:
921+
diags.diagnose(startLoc, diag::decl_no_accessibility);
922+
return None;
923+
case RenameAvailableKind::Unavailable_decl_from_clang:
924+
diags.diagnose(startLoc, diag::decl_from_clang);
925+
return None;
926+
}
927+
928+
SmallVector<DeclContext *, 8> scopes;
929+
analyzeRenameScope(info->VD, scopes);
930+
if (scopes.empty())
931+
return None;
932+
933+
RenameRangeCollector rangeCollector(info->VD, preferredName);
934+
for (DeclContext *DC : scopes)
935+
indexDeclContext(DC, rangeCollector);
936+
937+
return rangeCollector;
938+
}
939+
886940
bool RefactoringActionLocalRename::performChange() {
887941
if (StartLoc.isInvalid()) {
888942
DiagEngine.diagnose(SourceLoc(), diag::invalid_location);
@@ -897,40 +951,16 @@ bool RefactoringActionLocalRename::performChange() {
897951
MD->getNameStr());
898952
return true;
899953
}
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;
913954

914-
Optional<RenameRefInfo> RefInfo;
915-
if (ValueRefCursorInfo->isRef())
916-
RefInfo = {CursorInfo->getSourceFile(), CursorInfo->getLoc(),
917-
ValueRefCursorInfo->isKeywordArgument()};
918-
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);
955+
Optional<RenameRangeCollector> rangeCollector =
956+
localRenames(TheFile, StartLoc, PreferredName, DiagEngine);
957+
if (!rangeCollector)
932958
return true;
933-
}
959+
960+
auto consumers = DiagEngine.takeConsumers();
961+
assert(consumers.size() == 1);
962+
return syntacticRename(TheFile, rangeCollector->results(), EditConsumer,
963+
*consumers[0]);
934964
}
935965

936966
StringRef getDefaultPreferredName(RefactoringKind Kind) {
@@ -8783,9 +8813,9 @@ accept(SourceManager &SM, RegionType RegionType,
87838813
}
87848814
}
87858815

8786-
void swift::ide::collectRenameAvailabilityInfo(
8787-
const ValueDecl *VD, Optional<RenameRefInfo> RefInfo,
8788-
SmallVectorImpl<RenameAvailabilityInfo> &Infos) {
8816+
Optional<RenameAvailabilityInfo>
8817+
swift::ide::renameAvailabilityInfo(const ValueDecl *VD,
8818+
Optional<RenameRefInfo> RefInfo) {
87898819
RenameAvailableKind AvailKind = RenameAvailableKind::Available;
87908820
if (getRelatedSystemDecl(VD)){
87918821
AvailKind = RenameAvailableKind::Unavailable_system_symbol;
@@ -8800,22 +8830,22 @@ void swift::ide::collectRenameAvailabilityInfo(
88008830
if (isa<AbstractFunctionDecl>(VD)) {
88018831
// Disallow renaming accessors.
88028832
if (isa<AccessorDecl>(VD))
8803-
return;
8833+
return None;
88048834

88058835
// Disallow renaming deinit.
88068836
if (isa<DestructorDecl>(VD))
8807-
return;
8837+
return None;
88088838

88098839
// Disallow renaming init with no arguments.
88108840
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
88118841
if (!CD->getParameters()->size())
8812-
return;
8842+
return None;
88138843

88148844
if (RefInfo && !RefInfo->IsArgLabel) {
88158845
NameMatcher Matcher(*(RefInfo->SF));
88168846
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88178847
if (Resolved.LabelRanges.empty())
8818-
return;
8848+
return None;
88198849
}
88208850
}
88218851

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

88308860
if (RefInfo && !RefInfo->IsArgLabel) {
88318861
NameMatcher Matcher(*(RefInfo->SF));
88328862
auto Resolved = Matcher.resolve({RefInfo->Loc, /*ResolveArgs*/true});
88338863
if (Resolved.LabelRanges.empty())
8834-
return;
8864+
return None;
88358865
}
88368866
}
88378867
}
88388868
}
88398869

88408870
// Always return local rename for parameters.
88418871
// 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-
}
8872+
if (isa<ParamDecl>(VD))
8873+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
88468874

88478875
// If the indexer considers VD a global symbol, then we apply global rename.
88488876
if (index::isLocalSymbol(VD))
8849-
Infos.emplace_back(RefactoringKind::LocalRename, AvailKind);
8850-
else
8851-
Infos.emplace_back(RefactoringKind::GlobalRename, AvailKind);
8877+
return RenameAvailabilityInfo{RefactoringKind::LocalRename, AvailKind};
8878+
return RenameAvailabilityInfo{RefactoringKind::GlobalRename, AvailKind};
88528879
}
88538880

88548881
void swift::ide::collectAvailableRefactorings(
@@ -8858,27 +8885,10 @@ void swift::ide::collectAvailableRefactorings(
88588885
CursorInfo->getSourceFile()->getASTContext().SourceMgr);
88598886

88608887
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-
}
8888+
if (auto Info = getRenameInfo(CursorInfo)) {
8889+
if (Info->Availability.AvailableKind == RenameAvailableKind::Available) {
8890+
Kinds.push_back(Info->Availability.Kind);
8891+
}
88828892
}
88838893
}
88848894

@@ -9084,29 +9094,11 @@ int swift::ide::findLocalRenameRanges(
90849094
Diags.addConsumer(DiagConsumer);
90859095

90869096
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())
9097+
Optional<RenameRangeCollector> RangeCollector =
9098+
localRenames(SF, StartLoc, StringRef(), Diags);
9099+
if (!RangeCollector)
91059100
return true;
9106-
RenameRangeCollector RangeCollector(VD, StringRef());
9107-
for (DeclContext *DC : Scopes)
9108-
indexDeclContext(DC, RangeCollector);
91099101

9110-
return findSyntacticRenameRanges(SF, RangeCollector.results(), RenameConsumer,
9111-
DiagConsumer);
9102+
return findSyntacticRenameRanges(SF, RangeCollector->results(),
9103+
RenameConsumer, DiagConsumer);
91129104
}

0 commit comments

Comments
 (0)