Skip to content

Commit 0670d6f

Browse files
authored
Merge pull request #65582 from hamishknight/buffering-5.9
2 parents 1994869 + 65e462d commit 0670d6f

File tree

19 files changed

+1060
-187
lines changed

19 files changed

+1060
-187
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,7 @@ namespace swift {
11691169

11701170
/// Retrieve the set of child notes that describe how the generated
11711171
/// source buffer was derived, e.g., a macro expansion backtrace.
1172-
std::vector<Diagnostic> getGeneratedSourceBufferNotes(
1173-
SourceLoc loc, Optional<unsigned> &lastBufferID);
1172+
std::vector<Diagnostic> getGeneratedSourceBufferNotes(SourceLoc loc);
11741173

11751174
/// Handle a new diagnostic, which will either be emitted, or added to an
11761175
/// active transaction.

lib/AST/DiagnosticEngine.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,9 +1272,8 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
12721272
diagnostic.isChildNote());
12731273
}
12741274

1275-
std::vector<Diagnostic> DiagnosticEngine::getGeneratedSourceBufferNotes(
1276-
SourceLoc loc, Optional<unsigned> &lastBufferID
1277-
) {
1275+
std::vector<Diagnostic>
1276+
DiagnosticEngine::getGeneratedSourceBufferNotes(SourceLoc loc) {
12781277
// The set of child notes we're building up.
12791278
std::vector<Diagnostic> childNotes;
12801279

@@ -1285,12 +1284,6 @@ std::vector<Diagnostic> DiagnosticEngine::getGeneratedSourceBufferNotes(
12851284
// If we already emitted these notes for a prior part of the diagnostic,
12861285
// don't do so again.
12871286
auto currentBufferID = SourceMgr.findBufferContainingLoc(loc);
1288-
if (currentBufferID == lastBufferID)
1289-
return childNotes;
1290-
1291-
// Keep track of the last buffer ID we considered.
1292-
lastBufferID = currentBufferID;
1293-
12941287
SourceLoc currentLoc = loc;
12951288
do {
12961289
auto generatedInfo = SourceMgr.getGeneratedSourceInfo(currentBufferID);
@@ -1337,15 +1330,18 @@ std::vector<Diagnostic> DiagnosticEngine::getGeneratedSourceBufferNotes(
13371330
}
13381331

13391332
void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
1340-
Optional<unsigned> lastBufferID;
13411333

13421334
ArrayRef<Diagnostic> childNotes = diagnostic.getChildNotes();
13431335
std::vector<Diagnostic> extendedChildNotes;
13441336

13451337
if (auto info = diagnosticInfoForDiagnostic(diagnostic)) {
13461338
// If the diagnostic location is within a buffer containing generated
13471339
// source code, add child notes showing where the generation occurred.
1348-
extendedChildNotes = getGeneratedSourceBufferNotes(info->Loc, lastBufferID);
1340+
// We need to avoid doing this if this is itself a child note, as otherwise
1341+
// we'd end up doubling up on notes.
1342+
if (!info->IsChildNote) {
1343+
extendedChildNotes = getGeneratedSourceBufferNotes(info->Loc);
1344+
}
13491345
if (!extendedChildNotes.empty()) {
13501346
extendedChildNotes.insert(extendedChildNotes.end(),
13511347
childNotes.begin(), childNotes.end());

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
@@ -918,6 +918,15 @@ public struct InvalidMacro: PeerMacro, DeclarationMacro {
918918
}
919919
}
920920

921+
public struct CoerceToIntMacro: ExpressionMacro {
922+
public static func expansion(
923+
of node: some FreestandingMacroExpansionSyntax,
924+
in context: some MacroExpansionContext
925+
) -> ExprSyntax {
926+
"\(node.argumentList.first!.expression) as Int"
927+
}
928+
}
929+
921930
public struct WrapInType: PeerMacro {
922931
public static func expansion(
923932
of node: AttributeSyntax,

test/Macros/macro_expand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func testDiscardableStringify(x: Int) {
188188
func testNested() {
189189
struct Nested { }
190190
_ = #stringify(#assertAny(Nested()))
191-
// expected-note@-1 2 {{in expansion of macro 'stringify' here}}
191+
// expected-note@-1 {{in expansion of macro 'stringify' here}}
192192
// CHECK-DIAGS-NOT: error: cannot convert value of type 'Nested' to expected argument type 'Bool'
193193
// CHECK-DIAGS: @__swiftmacro_9MacroUser10testNestedyyF9stringifyfMf_9assertAnyfMf_.swift:1:8: error: cannot convert value of type 'Nested' to expected argument type 'Bool'
194194
// CHECK-DIAGS-NOT: error: cannot convert value of type 'Nested' to expected argument type 'Bool'

test/Macros/macro_expand_other.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Expanding macros that are defined in terms of other macros.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -parse-as-library -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
6+
// Diagnostics testing
7+
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-experimental-feature FreestandingMacros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS
8+
9+
// Execution testing
10+
// RUN: %target-build-swift -swift-version 5 -enable-experimental-feature FreestandingMacros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser
11+
// RUN: %target-codesign %t/main
12+
// RUN: %target-run %t/main | %FileCheck %s
13+
// REQUIRES: swift_swift_parser, executable_test
14+
15+
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
16+
17+
@freestanding(expression) macro stringifySeven() -> (Int, String) = #stringify(7)
18+
19+
@freestanding(expression) macro recurse(_: Bool) = #externalMacro(module: "MacroDefinition", type: "RecursiveMacro")
20+
21+
@freestanding(expression) macro recurseThrough(_ value: Bool) = #recurse(value)
22+
23+
func testFreestandingExpansionOfOther() {
24+
// CHECK: ---testFreestandingExpansionOfOther
25+
print("---testFreestandingExpansionOfOther")
26+
27+
// CHECK-NEXT: (7, "7")
28+
print(#stringifySeven)
29+
30+
#recurseThrough(false)
31+
32+
#if TEST_DIAGNOSTICS
33+
#recurseThrough(true)
34+
// expected-note@-1 {{in expansion of macro 'recurseThrough' here}}
35+
#endif
36+
}
37+
38+
testFreestandingExpansionOfOther()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %sourcekitd-test -req=diags %t/main.swift -- %t/main.swift -I %t | %FileCheck %s
4+
5+
//--- Header.h
6+
#define FOO(x) #x
7+
8+
//--- module.modulemap
9+
module HeaderWithMacro {
10+
header "Header.h"
11+
}
12+
13+
//--- main.swift
14+
import HeaderWithMacro
15+
16+
_ = FOO(5)
17+
18+
// rdar://107281079 – Make sure the note points in the .h file
19+
// CHECK: key.diagnostics: [
20+
// CHECK-NEXT: {
21+
// CHECK-NEXT: key.line: 3,
22+
// CHECK-NEXT: key.column: 5,
23+
// CHECK-NEXT: key.filepath: "{{.*}}main.swift",
24+
// CHECK-NEXT: key.severity: source.diagnostic.severity.error,
25+
// CHECK-NEXT: key.id: "cannot_find_in_scope",
26+
// CHECK-NEXT: key.description: "cannot find 'FOO' in scope",
27+
// CHECK-NEXT: key.ranges: [
28+
// CHECK-NEXT: {
29+
// CHECK-NEXT: key.offset: 28,
30+
// CHECK-NEXT: key.length: 3
31+
// CHECK-NEXT: }
32+
// CHECK-NEXT: ],
33+
// CHECK-NEXT: key.diagnostics: [
34+
// CHECK-NEXT: {
35+
// CHECK-NEXT: key.line: 1,
36+
// CHECK-NEXT: key.column: 9,
37+
// CHECK-NEXT: key.filepath: "{{.*}}Header.h",
38+
// CHECK-NEXT: key.severity: source.diagnostic.severity.note,
39+
// CHECK-NEXT: key.id: "macro_not_imported_function_like",
40+
// CHECK-NEXT: key.description: "macro 'FOO' unavailable: function like macros not supported"
41+
// CHECK-NEXT: }
42+
// CHECK-NEXT: ]
43+
// CHECK-NEXT: }
44+
// CHECK-NEXT: ]

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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
let _ = #stringify(#coerceToInt("c"))
14+
}
15+
16+
@Invalid
17+
struct Bad {}
18+
19+
// REQUIRES: swift_swift_parser
20+
21+
// RUN: %empty-directory(%t)
22+
23+
//##-- Prepare the macro plugin.
24+
// 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
25+
26+
// 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
27+
// RUN: %diff -u %s.response %t.response

0 commit comments

Comments
 (0)