Skip to content

Commit 222739a

Browse files
authored
Merge pull request #70255 from ahoppen/ahoppen/rename-refactoring
[Rename] Collection of improvements to make syntactic rename easier to read
2 parents 4673d63 + d53e1b9 commit 222739a

File tree

17 files changed

+337
-256
lines changed

17 files changed

+337
-256
lines changed

include/swift/IDE/IDEBridging.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,38 @@
2323
#endif
2424

2525
enum class LabelRangeType {
26+
/// The matched location did not have any arguments.
2627
None,
2728

29+
/// The argument of a function/initializer/macro/... call
30+
///
31+
/// ### Example
2832
/// `foo([a: ]2) or .foo([a: ]String)`
2933
CallArg,
3034

31-
/// `func([a b]: Int)`
35+
/// The parameter of a function/initializer/macro/... declaration
36+
///
37+
/// ### Example
38+
/// `func foo([a b]: Int)`
3239
Param,
3340

41+
/// Parameters of a function that can't be collapsed if they are the same.
42+
///
43+
/// This is the case for parameters of subscripts since subscripts have
44+
/// unnamed
45+
/// parameters by default.
46+
///
47+
/// ### Example
3448
/// `subscript([a a]: Int)`
3549
NoncollapsibleParam,
3650

37-
/// `#selector(foo.func([a]:))`
38-
Selector,
51+
/// A reference to a function that also specifies argument labels to
52+
/// disambiguate.
53+
///
54+
/// ### Examples
55+
/// - `#selector(foo.func([a]:))`
56+
/// - `foo.func([a]:)`
57+
CompoundName,
3958
};
4059

4160
enum class ResolvedLocContext { Default, Selector, Comment, StringLiteral };

include/swift/Refactoring/Refactoring.h

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#ifndef SWIFT_IDE_REFACTORING_H
14-
#define SWIFT_IDE_REFACTORING_H
13+
#ifndef SWIFT_REFACTORING_REFACTORING_H
14+
#define SWIFT_REFACTORING_REFACTORING_H
1515

1616
#include "swift/AST/DiagnosticConsumer.h"
1717
#include "swift/Basic/LLVM.h"
1818
#include "swift/Basic/StringExtras.h"
1919
#include "swift/IDE/CancellableResult.h"
2020
#include "swift/IDE/Utils.h"
21+
#include "swift/Refactoring/RenameLoc.h"
2122
#include "llvm/ADT/StringRef.h"
2223

2324
namespace swift {
@@ -61,21 +62,6 @@ struct RenameInfo {
6162

6263
llvm::Optional<RenameInfo> getRenameInfo(ResolvedCursorInfoPtr cursorInfo);
6364

64-
enum class NameUsage {
65-
Unknown,
66-
Reference,
67-
Definition,
68-
Call
69-
};
70-
71-
struct RenameLoc {
72-
unsigned Line;
73-
unsigned Column;
74-
NameUsage Usage;
75-
StringRef OldName;
76-
const bool IsFunctionLike;
77-
};
78-
7965
/// An array of \c RenameLoc that also keeps the underlying string storage of
8066
/// the \c StringRef inside the \c RenameLoc alive.
8167
class RenameLocs {
@@ -184,4 +170,4 @@ collectRefactorings(ResolvedCursorInfoPtr CursorInfo, bool ExcludeRename);
184170
} // namespace ide
185171
} // namespace swift
186172

187-
#endif // SWIFT_IDE_REFACTORING_H
173+
#endif // SWIFT_REFACTORING_REFACTORING_H

include/swift/Refactoring/RenameLoc.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_REFACTORING_RENAMELOC_H
14+
#define SWIFT_REFACTORING_RENAMELOC_H
15+
16+
#include "swift/Basic/LLVM.h"
17+
18+
namespace swift {
19+
namespace ide {
20+
21+
/// Describes how a `ResolvedLoc` is being used
22+
enum class RenameLocUsage {
23+
/// The definition of a function/subscript/variable/...
24+
Definition,
25+
26+
/// The symbol is being referenced.
27+
///
28+
/// This includes
29+
/// - References to variables
30+
/// - Unapplied references to functions (`myStruct.memberFunc`)
31+
/// - Calls to subscripts (`myArray[1]`, location is `[` here, length 1)
32+
Reference,
33+
34+
/// A function that is being called.
35+
Call,
36+
37+
/// Unknown name usage occurs if we don't have an entry in the index that
38+
/// tells us whether the location is a call, reference or a definition. The
39+
/// most common reasons why this happens is if the editor is adding syntactic
40+
/// results (eg. from comments or string literals).
41+
Unknown
42+
};
43+
44+
/// The input to `findSyntacticRenameRanges`.
45+
///
46+
/// Specifies the location of a base name for which `findSyntacticRenameRanges`
47+
/// should find the argument labels as well as some semantic information needed
48+
/// to resolve the rename ranges.
49+
struct RenameLoc {
50+
/// The line at which the base name starts (1-based).
51+
unsigned Line;
52+
53+
/// The column at which the base name (excluding trivia) starts (1-based).
54+
unsigned Column;
55+
56+
/// The offset at which the related name starts.
57+
unsigned Offset;
58+
59+
/// The length of the base name in the related identifier. For functions,
60+
/// this does not include the parameters/arguments.
61+
unsigned Length;
62+
63+
/// How the identifier is being used (call, reference, definition, unknown).
64+
///
65+
/// Used to decide whether a given occurance should be renamed and/or if its
66+
/// argument labels should be renamed.
67+
RenameLocUsage Usage;
68+
69+
/// The old decl name being renamed.
70+
///
71+
/// ### Examples
72+
/// - `foo(a:b:)` for a function with two parameters.
73+
/// - `foo` for a variable.
74+
/// - `foo(_:)` for a function with a single unnamed parameter
75+
/// - `foo()` for a function without parameters.
76+
StringRef OldName;
77+
78+
RenameLoc(unsigned Line, unsigned Column, RenameLocUsage Usage,
79+
StringRef OldName)
80+
: Line(Line), Column(Column), Usage(Usage), OldName(OldName) {}
81+
};
82+
83+
} // namespace ide
84+
} // namespace swift
85+
86+
#endif // SWIFT_REFACTORING_RENAMELOC_H

lib/ASTGen/Sources/SwiftIDEUtilsBridging/NameMatcherBridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fileprivate extension IDEBridging.LabelRangeType {
5151
case .call: self = .CallArg
5252
case .parameters: self = .Param
5353
case .noncollapsibleParameters: self = .NoncollapsibleParam
54-
case .selector: self = .Selector
54+
case .selector: self = .CompoundName
5555
}
5656
}
5757
}

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,8 +612,9 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc,
612612

613613
if (NameLoc.isCompound()) {
614614
auto Labels = getSelectorLabelRanges(getSourceMgr(), NameLoc);
615-
bool Resolved = tryResolve(Node, NameLoc.getBaseNameLoc(),
616-
LabelRangeType::Selector, Labels, llvm::None);
615+
bool Resolved =
616+
tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::CompoundName,
617+
Labels, llvm::None);
617618
if (!isDone()) {
618619
for (auto Label: Labels) {
619620
if (tryResolve(Node, Label.getStart())) {

lib/Refactoring/ExtractFunction.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ static SourceLoc getNewFuncInsertLoc(DeclContext *DC,
7777
return SourceLoc();
7878
}
7979

80-
static std::vector<NoteRegion> getNotableRegions(StringRef SourceText,
81-
unsigned NameOffset,
82-
StringRef Name,
83-
bool IsFunctionLike = false) {
80+
static std::vector<NoteRegion>
81+
getNotableRegions(StringRef SourceText, unsigned NameOffset, StringRef Name) {
8482
auto InputBuffer =
8583
llvm::MemoryBuffer::getMemBufferCopy(SourceText, "<extract>");
8684

@@ -106,8 +104,7 @@ static std::vector<NoteRegion> getNotableRegions(StringRef SourceText,
106104
assert(!Resolved.empty() && "Failed to resolve generated func name loc");
107105

108106
RenameLoc RenameConfig = {LineAndCol.first, LineAndCol.second,
109-
NameUsage::Definition, /*OldName=*/Name,
110-
IsFunctionLike};
107+
RenameLocUsage::Definition, /*OldName=*/Name};
111108
std::vector<RenameRangeDetail> Ranges =
112109
getSyntacticRenameRangeDetails(SM, Name, Resolved.back(), RenameConfig)
113110
.Ranges;
@@ -290,13 +287,11 @@ bool RefactoringActionExtractFunction::performChange() {
290287

291288
StringRef DeclStr(Buffer.begin() + FuncBegin, FuncEnd - FuncBegin);
292289
auto NotableFuncRegions =
293-
getNotableRegions(DeclStr, FuncNameOffset, ExtractedFuncName,
294-
/*IsFunctionLike=*/true);
290+
getNotableRegions(DeclStr, FuncNameOffset, ExtractedFuncName);
295291

296292
StringRef CallStr(Buffer.begin() + ReplaceBegin, ReplaceEnd - ReplaceBegin);
297293
auto NotableCallRegions =
298-
getNotableRegions(CallStr, CallNameOffset, ExtractedFuncName,
299-
/*IsFunctionLike=*/true);
294+
getNotableRegions(CallStr, CallNameOffset, ExtractedFuncName);
300295

301296
// Insert the new function's declaration.
302297
EditConsumer.accept(SM, InsertLoc, DeclStr, NotableFuncRegions);

lib/Refactoring/LocalRename.cpp

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -207,22 +207,25 @@ class RenameRangeCollector : public IndexDataConsumer {
207207
bool finishDependency(bool isClangModule) override { return true; }
208208

209209
Action startSourceEntity(const IndexSymbol &symbol) override {
210-
if (symbol.USR == usr) {
211-
if (auto loc = indexSymbolToRenameLoc(symbol)) {
212-
// Inside capture lists like `{ [test] in }`, 'test' refers to both the
213-
// newly declared, captured variable and the referenced variable it is
214-
// initialized from. Make sure to only rename it once.
215-
auto existingLoc = llvm::find_if(locations, [&](RenameLoc searchLoc) {
216-
return searchLoc.Line == loc->Line && searchLoc.Column == loc->Column;
217-
});
218-
if (existingLoc == locations.end()) {
219-
locations.push_back(std::move(*loc));
220-
} else {
221-
assert(existingLoc->OldName == loc->OldName &&
222-
existingLoc->IsFunctionLike == loc->IsFunctionLike &&
223-
"Asked to do a different rename for the same location?");
224-
}
225-
}
210+
if (symbol.USR != usr) {
211+
return IndexDataConsumer::Continue;
212+
}
213+
auto loc = indexSymbolToRenameLoc(symbol);
214+
if (!loc) {
215+
return IndexDataConsumer::Continue;
216+
}
217+
218+
// Inside capture lists like `{ [test] in }`, 'test' refers to both the
219+
// newly declared, captured variable and the referenced variable it is
220+
// initialized from. Make sure to only rename it once.
221+
auto existingLoc = llvm::find_if(locations, [&](RenameLoc searchLoc) {
222+
return searchLoc.Line == loc->Line && searchLoc.Column == loc->Column;
223+
});
224+
if (existingLoc == locations.end()) {
225+
locations.push_back(std::move(*loc));
226+
} else {
227+
assert(existingLoc->OldName == loc->OldName &&
228+
"Asked to do a different rename for the same location?");
226229
}
227230
return IndexDataConsumer::Continue;
228231
}
@@ -241,37 +244,19 @@ RenameRangeCollector::indexSymbolToRenameLoc(const index::IndexSymbol &symbol) {
241244
return llvm::None;
242245
}
243246

244-
NameUsage usage = NameUsage::Unknown;
247+
RenameLocUsage usage = RenameLocUsage::Unknown;
245248
if (symbol.roles & (unsigned)index::SymbolRole::Call) {
246-
usage = NameUsage::Call;
249+
usage = RenameLocUsage::Call;
247250
} else if (symbol.roles & (unsigned)index::SymbolRole::Definition) {
248-
usage = NameUsage::Definition;
251+
usage = RenameLocUsage::Definition;
249252
} else if (symbol.roles & (unsigned)index::SymbolRole::Reference) {
250-
usage = NameUsage::Reference;
253+
usage = RenameLocUsage::Reference;
251254
} else {
252255
llvm_unreachable("unexpected role");
253256
}
254257

255-
bool isFunctionLike = false;
256-
257-
switch (symbol.symInfo.Kind) {
258-
case index::SymbolKind::EnumConstant:
259-
case index::SymbolKind::Function:
260-
case index::SymbolKind::Constructor:
261-
case index::SymbolKind::ConversionFunction:
262-
case index::SymbolKind::InstanceMethod:
263-
case index::SymbolKind::ClassMethod:
264-
case index::SymbolKind::StaticMethod:
265-
isFunctionLike = true;
266-
break;
267-
case index::SymbolKind::Class:
268-
case index::SymbolKind::Enum:
269-
case index::SymbolKind::Struct:
270-
default:
271-
break;
272-
}
273258
StringRef oldName = stringStorage->copyString(symbol.name);
274-
return RenameLoc{symbol.line, symbol.column, usage, oldName, isFunctionLike};
259+
return RenameLoc{symbol.line, symbol.column, usage, oldName};
275260
}
276261

277262
/// Get the decl context that we need to walk when renaming \p VD.

lib/Refactoring/SyntacticRename.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ swift::ide::resolveRenameLocations(ArrayRef<RenameLoc> RenameLocs,
6363
return {};
6464
}
6565

66-
if (RenameLoc.Usage == NameUsage::Call && !RenameLoc.IsFunctionLike) {
66+
if (RenameLoc.Usage == RenameLocUsage::Call && !OldName.isFunction()) {
6767
Diags.diagnose(Location, diag::name_not_functionlike, NewName);
6868
return {};
6969
}

0 commit comments

Comments
 (0)