mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -5658,10 +5658,11 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
|
|||||||
HasPotentialRegexLiteral = false;
|
HasPotentialRegexLiteral = false;
|
||||||
|
|
||||||
unsigned OpenBraces = 1;
|
unsigned OpenBraces = 1;
|
||||||
|
unsigned OpenPoundIf = 0;
|
||||||
|
|
||||||
bool LastTokenWasFunc = false;
|
bool LastTokenWasFunc = false;
|
||||||
|
|
||||||
while (OpenBraces != 0 && P.Tok.isNot(tok::eof)) {
|
while ((OpenBraces != 0 || OpenPoundIf != 0) && P.Tok.isNot(tok::eof)) {
|
||||||
// Detect 'func' followed by an operator identifier.
|
// Detect 'func' followed by an operator identifier.
|
||||||
if (LastTokenWasFunc) {
|
if (LastTokenWasFunc) {
|
||||||
LastTokenWasFunc = false;
|
LastTokenWasFunc = false;
|
||||||
@@ -5692,6 +5693,24 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
|
|||||||
return OpenBraces;
|
return OpenBraces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match opening `#if` with closing `#endif` to match what the parser does,
|
||||||
|
// `#if` + `#endif` are considered stronger delimiters than `{` + `}`.
|
||||||
|
if (P.consumeIf(tok::pound_if)) {
|
||||||
|
OpenPoundIf += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (OpenPoundIf != 0) {
|
||||||
|
// We're in a `#if`, check to see if we've reached the end.
|
||||||
|
if (P.consumeIf(tok::pound_endif)) {
|
||||||
|
OpenPoundIf -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Consume the next token and continue iterating. We can swallow any
|
||||||
|
// amount of '{' and '}' while in the `#if`.
|
||||||
|
P.consumeToken();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (P.consumeIf(tok::l_brace)) {
|
if (P.consumeIf(tok::l_brace)) {
|
||||||
++OpenBraces;
|
++OpenBraces;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
36
test/Parse/rdar129195380.swift
Normal file
36
test/Parse/rdar129195380.swift
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// RUN: not %target-swift-frontend -experimental-skip-all-function-bodies -dump-parse %s | %FileCheck %s
|
||||||
|
|
||||||
|
// rdar://129195380 - Make sure the skipping logic can handle #if.
|
||||||
|
struct S {
|
||||||
|
// CHECK: func_decl{{.*}}:[[@LINE+1]]:3 - line:[[@LINE+11]]:3{{.*}}"foo()"
|
||||||
|
func foo() {
|
||||||
|
#if true
|
||||||
|
}
|
||||||
|
#if true
|
||||||
|
func bar() {
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// CHECK: func_decl{{.*}}:[[@LINE+1]]:3 - line:[[@LINE+1]]:15{{.*}}"baz()"
|
||||||
|
func baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The '#if' is unterminated here, so swallows the rest of the file.
|
||||||
|
// CHECK: struct_decl{{.*}}:[[@LINE+1]]:1 - line:[[@LINE+14]]:14{{.*}}"R"
|
||||||
|
struct R {
|
||||||
|
#if false
|
||||||
|
}
|
||||||
|
#if true
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
// CHECK-NOT: qux
|
||||||
|
func qux() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func flim() {}
|
||||||
13
test/SourceKit/CursorInfo/rdar129195380.swift
Normal file
13
test/SourceKit/CursorInfo/rdar129195380.swift
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// rdar://129195380 - Make sure we correctly handle '#if' when skipping function
|
||||||
|
// bodies.
|
||||||
|
class C {
|
||||||
|
func test1() {
|
||||||
|
#if FOOBAR
|
||||||
|
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 2):5 %s -- %s -DFOOBAR
|
||||||
|
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 1):5 %s -- %s
|
||||||
|
abc
|
||||||
|
}
|
||||||
|
|
||||||
|
func test2() {
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user