mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
632 lines
25 KiB
Swift
632 lines
25 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
@_spi(SourceKitLSP) import SKLogging
|
|
import SourceKitD
|
|
import SwiftExtensions
|
|
|
|
/// A single code completion result returned from sourcekitd + additional information. This is effectively a wrapper
|
|
/// around `swiftide_api_completion_item_t` that caches the properties which have already been retrieved.
|
|
/// - Note: There can many be `ASTCompletionItem` instances (e.g. global completion has ~100k items), make sure to check
|
|
/// layout when adding new fields to ensure we're not wasting a bunch of space.
|
|
/// (i.e.,`heap --showInternalFragmentation process_name`)
|
|
final class ASTCompletionItem {
|
|
let impl: swiftide_api_completion_item_t
|
|
|
|
/// The string that should be used to match against what the user type.
|
|
var filterName: String {
|
|
return _filterName.cachedValueOrCompute {
|
|
filterNameCString != nil ? String(cString: filterNameCString!) : ""
|
|
}
|
|
}
|
|
let filterNameCString: UnsafePointer<CChar>?
|
|
private var _filterName: LazyValue<String> = .uninitialized
|
|
|
|
/// The label with which the item should be displayed in an IDE
|
|
func label(in session: CompletionSession) -> String {
|
|
return _label.cachedValueOrCompute {
|
|
var value: String?
|
|
session.sourcekitd.ideApi.completion_item_get_label(session.response, impl, session.options.annotateResults) {
|
|
value = String(cString: $0!)
|
|
}
|
|
return value!
|
|
}
|
|
}
|
|
private var _label: LazyValue<String> = .uninitialized
|
|
|
|
func sourceText(in session: CompletionSession) -> String {
|
|
return _sourceText.cachedValueOrCompute {
|
|
var value: String?
|
|
session.sourcekitd.ideApi.completion_item_get_source_text(session.response, impl) {
|
|
value = String(cString: $0!)
|
|
}
|
|
return value!
|
|
}
|
|
}
|
|
private var _sourceText: LazyValue<String> = .uninitialized
|
|
|
|
/// The type that the code completion item produces.
|
|
///
|
|
/// Eg. the type of a variable or the return type of a function. `nil` for completions that don't have a type, like
|
|
/// keywords.
|
|
func typeName(in session: CompletionSession) -> String? {
|
|
return _typeName.cachedValueOrCompute {
|
|
var value: String?
|
|
session.sourcekitd.ideApi.completion_item_get_type_name(session.response, impl, session.options.annotateResults) {
|
|
if let cstr = $0 {
|
|
value = String(cString: cstr)
|
|
}
|
|
}
|
|
return value
|
|
}
|
|
}
|
|
private var _typeName: LazyValue<String?> = .uninitialized
|
|
|
|
/// The module that defines the code completion item or `nil` if the item is not defined in a module, like a keyword.
|
|
func moduleName(in session: CompletionSession) -> String? {
|
|
return _moduleName.cachedValueOrCompute {
|
|
var value: String?
|
|
session.sourcekitd.ideApi.completion_item_get_module_name(session.response, impl) {
|
|
if let cstr = $0 {
|
|
value = String(cString: cstr)
|
|
} else {
|
|
value = nil
|
|
}
|
|
}
|
|
if value == "" {
|
|
return nil
|
|
}
|
|
return value
|
|
}
|
|
}
|
|
private var _moduleName: LazyValue<String?> = .uninitialized
|
|
|
|
func priorityBucket(in session: CompletionSession) -> CompletionItem.PriorityBucket {
|
|
return _priorityBucket.cachedValueOrCompute {
|
|
CompletionItem.PriorityBucket(self, in: session)
|
|
}
|
|
}
|
|
private var _priorityBucket: LazyValue<CompletionItem.PriorityBucket> = .uninitialized
|
|
|
|
let completionKind: CompletionContext.Kind
|
|
|
|
let index: UInt32
|
|
|
|
func semanticScore(in session: CompletionSession) -> Double {
|
|
return _semanticScore.cachedValueOrCompute {
|
|
let semanticClassification = semanticClassification(in: session)
|
|
self.semanticClassification = semanticClassification
|
|
return semanticClassification.score
|
|
}
|
|
}
|
|
private var _semanticScore: LazyValue<Double> = .uninitialized
|
|
|
|
private func semanticClassification(in session: CompletionSession) -> SemanticClassification {
|
|
var module = moduleName(in: session)
|
|
if let baseModule = module?.split(separator: ".", maxSplits: 1).first {
|
|
// `PopularityIndex` is keyed on base module names.
|
|
// For example: "AppKit.NSImage" -> "AppKit".
|
|
module = String(baseModule)
|
|
}
|
|
let popularity = session.popularity(
|
|
ofSymbol: filterName,
|
|
inModule: module
|
|
)
|
|
return SemanticClassification(
|
|
availability: availability(in: session),
|
|
completionKind: semanticScoreCompletionKind(in: session),
|
|
flair: flair(in: session),
|
|
moduleProximity: moduleProximity(in: session),
|
|
popularity: popularity ?? .none,
|
|
scopeProximity: scopeProximity(in: session),
|
|
structuralProximity: structuralProximity(in: session),
|
|
synchronicityCompatibility: synchronicityCompatibility(in: session),
|
|
typeCompatibility: typeCompatibility(in: session)
|
|
)
|
|
}
|
|
var semanticClassification: SemanticClassification? = nil
|
|
|
|
var kind: CompletionItem.ItemKind
|
|
|
|
func semanticContext(in session: CompletionSession) -> CompletionItem.SemanticContext {
|
|
.init(
|
|
swiftide_api_completion_semantic_context_t(session.sourcekitd.ideApi.completion_item_get_semantic_context(impl))
|
|
)
|
|
}
|
|
|
|
func typeRelation(in session: CompletionSession) -> CompletionItem.TypeRelation {
|
|
.init(swiftide_api_completion_type_relation_t(session.sourcekitd.ideApi.completion_item_get_type_relation(impl)))
|
|
}
|
|
|
|
func numBytesToErase(in session: CompletionSession) -> Int {
|
|
Int(session.sourcekitd.ideApi.completion_item_get_num_bytes_to_erase(impl))
|
|
}
|
|
|
|
func notRecommended(in session: CompletionSession) -> Bool {
|
|
session.sourcekitd.ideApi.completion_item_is_not_recommended(impl)
|
|
}
|
|
|
|
func notRecommendedReason(in session: CompletionSession) -> NotRecommendedReason? {
|
|
guard notRecommended(in: session) else {
|
|
return nil
|
|
}
|
|
return NotRecommendedReason(impl, sourcekitd: session.sourcekitd)
|
|
}
|
|
|
|
func isSystem(in session: CompletionSession) -> Bool { session.sourcekitd.ideApi.completion_item_is_system(impl) }
|
|
|
|
func hasDiagnostic(in session: CompletionSession) -> Bool {
|
|
session.sourcekitd.ideApi.completion_item_has_diagnostic(impl)
|
|
}
|
|
|
|
init(
|
|
_ cresult: swiftide_api_completion_item_t,
|
|
filterName: UnsafePointer<CChar>?,
|
|
completionKind: CompletionContext.Kind,
|
|
index: UInt32,
|
|
sourcekitd: SourceKitD
|
|
) {
|
|
self.impl = cresult
|
|
self.filterNameCString = filterName
|
|
self.completionKind = completionKind
|
|
self.index = index
|
|
self.kind = .init(
|
|
swiftide_api_completion_item_kind_t(sourcekitd.ideApi.completion_item_get_kind(impl)),
|
|
associatedKind: sourcekitd.ideApi.completion_item_get_associated_kind(impl)
|
|
)
|
|
}
|
|
|
|
enum NotRecommendedReason {
|
|
case softDeprecated
|
|
case deprecated
|
|
case redundantImport
|
|
case redundantImportImplicit
|
|
case invalidAsyncContext
|
|
case crossActorReference
|
|
case variableUsedInOwnDefinition
|
|
case nonAsyncAlternativeUsedInAsyncContext
|
|
|
|
init?(_ item: swiftide_api_completion_item_t, sourcekitd: SourceKitD) {
|
|
let rawReason = sourcekitd.ideApi.completion_item_not_recommended_reason(item)
|
|
switch swiftide_api_completion_not_recommended_reason_t(rawReason) {
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_NONE:
|
|
return nil
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_REDUNDANT_IMPORT:
|
|
self = .redundantImport
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_DEPRECATED:
|
|
self = .deprecated
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_INVALID_ASYNC_CONTEXT:
|
|
self = .invalidAsyncContext
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_CROSS_ACTOR_REFERENCE:
|
|
self = .crossActorReference
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_VARIABLE_USED_IN_OWN_DEFINITION:
|
|
self = .variableUsedInOwnDefinition
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_SOFTDEPRECATED:
|
|
self = .softDeprecated
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_REDUNDANT_IMPORT_INDIRECT:
|
|
self = .redundantImportImplicit
|
|
case SWIFTIDE_COMPLETION_NOT_RECOMMENDED_NON_ASYNC_ALTERNATIVE_USED_IN_ASYNC_CONTEXT:
|
|
self = .nonAsyncAlternativeUsedInAsyncContext
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ASTCompletionItem {
|
|
private func semanticScoreCompletionKind(in session: CompletionSession) -> CompletionKind {
|
|
if session.sourcekitd.ideApi.completion_item_get_flair(impl) & SWIFTIDE_COMPLETION_FLAIR_ARGUMENTLABELS.rawValue
|
|
!= 0
|
|
{
|
|
return .argumentLabels
|
|
}
|
|
switch kind {
|
|
case .module:
|
|
return .module
|
|
case .class, .actor, .struct, .enum, .protocol, .associatedType, .typeAlias, .genericTypeParam, .precedenceGroup:
|
|
return .type
|
|
case .enumElement:
|
|
return .enumCase
|
|
case .constructor:
|
|
return .initializer
|
|
case .destructor:
|
|
// FIXME: add a "deinit" kind.
|
|
return .function
|
|
case .subscript:
|
|
// FIXME: add a "subscript" kind.
|
|
return .function
|
|
case .staticMethod, .instanceMethod, .freeFunction:
|
|
return .function
|
|
case .operator, .prefixOperatorFunction, .postfixOperatorFunction, .infixOperatorFunction:
|
|
// FIXME: add an "operator kind".
|
|
return .other
|
|
case .staticVar, .instanceVar, .localVar, .globalVar:
|
|
return .variable
|
|
case .keyword:
|
|
return .keyword
|
|
case .literal:
|
|
// FIXME: add a "literal" kind?
|
|
return .other
|
|
case .pattern:
|
|
// FIXME: figure out a kind for this.
|
|
return .other
|
|
case .macro:
|
|
// FIXME: add a "macro" kind?
|
|
return .type
|
|
case .unknown:
|
|
return .unknown
|
|
}
|
|
}
|
|
|
|
private func flair(in session: CompletionSession) -> Flair {
|
|
var result: Flair = []
|
|
let skFlair = session.sourcekitd.ideApi.completion_item_get_flair(impl)
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_EXPRESSIONSPECIFIC.rawValue != 0 {
|
|
result.insert(.oldExpressionSpecific_pleaseAddSpecificCaseToThisEnum)
|
|
}
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_SUPERCHAIN.rawValue != 0 {
|
|
result.insert(.chainedCallToSuper)
|
|
}
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_COMMONKEYWORDATCURRENTPOSITION.rawValue != 0 {
|
|
result.insert(.commonKeywordAtCurrentPosition)
|
|
}
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_RAREKEYWORDATCURRENTPOSITION.rawValue != 0 {
|
|
result.insert(.rareKeywordAtCurrentPosition)
|
|
}
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_RARETYPEATCURRENTPOSITION.rawValue != 0 {
|
|
result.insert(.rareKeywordAtCurrentPosition)
|
|
}
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_EXPRESSIONATNONSCRIPTORMAINFILESCOPE.rawValue != 0 {
|
|
result.insert(.expressionAtNonScriptOrMainFileScope)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private func moduleProximity(in session: CompletionSession) -> ModuleProximity {
|
|
switch semanticContext(in: session) {
|
|
case .none:
|
|
return .inapplicable
|
|
case .local, .currentNominal, .outsideNominal:
|
|
return .imported(distance: 0)
|
|
case .super:
|
|
// FIXME: we don't know whether the super class is from this module or another.
|
|
return .unspecified
|
|
case .currentModule:
|
|
return .imported(distance: 0)
|
|
case .otherModule:
|
|
let depth = session.sourcekitd.ideApi.completion_item_import_depth(session.response, self.impl)
|
|
if depth == ~0 {
|
|
return .unknown
|
|
} else {
|
|
return .imported(distance: Int(depth))
|
|
}
|
|
}
|
|
}
|
|
|
|
private func scopeProximity(in session: CompletionSession) -> ScopeProximity {
|
|
switch semanticContext(in: session) {
|
|
case .none:
|
|
return .inapplicable
|
|
case .local:
|
|
return .local
|
|
case .currentNominal:
|
|
return .container
|
|
case .super:
|
|
return .inheritedContainer
|
|
case .outsideNominal:
|
|
return .outerContainer
|
|
case .currentModule, .otherModule:
|
|
return .global
|
|
}
|
|
}
|
|
|
|
private func structuralProximity(in session: CompletionSession) -> StructuralProximity {
|
|
switch kind {
|
|
case .keyword, .literal:
|
|
return .inapplicable
|
|
default:
|
|
return isSystem(in: session) ? .sdk : .project(fileSystemHops: nil)
|
|
}
|
|
}
|
|
|
|
func synchronicityCompatibility(in session: CompletionSession) -> SynchronicityCompatibility {
|
|
return notRecommendedReason(in: session) == .invalidAsyncContext ? .incompatible : .compatible
|
|
}
|
|
|
|
func typeCompatibility(in session: CompletionSession) -> TypeCompatibility {
|
|
switch typeRelation(in: session) {
|
|
case .identical: return .compatible
|
|
case .convertible: return .compatible
|
|
case .notApplicable: return .inapplicable
|
|
case .unrelated: return .unrelated
|
|
// Note: currently `unknown` in sourcekit usually means there is no context (e.g. statement level), which is
|
|
// equivalent to `inapplicable`. For now, map it that way to avoid spurious penalties.
|
|
case .unknown: return .inapplicable
|
|
case .invalid: return .invalid
|
|
}
|
|
}
|
|
|
|
func availability(in session: CompletionSession) -> Availability {
|
|
switch notRecommendedReason(in: session) {
|
|
case .deprecated:
|
|
return .deprecated
|
|
case .softDeprecated:
|
|
return .softDeprecated
|
|
case .invalidAsyncContext, .crossActorReference:
|
|
return .available
|
|
case .redundantImport, .variableUsedInOwnDefinition:
|
|
return .softDeprecated
|
|
case .redundantImportImplicit:
|
|
return .available
|
|
case .nonAsyncAlternativeUsedInAsyncContext:
|
|
return .softDeprecated
|
|
case nil:
|
|
return .available
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionItem {
|
|
init(
|
|
_ astItem: ASTCompletionItem,
|
|
score: CompletionScore,
|
|
in session: CompletionSession,
|
|
completionReplaceRange: Range<Position>,
|
|
groupID: (_ baseName: String) -> Int
|
|
) {
|
|
self.label = astItem.label(in: session)
|
|
self.filterText = astItem.filterName
|
|
self.module = astItem.moduleName(in: session)
|
|
self.typeName = astItem.typeName(in: session)
|
|
var editRange = completionReplaceRange
|
|
if astItem.numBytesToErase(in: session) > 0 {
|
|
let newCol = editRange.lowerBound.utf8Column - astItem.numBytesToErase(in: session)
|
|
if newCol >= 1 {
|
|
editRange = Position(line: editRange.lowerBound.line, utf8Column: newCol)..<editRange.upperBound
|
|
} else {
|
|
session.logger.error("num_bytes_to_erase crosses line boundary. Resetting num_bytes_to_erase to 0.")
|
|
}
|
|
}
|
|
self.textEdit = TextEdit(range: editRange, newText: astItem.sourceText(in: session))
|
|
self.kind = astItem.kind
|
|
self.isSystem = astItem.isSystem(in: session)
|
|
self.textMatchScore = score.textComponent
|
|
self.priorityBucket = astItem.priorityBucket(in: session)
|
|
self.semanticScore = score.semanticComponent
|
|
self.semanticClassification = astItem.semanticClassification
|
|
self.id = Identifier(index: astItem.index)
|
|
self.hasDiagnostic = astItem.hasDiagnostic(in: session)
|
|
|
|
let needsGroupID =
|
|
switch kind {
|
|
case .staticVar, .instanceVar, .localVar, .globalVar:
|
|
// We don't want to group variables with functions that have an equal base name.
|
|
false
|
|
case .keyword:
|
|
false
|
|
default:
|
|
true
|
|
}
|
|
// Set groupId using the name before '('.
|
|
// This allows top-level completions to be grouped together
|
|
// (including the actual type completion).
|
|
// For example:
|
|
// ```
|
|
// MyClass
|
|
// MyClass(test:)
|
|
// MyClass(other:)
|
|
// ```
|
|
if needsGroupID {
|
|
var baseName = filterText
|
|
if let parenIdx = baseName.firstIndex(of: "(") {
|
|
baseName = String(baseName[..<parenIdx])
|
|
}
|
|
self.groupID = groupID(baseName)
|
|
} else {
|
|
self.groupID = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionItem.ItemKind {
|
|
init(_ ckind: swiftide_api_completion_item_kind_t, associatedKind: UInt32) {
|
|
switch ckind {
|
|
case SWIFTIDE_COMPLETION_ITEM_KIND_DECLARATION:
|
|
switch swiftide_api_completion_item_decl_kind_t(associatedKind) {
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_MODULE: self = .module
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_CLASS: self = .class
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_ACTOR: self = .actor
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_STRUCT: self = .struct
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_ENUM: self = .enum
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_ENUMELEMENT: self = .enumElement
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_PROTOCOL: self = .protocol
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_ASSOCIATEDTYPE: self = .associatedType
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_TYPEALIAS: self = .typeAlias
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_GENERICTYPEPARAM: self = .genericTypeParam
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_CONSTRUCTOR: self = .constructor
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_DESTRUCTOR: self = .destructor
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_SUBSCRIPT: self = .subscript
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_STATICMETHOD: self = .staticMethod
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_INSTANCEMETHOD: self = .instanceMethod
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_PREFIXOPERATORFUNCTION: self = .prefixOperatorFunction
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_POSTFIXOPERATORFUNCTION: self = .postfixOperatorFunction
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_INFIXOPERATORFUNCTION: self = .infixOperatorFunction
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_FREEFUNCTION: self = .freeFunction
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_STATICVAR: self = .staticVar
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_INSTANCEVAR: self = .instanceVar
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_LOCALVAR: self = .localVar
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_GLOBALVAR: self = .globalVar
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_PRECEDENCEGROUP: self = .precedenceGroup
|
|
case SWIFTIDE_COMPLETION_ITEM_DECL_KIND_MACRO: self = .macro
|
|
default: self = .unknown
|
|
}
|
|
case SWIFTIDE_COMPLETION_ITEM_KIND_KEYWORD:
|
|
self = .keyword
|
|
case SWIFTIDE_COMPLETION_ITEM_KIND_PATTERN:
|
|
self = .pattern
|
|
case SWIFTIDE_COMPLETION_ITEM_KIND_LITERAL:
|
|
self = .literal
|
|
case SWIFTIDE_COMPLETION_ITEM_KIND_BUILTINOPERATOR:
|
|
self = .operator
|
|
default: self = .unknown
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionContext.Kind {
|
|
init(_ ckind: swiftide_api_completion_kind_t) {
|
|
switch ckind {
|
|
case SWIFTIDE_COMPLETION_KIND_NONE: self = .none
|
|
case SWIFTIDE_COMPLETION_KIND_IMPORT: self = .import
|
|
case SWIFTIDE_COMPLETION_KIND_UNRESOLVEDMEMBER: self = .unresolvedMember
|
|
case SWIFTIDE_COMPLETION_KIND_DOTEXPR: self = .dotExpr
|
|
case SWIFTIDE_COMPLETION_KIND_STMTOREXPR: self = .stmtOrExpr
|
|
case SWIFTIDE_COMPLETION_KIND_POSTFIXEXPRBEGINNING: self = .postfixExprBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_POSTFIXEXPR: self = .postfixExpr
|
|
case SWIFTIDE_COMPLETION_KIND_POSTFIXEXPRPAREN: self = .postfixExprParen
|
|
case SWIFTIDE_COMPLETION_KIND_KEYPATHEXPROBJC: self = .keyPathExprObjC
|
|
case SWIFTIDE_COMPLETION_KIND_KEYPATHEXPRSWIFT: self = .keyPathExprSwift
|
|
case SWIFTIDE_COMPLETION_KIND_TYPEDECLRESULTBEGINNING: self = .typeDeclResultBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_TYPESIMPLEBEGINNING: self = .typeSimpleBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_TYPEIDENTIFIERWITHDOT: self = .typeIdentifierWithDot
|
|
case SWIFTIDE_COMPLETION_KIND_TYPEIDENTIFIERWITHOUTDOT: self = .typeIdentifierWithoutDot
|
|
case SWIFTIDE_COMPLETION_KIND_CASESTMTKEYWORD: self = .caseStmtKeyword
|
|
case SWIFTIDE_COMPLETION_KIND_CASESTMTBEGINNING: self = .caseStmtBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_NOMINALMEMBERBEGINNING: self = .nominalMemberBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_ACCESSORBEGINNING: self = .accessorBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_ATTRIBUTEBEGIN: self = .attributeBegin
|
|
case SWIFTIDE_COMPLETION_KIND_ATTRIBUTEDECLPAREN: self = .attributeDeclParen
|
|
case SWIFTIDE_COMPLETION_KIND_POUNDAVAILABLEPLATFORM: self = .poundAvailablePlatform
|
|
case SWIFTIDE_COMPLETION_KIND_CALLARG: self = .callArg
|
|
case SWIFTIDE_COMPLETION_KIND_LABELEDTRAILINGCLOSURE: self = .labeledTrailingClosure
|
|
case SWIFTIDE_COMPLETION_KIND_RETURNSTMTEXPR: self = .returnStmtExpr
|
|
case SWIFTIDE_COMPLETION_KIND_YIELDSTMTEXPR: self = .yieldStmtExpr
|
|
case SWIFTIDE_COMPLETION_KIND_FOREACHSEQUENCE: self = .forEachSequence
|
|
case SWIFTIDE_COMPLETION_KIND_AFTERPOUNDEXPR: self = .afterPoundExpr
|
|
case SWIFTIDE_COMPLETION_KIND_AFTERPOUNDDIRECTIVE: self = .afterPoundDirective
|
|
case SWIFTIDE_COMPLETION_KIND_PLATFORMCONDITON: self = .platformConditon
|
|
case SWIFTIDE_COMPLETION_KIND_AFTERIFSTMTELSE: self = .afterIfStmtElse
|
|
case SWIFTIDE_COMPLETION_KIND_GENERICREQUIREMENT: self = .genericRequirement
|
|
case SWIFTIDE_COMPLETION_KIND_PRECEDENCEGROUP: self = .precedenceGroup
|
|
case SWIFTIDE_COMPLETION_KIND_STMTLABEL: self = .stmtLabel
|
|
case SWIFTIDE_COMPLETION_KIND_EFFECTSSPECIFIER: self = .effectsSpecifier
|
|
case SWIFTIDE_COMPLETION_KIND_FOREACHPATTERNBEGINNING: self = .forEachPatternBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_TYPEATTRBEGINNING: self = .typeAttrBeginning
|
|
case SWIFTIDE_COMPLETION_KIND_OPTIONALBINDING: self = .optionalBinding
|
|
case SWIFTIDE_COMPLETION_KIND_FOREACHKWIN: self = .forEachKeywordIn
|
|
case SWIFTIDE_COMPLETION_KIND_THENSTMTEXPR: self = .thenStmtExpr
|
|
default: self = .none
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionItem.TypeRelation {
|
|
init(_ crelation: swiftide_api_completion_type_relation_t) {
|
|
switch crelation {
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_NOTAPPLICABLE: self = .notApplicable
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_UNKNOWN: self = .unknown
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_UNRELATED: self = .unrelated
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_INVALID: self = .invalid
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_CONVERTIBLE: self = .convertible
|
|
case SWIFTIDE_COMPLETION_TYPE_RELATION_IDENTICAL: self = .identical
|
|
default: self = .unknown
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionItem.SemanticContext {
|
|
init(_ ccontext: swiftide_api_completion_semantic_context_t) {
|
|
switch ccontext {
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_NONE: self = .none
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_LOCAL: self = .local
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_CURRENTNOMINAL: self = .currentNominal
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_SUPER: self = .super
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_OUTSIDENOMINAL: self = .outsideNominal
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_CURRENTMODULE: self = .currentModule
|
|
case SWIFTIDE_COMPLETION_SEMANTIC_CONTEXT_OTHERMODULE: self = .otherModule
|
|
default: self = .none
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CompletionItem.PriorityBucket {
|
|
init(_ item: ASTCompletionItem, in session: CompletionSession) {
|
|
if item.completionKind == .unresolvedMember {
|
|
switch item.kind {
|
|
case .enum:
|
|
self = .unresolvedMember_EnumElement
|
|
case .class, .actor, .staticVar:
|
|
self = .unresolvedMember_Var
|
|
case .staticMethod:
|
|
self = .unresolvedMember_Func
|
|
case .constructor:
|
|
self = .unresolvedMember_Constructor
|
|
default:
|
|
self = .unresolvedMember_Other
|
|
}
|
|
} else if item.kind == .constructor {
|
|
self = .constructor
|
|
} else if item.typeRelation(in: session) == .invalid {
|
|
self = .invalidTypeMatch
|
|
} else {
|
|
let skFlair = session.sourcekitd.ideApi.completion_item_get_flair(item.impl)
|
|
if skFlair & SWIFTIDE_COMPLETION_FLAIR_EXPRESSIONSPECIFIC.rawValue != 0
|
|
|| skFlair & SWIFTIDE_COMPLETION_FLAIR_SUPERCHAIN.rawValue != 0
|
|
{
|
|
self = .exprSpecific
|
|
return
|
|
}
|
|
// let typeRelation = item.typeRelation(in: CompletionSession)
|
|
let typeMatchPriorityBoost =
|
|
switch item.typeRelation(in: session) {
|
|
case .identical, .convertible: item.kind != .globalVar && item.kind != .keyword
|
|
default: false
|
|
}
|
|
switch (typeMatchPriorityBoost, item.semanticContext(in: session)) {
|
|
case (false, .none):
|
|
self = .noContext_TypeMismatch
|
|
case (false, .otherModule):
|
|
self = .otherModule_TypeMismatch
|
|
case (false, .currentModule):
|
|
self = .thisModule_TypeMismatch
|
|
case (false, .super):
|
|
self = .superClass_TypeMismatch
|
|
case (false, .currentNominal):
|
|
self = .thisClass_TypeMismatch
|
|
case (false, .local):
|
|
self = .local_TypeMismatch
|
|
case (false, .outsideNominal):
|
|
self = .otherClass_TypeMismatch
|
|
|
|
case (true, .none):
|
|
self = .noContext_TypeMatch
|
|
case (true, .otherModule):
|
|
self = .otherClass_TypeMatch
|
|
case (true, .currentModule):
|
|
self = .thisModule_TypeMatch
|
|
case (true, .super):
|
|
self = .superClass_TypeMatch
|
|
case (true, .currentNominal):
|
|
self = .thisClass_TypeMatch
|
|
case (true, .local):
|
|
self = .local_TypeMatch
|
|
case (true, .outsideNominal):
|
|
self = .otherClass_TypeMatch
|
|
}
|
|
}
|
|
}
|
|
}
|