Skip to content

Commit

Permalink
More optimizations (#632)
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Leitch <[email protected]>
  • Loading branch information
ileitch and Ian Leitch authored Jul 3, 2023
1 parent 2c403bf commit 9962bdd
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 165 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/ileitch/swift-indexstore",
"state" : {
"revision" : "4e20a3b2d8bb9bae8ebffb43515987eb6eb5efd8",
"version" : "9.0.2"
"revision" : "246d455063ddc8faf3ad791c4488e1f60c59aabd",
"version" : "9.0.3"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var dependencies: [Package.Dependency] = [
.package(url: "https://github.com/jpsim/Yams", from: "5.0.0"),
.package(url: "https://github.com/tadija/AEXML", from: "4.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
.package(url: "https://github.com/ileitch/swift-indexstore", from: "9.0.2"),
.package(url: "https://github.com/ileitch/swift-indexstore", from: "9.0.3"),
.package(url: "https://github.com/peripheryapp/swift-syntax", exact: "1.0.2"),
.package(url: "https://github.com/ileitch/swift-filename-matcher", from: "0.0.0"),
]
Expand Down
26 changes: 21 additions & 5 deletions Sources/PeripheryKit/Indexer/Declaration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ public final class Declaration {
Set(Kind.allCases.filter { $0.isFunctionKind })
}

static var protocolMemberKinds: [Kind] {
let functionKinds: [Kind] = [.functionMethodInstance, .functionMethodStatic, .functionSubscript, .functionOperator, .functionOperatorInfix, .functionOperatorPostfix, .functionOperatorPrefix, .functionConstructor]
let variableKinds: [Kind] = [.varInstance, .varStatic]
return functionKinds + variableKinds
}

static var protocolMemberConformingKinds: [Kind] {
// Protocols cannot declare 'class' members, yet classes can fulfill the requirement with either a 'class'
// or 'static' member.
protocolMemberKinds + [.varClass, .functionMethodClass, .associatedtype]
}

var isProtocolMemberKind: Bool {
Self.protocolMemberKinds.contains(self)
}

var isProtocolMemberConformingKind: Bool {
Self.protocolMemberConformingKinds.contains(self)
}

var isFunctionKind: Bool {
rawValue.hasPrefix("function")
}
Expand Down Expand Up @@ -157,10 +177,6 @@ public final class Declaration {
return nil
}
}

var referenceEquivalent: Reference.Kind? {
Reference.Kind(rawValue: rawValue)
}
}

public let location: SourceLocation
Expand Down Expand Up @@ -229,7 +245,7 @@ public final class Declaration {
}

var relatedEquivalentReferences: [Reference] {
related.filter { $0.kind == kind.referenceEquivalent && $0.name == name }
related.filter { $0.kind == kind && $0.name == name }
}

init(kind: Kind, usrs: Set<String>, location: SourceLocation) {
Expand Down
73 changes: 2 additions & 71 deletions Sources/PeripheryKit/Indexer/Reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,77 +21,8 @@ public final class Reference {
}
}

public enum Kind: String {
case `associatedtype` = "associatedtype"
case `class` = "class"
case `enum` = "enum"
case enumelement = "enumelement"
case `extension` = "extension"
case extensionClass = "extension.class"
case extensionEnum = "extension.enum"
case extensionProtocol = "extension.protocol"
case extensionStruct = "extension.struct"
case functionAccessorAddress = "function.accessor.address"
case functionAccessorDidset = "function.accessor.didset"
case functionAccessorGetter = "function.accessor.getter"
case functionAccessorMutableaddress = "function.accessor.mutableaddress"
case functionAccessorSetter = "function.accessor.setter"
case functionAccessorWillset = "function.accessor.willset"
case functionConstructor = "function.constructor"
case functionDestructor = "function.destructor"
case functionFree = "function.free"
case functionMethodClass = "function.method.class"
case functionMethodInstance = "function.method.instance"
case functionMethodStatic = "function.method.static"
case functionOperator = "function.operator"
case functionOperatorInfix = "function.operator.infix"
case functionOperatorPostfix = "function.operator.postfix"
case functionOperatorPrefix = "function.operator.prefix"
case functionSubscript = "function.subscript"
case genericTypeParam = "generic_type_param"
case module = "module"
case precedenceGroup = "precedencegroup"
case `protocol` = "protocol"
case `struct` = "struct"
case `typealias` = "typealias"
case varClass = "var.class"
case varGlobal = "var.global"
case varInstance = "var.instance"
case varLocal = "var.local"
case varParameter = "var.parameter"
case varStatic = "var.static"

static var protocolMemberKinds: [Kind] {
let functionKinds: [Kind] = [.functionMethodInstance, .functionMethodStatic, .functionSubscript, .functionOperator, .functionOperatorInfix, .functionOperatorPostfix, .functionOperatorPrefix, .functionConstructor]
let variableKinds: [Kind] = [.varInstance, .varStatic]
return functionKinds + variableKinds
}

static var protocolMemberConformingKinds: [Kind] {
// Protocols cannot declare 'class' members, yet classes can fulfill the requirement with either a 'class'
// or 'static' member.
protocolMemberKinds + [.varClass, .functionMethodClass, .associatedtype]
}

var isProtocolMemberKind: Bool {
Self.protocolMemberKinds.contains(self)
}

var isProtocolMemberConformingKind: Bool {
Self.protocolMemberConformingKinds.contains(self)
}

var isFunctionKind: Bool {
rawValue.hasPrefix("function")
}

var declarationEquivalent: Declaration.Kind? {
Declaration.Kind(rawValue: rawValue)
}
}

public let location: SourceLocation
public let kind: Kind
public let kind: Declaration.Kind
public let isRelated: Bool
public var name: String?
public var parent: Declaration?
Expand All @@ -101,7 +32,7 @@ public final class Reference {

private let identifier: Int

init(kind: Kind, usr: String, location: SourceLocation, isRelated: Bool = false) {
init(kind: Declaration.Kind, usr: String, location: SourceLocation, isRelated: Bool = false) {
self.kind = kind
self.usr = usr
self.isRelated = isRelated
Expand Down
60 changes: 7 additions & 53 deletions Sources/PeripheryKit/Indexer/SwiftIndexer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,8 @@ public final class SwiftIndexer: Indexer {
try indexStore.forEachRecordDependencies(for: unit) { dependency in
guard case let .record(record) = dependency else { return true }

try indexStore.forEachOccurrences(for: record) { occurrence in
guard occurrence.symbol.language == .swift,
let usr = occurrence.symbol.usr,
try indexStore.forEachOccurrences(for: record, language: .swift) { occurrence in
guard let usr = occurrence.symbol.usr,
let location = transformLocation(occurrence.location)
else { return true }

Expand Down Expand Up @@ -544,7 +543,7 @@ public final class SwiftIndexer: Indexer {
if rel.roles.contains(.overrideOf) {
let baseFunc = rel.symbol

if let baseFuncUsr = baseFunc.usr, let baseFuncKind = transformReferenceKind(baseFunc.kind, baseFunc.subKind) {
if let baseFuncUsr = baseFunc.usr, let baseFuncKind = transformDeclarationKind(baseFunc.kind, baseFunc.subKind) {
let reference = Reference(
kind: baseFuncKind,
usr: baseFuncUsr,
Expand All @@ -561,10 +560,10 @@ public final class SwiftIndexer: Indexer {
if !rel.roles.intersection([.baseOf, .calledBy, .extendedBy, .containedBy]).isEmpty {
let referencer = rel.symbol

if let referencerUsr = referencer.usr, let referencerKind = decl.kind.referenceEquivalent {
if let referencerUsr = referencer.usr {
for usr in decl.usrs {
let reference = Reference(
kind: referencerKind,
kind: decl.kind,
usr: usr,
location: decl.location,
isRelated: rel.roles.contains(.baseOf)
Expand Down Expand Up @@ -592,7 +591,7 @@ public final class SwiftIndexer: Indexer {
if rel.roles.contains(.overrideOf) {
let baseFunc = rel.symbol

if let baseFuncUsr = baseFunc.usr, let baseFuncKind = transformReferenceKind(baseFunc.kind, baseFunc.subKind) {
if let baseFuncUsr = baseFunc.usr, let baseFuncKind = transformDeclarationKind(baseFunc.kind, baseFunc.subKind) {
let reference = Reference(
kind: baseFuncKind,
usr: baseFuncUsr,
Expand All @@ -617,7 +616,7 @@ public final class SwiftIndexer: Indexer {
_ location: SourceLocation,
_ indexStore: IndexStore
) throws -> [Reference] {
guard let kind = transformReferenceKind(occurrence.symbol.kind, occurrence.symbol.subKind)
guard let kind = transformDeclarationKind(occurrence.symbol.kind, occurrence.symbol.subKind)
else { return [] }

guard kind != .varParameter else {
Expand Down Expand Up @@ -710,50 +709,5 @@ public final class SwiftIndexer: Indexer {
default: return nil
}
}

private func transformReferenceKind(_ kind: IndexStoreSymbol.Kind, _ subKind: IndexStoreSymbol.SubKind) -> Reference.Kind? {
switch subKind {
case .accessorGetter: return .functionAccessorGetter
case .accessorSetter: return .functionAccessorSetter
case .swiftAccessorDidSet: return .functionAccessorDidset
case .swiftAccessorWillSet: return .functionAccessorWillset
case .swiftAccessorMutableAddressor: return .functionAccessorMutableaddress
case .swiftAccessorAddressor: return .functionAccessorAddress
case .swiftSubscript: return .functionSubscript
case .swiftInfixOperator: return .functionOperatorInfix
case .swiftPrefixOperator: return .functionOperatorPrefix
case .swiftPostfixOperator: return .functionOperatorPostfix
case .swiftGenericTypeParam: return .genericTypeParam
case .swiftAssociatedtype: return .associatedtype
case .swiftExtensionOfClass: return .extensionClass
case .swiftExtensionOfStruct: return .extensionStruct
case .swiftExtensionOfProtocol: return .extensionProtocol
case .swiftExtensionOfEnum: return .extensionEnum
default: break
}

switch kind {
case .module: return .module
case .enum: return .enum
case .struct: return .struct
case .class: return .class
case .protocol: return .protocol
case .extension: return .extension
case .typealias: return .typealias
case .function: return .functionFree
case .variable: return .varGlobal
case .enumConstant: return .enumelement
case .instanceMethod: return .functionMethodInstance
case .classMethod: return .functionMethodClass
case .staticMethod: return .functionMethodStatic
case .instanceProperty: return .varInstance
case .classProperty: return .varClass
case .staticProperty: return .varStatic
case .constructor: return .functionConstructor
case .destructor: return .functionDestructor
case .parameter: return .varParameter
default: return nil
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ final class ComplexPropertyAccessorReferenceBuilder: SourceGraphMutator {
let declarations = graph.declarations(ofKinds: Array(Declaration.Kind.accessorKinds))

for declaration in declarations {
guard let parent = declaration.parent,
let kind = declaration.kind.referenceEquivalent else { continue }
guard let parent = declaration.parent else { continue }

if parent.isComplexProperty {
for usr in declaration.usrs {
let reference = Reference(kind: kind,
let reference = Reference(kind: declaration.kind,
usr: usr,
location: declaration.location)
reference.parent = parent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ final class ExtensionReferenceBuilder: SourceGraphMutator {
private func referenceExtendedTypeAliases(of extendedTypeReference: Reference, from extensionDeclaration: Declaration) {
// Extensions on type aliases reference the existing type, not the alias.
// We need to find the typealias and build a reference to it.
for aliasDecl in graph.declarations(ofKind: .typealias) {
if aliasDecl.references.contains(where: { $0.usr == extendedTypeReference.usr }) {
for usr in aliasDecl.usrs {
let aliasReference = Reference(kind: .typealias, usr: usr, location: extensionDeclaration.location)
aliasReference.name = aliasDecl.name
graph.add(aliasReference, from: extensionDeclaration)
}
let extendedTypeReferences = graph.allReferencesByUsr[extendedTypeReference.usr, default: []]

for reference in extendedTypeReferences {
guard let aliasDecl = reference.parent, aliasDecl.kind == .typealias else { continue }
for usr in aliasDecl.usrs {
let aliasReference = Reference(kind: .typealias, usr: usr, location: extensionDeclaration.location)
aliasReference.name = aliasDecl.name
graph.add(aliasReference, from: extensionDeclaration)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ final class ProtocolConformanceReferenceBuilder: SourceGraphMutator {
if let declInSuperclass = declInSuperclass {
// Build a reference from the protocol declarations to the
// declaration implemented by the superclass.
guard let referenceKind = declInSuperclass.kind.referenceEquivalent else { continue }

for usr in declInSuperclass.usrs {
let reference = Reference(
kind: referenceKind,
kind: declInSuperclass.kind,
usr: usr,
location: declInSuperclass.location,
isRelated: true
Expand All @@ -83,23 +81,22 @@ final class ProtocolConformanceReferenceBuilder: SourceGraphMutator {
let relatedReferences = graph.allReferences.filter { $0.isRelated && $0.kind.isProtocolMemberConformingKind }

for relatedReference in relatedReferences.subtracting(nonInvertableReferences) {
guard let conformingDeclaration = relatedReference.parent,
let equivalentDeclarationKind = relatedReference.kind.declarationEquivalent
guard let conformingDeclaration = relatedReference.parent
else { continue }

var equivalentDeclarationKinds = [equivalentDeclarationKind]
var equivalentDeclarationKinds = [relatedReference.kind]

// A conforming declaration can be declared either 'class' or 'static', whereas
// protocol members can only be declared as 'static'.
if equivalentDeclarationKind == .functionMethodStatic {
if relatedReference.kind == .functionMethodStatic {
equivalentDeclarationKinds.append(.functionMethodClass)
} else if equivalentDeclarationKind == .functionMethodClass {
} else if relatedReference.kind == .functionMethodClass {
equivalentDeclarationKinds.append(.functionMethodStatic)
} else if equivalentDeclarationKind == .varStatic {
} else if relatedReference.kind == .varStatic {
equivalentDeclarationKinds.append(.varClass)
} else if equivalentDeclarationKind == .varClass {
} else if relatedReference.kind == .varClass {
equivalentDeclarationKinds.append(.varStatic)
} else if equivalentDeclarationKind == .associatedtype {
} else if relatedReference.kind == .associatedtype {
equivalentDeclarationKinds.append(contentsOf: Declaration.Kind.concreteTypeDeclarableKinds)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ final class RedundantExplicitPublicAccessibilityMarker: SourceGraphMutator {
}

private func nonTestableModulesReferencing(_ decl: Declaration) throws -> Set<String> {
let referenceFiles = graph.references(to: decl).mapSet { $0.location.file }
let referenceFiles = graph.references(to: decl).map { $0.location.file }

let referenceModules = referenceFiles.flatMapSet { file -> Set<String> in
let importsDeclModuleTestable = file.importStatements.contains(where: { (parts, isTestable) in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ final class UsedDeclarationMarker: SourceGraphMutator {
removeErroneousProtocolReferences()
markUsed(graph.retainedDeclarations)

let rootReferencedDeclarations = graph.rootReferences.flatMapSet { declarationsReferenced(by: $0) }
markUsed(rootReferencedDeclarations)
graph.rootReferences.forEach { markUsed(declarationsReferenced(by: $0)) }

ignoreUnusedDescendents(in: graph.rootDeclarations,
unusedDeclarations: graph.unusedDeclarations)
Expand Down Expand Up @@ -45,13 +44,15 @@ final class UsedDeclarationMarker: SourceGraphMutator {
guard !graph.isUsed(declaration) else { continue }

graph.markUsed(declaration)
markUsed(declarationsReferenced(by: declaration))
}
}

private func declarationsReferenced(by declaration: Declaration) -> Set<Declaration> {
let allReferences = declaration.references.union(declaration.related)
return allReferences.flatMapSet { declarationsReferenced(by: $0) }
for ref in declaration.references {
markUsed(declarationsReferenced(by: ref))
}

for ref in declaration.related {
markUsed(declarationsReferenced(by: ref))
}
}
}

private func declarationsReferenced(by reference: Reference) -> Set<Declaration> {
Expand Down
Loading

0 comments on commit 9962bdd

Please sign in to comment.