Skip to content

Commit 110f114

Browse files
committed
[IDE] Avoid uses of isBeforeInBuffer in TypeCheckASTNodeAtLocRequest
Use the higher level APIs on SourceManager that handle locations in parent vs child buffers. This then allows us to fix `walkToDeclPre` such that we don't set the found DeclContext unless the location is actually within that decl (here the location may well be in a separate buffer as we may have a replaced function body).
1 parent 84febf6 commit 110f114

File tree

2 files changed

+47
-34
lines changed

2 files changed

+47
-34
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,12 +2462,29 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
24622462
return MacroWalking::ArgumentsAndExpansion;
24632463
}
24642464

2465+
/// Checks whether the given range, when treated as a character range,
2466+
/// contains the searched location.
2467+
bool charRangeContainsLoc(SourceRange range) {
2468+
if (!range)
2469+
return false;
2470+
2471+
if (SM.isBefore(Loc, range.Start))
2472+
return false;
2473+
2474+
// NOTE: We need to check the character loc here because the target
2475+
// loc can be inside the last token of the node. i.e. interpolated
2476+
// string.
2477+
return SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End));
2478+
}
2479+
24652480
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
24662481
if (auto *brace = dyn_cast<BraceStmt>(S)) {
2467-
auto braceCharRange = Lexer::getCharSourceRangeFromSourceRange(
2468-
SM, brace->getSourceRange());
2482+
auto braceRange = brace->getSourceRange();
2483+
auto braceCharRange = SourceRange(
2484+
braceRange.Start, Lexer::getLocForEndOfToken(SM, braceRange.End));
2485+
24692486
// Unless this brace contains the loc, there's nothing to do.
2470-
if (!braceCharRange.contains(Loc))
2487+
if (!SM.containsLoc(braceCharRange, Loc))
24712488
return Action::SkipNode(S);
24722489

24732490
// Reset the node found in a parent context if it's not part of this
@@ -2477,22 +2494,22 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
24772494
// syntactically part of the brace stmt's range but won't be walked as
24782495
// a child of the brace stmt.
24792496
if (!brace->isImplicit() && FoundNode) {
2480-
auto foundNodeCharRange = Lexer::getCharSourceRangeFromSourceRange(
2481-
SM, FoundNode->getSourceRange());
2482-
if (!braceCharRange.contains(foundNodeCharRange)) {
2497+
auto foundRange = FoundNode->getSourceRange();
2498+
auto foundCharRange = SourceRange(
2499+
foundRange.Start, Lexer::getLocForEndOfToken(SM, foundRange.End));
2500+
if (!SM.encloses(braceCharRange, foundCharRange))
24832501
FoundNode = nullptr;
2484-
}
24852502
}
24862503

24872504
for (ASTNode &node : brace->getElements()) {
2488-
if (SM.isBeforeInBuffer(Loc, node.getStartLoc()))
2505+
auto range = node.getSourceRange();
2506+
if (SM.isBefore(Loc, range.Start))
24892507
break;
24902508

24912509
// NOTE: We need to check the character loc here because the target
24922510
// loc can be inside the last token of the node. i.e. interpolated
24932511
// string.
2494-
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, node.getEndLoc());
2495-
if (SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc)
2512+
if (!SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End)))
24962513
continue;
24972514

24982515
// 'node' may be the target node, except 'CaseStmt' which cannot be
@@ -2509,13 +2526,11 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25092526
return Action::Stop();
25102527
} else if (auto Conditional = dyn_cast<LabeledConditionalStmt>(S)) {
25112528
for (StmtConditionElement &Cond : Conditional->getCond()) {
2512-
if (SM.isBeforeInBuffer(Loc, Cond.getStartLoc())) {
2529+
auto range = Cond.getSourceRange();
2530+
if (SM.isBefore(Loc, range.Start))
25132531
break;
2514-
}
2515-
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, Cond.getEndLoc());
2516-
if (SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc) {
2532+
if (!SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End)))
25172533
continue;
2518-
}
25192534

25202535
FoundNodeStorage = ASTNode(&Cond);
25212536
FoundNode = &FoundNodeStorage;
@@ -2527,11 +2542,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25272542
}
25282543

25292544
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
2530-
if (SM.isBeforeInBuffer(Loc, E->getStartLoc()))
2531-
return Action::SkipNode(E);
2532-
2533-
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, E->getEndLoc());
2534-
if (SM.isBeforeInBuffer(endLoc, Loc))
2545+
if (!charRangeContainsLoc(E->getSourceRange()))
25352546
return Action::SkipNode(E);
25362547

25372548
// Don't walk into 'TapExpr'. They should be type checked with parent
@@ -2546,9 +2557,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25462557
if (auto *SVE = dyn_cast<SingleValueStmtExpr>(E)) {
25472558
SmallVector<Expr *> scratch;
25482559
for (auto *result : SVE->getResultExprs(scratch)) {
2549-
auto resultCharRange = Lexer::getCharSourceRangeFromSourceRange(
2550-
SM, result->getSourceRange());
2551-
if (resultCharRange.contains(Loc)) {
2560+
if (charRangeContainsLoc(result->getSourceRange())) {
25522561
if (!result->walk(*this))
25532562
return Action::Stop();
25542563

@@ -2570,20 +2579,15 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25702579
}
25712580

25722581
PreWalkAction walkToDeclPre(Decl *D) override {
2582+
if (!charRangeContainsLoc(D->getSourceRange()))
2583+
return Action::SkipNode();
2584+
25732585
if (auto *newDC = dyn_cast<DeclContext>(D))
25742586
DC = newDC;
25752587

2576-
if (!SM.isBeforeInBuffer(Loc, D->getStartLoc())) {
2577-
// NOTE: We need to check the character loc here because the target
2578-
// loc can be inside the last token of the node. i.e. interpolated
2579-
// string.
2580-
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, D->getEndLoc());
2581-
if (!(SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc)) {
2582-
if (!isa<TopLevelCodeDecl>(D)) {
2583-
FoundNodeStorage = ASTNode(D);
2584-
FoundNode = &FoundNodeStorage;
2585-
}
2586-
}
2588+
if (!isa<TopLevelCodeDecl>(D)) {
2589+
FoundNodeStorage = ASTNode(D);
2590+
FoundNode = &FoundNodeStorage;
25872591
}
25882592
return Action::Continue();
25892593
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %batch-code-completion
2+
3+
// Make sure we don't crash.
4+
func foo(xs: [[Int]], ys: [Int]) {
5+
for x in ys {
6+
_ = xs.map{ $0.filter{ $0 == x } #^COMPLETE^# }
7+
// COMPLETE: Begin completions
8+
}
9+
}

0 commit comments

Comments
 (0)