Skip to content

Commit 3e200b7

Browse files
committed
[CodeCompletion] Skip typechecking unrelated statements in func bodies
rdar://problem/58687608
1 parent 68ba9cf commit 3e200b7

File tree

5 files changed

+42
-21
lines changed

5 files changed

+42
-21
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5736,7 +5736,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
57365736

57375737
typeCheckContextUntil(
57385738
CurDeclContext,
5739-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
5739+
ParsedExpr
5740+
? ParsedExpr->getLoc()
5741+
: CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
57405742

57415743
// Add keywords even if type checking fails completely.
57425744
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);

lib/IDE/ConformingMethodList.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ void ConformingMethodListCallbacks::doneParsing() {
6767
if (!ParsedExpr)
6868
return;
6969

70-
typeCheckContextUntil(
71-
CurDeclContext,
72-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
70+
typeCheckContextUntil(CurDeclContext, ParsedExpr->getLoc());
7371

7472
Type T = ParsedExpr->getType();
7573

lib/IDE/TypeContextInfo.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ void ContextInfoCallbacks::doneParsing() {
8888
if (!ParsedExpr)
8989
return;
9090

91-
typeCheckContextUntil(
92-
CurDeclContext,
93-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
91+
typeCheckContextUntil(CurDeclContext, ParsedExpr->getLoc());
9492

9593
ExprContextInfo Info(CurDeclContext, ParsedExpr);
9694

lib/Sema/TypeCheckStmt.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,12 +1563,19 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
15631563
}
15641564

15651565
for (auto &elem : BS->getElements()) {
1566-
if (auto *SubExpr = elem.dyn_cast<Expr*>()) {
1567-
SourceLoc Loc = SubExpr->getStartLoc();
1568-
if (EndTypeCheckLoc.isValid() &&
1569-
(Loc == EndTypeCheckLoc || SM.isBeforeInBuffer(EndTypeCheckLoc, Loc)))
1566+
if (EndTypeCheckLoc.isValid()) {
1567+
if (SM.isBeforeInBuffer(EndTypeCheckLoc, elem.getStartLoc()))
15701568
break;
15711569

1570+
// NOTE: We need to check the character loc here because the target loc
1571+
// can be inside the last token of the node. i.e. string interpolation.
1572+
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, elem.getEndLoc());
1573+
if (endLoc == EndTypeCheckLoc ||
1574+
SM.isBeforeInBuffer(endLoc, EndTypeCheckLoc))
1575+
continue;
1576+
}
1577+
1578+
if (auto *SubExpr = elem.dyn_cast<Expr*>()) {
15721579
// Type check the expression.
15731580
TypeCheckExprOptions options = TypeCheckExprFlags::IsExprStmt;
15741581
bool isDiscarded = (!getASTContext().LangOpts.Playground &&
@@ -1607,22 +1614,12 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
16071614
}
16081615

16091616
if (auto *SubStmt = elem.dyn_cast<Stmt*>()) {
1610-
SourceLoc Loc = SubStmt->getStartLoc();
1611-
if (EndTypeCheckLoc.isValid() &&
1612-
(Loc == EndTypeCheckLoc || SM.isBeforeInBuffer(EndTypeCheckLoc, Loc)))
1613-
break;
1614-
16151617
typeCheckStmt(SubStmt);
16161618
elem = SubStmt;
16171619
continue;
16181620
}
16191621

16201622
Decl *SubDecl = elem.get<Decl *>();
1621-
SourceLoc Loc = SubDecl->getStartLoc();
1622-
if (EndTypeCheckLoc.isValid() &&
1623-
(Loc == EndTypeCheckLoc || SM.isBeforeInBuffer(EndTypeCheckLoc, Loc)))
1624-
break;
1625-
16261623
TypeChecker::typeCheckDecl(SubDecl);
16271624
}
16281625

test/IDE/complete_skipbody.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token COMPLETE -debug-forbid-typecheck-prefix FORBIDDEN | %FileCheck %s
2+
struct FORBIDDEN_Struct {
3+
func FORBIDDEN_method() -> Int? { 1 }
4+
}
5+
6+
struct MyStruct {
7+
var x: Int { 1 }
8+
var y: Int { 1 }
9+
}
10+
11+
func test(value: MyStruct) {
12+
13+
let FORBIDDEN_localVar = 1
14+
let unrelated = FORBIDDEN_Struct()
15+
guard let a = unrelated.FORBIDDEN_method() else {
16+
return
17+
}
18+
19+
_ = value.#^COMPLETE^#
20+
}
21+
22+
// CHECK: Begin completions, 3 items
23+
// CHECK-DAG: Keyword[self]/CurrNominal: self[#MyStruct#]; name=self
24+
// CHECK-DAG: Decl[InstanceVar]/CurrNominal: x[#Int#]; name=x
25+
// CHECK-DAG: Decl[InstanceVar]/CurrNominal: y[#Int#]; name=y
26+
// CHECK: End completions

0 commit comments

Comments
 (0)