File: CompletionResultsArrayBuilder.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (116 lines) | stat: -rw-r--r-- 4,306 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import CompletionScoring
import Csourcekitd
import Foundation
import SourceKitD
import SwiftSourceKitPluginCommon

struct CompletionResultsArrayBuilder {
  private let bufferKind: UInt64
  private var results: [CompletionResult] = []
  private var stringTable: [String: Int] = [:]
  private var nextString: Int = 0
  private let startLoc: Position

  init(bufferKind: UInt64, numResults: Int, session: CompletionSession) {
    self.bufferKind = bufferKind
    self.results.reserveCapacity(numResults)
    self.stringTable.reserveCapacity(numResults * 3)
    self.startLoc = session.location.position
  }

  private mutating func addString(_ str: String) -> CompletionResult.StringEntry {
    if let value = stringTable[str] {
      return CompletionResult.StringEntry(start: UInt32(value))
    } else {
      let value = nextString
      precondition(value < Int(UInt32.max))
      nextString += str.utf8.count + 1

      stringTable[str] = value
      return CompletionResult.StringEntry(start: UInt32(value))
    }
  }

  private mutating func addString(_ str: String?) -> CompletionResult.StringEntry? {
    guard let str else {
      return nil
    }
    return addString(str) as CompletionResult.StringEntry
  }

  mutating func add(_ item: CompletionItem, includeSemanticComponents: Bool, sourcekitd: SourceKitD) {
    let result = CompletionResult(
      kind: sourcekitd_api_uid_t(item.kind, sourcekitd: sourcekitd),
      identifier: item.id.opaqueValue,
      name: addString(item.filterText),
      description: addString(item.label),
      sourceText: addString(item.textEdit.newText),
      module: addString(item.module),
      typename: addString(item.typeName ?? ""),
      textMatchScore: item.textMatchScore,
      semanticScore: item.semanticScore,
      semanticScoreComponents: includeSemanticComponents ? addString(item.semanticClassification?.asBase64) : nil,
      priorityBucket: Int32(item.priorityBucket.rawValue),
      isSystem: item.isSystem,
      numBytesToErase: item.numBytesToErase(from: startLoc),
      hasDiagnostic: item.hasDiagnostic,
      groupID: Int64(item.groupID ?? 0)
    )
    results.append(result)
  }

  func bytes() -> [UInt8] {
    let capacity =
      MemoryLayout<UInt64>.size  // kind
      + MemoryLayout<Int>.size  // numResults
      + results.count * MemoryLayout<CompletionResult>.stride + nextString

    return Array<UInt8>(unsafeUninitializedCapacity: capacity) {
      (bytes: inout UnsafeMutableBufferPointer<UInt8>, size: inout Int) in
      size = capacity
      var cursor = UnsafeMutableRawBufferPointer(bytes)
      cursor.storeBytes(of: self.bufferKind, toByteOffset: 0, as: UInt64.self)
      cursor = UnsafeMutableRawBufferPointer(rebasing: cursor[MemoryLayout<UInt64>.size...])
      cursor.storeBytes(of: self.results.count, toByteOffset: 0, as: Int.self)
      cursor = UnsafeMutableRawBufferPointer(rebasing: cursor[MemoryLayout<Int>.size...])
      self.results.withUnsafeBytes { raw in
        cursor.copyMemory(from: raw)
        cursor = UnsafeMutableRawBufferPointer(rebasing: cursor[raw.count...])
      }
      for (str, startOffset) in stringTable {
        let slice = UnsafeMutableRawBufferPointer(rebasing: cursor[startOffset...])
        str.utf8CString.withUnsafeBytes { raw in
          slice.copyMemory(from: raw)
        }
      }
    }
  }
}

extension CompletionItem {
  func numBytesToErase(from: Position) -> Int {
    guard textEdit.range.lowerBound.line == from.line else {
      assertionFailure("unsupported multi-line completion edit start \(from) vs \(textEdit)")
      return 0
    }
    return from.utf8Column - textEdit.range.lowerBound.utf8Column
  }
}

extension SemanticClassification {
  var asBase64: String {
    return Data(self.byteRepresentation()).base64EncodedString()
  }
}