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

[WIP] Typed declarations. #112

Closed
wants to merge 2 commits into from
Closed
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
15 changes: 15 additions & 0 deletions Source/SourceKittenFramework/Accessibility.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Accessibility.swift
// SourceKitten
//
// Created by Paul Young on 12/4/15.
// Copyright © 2015 SourceKitten. All rights reserved.
//

import Foundation

public enum Accessibility: String {
case Internal = "source.lang.swift.accessibility.internal"
case Private = "source.lang.swift.accessibility.private"
case Public = "source.lang.swift.accessibility.public"
}
9 changes: 9 additions & 0 deletions Source/SourceKittenFramework/DeclarationKindType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//
// DeclarationKindType.swift
// SourceKitten
//
// Created by Paul Young on 12/4/15.
// Copyright © 2015 SourceKitten. All rights reserved.
//

public protocol DeclarationKindType {}
20 changes: 20 additions & 0 deletions Source/SourceKittenFramework/DeclarationType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// DeclarationType.swift
// SourceKitten
//
// Created by Paul Young on 12/4/15.
// Copyright © 2015 SourceKitten. All rights reserved.
//

public protocol DeclarationType {
var language: Language { get }
var kind: DeclarationKindType? { get }
var location: SourceLocation { get }
var extent: (start: SourceLocation, end: SourceLocation) { get }
var name: String? { get }
var typeName: String? { get }
var usr: String? { get }
var declaration: String? { get }
var documentationComment: String? { get }
var children: [DeclarationType] { get }
}
110 changes: 110 additions & 0 deletions Source/SourceKittenFramework/ObjCDeclaration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// ObjCDeclaration.swift
// SourceKitten
//
// Created by Paul Young on 12/4/15.
// Copyright © 2015 SourceKitten. All rights reserved.
//

import Foundation

public struct ObjCDeclaration: DeclarationType {
public let language: Language = .Swift
public let kind: ObjCDeclarationKind? // FIXME: Type 'ObjCDeclaration' does not conform to protocol 'DeclarationType'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the expected type here DeclarationKindType.

public let location: SourceLocation
public let extent: (start: SourceLocation, end: SourceLocation)
public let name: String?
public let typeName: String?
public let usr: String?
public let declaration: String?
public let documentationComment: String?
public let children: [DeclarationType]

/// Returns the USR for the auto-generated getter for this property.
///
/// - warning: can only be invoked if `type == .Property`.
var getterUSR: String {
return generateAccessorUSR(getter: true)
}

/// Returns the USR for the auto-generated setter for this property.
///
/// - warning: can only be invoked if `type == .Property`.
var setterUSR: String {
return generateAccessorUSR(getter: false)
}

private func generateAccessorUSR(getter getter: Bool) -> String {
assert(kind == .Property)
guard let usr = usr else {
fatalError("Couldn't extract USR")
}
guard let declaration = declaration else {
fatalError("Couldn't extract declaration")
}
let pyStartIndex = usr.rangeOfString("(py)")!.startIndex
let usrPrefix = usr.substringToIndex(pyStartIndex)
let fullDeclarationRange = NSRange(location: 0, length: (declaration as NSString).length)
let regex = try! NSRegularExpression(pattern: getter ? "getter\\s*=\\s*(\\w+)" : "setter\\s*=\\s*(\\w+:)", options: [])
let matches = regex.matchesInString(declaration, options: [], range: fullDeclarationRange)
if matches.count > 0 {
let accessorName = (declaration as NSString).substringWithRange(matches[0].rangeAtIndex(1))
return usrPrefix + "(im)\(accessorName)"
} else if getter {
return usr.stringByReplacingOccurrencesOfString("(py)", withString: "(im)")
}
// Setter
let capitalFirstLetter = String(usr.characters[pyStartIndex.advancedBy(4)]).capitalizedString
let restOfSetterName = usr.substringFromIndex(pyStartIndex.advancedBy(5))
return "\(usrPrefix)(im)set\(capitalFirstLetter)\(restOfSetterName):"
}
}

extension ObjCDeclaration {
public init?(cursor: CXCursor) {
guard cursor.shouldDocument() else {
return nil
}
kind = cursor.objCKind()
extent = cursor.extent()
name = cursor.name()
//typeName = cursor. // FIXME: no cursor.typeName()
usr = cursor.usr()
declaration = cursor.declaration()
documentationComment = cursor.parsedComment() // FIXME: Cannot assign value of type 'CXComment' to type 'String?'
children = cursor.flatMap(ObjCDeclaration.init).rejectPropertyMethods() // FIXME: Cannot assign value of type '[ObjCDeclaration]' to type '[DeclarationType]'
}
}

extension SequenceType where Generator.Element == ObjCDeclaration {
/// Removes implicitly generated property getters & setters
func rejectPropertyMethods() -> [ObjCDeclaration] {
let propertyGetterSetterUSRs = filter {
$0.kind == .Property
}.flatMap {
[$0.getterUSR, $0.setterUSR]
}
return filter { !propertyGetterSetterUSRs.contains($0.usr!) }
}
}

// MARK: Hashable

extension ObjCDeclaration: Hashable {
public var hashValue: Int {
return usr?.hashValue ?? 0
}
}

public func ==(lhs: ObjCDeclaration, rhs: ObjCDeclaration) -> Bool {
return lhs.usr == rhs.usr &&
lhs.location == rhs.location
}

// MARK: Comparable

/// A [strict total order](http://en.wikipedia.org/wiki/Total_order#Strict_total_order)
/// over instances of `Self`.
public func <(lhs: ObjCDeclaration, rhs: ObjCDeclaration) -> Bool {
return lhs.location < rhs.location
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was for Hashable / Comparable conformance to be on DeclarationType. Let me take a stab at that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think because of the use of Self in Equatable, we'd need AnyDeclarationType.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this in paulyoung#1.

2 changes: 2 additions & 0 deletions Source/SourceKittenFramework/ObjCDeclarationKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,5 @@ public enum ObjCDeclarationKind: String {
}
}
}

extension ObjCDeclarationKind: DeclarationKindType {}
75 changes: 75 additions & 0 deletions Source/SourceKittenFramework/SwiftDeclaration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// SwiftDeclaration.swift
// SourceKitten
//
// Created by Paul Young on 12/4/15.
// Copyright © 2015 SourceKitten. All rights reserved.
//

import SwiftXPC

public struct SwiftDeclaration: DeclarationType {
public let language: Language = .Swift
public let kind: DeclarationKindType?
public let location: SourceLocation
public let extent: (start: SourceLocation, end: SourceLocation)
public let name: String?
public let typeName: String?
public let usr: String?
public let declaration: String?
public let documentationComment: String?
public let children: [DeclarationType]
public let accessibility: Accessibility?
}

extension SwiftDeclaration {
public init(dictionary: XPCDictionary) {
kind = SwiftDocKey.getKind(dictionary).flatMap { SwiftDeclarationKind(rawValue: $0) } // FIXME: why doesn't .flatMap(SwiftDeclarationKind.init) work here?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure I've done this elsewhere. Maybe it doesn't work for enums.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that's odd, but not a big deal.


if let file = SwiftDocKey.getDocFile(dictionary),
line = SwiftDocKey.getDocLine(dictionary).map({ UInt32($0) }),
column = SwiftDocKey.getDocColumn(dictionary).map({ UInt32($0) }) {

if let offset = SwiftDocKey.getOffset(dictionary).map({ UInt32($0) }) {
location = SourceLocation(file: file, line: line, column: column, offset: offset)
}

if let parsedScopeStart = SwiftDocKey.getParsedScopeStart(dictionary).map({ UInt32($0) }),
parsedScopeEnd = SwiftDocKey.getParsedScopeEnd(dictionary).map({ UInt32($0) }) {

let start = SourceLocation.init(file: file, line: line, column: column, offset: parsedScopeStart)
let end = SourceLocation.init(file: file, line: line, column: column, offset: parsedScopeEnd)
extent = (start: start, end: end)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure that this is the right thing to do here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW .map(UInt32.init) didn't work here ¯_(ツ)_/¯


name = SwiftDocKey.getName(dictionary)
typeName = SwiftDocKey.getTypeName(dictionary)
usr = SwiftDocKey.getUSR(dictionary)
declaration = SwiftDocKey.getParsedDeclaration(dictionary)
documentationComment = // FIXME
children = SwiftDocKey.getSubstructure(dictionary) // FIXME: Cannot assign value of type 'XPCArray?' to type '[DeclarationType]'
accessibility = // FIXME: Accessibility(rawValue: ...)
}
}

// MARK: Hashable

extension SwiftDeclaration: Hashable {
public var hashValue: Int {
return usr?.hashValue ?? 0
}
}

public func ==(lhs: SwiftDeclaration, rhs: SwiftDeclaration) -> Bool {
return lhs.usr == rhs.usr &&
lhs.location == rhs.location
}

// MARK: Comparable

/// A [strict total order](http://en.wikipedia.org/wiki/Total_order#Strict_total_order)
/// over instances of `Self`.
public func <(lhs: SwiftDeclaration, rhs: SwiftDeclaration) -> Bool {
return lhs.location < rhs.location
}
2 changes: 2 additions & 0 deletions Source/SourceKittenFramework/SwiftDeclarationKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ public enum SwiftDeclarationKind: String {
/// `var.static`.
case VarStatic = "source.lang.swift.decl.var.static"
}

extension SwiftDeclarationKind: DeclarationKindType {}
100 changes: 94 additions & 6 deletions Source/SourceKittenFramework/SwiftDocKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ internal enum SwiftDocKey: String {
case DocName = "key.doc.name"
/// Parameters of documented token (XPCArray).
case DocParameters = "key.doc.parameters"
/// Parsed declaration (String).
/// Result discussion documentation of documented token (XPCArray).
case DocResultDiscussion = "key.doc.result_discussion"
/// Parsed scope start (Int64).
/// Type of documented token (String).
case DocType = "key.doc.type"
/// Parsed scope start end (Int64).
/// USR of documented token (String).
case USR = "key.usr"
/// Result discussion documentation of documented token (XPCArray).
/// Parsed declaration (String).
case ParsedDeclaration = "key.parsed_declaration"
/// Type of documented token (String).
/// Parsed scope end (Int64).
case ParsedScopeEnd = "key.parsed_scope.end"
/// USR of documented token (String).
/// Parsed scope start (Int64).
case ParsedScopeStart = "key.parsed_scope.start"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move this to another PR if necessary.



Expand Down Expand Up @@ -166,6 +166,17 @@ internal enum SwiftDocKey: String {
internal static func getSubstructure(dictionary: XPCDictionary) -> XPCArray? {
return get(.Substructure, dictionary)
}

/**
Get name string from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: Name string if successful.
*/
internal static func getName(dictionary: XPCDictionary) -> String? {
return get(.Name, dictionary)
}

/**
Get name offset int from dictionary.
Expand Down Expand Up @@ -232,4 +243,81 @@ internal enum SwiftDocKey: String {
internal static func getFullXMLDocs(dictionary: XPCDictionary) -> String? {
return get(.FullXMLDocs, dictionary)
}

/**
Get USR string from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: USR string if successful.
*/
internal static func getUSR(dictionary: XPCDictionary) -> String? {
return get(.USR, dictionary)
}

/**
Get parsed declaration string from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: parsed declaration string if successful.
*/
internal static func getParsedDeclaration(dictionary: XPCDictionary) -> String? {
return get(.ParsedDeclaration, dictionary)
}

/**
Get parsed scope start int from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: parsed scope start int if successful.
*/
internal static func getParsedScopeStart(dictionary: XPCDictionary) -> Int64? {
return get(.ParsedScopeStart, dictionary)
}

/**
Get parsed scope end int from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: parsed scope end int if successful.
*/
internal static func getParsedScopeEnd(dictionary: XPCDictionary) -> Int64? {
return get(.ParsedScopeEnd, dictionary)
}

/**
Get doc file string from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: doc file string if successful.
*/
internal static func getDocFile(dictionary: XPCDictionary) -> String? {
return get(.DocFile, dictionary)
}

/**
Get doc column int from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: doc column int if successful.
*/
internal static func getDocColumn(dictionary: XPCDictionary) -> Int64? {
return get(.DocColumn, dictionary)
}

/**
Get doc line int from dictionary.

- parameter dictionary: Dictionary to get value from.

- returns: doc line int if successful.
*/
internal static func getDocLine(dictionary: XPCDictionary) -> Int64? {
return get(.DocLine, dictionary)
}
}
Loading