Skip to content

Commit 6b18eeb

Browse files
committed
[SourceKit] Include generated macro buffers in diagnostic responses
Introduce a new key `generated_buffers`, which stores an array of generated buffers. These include the buffer text, as well as its original location and any parent buffers. While here, also fix rdar://107281079 such that only apply the filename fallback logic to the pretty-printed Decl case. We ought to remove this fallback once the editor can handle it though. rdar://107281079 rdar://107952288
1 parent c21dd79 commit 6b18eeb

File tree

17 files changed

+1032
-144
lines changed

17 files changed

+1032
-144
lines changed

lib/Frontend/SerializedDiagnosticConsumer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ unsigned SerializedDiagnosticConsumer::getEmitFile(
231231
// NOTE: Using Filename.data() here relies on SourceMgr using
232232
// const char* as buffer identifiers. This is fast, but may
233233
// be brittle. We can always switch over to using a StringMap.
234+
// Note that the logic in EditorDiagConsumer::getBufferInfo
235+
// will also need changing.
234236
unsigned &existingEntry = State->Files[Filename.data()];
235237
if (existingEntry)
236238
return existingEntry;

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,15 @@ public struct InvalidMacro: PeerMacro, DeclarationMacro {
897897
}
898898
}
899899

900+
public struct CoerceToIntMacro: ExpressionMacro {
901+
public static func expansion(
902+
of node: some FreestandingMacroExpansionSyntax,
903+
in context: some MacroExpansionContext
904+
) -> ExprSyntax {
905+
"\(node.argumentList.first!.expression) as Int"
906+
}
907+
}
908+
900909
public struct WrapInType: PeerMacro {
901910
public static func expansion(
902911
of node: AttributeSyntax,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %sourcekitd-test -req=diags %s -- %s -I %S/../Inputs/header_with_macro | %FileCheck %s
2+
3+
import HeaderWithMacro
4+
5+
_ = FOO(5)
6+
7+
// CHECK: key.diagnostics: [
8+
// CHECK-NEXT: {
9+
// CHECK-NEXT: key.line: 5,
10+
// CHECK-NEXT: key.column: 5,
11+
// CHECK-NEXT: key.filepath: "{{.*}}/rdar107281079.swift",
12+
// CHECK-NEXT: key.severity: source.diagnostic.severity.error,
13+
// CHECK-NEXT: key.id: "cannot_find_in_scope",
14+
// CHECK-NEXT: key.description: "cannot find 'FOO' in scope",
15+
// CHECK-NEXT: key.ranges: [
16+
// CHECK-NEXT: {
17+
// CHECK-NEXT: key.offset: 124,
18+
// CHECK-NEXT: key.length: 3
19+
// CHECK-NEXT: }
20+
// CHECK-NEXT: ],
21+
// CHECK-NEXT: key.diagnostics: [
22+
// CHECK-NEXT: {
23+
// CHECK-NEXT: key.line: 4,
24+
// CHECK-NEXT: key.column: 9,
25+
// CHECK-NEXT: key.filepath: "{{.*}}/Inputs/header_with_macro/Header.h",
26+
// CHECK-NEXT: key.severity: source.diagnostic.severity.note,
27+
// CHECK-NEXT: key.id: "macro_not_imported_function_like",
28+
// CHECK-NEXT: key.description: "macro 'FOO' unavailable: function like macros not supported"
29+
// CHECK-NEXT: }
30+
// CHECK-NEXT: ]
31+
// CHECK-NEXT: }
32+
// CHECK-NEXT: ]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef Header_h
2+
#define Header_h
3+
4+
#define FOO(x) #x
5+
6+
#endif /* Header_h */
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module HeaderWithMacro {
2+
header "Header.h"
3+
}

test/SourceKit/Inputs/sourcekitd_path_sanitize.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,35 @@
1212
import re
1313
import sys
1414

15-
SWIFTMODULE_BUNDLE_RE = re.compile(
16-
r'key.filepath: ".*[/\\](.*)\.swiftmodule[/\\].*\.swiftmodule"')
17-
SWIFTMODULE_RE = re.compile(r'key.filepath: ".*[/\\](.*)\.swiftmodule"')
18-
SWIFT_RE = re.compile(r'key.filepath: ".*[/\\](.*)\.swift"')
19-
PCM_RE = re.compile(r'key.filepath: ".*[/\\](.*)-[0-9A-Z]*\.pcm"')
20-
HEADER_RE = re.compile(r' file=\\".*[/\\](.*)\.h\\"')
15+
# I'm sorry dear reader, unfortunately my knowledge of regex trumps my knowledge of
16+
# Python. This pattern allows us to clean up file paths by stripping them down to
17+
# just the relevant file name.
18+
RE = re.compile(
19+
# The key can either be 'filepath' or 'buffer_name'. Also apply this logic to
20+
# the file name in XML, which is written 'file=\"...\"'.
21+
r'(key\.(?:filepath|buffer_name): |file=)'
22+
23+
# Open delimiter with optional escape.
24+
r'\\?"'
25+
26+
# Lazily match characters until we hit a slash, then match any non-slash that
27+
# ends in the right file extension, capturing the result.
28+
r'.*?[/\\]+([^/\\]*\.(?:swiftmodule|swift|pcm|h))'
29+
30+
# For swiftmodule bundles, we want to match against the directory name, so
31+
# optionally match the .swiftmodule filename here. The lazy matching of the
32+
# previous logic means we'll prefer to match the previous '.swiftmodule' as the
33+
# directory.
34+
r'(?:[/\\]+[^/\\]*\.swiftmodule)?'
35+
36+
# Close delimiter with optional escape.
37+
r'\\?"'
38+
)
2139

2240
try:
2341
for line in sys.stdin.readlines():
24-
line = re.sub(SWIFTMODULE_BUNDLE_RE,
25-
r'key.filepath: \1.swiftmodule', line)
26-
line = re.sub(SWIFTMODULE_RE, r'key.filepath: \1.swiftmodule', line)
27-
line = re.sub(SWIFT_RE, r'key.filepath: \1.swift', line)
28-
line = re.sub(PCM_RE, r'key.filepath: \1.pcm', line)
29-
line = re.sub(HEADER_RE, r' file=\1.h', line)
42+
# We substitute in both the key and the matched filename.
43+
line = re.sub(RE, r'\1\2', line)
3044
sys.stdout.write(line)
3145
except KeyboardInterrupt:
3246
sys.stdout.flush()

test/SourceKit/Macros/diags.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@freestanding(expression)
2+
macro coerceToInt<T>(_: T) -> Int = #externalMacro(module: "MacroDefinition", type: "CoerceToIntMacro")
3+
4+
@freestanding(expression)
5+
macro stringify<T>(_: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
6+
7+
@attached(peer)
8+
macro Invalid() = #externalMacro(module: "MacroDefinition", type: "InvalidMacro")
9+
10+
func foo() {
11+
let _ = #coerceToInt("a")
12+
let _ = #coerceToInt("b")
13+
14+
// FIXME: There's currently a duplicate diagnostic issue with this,
15+
// so the response lists the same diagnostic twice, and has a spurious
16+
// buffer containing the expansion of `#coerceToInt` on its own (rdar://108622244).
17+
let _ = #stringify(#coerceToInt("c"))
18+
}
19+
20+
@Invalid
21+
struct Bad {}
22+
23+
// REQUIRES: swift_swift_parser
24+
25+
// RUN: %empty-directory(%t)
26+
27+
//##-- Prepare the macro plugin.
28+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/../../Macros/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
29+
30+
// RUN: %sourcekitd-test -req=diags %s -- -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser %s | %sed_clean > %t.response
31+
// RUN: %diff -u %s.response %t.response

0 commit comments

Comments
 (0)