Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More optimizations #632

Merged
merged 1 commit into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading