Skip to content

Commit

Permalink
Add sourceRange property to Symbol (apple#237)
Browse files Browse the repository at this point in the history
* Set source range for symbols

* Adopt Equatable, Comparable, and Hashable in extension on SourceRange

* Refactor with sourceRange(using:) helper method

* Deprecate sourceLocation

Replace existing use of sourceLocation in DCOV extension

* Add changelog entries for apple#237
  • Loading branch information
mattt committed Mar 30, 2021
1 parent e4f88b5 commit b0e3615
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 20 deletions.
11 changes: 11 additions & 0 deletions Changelog.md
Expand Up @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#219 by @Lukas-Stuehrk.
- Added support for documenting default implementations.
#221 by @Lukas-Stuehrk.
- Added `sourceRange` property to `Symbol`.
#237 by @mattt.

### Fixed

Expand All @@ -27,6 +29,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Changed display of code declarations in HTML.
#204 by @mattt.
- Changed serialization of `Symbol` to encode and decode `sourceRange` key
instead of `sourceLocation` key.
#237 by @mattt.

### Deprecated

- Deprecated `Symbol.sourceLocation` property.
Use `Symbol.sourceRange.start` instead.
#237 by @mattt.
- Changed the `generate` command to skip hidden files
and top-level `Tests` directories.
#229 by @mattt.
Expand Down
27 changes: 27 additions & 0 deletions Sources/SwiftDoc/Extensions/SwiftSyntax+Extensions.swift
Expand Up @@ -21,10 +21,37 @@ extension SourceLocation: Hashable {

// MARK: -

extension SourceRange: Equatable {
public static func == (lhs: SourceRange, rhs: SourceRange) -> Bool {
return lhs.start == rhs.start && lhs.end == rhs.end
}
}

extension SourceRange: Comparable {
public static func < (lhs: SourceRange, rhs: SourceRange) -> Bool {
return lhs.start < rhs.start
}
}

extension SourceRange: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(start)
hasher.combine(end)
}
}

// MARK: -

protocol SymbolDeclProtocol: SyntaxProtocol {
var declaration: Syntax { get }
}

extension SymbolDeclProtocol {
func sourceRange(using converter: SourceLocationConverter) -> SourceRange {
return SourceRange(start: startLocation(converter: converter), end: endLocation(converter: converter))
}
}

extension AssociatedtypeDeclSyntax: SymbolDeclProtocol {}
extension ClassDeclSyntax: SymbolDeclProtocol {}
extension EnumDeclSyntax: SymbolDeclProtocol {}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDoc/Interface.swift
Expand Up @@ -68,7 +68,7 @@ public final class Interface {
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: [], documentation: nil, sourceLocation: nil)
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: [], documentation: nil, sourceRange: nil)
relationships.insert(Relationship(subject: symbol, predicate: .conformsTo, object: inherited))
} else {
for inherited in inheritedTypes {
Expand Down
8 changes: 4 additions & 4 deletions Sources/SwiftDoc/SourceFile.swift
Expand Up @@ -56,14 +56,14 @@ public struct SourceFile: Hashable, Codable {
func symbol<Node, Declaration>(_ type: Declaration.Type, _ node: Node) -> Symbol? where Declaration: API & ExpressibleBySyntax, Node == Declaration.Syntax, Node: SymbolDeclProtocol {
guard let api = Declaration(node) else { return nil }
guard let documentation = try? Documentation.parse(node.documentation) else { return nil }
let sourceLocation = sourceLocationConverter.location(for: node.position)
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceLocation: sourceLocation)
let sourceRange = node.sourceRange(using: sourceLocationConverter)
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceRange: sourceRange)
}

func symbol<Node: SymbolDeclProtocol>(_ node: Node, api: API) -> Symbol? {
guard let documentation = try? Documentation.parse(node.documentation) else { return nil }
let sourceLocation = sourceLocationConverter.location(for: node.position)
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceLocation: sourceLocation)
let sourceRange = node.sourceRange(using: sourceLocationConverter)
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceRange: sourceRange)
}

func declaration<Node: SymbolDeclProtocol>(for node: Node) -> [Token] {
Expand Down
27 changes: 15 additions & 12 deletions Sources/SwiftDoc/Symbol.swift
Expand Up @@ -10,17 +10,20 @@ public final class Symbol {
public let context: [Contextual]
public let declaration: [Token]
public let documentation: Documentation?
public let sourceLocation: SourceLocation?
public let sourceRange: SourceRange?

@available(swift, deprecated: 0.0.1, message: "Use sourceRange instead")
public var sourceLocation: SourceLocation? { sourceRange?.start }

public private(set) lazy var `extension`: Extension? = context.compactMap { $0 as? Extension }.first
public private(set) lazy var conditions: [CompilationCondition] = context.compactMap { $0 as? CompilationCondition }

init(api: API, context: [Contextual], declaration: [Token], documentation: Documentation?, sourceLocation: SourceLocation?) {
init(api: API, context: [Contextual], declaration: [Token], documentation: Documentation?, sourceRange: SourceRange?) {
self.api = api
self.context = context
self.declaration = declaration
self.documentation = documentation
self.sourceLocation = sourceLocation
self.sourceRange = sourceRange
}

public var name: String {
Expand Down Expand Up @@ -114,8 +117,8 @@ public final class Symbol {
extension Symbol: Equatable {
public static func == (lhs: Symbol, rhs: Symbol) -> Bool {
guard lhs.documentation == rhs.documentation,
lhs.sourceLocation == rhs.sourceLocation
else { return false }
lhs.sourceRange == rhs.sourceRange
else { return false }

guard lhs.context.count == rhs.context.count else { return false}
for (lc, rc) in zip(lhs.context, rhs.context) {
Expand Down Expand Up @@ -170,8 +173,8 @@ extension Symbol: Equatable {

extension Symbol: Comparable {
public static func < (lhs: Symbol, rhs: Symbol) -> Bool {
if let lsl = lhs.sourceLocation, let rsl = rhs.sourceLocation {
return lsl < rsl
if let lsr = lhs.sourceRange, let rsr = rhs.sourceRange {
return lsr < rsr
} else {
return lhs.name < rhs.name
}
Expand All @@ -183,7 +186,7 @@ extension Symbol: Comparable {
extension Symbol: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(documentation)
hasher.combine(sourceLocation)
hasher.combine(sourceRange)
switch api {
case let api as AssociatedType:
hasher.combine(api)
Expand Down Expand Up @@ -225,7 +228,7 @@ extension Symbol: Codable {
private enum CodingKeys: String, CodingKey {
case declaration
case documentation
case sourceLocation
case sourceRange

case associatedType
case `case`
Expand Down Expand Up @@ -282,9 +285,9 @@ extension Symbol: Codable {

let declaration = try container.decodeIfPresent([Token].self, forKey: .declaration)
let documentation = try container.decodeIfPresent(Documentation.self, forKey: .documentation)
let sourceLocation = try container.decodeIfPresent(SourceLocation.self, forKey: .sourceLocation)
let sourceRange = try container.decodeIfPresent(SourceRange.self, forKey: .sourceRange)

self.init(api: api, context: [] /* TODO */, declaration: declaration ?? [], documentation: documentation, sourceLocation: sourceLocation)
self.init(api: api, context: [] /* TODO */, declaration: declaration ?? [], documentation: documentation, sourceRange: sourceRange)
}

public func encode(to encoder: Encoder) throws {
Expand Down Expand Up @@ -323,6 +326,6 @@ extension Symbol: Codable {
}

try container.encode(documentation, forKey: .documentation)
try container.encode(sourceLocation, forKey: .sourceLocation)
try container.encode(sourceRange, forKey: .sourceRange)
}
}
6 changes: 3 additions & 3 deletions Sources/swift-doc/Extensions/DCOV+Extensions.swift
Expand Up @@ -7,9 +7,9 @@ extension Entry {
let name = symbol.id.description
let type = String(describing: Swift.type(of: symbol.api))
let documented = symbol.isDocumented
let file = symbol.sourceLocation?.file
let line = symbol.sourceLocation?.line
let column = symbol.sourceLocation?.column
let file = symbol.sourceRange?.start.file
let line = symbol.sourceRange?.start.line
let column = symbol.sourceRange?.start.column

self.init(name: name, type: type, documented: documented, file: file, line: line, column: column)
}
Expand Down

0 comments on commit b0e3615

Please sign in to comment.