Repository: swiftlang/swift
Pull request #80126: [DiagnosticBridge] NFC: Refactor `addQueuedDiagnostic` to use Bridged* types instead of pointers
Author: login: xedin
Created: 2025-03-19T17:20:58Z | Merged: 2025-03-20T07:11:19Z

Instead of pointer + size for strings, `void *` for source locks and multiple entries for highlights refactor the API to use `BridgedStringRef`, `BridgedSourceLoc` and `BridgedCharSourceRange`.

<!--
If this pull request is targeting a release branch, please fill out the
following form:
https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1

Otherwise, replace this comment with a description of your changes and
rationale. Provide links to external references/discussions if appropriate.
If this pull request resolves any GitHub issues, link them like so:

  Resolves <link to issue>, resolves <link to another issue>.

For more information about linking a pull request to an issue, see:
https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->

<!--
Before merging this pull request, you must run the Swift continuous integration tests.
For information about triggering CI builds via @swift-ci, see:
https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci

Thank you for your contribution to Swift!
-->



Diff:
diff --git a/include/swift/Bridging/ASTGen.h b/include/swift/Bridging/ASTGen.h
index e50bad4780563..936e28a4af3d1 100644
--- a/include/swift/Bridging/ASTGen.h
+++ b/include/swift/Bridging/ASTGen.h
@@ -27,12 +27,12 @@ void swift_ASTGen_addQueuedSourceFile(
     intptr_t displayNameLength, ssize_t parentID, ssize_t positionInParent);
 void swift_ASTGen_addQueuedDiagnostic(
     void *_Nonnull queued, void *_Nonnull state,
-    const char *_Nonnull text, ptrdiff_t textLength,
-    BridgedDiagnosticSeverity severity, const void *_Nullable sourceLoc,
-    const char *_Nullable categoryName, ptrdiff_t categoryNameLength,
-    const char *_Nullable documentationPath,
-    ptrdiff_t documentationPathLength,
-    const void *_Nullable *_Nullable highlightRanges,
+    BridgedStringRef text,
+    BridgedDiagnosticSeverity severity,
+    BridgedSourceLoc sourceLoc,
+    BridgedStringRef categoryName,
+    BridgedStringRef documentationPath,
+    const BridgedCharSourceRange *_Nullable highlightRanges,
     ptrdiff_t numHighlightRanges);
 void swift_ASTGen_renderQueuedDiagnostics(
     void *_Nonnull queued, ssize_t contextSize, ssize_t colorize,
diff --git a/lib/AST/DiagnosticBridge.cpp b/lib/AST/DiagnosticBridge.cpp
index bf41c2a0e7da5..c2c7ab5bb6b73 100644
--- a/lib/AST/DiagnosticBridge.cpp
+++ b/lib/AST/DiagnosticBridge.cpp
@@ -56,13 +56,10 @@ static void addQueueDiagnostic(void *queuedDiagnostics,
   }
 
   // Map the highlight ranges.
-  SmallVector<const void *, 2> highlightRanges;
+  SmallVector<BridgedCharSourceRange, 2> highlightRanges;
   for (const auto &range : info.Ranges) {
-    if (range.isInvalid())
-      continue;
-
-    highlightRanges.push_back(range.getStart().getOpaquePointerValue());
-    highlightRanges.push_back(range.getEnd().getOpaquePointerValue());
+    if (range.isValid())
+      highlightRanges.push_back(range);
   }
 
   StringRef documentationPath;
@@ -71,14 +68,12 @@ static void addQueueDiagnostic(void *queuedDiagnostics,
 
   // FIXME: Translate Fix-Its.
   swift_ASTGen_addQueuedDiagnostic(queuedDiagnostics, perFrontendState,
-                                   text.data(), text.size(),
-                                   severity, info.Loc.getOpaquePointerValue(),
-                                   info.Category.data(),
-                                   info.Category.size(),
-                                   documentationPath.data(),
-                                   documentationPath.size(),
+                                   text.str(),
+                                   severity, info.Loc,
+                                   info.Category,
+                                   documentationPath,
                                    highlightRanges.data(),
-                                   highlightRanges.size() / 2);
+                                   highlightRanges.size());
 
   // TODO: A better way to do this would be to pass the notes as an
   // argument to `swift_ASTGen_addQueuedDiagnostic` but that requires
diff --git a/lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift b/lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
index f367292963c50..ead74ef9af587 100644
--- a/lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
+++ b/lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
@@ -241,15 +241,12 @@ public func addQueuedSourceFile(
 public func addQueuedDiagnostic(
   queuedDiagnosticsPtr: UnsafeMutableRawPointer,
   perFrontendDiagnosticStatePtr: UnsafeMutableRawPointer,
-  text: UnsafePointer<UInt8>,
-  textLength: Int,
+  text: BridgedStringRef,
   severity: BridgedDiagnosticSeverity,
   cLoc: BridgedSourceLoc,
-  categoryName: UnsafePointer<UInt8>?,
-  categoryLength: Int,
-  documentationPath: UnsafePointer<UInt8>?,
-  documentationPathLength: Int,
-  highlightRangesPtr: UnsafePointer<BridgedSourceLoc>?,
+  categoryName: BridgedStringRef,
+  documentationPath: BridgedStringRef,
+  highlightRangesPtr: UnsafePointer<BridgedCharSourceRange>?,
   numHighlightRanges: Int
 ) {
   let queuedDiagnostics = queuedDiagnosticsPtr.assumingMemoryBound(
@@ -302,14 +299,16 @@ public func addQueuedDiagnostic(
 
   // Map the highlights.
   var highlights: [Syntax] = []
-  let highlightRanges = UnsafeBufferPointer<BridgedSourceLoc>(
+  let highlightRanges = UnsafeBufferPointer<BridgedCharSourceRange>(
     start: highlightRangesPtr,
-    count: numHighlightRanges * 2
+    count: numHighlightRanges
   )
   for index in 0..<numHighlightRanges {
+    let range = highlightRanges[index]
+
     // Make sure both the start and the end land within this source file.
-    guard let start = highlightRanges[index * 2].getOpaquePointerValue(),
-      let end = highlightRanges[index * 2 + 1].getOpaquePointerValue()
+    guard let start = range.start.getOpaquePointerValue(),
+      let end = range.start.advanced(by: range.byteLength).getOpaquePointerValue()
     else {
       continue
     }
@@ -349,53 +348,37 @@ public func addQueuedDiagnostic(
     }
   }
 
-  let category: DiagnosticCategory? = categoryName.flatMap { categoryNamePtr in
-    let categoryNameBuffer = UnsafeBufferPointer(
-      start: categoryNamePtr,
-      count: categoryLength
-    )
-    let categoryName = String(decoding: categoryNameBuffer, as: UTF8.self)
-
-    // If the data comes from serialized diagnostics, it's possible that
-    // the category name is empty because StringRef() is serialized into
-    // an empty string.
-    guard !categoryName.isEmpty else {
-      return nil
+  let documentationPath = String(bridged: documentationPath)
+  let documentationURL: String? = if !documentationPath.isEmpty {
+      // If this looks doesn't look like a URL, prepend file://.
+      documentationPath.looksLikeURL ? documentationPath : "file://\(documentationPath)"
+    } else {
+      nil
     }
 
-    let documentationURL = documentationPath.map { documentationPathPtr in
-      let documentationPathBuffer = UnsafeBufferPointer(
-        start: documentationPathPtr,
-        count: documentationPathLength
+  let categoryName = String(bridged: categoryName)
+  // If the data comes from serialized diagnostics, it's possible that
+  // the category name is empty because StringRef() is serialized into
+  // an empty string.
+  let category: DiagnosticCategory? = if !categoryName.isEmpty {
+      DiagnosticCategory(
+        name: categoryName,
+        documentationURL: documentationURL
       )
-
-      let documentationPath = String(decoding: documentationPathBuffer, as: UTF8.self)
-
-      // If this looks doesn't look like a URL, prepend file://.
-      if !documentationPath.looksLikeURL {
-        return "file://\(documentationPath)"
-      }
-
-      return documentationPath
+    } else {
+      nil
     }
 
-    return DiagnosticCategory(
-      name: categoryName,
-      documentationURL: documentationURL
-    )
-  }
-
   // Note that we referenced this category.
   if let category {
     diagnosticState.pointee.referencedCategories.insert(category)
   }
 
-  let textBuffer = UnsafeBufferPointer(start: text, count: textLength)
   let diagnostic = Diagnostic(
     node: node,
     position: position,
     message: SimpleDiagnostic(
-      message: String(decoding: textBuffer, as: UTF8.self),
+      message: String(bridged: text),
       severity: severity.asSeverity,
       category: category
     ),


Reviews:
user: login: rintaro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T17:29:42Z
user: login: rintaro
body: Thank you!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-19T19:08:53Z

Review comments:
diff_hunk: @@ -349,10 +348,10 @@ public func addQueuedDiagnostic(
     }
   }
 
-  let category: DiagnosticCategory? = categoryName.flatMap { categoryNamePtr in
+  let category: DiagnosticCategory? = categoryName.data.flatMap { categoryNamePtr in
     let categoryNameBuffer = UnsafeBufferPointer(
       start: categoryNamePtr,
-      count: categoryLength
+      count: categoryName.count
     )
     let categoryName = String(decoding: categoryNameBuffer, as: UTF8.self)
path: lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
user: login: rintaro
body: `String` has an extension `init(bridging: BridgedStringRef)`
created_at: 2025-03-19T17:28:19Z
author_association: MEMBER
diff_hunk: @@ -363,10 +362,10 @@ public func addQueuedDiagnostic(
       return nil
     }
 
-    let documentationURL = documentationPath.map { documentationPathPtr in
+    let documentationURL = documentationPath.data.map { documentationPathPtr in
       let documentationPathBuffer = UnsafeBufferPointer(
         start: documentationPathPtr,
-        count: documentationPathLength
+        count: documentationPath.count
       )
 
       let documentationPath = String(decoding: documentationPathBuffer, as: UTF8.self)
path: lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
user: login: rintaro
body: ditto `init(bridging: BridgedStringRef)`
created_at: 2025-03-19T17:28:34Z
author_association: MEMBER
diff_hunk: @@ -390,7 +389,11 @@ public func addQueuedDiagnostic(
     diagnosticState.pointee.referencedCategories.insert(category)
   }
 
-  let textBuffer = UnsafeBufferPointer(start: text, count: textLength)
+  guard let textPtr = text.data, !text.isEmpty else {
+    return
+  }
+  
+  let textBuffer = UnsafeBufferPointer(start: textPtr, count: text.count)
path: lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
user: login: rintaro
body: ditto `String.init(bridging: BridgedStringRef)`
created_at: 2025-03-19T17:29:23Z
author_association: MEMBER

PR comments:
user: login: xedin
created_at: 2025-03-19T17:21:58Z
body: @swift-ci please test
author_association: CONTRIBUTOR
user: login: xedin
created_at: 2025-03-19T19:38:50Z
body: @swift-ci please test
author_association: CONTRIBUTOR