Skip to content

Commit eeced06

Browse files
committed
[Parse] Handle #if in brace skipping logic
Previously we would strictly match `{` + `}`, but that ignored the fact that when parsing we consider `#if` + `#endif` to be a stronger delimiter than `{` + `}`, so can ignore a stray `}` in a `#if`. Update the logic to also track opening and closing `#if` decls, ignoring any braces that happen within them. rdar://129195380
1 parent a85ca13 commit eeced06

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5658,10 +5658,11 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
56585658
HasPotentialRegexLiteral = false;
56595659

56605660
unsigned OpenBraces = 1;
5661+
unsigned OpenPoundIf = 0;
56615662

56625663
bool LastTokenWasFunc = false;
56635664

5664-
while (OpenBraces != 0 && P.Tok.isNot(tok::eof)) {
5665+
while ((OpenBraces != 0 || OpenPoundIf != 0) && P.Tok.isNot(tok::eof)) {
56655666
// Detect 'func' followed by an operator identifier.
56665667
if (LastTokenWasFunc) {
56675668
LastTokenWasFunc = false;
@@ -5692,6 +5693,24 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
56925693
return OpenBraces;
56935694
}
56945695

5696+
// Match opening `#if` with closing `#endif` to match what the parser does,
5697+
// `#if` + `#endif` are considered stronger delimiters than `{` + `}`.
5698+
if (P.consumeIf(tok::pound_if)) {
5699+
OpenPoundIf += 1;
5700+
continue;
5701+
}
5702+
if (OpenPoundIf != 0) {
5703+
// We're in a `#if`, check to see if we've reached the end.
5704+
if (P.consumeIf(tok::pound_endif)) {
5705+
OpenPoundIf -= 1;
5706+
continue;
5707+
}
5708+
// Consume the next token and continue iterating. We can swallow any
5709+
// amount of '{' and '}' while in the `#if`.
5710+
P.consumeToken();
5711+
continue;
5712+
}
5713+
56955714
if (P.consumeIf(tok::l_brace)) {
56965715
++OpenBraces;
56975716
continue;

test/Parse/rdar129195380.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: not %target-swift-frontend -experimental-skip-all-function-bodies -dump-parse %s | %FileCheck %s
2+
3+
// rdar://129195380 - Make sure the skipping logic can handle #if.
4+
struct S {
5+
// CHECK: func_decl{{.*}}:[[@LINE+1]]:3 - line:[[@LINE+11]]:3{{.*}}"foo()"
6+
func foo() {
7+
#if true
8+
}
9+
#if true
10+
func bar() {
11+
#else
12+
}
13+
#endif
14+
}
15+
#endif
16+
}
17+
// CHECK: func_decl{{.*}}:[[@LINE+1]]:3 - line:[[@LINE+1]]:15{{.*}}"baz()"
18+
func baz() {}
19+
}
20+
21+
// The '#if' is unterminated here, so swallows the rest of the file.
22+
// CHECK: struct_decl{{.*}}:[[@LINE+1]]:1 - line:[[@LINE+14]]:14{{.*}}"R"
23+
struct R {
24+
#if false
25+
}
26+
#if true
27+
}
28+
#endif
29+
}
30+
#else
31+
}
32+
// CHECK-NOT: qux
33+
func qux() {}
34+
}
35+
36+
func flim() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// rdar://129195380 - Make sure we correctly handle '#if' when skipping function
2+
// bodies.
3+
class C {
4+
func test1() {
5+
#if FOOBAR
6+
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 2):5 %s -- %s -DFOOBAR
7+
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 1):5 %s -- %s
8+
abc
9+
}
10+
11+
func test2() {
12+
}
13+
}

0 commit comments

Comments
 (0)