Skip to content

Commit 48821d8

Browse files
committed
[SourceKit] Consider source location in the orignal buffer when computing refactoring actions
1 parent 2435b3e commit 48821d8

File tree

5 files changed

+64
-28
lines changed

5 files changed

+64
-28
lines changed

include/swift/IDE/Utils.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ struct ResolvedCursorInfo {
139139
CursorInfoKind Kind = CursorInfoKind::Invalid;
140140
SourceFile *SF = nullptr;
141141
SourceLoc Loc;
142+
/// If \c Loc resides in a temporary buffer during AST reuse, the
143+
/// corresponding location in the original, full buffer.
144+
SourceLoc LocInOriginalBuffer;
142145

143146
// Technically, these structs could form a union (because only one of them is
144147
// active at a time). But I had issues with C++ complaining about copy
@@ -185,7 +188,11 @@ struct ResolvedCursorInfo {
185188
SourceFile *getSourceFile() const { return SF; }
186189

187190
SourceLoc getLoc() const { return Loc; }
188-
void setLoc(SourceLoc Loc) { this->Loc = Loc; }
191+
SourceLoc getLocInOriginalBuffer() const { return LocInOriginalBuffer; }
192+
void setLoc(SourceLoc Loc, SourceLoc LocInOriginalBuffer) {
193+
this->Loc = Loc;
194+
this->LocInOriginalBuffer = LocInOriginalBuffer;
195+
}
189196

190197
friend bool operator==(const ResolvedCursorInfo &lhs,
191198
const ResolvedCursorInfo &rhs) {

lib/IDE/CursorInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
247247
/*CtorTyRef=*/nullptr,
248248
/*ExtTyRef=*/nullptr, /*IsRef=*/false, /*Ty=*/Type(),
249249
/*ContainerType=*/Type());
250-
CursorInfo->setLoc(RequestedLoc);
250+
CursorInfo->setLoc(RequestedLoc, RequestedLocInOriginalBuffer);
251251
CursorInfo->setShorthandShadowedDecls(
252252
Finder.getShorthandShadowedDecls(DeclResult->getDecl()));
253253
return CursorInfo;

lib/IDE/IDERequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ bool CursorInfoResolver::visitSubscriptReference(ValueDecl *D,
175175
ResolvedCursorInfo CursorInfoResolver::resolve(SourceLoc Loc) {
176176
assert(Loc.isValid());
177177
LocToResolve = Loc;
178-
CursorInfo.setLoc(Loc);
178+
CursorInfo.setLoc(Loc, /*LocInOriginalBuffer=*/Loc);
179179

180180
walk(SrcFile);
181181

lib/Refactoring/Refactoring.cpp

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,33 @@ class ContextFinder : public SourceEntityWalker {
4949
ASTContext &Ctx;
5050
SourceManager &SM;
5151
SourceRange Target;
52-
std::function<bool(ASTNode)> IsContext;
52+
SourceRange TargetInOriginalBuffer;
5353
SmallVector<ASTNode, 4> AllContexts;
5454
bool contains(ASTNode Enclosing) {
55-
auto Result = SM.rangeContains(Enclosing.getSourceRange(), Target);
56-
if (Result && IsContext(Enclosing))
55+
auto Result =
56+
SM.rangeContains(Enclosing.getSourceRange(), Target) ||
57+
SM.rangeContains(Enclosing.getSourceRange(), TargetInOriginalBuffer);
58+
if (Result && IsContext(Enclosing)) {
5759
AllContexts.push_back(Enclosing);
60+
}
5861
return Result;
5962
}
6063
public:
61-
ContextFinder(SourceFile &SF, ASTNode TargetNode,
62-
std::function<bool(ASTNode)> IsContext =
63-
[](ASTNode N) { return true; }) :
64-
SF(SF), Ctx(SF.getASTContext()), SM(Ctx.SourceMgr),
65-
Target(TargetNode.getSourceRange()), IsContext(IsContext) {}
66-
ContextFinder(SourceFile &SF, SourceLoc TargetLoc,
67-
std::function<bool(ASTNode)> IsContext =
68-
[](ASTNode N) { return true; }) :
69-
SF(SF), Ctx(SF.getASTContext()), SM(Ctx.SourceMgr),
70-
Target(TargetLoc), IsContext(IsContext) {
71-
assert(TargetLoc.isValid() && "Invalid loc to find");
72-
}
64+
ContextFinder(
65+
SourceFile &SF, ASTNode TargetNode,
66+
std::function<bool(ASTNode)> IsContext = [](ASTNode N) { return true; })
67+
: SF(SF), Ctx(SF.getASTContext()), SM(Ctx.SourceMgr),
68+
Target(TargetNode.getSourceRange()),
69+
TargetInOriginalBuffer(TargetNode.getSourceRange()),
70+
IsContext(IsContext) {}
71+
ContextFinder(
72+
SourceFile &SF, SourceLoc TargetLoc, SourceLoc TargetLocInOriginalBuffer,
73+
std::function<bool(ASTNode)> IsContext = [](ASTNode N) { return true; })
74+
: SF(SF), Ctx(SF.getASTContext()), SM(Ctx.SourceMgr), Target(TargetLoc),
75+
TargetInOriginalBuffer(TargetLocInOriginalBuffer),
76+
IsContext(IsContext) {
77+
assert(TargetLoc.isValid() && "Invalid loc to find");
78+
}
7379
bool walkToDeclPre(Decl *D, CharSourceRange Range) override { return contains(D); }
7480
bool walkToStmtPre(Stmt *S) override { return contains(S); }
7581
bool walkToExprPre(Expr *E) override { return contains(E); }
@@ -3928,10 +3934,11 @@ static CallExpr *findTrailingClosureTarget(
39283934
return nullptr;
39293935

39303936
// Find inner most CallExpr
3931-
ContextFinder Finder(
3932-
*CursorInfo.getSourceFile(), CursorInfo.getLoc(), [](ASTNode N) {
3933-
return N.isStmt(StmtKind::Brace) || N.isExpr(ExprKind::Call);
3934-
});
3937+
ContextFinder Finder(*CursorInfo.getSourceFile(), CursorInfo.getLoc(),
3938+
CursorInfo.getLocInOriginalBuffer(), [](ASTNode N) {
3939+
return N.isStmt(StmtKind::Brace) ||
3940+
N.isExpr(ExprKind::Call);
3941+
});
39353942
Finder.resolve();
39363943
auto contexts = Finder.getContexts();
39373944
if (contexts.empty())
@@ -4165,7 +4172,7 @@ CallExpr *findOuterCall(const ResolvedCursorInfo &CursorInfo) {
41654172
// already generated a slice of the AST for anything that contains
41664173
// the cursor location
41674174
ContextFinder Finder(*CursorInfo.getSourceFile(), CursorInfo.getLoc(),
4168-
IncludeInContext);
4175+
CursorInfo.getLocInOriginalBuffer(), IncludeInContext);
41694176
Finder.resolve();
41704177
auto Contexts = Finder.getContexts();
41714178
if (Contexts.empty())
@@ -4191,7 +4198,7 @@ FuncDecl *findFunction(const ResolvedCursorInfo &CursorInfo) {
41914198
};
41924199

41934200
ContextFinder Finder(*CursorInfo.getSourceFile(), CursorInfo.getLoc(),
4194-
IncludeInContext);
4201+
CursorInfo.getLocInOriginalBuffer(), IncludeInContext);
41954202
Finder.resolve();
41964203

41974204
auto Contexts = Finder.getContexts();
@@ -8282,9 +8289,10 @@ bool RefactoringActionConvertCallToAsyncAlternative::performChange() {
82828289
"Should not run performChange when refactoring is not applicable");
82838290

82848291
// Find the scope this call is in
8285-
ContextFinder Finder(
8286-
*CursorInfo.getSourceFile(), CursorInfo.getLoc(),
8287-
[](ASTNode N) { return N.isStmt(StmtKind::Brace) && !N.isImplicit(); });
8292+
ContextFinder Finder(*CursorInfo.getSourceFile(), CursorInfo.getLoc(),
8293+
CursorInfo.getLocInOriginalBuffer(), [](ASTNode N) {
8294+
return N.isStmt(StmtKind::Brace) && !N.isImplicit();
8295+
});
82888296
Finder.resolve();
82898297
auto Scopes = Finder.getContexts();
82908298
BraceStmt *Scope = nullptr;
@@ -8437,7 +8445,8 @@ findMacroExpansionTargetExpr(const ResolvedCursorInfo &Info) {
84378445
if (auto refInfo = dyn_cast<ResolvedValueRefCursorInfo>(&Info)) {
84388446
if (refInfo->isRef() && isa_and_nonnull<MacroDecl>(refInfo->getValueD())) {
84398447
ContextFinder Finder(
8440-
*Info.getSourceFile(), Info.getLoc(), [&](ASTNode N) {
8448+
*Info.getSourceFile(), Info.getLoc(), Info.getLocInOriginalBuffer(),
8449+
[&](ASTNode N) {
84418450
auto *expr =
84428451
dyn_cast_or_null<MacroExpansionExpr>(N.dyn_cast<Expr *>());
84438452
return expr &&
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
func materialize() {
2+
let a = 2
3+
}
4+
5+
func outer() {
6+
func inner() {
7+
}
8+
}
9+
10+
// RUN: %sourcekitd-test -req=cursor -pos=2:6 %s -- %s == \
11+
// RUN: -req=cursor -req-opts=retrieve_refactor_actions=1 -pos=6:8 %s -- %s | %FileCheck %s
12+
13+
// CHECK: source.lang.swift.decl.function.free (6:8-6:15)
14+
// CHECK: inner()
15+
// CHECK: ACTIONS BEGIN
16+
// CHECK-DAG: source.refactoring.kind.rename.local
17+
// CHECK-DAG: Local Rename
18+
// CHECK-DAG: source.refactoring.kind.convert.func-to-async
19+
// CHECK-DAG: Convert Function to Async
20+
// CHECK: ACTIONS END

0 commit comments

Comments
 (0)