Skip to content

Commit

Permalink
Merge pull request #291 from jpsim/fix/class-properties
Browse files Browse the repository at this point in the history
Supprt Objective-C class properties
  • Loading branch information
jpsim authored Nov 3, 2016
2 parents 867406c + 54f60f7 commit 9ede44f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 26 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
* Now supports docinfo requests for sourcetext and module keys.
[Erik Abair](https://github.com/abaire)

* Now supports Objective-C class properties.
[Jérémie Girault](https://github.com/jeremiegirault)
[JP Simard](https://github.com/jpsim)
[#243](https://github.com/jpsim/SourceKitten/issues/243)

##### Bug Fixes

* `NSString.lines()` generated surplus line when string ended with newline
Expand Down
49 changes: 38 additions & 11 deletions Source/SourceKittenFramework/SourceDeclaration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,48 @@ public struct SourceDeclaration {
guard let declaration = declaration else {
fatalError("Couldn't extract declaration")
}
let pyStartIndex = usr.range(of: "(py)")!.lowerBound
let usrPrefix = usr.substring(to: 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.matches(in: declaration, options: [], range: fullDeclarationRange)
enum AccessorType {
case `class`, instance

var propertyTypeString: String {
switch self {
case .class: return "(cpy)"
case .instance: return "(py)"
}
}

var methodTypeString: String {
switch self {
case .class: return "(cm)"
case .instance: return "(im)"
}
}
}
let propertyTypeStringStart: String.Index
let accessorType: AccessorType
if let accessorTypeStringStartIndex = usr.range(of: AccessorType.class.propertyTypeString)?.lowerBound {
propertyTypeStringStart = accessorTypeStringStartIndex
accessorType = .class
} else if let accessorTypeStringStartIndex = usr.range(of: AccessorType.instance.propertyTypeString)?.lowerBound {
propertyTypeStringStart = accessorTypeStringStartIndex
accessorType = .instance
} else {
fatalError("expected an instance or class property by got \(usr)")
}
let nsDeclaration = declaration as NSString
let usrPrefix = usr.substring(to: propertyTypeStringStart)
let regex = try! NSRegularExpression(pattern: getter ? "getter\\s*=\\s*(\\w+)" : "setter\\s*=\\s*(\\w+:)")
let matches = regex.matches(in: declaration, options: [], range: NSRange(location: 0, length: nsDeclaration.length))
if matches.count > 0 {
let accessorName = (declaration as NSString).substring(with: matches[0].rangeAt(1))
return usrPrefix + "(im)\(accessorName)"
let accessorName = nsDeclaration.substring(with: matches[0].rangeAt(1))
return usrPrefix + accessorType.methodTypeString + accessorName
} else if getter {
return usr.replacingOccurrences(of: "(py)", with: "(im)")
return usr.replacingOccurrences(of: accessorType.propertyTypeString, with: accessorType.methodTypeString)
}
// Setter
let capitalFirstLetter = String(usr.characters[usr.characters.index(pyStartIndex, offsetBy: 4)]).capitalized
let restOfSetterName = usr.substring(from: usr.characters.index(pyStartIndex, offsetBy: 5))
return "\(usrPrefix)(im)set\(capitalFirstLetter)\(restOfSetterName):"
let setterOffset = accessorType.propertyTypeString.characters.count
let capitalizedSetterName = usr.substring(from: usr.characters.index(propertyTypeStringStart, offsetBy: setterOffset)).capitalizingFirstLetter()
return "\(usrPrefix)\(accessorType.methodTypeString)set\(capitalizedSetterName):"
}
}

Expand Down
4 changes: 4 additions & 0 deletions Source/SourceKittenFramework/String+SourceKitten.swift
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ extension String {
return FileManager.default.fileExists(atPath: self)
}

internal func capitalizingFirstLetter() -> String {
return String(characters.prefix(1)).capitalized + String(characters.dropFirst())
}

#if !os(Linux)
/// Returns the `#pragma mark`s in the string.
/// Just the content; no leading dashes or leading `#pragma mark`.
Expand Down
5 changes: 4 additions & 1 deletion Tests/SourceKittenFrameworkTests/Fixtures/Musician.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@

#pragma mark - Properties

/// Always returns `YES`.
@property (class, readwrite, nonatomic) BOOL isMusician;

/**
The name of the musician. i.e. "John Coltrane"
*/
@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSString *name;

/**
The year the musician was born. i.e. 1926
Expand Down
47 changes: 33 additions & 14 deletions Tests/SourceKittenFrameworkTests/Fixtures/Musician.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,47 +24,66 @@
"key.deprecation_message" : "",
"key.always_unavailable" : false,
"key.unavailable_message" : "",
"key.parsed_scope.start" : 19,
"key.parsed_scope.start" : 17,
"key.kind" : "sourcekitten.source.lang.objc.decl.property",
"key.swift_declaration" : "class var isMusician: Bool { get set }",
"key.doc.full_as_xml" : "",
"key.always_deprecated" : false,
"key.doc.line" : 17,
"key.doc.column" : 46,
"key.name" : "isMusician",
"key.doc.comment" : "Always returns `YES`.",
"key.usr" : "c:objc(cs)JAZMusician(cpy)isMusician",
"key.parsed_declaration" : "@property (assign, readwrite, nonatomic, class) BOOL isMusician;",
"key.parsed_scope.end" : 17
},
{
"key.filepath" : "Musician.h",
"key.doc.file" : "Musician.h",
"key.deprecation_message" : "",
"key.always_unavailable" : false,
"key.unavailable_message" : "",
"key.parsed_scope.start" : 22,
"key.kind" : "sourcekitten.source.lang.objc.decl.property",
"key.swift_declaration" : "var name: String! { get }",
"key.doc.full_as_xml" : "",
"key.always_deprecated" : false,
"key.doc.line" : 19,
"key.doc.column" : 44,
"key.doc.line" : 22,
"key.doc.column" : 43,
"key.name" : "name",
"key.doc.comment" : "The name of the musician. i.e. \"John Coltrane\"",
"key.usr" : "c:objc(cs)JAZMusician(py)name",
"key.parsed_declaration" : "@property (readonly, nonatomic) NSString *name;",
"key.parsed_scope.end" : 19
"key.parsed_scope.end" : 22
},
{
"key.filepath" : "Musician.h",
"key.doc.file" : "Musician.h",
"key.deprecation_message" : "",
"key.always_unavailable" : false,
"key.unavailable_message" : "",
"key.parsed_scope.start" : 24,
"key.parsed_scope.start" : 27,
"key.kind" : "sourcekitten.source.lang.objc.decl.property",
"key.swift_declaration" : "var birthyear: UInt { get }",
"key.doc.full_as_xml" : "",
"key.always_deprecated" : false,
"key.doc.line" : 24,
"key.doc.line" : 27,
"key.doc.column" : 44,
"key.name" : "birthyear",
"key.doc.comment" : "The year the musician was born. i.e. 1926",
"key.usr" : "c:objc(cs)JAZMusician(py)birthyear",
"key.parsed_declaration" : "@property (readonly, nonatomic) NSUInteger birthyear;",
"key.parsed_scope.end" : 24
"key.parsed_scope.end" : 27
},
{
"key.filepath" : "Musician.h",
"key.doc.file" : "Musician.h",
"key.doc.line" : 26,
"key.doc.line" : 29,
"key.doc.column" : 1,
"key.name" : "Initializers-hyphenated",
"key.parsed_scope.start" : 26,
"key.parsed_scope.start" : 29,
"key.kind" : "sourcekitten.source.lang.objc.mark",
"key.parsed_scope.end" : 26
"key.parsed_scope.end" : 29
},
{
"key.filepath" : "Musician.h",
Expand Down Expand Up @@ -92,12 +111,12 @@
}
],
"key.unavailable_message" : "",
"key.parsed_scope.start" : 40,
"key.parsed_scope.start" : 43,
"key.kind" : "sourcekitten.source.lang.objc.decl.method.instance",
"key.swift_declaration" : "init!(name: String!, birthyear: UInt)",
"key.doc.full_as_xml" : "",
"key.always_deprecated" : false,
"key.doc.line" : 40,
"key.doc.line" : 43,
"key.doc.column" : 17,
"key.name" : "-initWithName:birthyear:",
"key.doc.comment" : "Initialize a JAZMusician.\nDon't forget to have a name and a birthyear.\n\n- warning: Jazz can be addicting.\nPlease be careful out there.\n\n- parameter: name The name of the musician.\n- parameter: birthyear The year the musician was born.\n\n- returns: An initialized JAZMusician instance.",
Expand All @@ -109,7 +128,7 @@
"Para" : "An initialized JAZMusician instance."
}
],
"key.parsed_scope.end" : 40
"key.parsed_scope.end" : 43
}
],
"key.unavailable_message" : "",
Expand All @@ -124,7 +143,7 @@
"key.doc.comment" : "JAZMusician models, you guessed it... Jazz Musicians!\nFrom Ellington to Marsalis, this class has you covered.",
"key.usr" : "c:objc(cs)JAZMusician",
"key.parsed_declaration" : "@interface JAZMusician : NSObject",
"key.parsed_scope.end" : 42
"key.parsed_scope.end" : 45
}
],
"key.diagnostic_stage" : ""
Expand Down

0 comments on commit 9ede44f

Please sign in to comment.