Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Fix "malloc: Double free of object" #99

Merged
merged 1 commit into from
May 8, 2020
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
185 changes: 87 additions & 98 deletions Sources/SwiftDoc/Interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,135 +2,124 @@ import Foundation
import SwiftSemantics
import struct SwiftSemantics.Protocol

public final class Interface: Codable {
public final class Interface {
public let imports: [Import]
public let symbols: [Symbol]

public required init(imports: [Import], symbols: [Symbol]) {
self.imports = imports
self.symbols = symbols.filter { $0.isPublic }
}

// MARK: -

public lazy var symbolsGroupedByIdentifier: [Symbol.ID: [Symbol]] = {
return Dictionary(grouping: symbols, by: { $0.id })
}()

public lazy var symbolsGroupedByQualifiedName: [String: [Symbol]] = {
return Dictionary(grouping: symbols, by: { $0.id.description })
}()
self.symbolsGroupedByIdentifier = Dictionary(grouping: symbols, by: { $0.id })
self.symbolsGroupedByQualifiedName = Dictionary(grouping: symbols, by: { $0.id.description })
self.topLevelSymbols = symbols.filter { $0.api is Type || $0.id.pathComponents.isEmpty }

public private(set) lazy var topLevelSymbols: [Symbol] = {
return symbols.filter { $0.api is Type || $0.id.pathComponents.isEmpty }
}()
self.relationships = {
let extensionsByExtendedType: [String: [Extension]] = Dictionary(grouping: symbols.flatMap { $0.context.compactMap { $0 as? Extension } }, by: { $0.extendedType })

public private(set) lazy var baseClasses: [Symbol] = {
return symbols.filter { $0.api is Class &&
typesInherited(by: $0).isEmpty }
}()
var relationships: Set<Relationship> = []
for symbol in symbols {
let lastDeclarationScope = symbol.context.last(where: { $0 is Extension || $0 is Symbol })

if let container = lastDeclarationScope as? Symbol {
let predicate: Relationship.Predicate

public private(set) lazy var classHierarchies: [Symbol: Set<Symbol>] = {
var classClusters: [Symbol: Set<Symbol>] = [:]
switch container.api {
case is Protocol:
if symbol.api.modifiers.contains(where: { $0.name == "optional" }) {
predicate = .optionalRequirementOf
} else {
predicate = .requirementOf
}
default:
predicate = .memberOf
}

for baseClass in baseClasses {
var superclasses = Set(CollectionOfOne(baseClass))
relationships.insert(Relationship(subject: symbol, predicate: predicate, object: container))
}

while !superclasses.isEmpty {
let subclasses = Set(superclasses.flatMap { typesInheriting(from: $0) }.filter { $0.isPublic })
defer { superclasses = subclasses }
classClusters[baseClass, default: []].formUnion(subclasses)
}
}
if let `extension` = lastDeclarationScope as? Extension {
if let extended = symbols.first(where: { $0.api is Type && $0.id.matches(`extension`.extendedType) }) {

return classClusters
}()
let predicate: Relationship.Predicate
switch extended.api {
case is Protocol:
predicate = .defaultImplementationOf
default:
predicate = .memberOf
}

private lazy var extensionsByExtendedType: [String: [Extension]] = {
return Dictionary(grouping: symbols.flatMap { $0.context.compactMap { $0 as? Extension } }) {
$0.extendedType
}
}()

public private(set) lazy var relationships: [Relationship] = {
var relationships: Set<Relationship> = []
for symbol in symbols {
let lastDeclarationScope = symbol.context.last(where: { $0 is Extension || $0 is Symbol })

if let container = lastDeclarationScope as? Symbol {
let predicate: Relationship.Predicate

switch container.api {
case is Protocol:
if symbol.api.modifiers.contains(where: { $0.name == "optional" }) {
predicate = .optionalRequirementOf
} else {
predicate = .requirementOf
relationships.insert(Relationship(subject: symbol, predicate: predicate, object: extended))
}
default:
predicate = .memberOf
}

relationships.insert(Relationship(subject: symbol, predicate: predicate, object: container))
}

if let `extension` = lastDeclarationScope as? Extension {
if let extended = symbols.first(where: { $0.api is Type && $0.id.matches(`extension`.extendedType) }) {
if let type = symbol.api as? Type {
var inheritedTypeNames: Set<String> = []
inheritedTypeNames.formUnion(type.inheritance.flatMap { $0.split(separator: "&").map { $0.trimmingCharacters(in: .whitespaces) }
})

let predicate: Relationship.Predicate
switch extended.api {
case is Protocol:
predicate = .defaultImplementationOf
default:
predicate = .memberOf
for `extension` in extensionsByExtendedType[symbol.id.description] ?? [] {
inheritedTypeNames.formUnion(`extension`.inheritance)
}

relationships.insert(Relationship(subject: symbol, predicate: predicate, object: extended))
inheritedTypeNames = Set(inheritedTypeNames.flatMap { $0.split(separator: "&").map { $0.trimmingCharacters(in: .whitespaces) } })

for name in inheritedTypeNames {
let inheritedTypes = symbols.filter({ ($0.api is Class || $0.api is Protocol) && $0.id.description == name })
if inheritedTypes.isEmpty {
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: nil, documentation: nil, sourceLocation: nil)
relationships.insert(Relationship(subject: symbol, predicate: .conformsTo, object: inherited))
} else {
for inherited in inheritedTypes {
let predicate: Relationship.Predicate
if symbol.api is Class, inherited.api is Class {
predicate = .inheritsFrom
} else {
predicate = .conformsTo
}

relationships.insert(Relationship(subject: symbol, predicate: predicate, object: inherited))
}
}
}
}
}

if let type = symbol.api as? Type {
var inheritedTypeNames: Set<String> = []
inheritedTypeNames.formUnion(type.inheritance.flatMap { $0.split(separator: "&").map { $0.trimmingCharacters(in: .whitespaces) }
})
return Array(relationships)
}()

for `extension` in extensionsByExtendedType[symbol.id.description] ?? [] {
inheritedTypeNames.formUnion(`extension`.inheritance)
}
self.relationshipsBySubject = Dictionary(grouping: relationships, by: { $0.subject.id })
self.relationshipsByObject = Dictionary(grouping: relationships, by: { $0.object.id })
}

inheritedTypeNames = Set(inheritedTypeNames.flatMap { $0.split(separator: "&").map { $0.trimmingCharacters(in: .whitespaces) } })

for name in inheritedTypeNames {
let inheritedTypes = symbols.filter({ ($0.api is Class || $0.api is Protocol) && $0.id.description == name })
if inheritedTypes.isEmpty {
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: nil, documentation: nil, sourceLocation: nil)
relationships.insert(Relationship(subject: symbol, predicate: .conformsTo, object: inherited))
} else {
for inherited in inheritedTypes {
let predicate: Relationship.Predicate
if symbol.api is Class, inherited.api is Class {
predicate = .inheritsFrom
} else {
predicate = .conformsTo
}
// MARK: -

relationships.insert(Relationship(subject: symbol, predicate: predicate, object: inherited))
}
}
}
public let symbolsGroupedByIdentifier: [Symbol.ID: [Symbol]]
public let symbolsGroupedByQualifiedName: [String: [Symbol]]
public let topLevelSymbols: [Symbol]
public var baseClasses: [Symbol] {
symbols.filter { $0.api is Class && typesInherited(by: $0).isEmpty }
}
public var classHierarchies: [Symbol: Set<Symbol>] {
var classClusters: [Symbol: Set<Symbol>] = [:]

for baseClass in baseClasses {
var superclasses = Set(CollectionOfOne(baseClass))

while !superclasses.isEmpty {
let subclasses = Set(superclasses.flatMap { typesInheriting(from: $0) }.filter { $0.isPublic })
defer { superclasses = subclasses }
classClusters[baseClass, default: []].formUnion(subclasses)
}
}

return Array(relationships)
}()
return classClusters

public private(set) lazy var relationshipsBySubject: [Symbol.ID: [Relationship]] = {
Dictionary(grouping: relationships, by: { $0.subject.id })
}()
}

public private(set) lazy var relationshipsByObject: [Symbol.ID: [Relationship]] = {
Dictionary(grouping: relationships, by: { $0.object.id })
}()
public let relationships: [Relationship]
public let relationshipsBySubject: [Symbol.ID: [Relationship]]
public let relationshipsByObject: [Symbol.ID: [Relationship]]

// MARK: -

Expand Down
14 changes: 6 additions & 8 deletions Sources/SwiftDoc/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@ import Foundation
import SwiftSemantics
import struct SwiftSemantics.Protocol

public final class Module: Codable {
public final class Module {
public let name: String

public let sourceFiles: [SourceFile]

public lazy var interface: Interface = {
let imports = sourceFiles.flatMap { $0.imports }
let symbols = sourceFiles.flatMap { $0.symbols }
return Interface(imports: imports, symbols: symbols)
}()
public let interface: Interface

public required init(name: String = "Anonymous", sourceFiles: [SourceFile]) {
self.name = name
self.sourceFiles = sourceFiles

let imports = sourceFiles.flatMap { $0.imports }
let symbols = sourceFiles.flatMap { $0.symbols }
self.interface = Interface(imports: imports, symbols: symbols)
}

public convenience init(name: String = "Anonymous", paths: [String]) throws {
Expand Down