Skip to content

Commit 221d81e

Browse files
authored
Merge pull request #37761 from hamishknight/walk-this-way-5.5
[5.5] Visit ForEachStmt in source order in SemaAnnotator
2 parents 952e457 + 49a7398 commit 221d81e

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

lib/IDE/SourceEntityWalker.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,65 @@ std::pair<bool, Stmt *> SemaAnnotator::walkToStmtPre(Stmt *S) {
234234
// Already walked children.
235235
return { false, Continue ? DeferS : nullptr };
236236
}
237+
238+
auto doSkipChildren = [&]() -> std::pair<bool, Stmt *> {
239+
if (!walkToStmtPost(S))
240+
return {false, nullptr};
241+
return {false, S};
242+
};
243+
244+
auto doStopTraversal = [&]() -> std::pair<bool, Stmt *> {
245+
Cancelled = true;
246+
return {false, nullptr};
247+
};
248+
249+
// Make sure to walk a ForEachStmt in source order. Note this is a narrow
250+
// fix for release/5.5. On main, this is fixed in the ASTWalker itself.
251+
// rdar://78781061
252+
if (auto *FE = dyn_cast<ForEachStmt>(S)) {
253+
if (auto *P = FE->getPattern()) {
254+
auto *NewP = P->walk(*this);
255+
if (!NewP)
256+
return doStopTraversal();
257+
assert(NewP == P);
258+
}
259+
if (auto *SE = FE->getSequence()) {
260+
auto *NewSE = SE->walk(*this);
261+
if (!NewSE)
262+
return doStopTraversal();
263+
assert(NewSE == SE);
264+
}
265+
if (auto *Where = FE->getWhere()) {
266+
auto *NewWhere = Where->walk(*this);
267+
if (!NewWhere)
268+
return doStopTraversal();
269+
assert(NewWhere == Where);
270+
}
271+
if (auto *IteratorNext = FE->getConvertElementExpr()) {
272+
auto *NewIteratorNext = IteratorNext->walk(*this);
273+
if (!NewIteratorNext)
274+
return doStopTraversal();
275+
assert(NewIteratorNext == IteratorNext);
276+
}
277+
if (auto *IteratorVar = FE->getIteratorVar()) {
278+
if (IteratorVar->walk(*this))
279+
return doStopTraversal();
280+
}
281+
if (auto *IteratorVarRef = FE->getIteratorVarRef()) {
282+
auto *NewIteratorVarRef = IteratorVarRef->walk(*this);
283+
if (!NewIteratorVarRef)
284+
return doStopTraversal();
285+
assert(NewIteratorVarRef == IteratorVarRef);
286+
}
287+
if (auto *Body = FE->getBody()) {
288+
auto *NewBody = Body->walk(*this);
289+
if (!NewBody)
290+
return doStopTraversal();
291+
assert(NewBody == Body);
292+
}
293+
// Already visited.
294+
return doSkipChildren();
295+
}
237296
}
238297
return { TraverseChildren, S };
239298
}

test/refactoring/ConvertAsync/basic.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,22 @@ class TestConvertFunctionWithCallToFunctionsWithSpecialName {
855855
_ = x[1]
856856
return x
857857
}
858-
}
858+
}
859+
860+
// rdar://78781061
861+
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=FOR-IN-WHERE %s
862+
func testForInWhereRefactoring() {
863+
let arr: [String] = []
864+
for str in arr where str.count != 0 {
865+
simple { res in
866+
print(res)
867+
}
868+
}
869+
}
870+
// FOR-IN-WHERE: func testForInWhereRefactoring() async {
871+
// FOR-IN-WHERE-NEXT: let arr: [String] = []
872+
// FOR-IN-WHERE-NEXT: for str in arr where str.count != 0 {
873+
// FOR-IN-WHERE-NEXT: let res = await simple()
874+
// FOR-IN-WHERE-NEXT: print(res)
875+
// FOR-IN-WHERE-NEXT: }
876+
// FOR-IN-WHERE-NEXT: }

0 commit comments

Comments
 (0)