├── .codecov.yml ├── .gitignore ├── .swiftlint.yml ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── IBAnalyzer.podspec ├── IBAnalyzer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── IBAnalyzer.xcscheme ├── IBAnalyzer.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IBAnalyzer ├── Analyzers │ ├── Analyzer.swift │ └── ConnectionAnalyzer.swift ├── Helpers │ └── DirectoryContentsEnumerator.swift ├── Info.plist ├── Models │ ├── Class.swift │ └── Nib.swift ├── Parsers │ ├── NibParser.swift │ ├── SwiftParser.swift │ └── UIKitOutlets.swift ├── Runner.swift └── main.swift ├── IBAnalyzerTests ├── ConnectionAnalyzerTests.swift ├── DirectoryContentsEnumeratorTests.swift ├── Examples │ └── Example.storyboard ├── Info.plist ├── NibParserTests.swift ├── RunnerTests.swift ├── Stubs.swift └── SwiftParserTests.swift ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── Manifest.lock ├── Manifest.lock-e ├── Pods.xcodeproj │ ├── project.pbxproj │ └── project.pbxproj-e ├── SWXMLHash │ ├── LICENSE │ ├── README.md │ └── Source │ │ ├── SWXMLHash+TypeConversion.swift │ │ └── SWXMLHash.swift ├── SourceKittenFramework │ ├── LICENSE │ ├── README.md │ └── Source │ │ └── SourceKittenFramework │ │ ├── Clang+SourceKitten.swift │ │ ├── ClangTranslationUnit.swift │ │ ├── CodeCompletionItem.swift │ │ ├── Dictionary+Merge.swift │ │ ├── Documentation.swift │ │ ├── File.swift │ │ ├── JSONOutput.swift │ │ ├── Language.swift │ │ ├── LinuxCompatibility.swift │ │ ├── Module.swift │ │ ├── ObjCDeclarationKind.swift │ │ ├── OffsetMap.swift │ │ ├── Parameter.swift │ │ ├── Request.swift │ │ ├── SourceDeclaration.swift │ │ ├── SourceLocation.swift │ │ ├── StatementKind.swift │ │ ├── String+SourceKitten.swift │ │ ├── Structure.swift │ │ ├── SwiftDeclarationKind.swift │ │ ├── SwiftDocKey.swift │ │ ├── SwiftDocs.swift │ │ ├── SwiftLangSyntax.swift │ │ ├── SyntaxKind.swift │ │ ├── SyntaxMap.swift │ │ ├── SyntaxToken.swift │ │ ├── Text.swift │ │ ├── Version.swift │ │ ├── Xcode.swift │ │ ├── clang-c │ │ ├── BuildSystem.h │ │ ├── CXCompilationDatabase.h │ │ ├── CXErrorCode.h │ │ ├── CXString.h │ │ ├── Documentation.h │ │ ├── Index.h │ │ └── Platform.h │ │ ├── library_wrapper.swift │ │ ├── library_wrapper_CXString.swift │ │ ├── library_wrapper_Documentation.swift │ │ ├── library_wrapper_Index.swift │ │ ├── library_wrapper_sourcekitd.swift │ │ └── sourcekitd.h ├── Target Support Files │ ├── Pods-IBAnalyzer-IBAnalyzerTests │ │ ├── Info.plist │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-acknowledgements.markdown │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-acknowledgements.plist │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-dummy.m │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-frameworks.sh │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-resources.sh │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests-umbrella.h │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests.debug.xcconfig │ │ ├── Pods-IBAnalyzer-IBAnalyzerTests.modulemap │ │ └── Pods-IBAnalyzer-IBAnalyzerTests.release.xcconfig │ ├── Pods-IBAnalyzer │ │ ├── Info.plist │ │ ├── Pods-IBAnalyzer-acknowledgements.markdown │ │ ├── Pods-IBAnalyzer-acknowledgements.plist │ │ ├── Pods-IBAnalyzer-dummy.m │ │ ├── Pods-IBAnalyzer-frameworks.sh │ │ ├── Pods-IBAnalyzer-resources.sh │ │ ├── Pods-IBAnalyzer-umbrella.h │ │ ├── Pods-IBAnalyzer.debug.xcconfig │ │ ├── Pods-IBAnalyzer.modulemap │ │ └── Pods-IBAnalyzer.release.xcconfig │ ├── SWXMLHash │ │ ├── Info.plist │ │ ├── SWXMLHash-dummy.m │ │ ├── SWXMLHash-prefix.pch │ │ ├── SWXMLHash-umbrella.h │ │ ├── SWXMLHash.modulemap │ │ └── SWXMLHash.xcconfig │ ├── SourceKittenFramework │ │ ├── Info.plist │ │ ├── SourceKittenFramework-dummy.m │ │ ├── SourceKittenFramework-prefix.pch │ │ ├── SourceKittenFramework-umbrella.h │ │ ├── SourceKittenFramework.modulemap │ │ └── SourceKittenFramework.xcconfig │ └── Yams │ │ ├── Info.plist │ │ ├── Yams-dummy.m │ │ ├── Yams-prefix.pch │ │ ├── Yams-umbrella.h │ │ ├── Yams.modulemap │ │ └── Yams.xcconfig └── Yams │ ├── LICENSE │ ├── README.md │ └── Sources │ ├── CYaml │ ├── include │ │ ├── CYaml.h │ │ └── yaml.h │ └── src │ │ ├── api.c │ │ ├── emitter.c │ │ ├── parser.c │ │ ├── reader.c │ │ ├── scanner.c │ │ ├── writer.c │ │ └── yaml_private.h │ └── Yams │ ├── Constructor.swift │ ├── Decoder.swift │ ├── Emitter.swift │ ├── Encoder.swift │ ├── Mark.swift │ ├── Node.Mapping.swift │ ├── Node.Scalar.swift │ ├── Node.Sequence.swift │ ├── Node.swift │ ├── Parser.swift │ ├── Representer.swift │ ├── Resolver.swift │ ├── String+Yams.swift │ ├── Tag.swift │ ├── YamlError.swift │ └── Yams.h ├── README.md ├── Rakefile ├── Resources ├── unnecessary-action@2x.png └── unnecessary-outlet@2x.png └── bin └── ibanalyzer /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - Pods/* 4 | status: 5 | patch: false 6 | changes: false 7 | project: 8 | default: 9 | target: 75 10 | comment: false 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | bin/IBAnalyzer.app 8 | DerivedData/ 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xcuserstate 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | .build/ 40 | 41 | # CocoaPods 42 | # 43 | # We recommend against adding the Pods directory to your .gitignore. However 44 | # you should judge for yourself, the pros and cons are mentioned at: 45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 46 | # 47 | # Pods/ 48 | Pods/SwiftLint/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | .apitoken 70 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: # paths to ignore during linting. overridden byincluded. 2 | - Pods 3 | disabled_rules: 4 | - line_length 5 | 6 | # configurable rules can be customized from this configuration file 7 | # binary rules can set their severity level 8 | shorthand_operator: warning # implicitly 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode9.2 3 | script: 4 | - xcodebuild -scheme IBAnalyzer -workspace IBAnalyzer.xcworkspace 5 | - xcodebuild test -scheme IBAnalyzer -workspace IBAnalyzer.xcworkspace 6 | after_success: 7 | - bash <(curl -s https://codecov.io/bash) -J 'IBAnalyzer' 8 | 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # IBAnalyzer CHANGELOG 2 | 3 | --- 4 | 5 | ## 0.3.0 6 | 7 | - Swift 4.1 compatibility. 8 | 9 | ## 0.2.1 10 | 11 | - Improved README. 12 | - Replaces errors with warnings. 13 | 14 | ## 0.2.0 15 | 16 | - Build phase integration through CocoaPods. 17 | 18 | ## 0.1.1 19 | 20 | - Fixes relative paths passed to CLI not working correctly. 21 | 22 | ## 0.1.0 23 | 24 | Initial release. 25 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cocoapods', '1.5.3' 4 | gem 'xcpretty', '0.2.4' 5 | gem 'rake', '12.3.1' 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.0) 5 | activesupport (4.2.10) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | atomos (0.1.2) 11 | claide (1.0.2) 12 | cocoapods (1.5.3) 13 | activesupport (>= 4.0.2, < 5) 14 | claide (>= 1.0.2, < 2.0) 15 | cocoapods-core (= 1.5.3) 16 | cocoapods-deintegrate (>= 1.0.2, < 2.0) 17 | cocoapods-downloader (>= 1.2.0, < 2.0) 18 | cocoapods-plugins (>= 1.0.0, < 2.0) 19 | cocoapods-search (>= 1.0.0, < 2.0) 20 | cocoapods-stats (>= 1.0.0, < 2.0) 21 | cocoapods-trunk (>= 1.3.0, < 2.0) 22 | cocoapods-try (>= 1.1.0, < 2.0) 23 | colored2 (~> 3.1) 24 | escape (~> 0.0.4) 25 | fourflusher (~> 2.0.1) 26 | gh_inspector (~> 1.0) 27 | molinillo (~> 0.6.5) 28 | nap (~> 1.0) 29 | ruby-macho (~> 1.1) 30 | xcodeproj (>= 1.5.7, < 2.0) 31 | cocoapods-core (1.5.3) 32 | activesupport (>= 4.0.2, < 6) 33 | fuzzy_match (~> 2.0.4) 34 | nap (~> 1.0) 35 | cocoapods-deintegrate (1.0.2) 36 | cocoapods-downloader (1.2.1) 37 | cocoapods-plugins (1.0.0) 38 | nap 39 | cocoapods-search (1.0.0) 40 | cocoapods-stats (1.0.0) 41 | cocoapods-trunk (1.3.0) 42 | nap (>= 0.8, < 2.0) 43 | netrc (~> 0.11) 44 | cocoapods-try (1.1.0) 45 | colored2 (3.1.2) 46 | concurrent-ruby (1.0.5) 47 | escape (0.0.4) 48 | fourflusher (2.0.1) 49 | fuzzy_match (2.0.4) 50 | gh_inspector (1.1.3) 51 | i18n (0.9.5) 52 | concurrent-ruby (~> 1.0) 53 | minitest (5.11.3) 54 | molinillo (0.6.5) 55 | nanaimo (0.2.5) 56 | nap (1.1.0) 57 | netrc (0.11.0) 58 | rake (12.3.1) 59 | rouge (1.11.1) 60 | ruby-macho (1.2.0) 61 | thread_safe (0.3.6) 62 | tzinfo (1.2.5) 63 | thread_safe (~> 0.1) 64 | xcodeproj (1.5.9) 65 | CFPropertyList (>= 2.3.3, < 4.0) 66 | atomos (~> 0.1.2) 67 | claide (>= 1.0.2, < 2.0) 68 | colored2 (~> 3.1) 69 | nanaimo (~> 0.2.5) 70 | xcpretty (0.2.4) 71 | rouge (~> 1.8) 72 | 73 | PLATFORMS 74 | ruby 75 | 76 | DEPENDENCIES 77 | cocoapods (= 1.5.3) 78 | rake (= 12.3.1) 79 | xcpretty (= 0.2.4) 80 | 81 | BUNDLED WITH 82 | 1.16.1 83 | -------------------------------------------------------------------------------- /IBAnalyzer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "IBAnalyzer" 4 | s.version = "0.3.0" 5 | s.summary = "Tool for finding xib and storyboard-related issues at the build time." 6 | 7 | s.homepage = "https://github.com/fastred/IBAnalyzer" 8 | s.license = "MIT" 9 | s.author = { "Arkadiusz Holko" => "fastred@fastred.org" } 10 | s.social_media_url = "https://twitter.com/arekholko" 11 | 12 | s.source = { :http => "https://github.com/fastred/IBAnalyzer/releases/download/#{s.version}/ibanalyzer-#{s.version}.zip" } 13 | s.preserve_paths = '*' 14 | 15 | end 16 | -------------------------------------------------------------------------------- /IBAnalyzer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IBAnalyzer.xcodeproj/xcshareddata/xcschemes/IBAnalyzer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 35 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 67 | 69 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 88 | 89 | 90 | 91 | 92 | 93 | 99 | 101 | 107 | 108 | 109 | 110 | 112 | 113 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /IBAnalyzer.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /IBAnalyzer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IBAnalyzer/Analyzers/Analyzer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Analyzer.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct AnalyzerConfiguration { 12 | let classNameToNibMap: [String: Nib] 13 | let classNameToClassMap: [String: Class] 14 | let uiKitClassNameToClassMap: [String: Class] 15 | 16 | init(classNameToNibMap: [String: Nib], 17 | classNameToClassMap: [String: Class], 18 | uiKitClassNameToClassMap: [String: Class] = uiKitClassNameToClass()) { 19 | self.classNameToNibMap = classNameToNibMap 20 | self.classNameToClassMap = classNameToClassMap 21 | self.uiKitClassNameToClassMap = uiKitClassNameToClassMap 22 | } 23 | } 24 | 25 | protocol Issue: CustomStringConvertible { 26 | var isSeriousViolation: Bool { get } 27 | } 28 | 29 | protocol Analyzer { 30 | func issues(for configuration: AnalyzerConfiguration) -> [Issue] 31 | } 32 | -------------------------------------------------------------------------------- /IBAnalyzer/Helpers/DirectoryContentsEnumerator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DirectoryContentsEnumerator.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 24-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol DirectoryContentsEnumeratorType { 12 | func files(at url: URL, fileManager: FileManager) throws -> [URL] 13 | } 14 | 15 | struct DirectoryContentsEnumerator: DirectoryContentsEnumeratorType { 16 | 17 | func files(at url: URL, fileManager: FileManager = FileManager.default) throws -> [URL] { 18 | guard let enumerator = fileManager.enumerator(at: url, 19 | includingPropertiesForKeys: [], 20 | options: [], 21 | errorHandler: nil) else { 22 | return [] 23 | } 24 | 25 | var fileURLs: [URL] = [] 26 | 27 | for case let fileURL as URL in enumerator { 28 | let resourceValues = try fileURL.resolvingSymlinksInPath() 29 | .resourceValues(forKeys: [.pathKey, .isDirectoryKey]) 30 | if let isDirectory = resourceValues.isDirectory, 31 | !isDirectory, 32 | let path = resourceValues.path { 33 | 34 | fileURLs.append(URL(fileURLWithPath: path)) 35 | } 36 | } 37 | 38 | return fileURLs 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /IBAnalyzer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2016 Arkadiusz Holko. All rights reserved. 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /IBAnalyzer/Models/Class.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Class.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Class { 12 | var outlets: [Declaration] 13 | var actions: [Declaration] 14 | var inherited: [String] 15 | } 16 | 17 | extension Class: Equatable { 18 | public static func == (lhs: Class, rhs: Class) -> Bool { 19 | return lhs.outlets == rhs.outlets 20 | && lhs.actions == rhs.actions 21 | && lhs.inherited == rhs.inherited 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /IBAnalyzer/Models/Nib.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nib.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Nib { 12 | var outlets: [Declaration] 13 | var actions: [Declaration] 14 | } 15 | 16 | extension Nib: Equatable { 17 | public static func == (lhs: Nib, rhs: Nib) -> Bool { 18 | return lhs.outlets == rhs.outlets && lhs.actions == rhs.actions 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IBAnalyzer/Parsers/NibParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NibParser.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 24-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol NibParserType { 12 | func mappingForFile(at url: URL) throws -> [String: Nib] 13 | } 14 | 15 | class NibParser: NibParserType { 16 | func mappingForFile(at url: URL) throws -> [String: Nib] { 17 | let parser = XMLParser(data: try Data(contentsOf: url)) 18 | 19 | let delegate = ParserDelegate() 20 | delegate.url = url 21 | parser.delegate = delegate 22 | parser.parse() 23 | 24 | return delegate.classNameToNibMap 25 | } 26 | } 27 | 28 | // Thanks to SwiftGen for the inspiration :) 29 | 30 | private class ParserDelegate: NSObject, XMLParserDelegate { 31 | 32 | private struct Element { 33 | let tag: String 34 | let customClassName: String? 35 | } 36 | 37 | var url: URL! 38 | var inObjects = false 39 | var inConnections = false 40 | private var stack: [Element] = [] 41 | 42 | var classNameToNibMap: [String: Nib] = [:] 43 | var idToCustomClassMap: [String: String] = [:] 44 | 45 | @objc func parser(_ parser: XMLParser, didStartElement elementName: String, 46 | namespaceURI: String?, qualifiedName qName: String?, 47 | attributes attributeDict: [String: String]) { 48 | 49 | switch elementName { 50 | case "objects": 51 | inObjects = true 52 | stack = [] 53 | case "connections": 54 | inConnections = true 55 | case "outlet" where inConnections, "outletCollection" where inConnections: 56 | guard let property = attributeDict["property"], 57 | let customClassName = stack.last?.customClassName else { 58 | break 59 | } 60 | 61 | let outlet = Declaration(name: property, line: parser.lineNumber, column: parser.columnNumber, url: url) 62 | classNameToNibMap[customClassName]?.outlets.append(outlet) 63 | case "action" where inConnections: 64 | guard let selector = attributeDict["selector"], 65 | let destination = attributeDict["destination"], 66 | let customClassName = idToCustomClassMap[destination] else { 67 | break 68 | } 69 | let action = Declaration(name: selector, line: parser.lineNumber, column: parser.columnNumber, url: url) 70 | classNameToNibMap[customClassName]?.actions.append(action) 71 | case let tag where (inObjects && tag != "viewControllerPlaceholder"): 72 | // swiftlint:disable identifier_name superfluous_disable_command 73 | let customClass = attributeDict["customClass"] 74 | let id = attributeDict["id"] 75 | stack.append(Element(tag: tag, customClassName: customClass)) 76 | 77 | if let customClass = customClass, let id = id { 78 | idToCustomClassMap[id] = customClass 79 | classNameToNibMap[customClass] = Nib(outlets: [], actions: []) 80 | } 81 | // swiftlint:disable identifier_name superfluous_disable_command 82 | default: 83 | break 84 | } 85 | } 86 | 87 | @objc func parser(_ parser: XMLParser, didEndElement elementName: String, 88 | namespaceURI: String?, qualifiedName qName: String?) { 89 | switch elementName { 90 | case "objects": 91 | inObjects = false 92 | assert(stack.count == 0) 93 | case "connections": 94 | inConnections = false 95 | case "outlet", "outletCollection", "action": 96 | break 97 | case let tag where (inObjects && tag != "viewControllerPlaceholder"): 98 | stack.removeLast() 99 | default: 100 | break 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /IBAnalyzer/Parsers/SwiftParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftParser.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 26-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SourceKittenFramework 11 | 12 | protocol SwiftParserType { 13 | func mappingForFile(at url: URL, result: inout [String: Class]) throws 14 | func mappingForContents(_ contents: String, result: inout [String: Class]) throws 15 | } 16 | 17 | enum SwiftParserError: Error { 18 | case incorrectPath(path: String) 19 | } 20 | 21 | class SwiftParser: SwiftParserType { 22 | func mappingForFile(at url: URL, result: inout [String: Class]) throws { 23 | if let file = File(path: url.path) { 24 | return try mapping(for: file, result: &result) 25 | } else { 26 | throw SwiftParserError.incorrectPath(path: url.path) 27 | } 28 | } 29 | 30 | func mappingForContents(_ contents: String, result: inout [String: Class]) throws { 31 | return try mapping(for: File(contents: contents), result: &result) 32 | } 33 | 34 | private func mapping(for file: File, result: inout [String: Class]) throws { 35 | let fileStructure = try Structure(file: file) 36 | let dictionary = fileStructure.dictionary 37 | 38 | parseSubstructure(dictionary.substructure, result: &result, file: file) 39 | } 40 | 41 | private func parseSubstructure(_ substructure: [[String: SourceKitRepresentable]], 42 | result: inout [String: Class], 43 | file: File) { 44 | for structure in substructure { 45 | var outlets: [Declaration] = [] 46 | var actions: [Declaration] = [] 47 | 48 | if let kind = structure["key.kind"] as? String, 49 | let name = structure["key.name"] as? String, 50 | kind == "source.lang.swift.decl.class" || kind == "source.lang.swift.decl.extension" { 51 | 52 | for insideStructure in structure.substructure { 53 | if let attributes = insideStructure["key.attributes"] as? [[String: AnyObject]], 54 | let propertyName = insideStructure["key.name"] as? String { 55 | 56 | let isOutlet = attributes.contains { dict -> Bool in 57 | return dict.values.contains(where: { $0 as? String == "source.decl.attribute.iboutlet" }) 58 | } 59 | 60 | if isOutlet, let nameOffset64 = insideStructure["key.nameoffset"] as? Int64 { 61 | outlets.append(Declaration(name: propertyName, file: file, offset: nameOffset64, isOptional: insideStructure.isOptional)) 62 | } 63 | 64 | let isIBAction = attributes.contains { dict -> Bool in 65 | return dict.values.contains(where: { $0 as? String == "source.decl.attribute.ibaction" }) 66 | } 67 | 68 | if isIBAction, let selectorName = insideStructure["key.selector_name"] as? String, 69 | let nameOffset64 = insideStructure["key.nameoffset"] as? Int64 { 70 | actions.append(Declaration(name: selectorName, file: file, offset: nameOffset64)) 71 | } 72 | } 73 | } 74 | 75 | parseSubstructure(structure.substructure, result: &result, file: file) 76 | let inherited = extractedInheritedTypes(structure: structure) 77 | let existing = result[name] 78 | 79 | // appending needed because of extensions 80 | result[name] = Class(outlets: outlets + (existing?.outlets ?? []), 81 | actions: actions + (existing?.actions ?? []), 82 | inherited: inherited + (existing?.inherited ?? [])) 83 | } 84 | } 85 | } 86 | 87 | private func extractedInheritedTypes(structure: [String: SourceKitRepresentable]) -> [String] { 88 | guard let inherited = structure["key.inheritedtypes"] as? [[String: String]] else { 89 | return [] 90 | } 91 | 92 | let result = inherited.map { $0["key.name"] }.flatMap { $0 } 93 | return result 94 | } 95 | } 96 | 97 | private extension Dictionary where Key: ExpressibleByStringLiteral { 98 | var substructure: [[String: SourceKitRepresentable]] { 99 | let substructure = self["key.substructure"] as? [SourceKitRepresentable] ?? [] 100 | return substructure.flatMap { $0 as? [String: SourceKitRepresentable] } 101 | } 102 | 103 | var isOptional: Bool { 104 | if let typename = self["key.typename"] as? String, 105 | let optionalString = typename.last { 106 | return optionalString == "?" 107 | } 108 | return false 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /IBAnalyzer/Parsers/UIKitOutlets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIKitOutlets.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 17/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Special outlets declared in UIKit classes. 12 | private let uiKitOutlets: [String: [String]] = [ 13 | "UITextField": ["delegate"], 14 | "UITableView": ["delegate", "dataSource"], 15 | "UITableViewCell": ["accessoryView", "backgroundView", "editingAccessoryView", "selectedBackgroundView"], 16 | "UICollectionView": ["delegate", "dataSource", "prefetchDataSource"], 17 | "UICollectionViewCell": ["backgroundView", "selectedBackgroundView"], 18 | "UITextView": ["delegate"], 19 | "UIScrollView": ["delegate"], 20 | "UIPickerView": ["delegate", "dataSource"], 21 | "MKMapView": ["delegate"], 22 | "GLKView": ["delegate"], 23 | "SCNView": ["delegate"], 24 | "UIWebView": ["delegate"], 25 | "UITapGestureRecognizer": ["delegate"], 26 | "UIPinchGestureRecognizer": ["delegate"], 27 | "UIRotationGestureRecognizer": ["delegate"], 28 | "UISwipeGestureRecognizer": ["delegate"], 29 | "UIPanGestureRecognizer": ["delegate"], 30 | "UIScreenEdgePanGestureRecognizer": ["delegate"], 31 | "UILongPressGestureRecognizer": ["delegate"], 32 | "UIGestureRecognizer": ["delegate"], 33 | "UINavigationBar": ["delegate"], 34 | "UINavigationItem": ["backBarButtonItem", "leftBarButtonItem", "rightBarButtonItem", "titleView"], 35 | "UIToolbar": ["delegate"], 36 | "UITabBar": ["delegate"], 37 | "UISearchBar": ["delegate"], 38 | "UIViewController": ["view"] 39 | ] 40 | 41 | func uiKitClassNameToClass() -> [String: Class] { 42 | var dict: [String: Class] = [:] 43 | for (name, outlets) in uiKitOutlets { 44 | var outletArray: [Declaration] = [] 45 | for outlet in outlets { 46 | outletArray.append(Declaration(name: outlet, line: 0, column: 0)) 47 | } 48 | dict[name] = Class(outlets: outletArray, actions: [], inherited: []) 49 | } 50 | 51 | return dict 52 | } 53 | -------------------------------------------------------------------------------- /IBAnalyzer/Runner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Runner.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SourceKittenFramework 11 | 12 | class Runner { 13 | let path: String 14 | let directoryEnumerator: DirectoryContentsEnumeratorType 15 | let nibParser: NibParserType 16 | let swiftParser: SwiftParserType 17 | let fileManager: FileManager 18 | 19 | init(path: String, 20 | directoryEnumerator: DirectoryContentsEnumeratorType = DirectoryContentsEnumerator(), 21 | nibParser: NibParserType = NibParser(), 22 | swiftParser: SwiftParserType = SwiftParser(), 23 | fileManager: FileManager = FileManager()) { 24 | self.path = path 25 | self.directoryEnumerator = directoryEnumerator 26 | self.nibParser = nibParser 27 | self.swiftParser = swiftParser 28 | self.fileManager = fileManager 29 | } 30 | 31 | func issues(using analyzers: [Analyzer]) throws -> [Issue] { 32 | var classNameToNibMap: [String: Nib] = [:] 33 | var classNameToClassMap: [String: Class] = [:] 34 | 35 | for url in try nibFiles() { 36 | let connections = try nibParser.mappingForFile(at: url) 37 | for (key, value) in connections { 38 | classNameToNibMap[key] = value 39 | } 40 | } 41 | 42 | for url in try swiftFiles() { 43 | try swiftParser.mappingForFile(at: url, result: &classNameToClassMap) 44 | } 45 | 46 | let configuration = AnalyzerConfiguration(classNameToNibMap: classNameToNibMap, 47 | classNameToClassMap: classNameToClassMap, 48 | uiKitClassNameToClassMap: uiKitClassNameToClass()) 49 | 50 | return analyzers.flatMap { $0.issues(for: configuration) } 51 | } 52 | 53 | func nibFiles() throws -> [URL] { 54 | return try files().filter { $0.pathExtension == "storyboard" || $0.pathExtension == "xib"} 55 | } 56 | 57 | func swiftFiles() throws -> [URL] { 58 | return try files().filter { $0.pathExtension == "swift" } 59 | } 60 | 61 | fileprivate func files() throws -> [URL] { 62 | let url = URL(fileURLWithPath: path) 63 | return try directoryEnumerator.files(at: url, fileManager: fileManager) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /IBAnalyzer/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 24-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppKit 11 | 12 | let isInUnitTests = NSClassFromString("XCTest") != nil 13 | 14 | if !isInUnitTests { 15 | do { 16 | let args = ProcessInfo.processInfo.arguments 17 | guard args.count > 1 else { 18 | print("Please provide a project path as a first argument.") 19 | exit(1) 20 | } 21 | 22 | let currentDirectoryPath = FileManager.default.currentDirectoryPath 23 | let url = URL(fileURLWithPath: args[1], relativeTo: URL(fileURLWithPath: currentDirectoryPath)) 24 | 25 | guard FileManager.default.fileExists(atPath: url.path) else { 26 | print("Path \(url.path) doesn't exist.") 27 | exit(1) 28 | } 29 | 30 | print("Analyzing files located at: \(url.path)") 31 | 32 | let runner = Runner(path: url.path) 33 | Configuration.shared.setup(with: args) 34 | let issues = try runner.issues(using: [ConnectionAnalyzer()]) 35 | var hasSeriousViolation: Bool = false 36 | for issue in issues { 37 | if issue.isSeriousViolation { 38 | hasSeriousViolation = true 39 | } 40 | print(issue) 41 | } 42 | if hasSeriousViolation { 43 | exit(2) 44 | } 45 | } catch let error { 46 | print(error.localizedDescription) 47 | exit(1) 48 | } 49 | } else { 50 | final class TestAppDelegate: NSObject, NSApplicationDelegate { 51 | let window = NSWindow() 52 | 53 | func applicationDidFinishLaunching(aNotification: NSNotification) { 54 | window.setFrame(CGRect(x: 0, y: 0, width: 0, height: 0), display: false) 55 | window.makeKeyAndOrderFront(self) 56 | } 57 | } 58 | 59 | // This is required for us to be able to run unit tests. 60 | autoreleasepool { () -> Void in 61 | let app = NSApplication.shared() 62 | let appDelegate = TestAppDelegate() 63 | app.delegate = appDelegate 64 | app.run() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /IBAnalyzerTests/ConnectionAnalyzerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectionAnalyzerTests.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 14/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import IBAnalyzer 11 | 12 | extension ConnectionIssue: Equatable { 13 | public static func == (lhs: ConnectionIssue, rhs: ConnectionIssue) -> Bool { 14 | // Not pretty but probably good enough for tests. 15 | return String(describing: lhs) == String(describing: rhs) 16 | } 17 | } 18 | 19 | class ConnectionAnalyzerTests: XCTestCase { 20 | func testNoOutletsAndActions() { 21 | let nib = Nib(outlets: [], actions: []) 22 | let klass = Class(outlets: [], actions: [], inherited: []) 23 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 24 | classNameToClassMap: ["A": klass]) 25 | XCTAssertEqual(issues(for: configuration), []) 26 | } 27 | 28 | func testMissingOutlet() { 29 | let label = Declaration(name: "label", line: 1, column: 0) 30 | let nib = Nib(outlets: [label], actions: []) 31 | let klass = Class(outlets: [], actions: [], inherited: []) 32 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 33 | classNameToClassMap: ["A": klass]) 34 | XCTAssertEqual(issues(for: configuration), [ConnectionIssue.missingOutlet(className: "A", outlet: label)]) 35 | } 36 | 37 | func testMissingAction() { 38 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 39 | let nib = Nib(outlets: [], actions: [didTapButton]) 40 | let klass = Class(outlets: [], actions: [], inherited: []) 41 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 42 | classNameToClassMap: ["A": klass]) 43 | XCTAssertEqual(issues(for: configuration), 44 | [ConnectionIssue.missingAction(className: "A", action: didTapButton)]) 45 | } 46 | 47 | func testUnnecessaryOutlet() { 48 | let nib = Nib(outlets: [], actions: []) 49 | let label = Declaration(name: "label", line: 1, column: 0) 50 | let klass = Class(outlets: [label], actions: [], inherited: []) 51 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 52 | classNameToClassMap: ["A": klass]) 53 | XCTAssertEqual(issues(for: configuration), 54 | [ConnectionIssue.unnecessaryOutlet(className: "A", outlet: label)]) 55 | } 56 | 57 | func testUnnecessaryAction() { 58 | let nib = Nib(outlets: [], actions: []) 59 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 60 | let klass = Class(outlets: [], actions: [didTapButton], inherited: []) 61 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 62 | classNameToClassMap: ["A": klass]) 63 | XCTAssertEqual(issues(for: configuration), 64 | [ConnectionIssue.unnecessaryAction(className: "A", action: didTapButton)]) 65 | } 66 | 67 | func testNoIssueWhenOutletInSuperClass() { 68 | let label = Declaration(name: "label", line: 1, column: 0) 69 | let nib = Nib(outlets: [label], actions: []) 70 | let map = ["A": Class(outlets: [label], actions: [], inherited: []), 71 | "B": Class(outlets: [], actions: [], inherited: ["A"])] 72 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["B": nib], 73 | classNameToClassMap: map) 74 | XCTAssertEqual(issues(for: configuration), []) 75 | } 76 | 77 | func testNoIssueWhenOutletInSuperSuperClass() { 78 | let label = Declaration(name: "label", line: 1, column: 0) 79 | let nib = Nib(outlets: [label], actions: []) 80 | let map = ["A": Class(outlets: [label], actions: [], inherited: []), 81 | "B": Class(outlets: [], actions: [], inherited: ["A"]), 82 | "C": Class(outlets: [], actions: [], inherited: ["B"])] 83 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["C": nib], 84 | classNameToClassMap: map) 85 | XCTAssertEqual(issues(for: configuration), []) 86 | } 87 | 88 | func testNoIssueWhenActionInSuperClass() { 89 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 90 | let nib = Nib(outlets: [], actions: [didTapButton]) 91 | let map = ["A": Class(outlets: [], actions: [didTapButton], inherited: []), 92 | "B": Class(outlets: [], actions: [], inherited: ["A"]), 93 | "C": Class(outlets: [], actions: [], inherited: ["B"])] 94 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["C": nib], 95 | classNameToClassMap: map) 96 | XCTAssertEqual(issues(for: configuration), []) 97 | } 98 | 99 | func testUsesUIKitClasses() { 100 | let delegate = Declaration(name: "delegate:", line: 1, column: 0) 101 | let nib = Nib(outlets: [delegate], actions: []) 102 | let klass = Class(outlets: [], actions: [], inherited: ["UITextField"]) 103 | let textField = Class(outlets: [delegate], actions: [], inherited: []) 104 | let configuration = AnalyzerConfiguration(classNameToNibMap: ["A": nib], 105 | classNameToClassMap: ["A": klass], 106 | uiKitClassNameToClassMap: ["UITextField": textField]) 107 | XCTAssertEqual(issues(for: configuration), []) 108 | } 109 | 110 | private func issues(for configuration: AnalyzerConfiguration) -> [ConnectionIssue] { 111 | let analyzer = ConnectionAnalyzer() 112 | return (analyzer.issues(for: configuration) as? [ConnectionIssue]) ?? [] 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /IBAnalyzerTests/DirectoryContentsEnumeratorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DirectoryContentsEnumeratorTests.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 14/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import IBAnalyzer 11 | 12 | // swiftlint:disable force_try 13 | // swiftlint:disable line_length 14 | class DirectoryContentsEnumeratorTests: XCTestCase { 15 | 16 | var directoryEnumerator = DirectoryContentsEnumerator() 17 | 18 | func testFlatDirectory() { 19 | let directoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)! 20 | try! FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) 21 | let fileURL = directoryURL.appendingPathComponent("file.txt") 22 | try! "test".data(using: .utf8)?.write(to: fileURL) 23 | 24 | let files = try! directoryEnumerator.files(at: directoryURL) 25 | XCTAssertEqual(files, [fileURL]) 26 | } 27 | 28 | func testNestedDirectory() { 29 | let directoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)! 30 | try! FileManager.default.createDirectory(at: directoryURL, 31 | withIntermediateDirectories: true, 32 | attributes: nil) 33 | let fileURL = directoryURL.appendingPathComponent("file.txt") 34 | try! "test".data(using: .utf8)?.write(to: fileURL) 35 | 36 | let subDirectoryURL = directoryURL.appendingPathComponent("sub", isDirectory: true) 37 | try! FileManager.default.createDirectory(at: subDirectoryURL, 38 | withIntermediateDirectories: true, 39 | attributes: nil) 40 | 41 | let fileInSubURL = subDirectoryURL.appendingPathComponent("file2.txt") 42 | try! "test2".data(using: .utf8)?.write(to: fileInSubURL) 43 | 44 | let files = try! directoryEnumerator.files(at: directoryURL) 45 | XCTAssertEqual(files, [fileURL, fileInSubURL]) 46 | } 47 | 48 | func testEmptyForNonExistingDirectory() { 49 | let files = try! directoryEnumerator.files(at: URL(fileURLWithPath: "/incorrect/")) 50 | XCTAssertEqual(files, []) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /IBAnalyzerTests/Examples/Example.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /IBAnalyzerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /IBAnalyzerTests/NibParserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NibParserTests.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 27-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import IBAnalyzer 11 | 12 | class NibParserTests: XCTestCase { 13 | 14 | func testExampleStoryboard() { 15 | guard let srcRoot = ProcessInfo.processInfo.environment["SRCROOT"] else { 16 | fatalError("SRCROOT should be non-nil") 17 | } 18 | 19 | let path = "/IBAnalyzerTests/Examples/Example.storyboard" 20 | let storyboardPath = (srcRoot as NSString).appendingPathComponent(path) 21 | let url = URL(fileURLWithPath: storyboardPath) 22 | let parser = NibParser() 23 | let button = Declaration(name: "button", line: 1, column: 0) 24 | let titleLabel = Declaration(name: "titleLabel", line: 1, column: 0) 25 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 26 | let expected = ["ViewController": Nib(outlets: [button, titleLabel], actions: [didTapButton]), 27 | "ViewController2": Nib(outlets: [], actions: [])] 28 | do { 29 | let result = try parser.mappingForFile(at: url) 30 | XCTAssertEqual(result, expected) 31 | } catch let error { 32 | XCTFail(error.localizedDescription) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IBAnalyzerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RunnerTests.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SourceKittenFramework 11 | @testable import IBAnalyzer 12 | 13 | private class MockAnalyzer: Analyzer { 14 | var lastUsedConfiguration: AnalyzerConfiguration? 15 | 16 | func issues(for configuration: AnalyzerConfiguration) -> [Issue] { 17 | lastUsedConfiguration = configuration 18 | return [] 19 | } 20 | } 21 | 22 | class RunnerTests: XCTestCase { 23 | func testCallsAnalyzerWithCorrectConfiguration() { 24 | let runner = Runner(path: "example", 25 | directoryEnumerator: StubFineDirectoryContentsEnumerator(), 26 | nibParser: StubNibParser(), 27 | swiftParser: StubSwiftParser(), 28 | fileManager: FileManager.default) 29 | 30 | let mockAnalyzer = MockAnalyzer() 31 | do { 32 | _ = try runner.issues(using: [mockAnalyzer]) 33 | let configuration = mockAnalyzer.lastUsedConfiguration! 34 | 35 | let nibMap = StubNibParser.cMap.merging(other: StubNibParser.dMap) 36 | XCTAssertEqual(configuration.classNameToNibMap, nibMap) 37 | 38 | let swiftMap = StubSwiftParser.aMap.merging(other: StubSwiftParser.eMap) 39 | XCTAssertEqual(configuration.classNameToClassMap, swiftMap) 40 | } catch let error { 41 | XCTFail("Unexpected error: \(error)") 42 | } 43 | } 44 | } 45 | 46 | class RunnerFilesTests: XCTestCase { 47 | 48 | func testNibFiles() { 49 | let runner = Runner(path: "example", directoryEnumerator: StubFineDirectoryContentsEnumerator()) 50 | XCTAssertEqual(try runner.nibFiles(), ["c.xib", "d.storyboard"].map { URL(fileURLWithPath: $0) }) 51 | } 52 | 53 | func testSwiftFiles() { 54 | let runner = Runner(path: "example", directoryEnumerator: StubFineDirectoryContentsEnumerator()) 55 | XCTAssertEqual(try runner.swiftFiles(), ["a.swift", "e.swift"].map { URL(fileURLWithPath: $0) }) 56 | } 57 | 58 | func testNibFilesThrows() { 59 | let runner = Runner(path: "example", directoryEnumerator: StubThrowingDirectoryContentsEnumerator()) 60 | XCTAssertThrowsError(try runner.nibFiles()) 61 | } 62 | 63 | func testSwiftFilesThrows() { 64 | let runner = Runner(path: "example", directoryEnumerator: StubThrowingDirectoryContentsEnumerator()) 65 | XCTAssertThrowsError(try runner.swiftFiles()) 66 | } 67 | } 68 | 69 | private extension Dictionary { 70 | func merging(other: [Key: Value]) -> [Key: Value] { 71 | var mutableCopy = self 72 | for (key, value) in other { 73 | // If both dictionaries have a value for same key, the value of the other dictionary is used. 74 | mutableCopy[key] = value 75 | } 76 | return mutableCopy 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /IBAnalyzerTests/Stubs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Stubs.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 29/01/2017. 6 | // Copyright © 2017 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | @testable import IBAnalyzer 11 | 12 | struct StubFineDirectoryContentsEnumerator: DirectoryContentsEnumeratorType { 13 | func files(at url: URL, fileManager: FileManager) throws -> [URL] { 14 | return ["a.swift", "b.m", "c.xib", "d.storyboard", "e.swift", "f.swift2"].map { 15 | URL(fileURLWithPath: $0) 16 | } 17 | } 18 | } 19 | 20 | struct StubThrowingDirectoryContentsEnumerator: DirectoryContentsEnumeratorType { 21 | func files(at url: URL, fileManager: FileManager) throws -> [URL] { 22 | throw NSError(domain: "test", code: 0, userInfo: nil) 23 | } 24 | } 25 | 26 | struct StubNibParser: NibParserType { 27 | static let button = Declaration(name: "button", line: 1, column: 0) 28 | static let label = Declaration(name: "label", line: 1, column: 0) 29 | static let cMap = ["C": Nib(outlets: [StubNibParser.label, StubNibParser.button], actions: [])] 30 | static let tappedButton = Declaration(name: "tappedButton:", line: 1, column: 0) 31 | static let titleView = Declaration(name: "titleView", line: 1, column: 0) 32 | static let dMap = ["FirstViewController": Nib(outlets: [], actions: [StubNibParser.tappedButton]), 33 | "SecondViewController": Nib(outlets: [StubNibParser.titleView], actions: [])] 34 | 35 | func mappingForFile(at url: URL) throws -> [String: Nib] { 36 | switch url { 37 | case URL(fileURLWithPath: "c.xib"): 38 | return type(of: self).cMap 39 | case URL(fileURLWithPath: "d.storyboard"): 40 | return type(of: self).dMap 41 | default: 42 | fatalError() 43 | } 44 | } 45 | } 46 | 47 | struct StubSwiftParser: SwiftParserType { 48 | static let label = Declaration(name: "label", line: 1, column: 0) 49 | static let aMap = ["C": Class(outlets: [StubSwiftParser.label], actions: [], inherited: [])] 50 | static let buttonTapped = Declaration(name: "buttonTapped:", line: 1, column: 0) 51 | static let eMap = ["FirstViewController": Class(outlets: [], actions: [StubSwiftParser.buttonTapped], inherited: [])] 52 | 53 | func mappingForFile(at url: URL, result: inout [String: Class]) throws { 54 | switch url { 55 | case URL(fileURLWithPath: "a.swift"): 56 | result += type(of: self).aMap 57 | case URL(fileURLWithPath: "e.swift"): 58 | result += type(of: self).eMap 59 | default: 60 | fatalError() 61 | } 62 | } 63 | 64 | func mappingForContents(_ contents: String, result: inout [String: Class]) throws { 65 | //do nothing 66 | } 67 | } 68 | 69 | func += (left: inout [K: V], right: [K: V]) { 70 | for (key, value) in right { 71 | left.updateValue(value, forKey: key) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /IBAnalyzerTests/SwiftParserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftParserTests.swift 3 | // IBAnalyzer 4 | // 5 | // Created by Arkadiusz Holko on 26-12-16. 6 | // Copyright © 2016 Arkadiusz Holko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SourceKittenFramework 11 | @testable import IBAnalyzer 12 | 13 | // swiftlint:disable line_length 14 | class SwiftParserTests: XCTestCase { 15 | 16 | func testViewControllerWithoutOutletsAndActions() { 17 | let source = "class TestViewController: UIViewController { var button: UIButton!; func didTapButton(_ sender: UIButton) {} }" 18 | 19 | let expected = Class(outlets: [], actions: [], inherited: ["UIViewController"]) 20 | XCTAssertEqual(mappingFor(contents: source), ["TestViewController": expected]) 21 | } 22 | 23 | func testViewControllerWithOneOutlet() { 24 | let source = "class TestViewController: UIViewController { @IBOutlet weak var button: UIButton! }" 25 | let button = Declaration(name: "button", line: 1, column: 0) 26 | let expected = Class(outlets: [button], actions: [], inherited: ["UIViewController"]) 27 | XCTAssertEqual(mappingFor(contents: source), ["TestViewController": expected]) 28 | } 29 | 30 | func testNestedViewControllerWithOneOutlet() { 31 | let source = "class Outer { class TestViewController: UIViewController { @IBOutlet weak var button: UIButton! }}" 32 | 33 | let expectedOuter = Class(outlets: [], actions: [], inherited: []) 34 | let button = Declaration(name: "button", line: 1, column: 0) 35 | let expectedInner = Class(outlets: [button], actions: [], inherited: ["UIViewController"]) 36 | XCTAssertEqual(mappingFor(contents: source), ["Outer": expectedOuter, 37 | "TestViewController": expectedInner]) 38 | } 39 | 40 | func testViewControllerWithOneAction() { 41 | let source = "class TestViewController: UIViewController { @IBAction func didTapButton(_ sender: UIButton) {} }" 42 | 43 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 44 | let expected = Class(outlets: [], actions: [didTapButton], inherited: ["UIViewController"]) 45 | XCTAssertEqual(mappingFor(contents: source), ["TestViewController": expected]) 46 | } 47 | 48 | func testMultipleInheritance() { 49 | let source = "class TestViewController: UIViewController, SomeProtocol { }" 50 | 51 | let expected = Class(outlets: [], actions: [], inherited: ["UIViewController", "SomeProtocol"]) 52 | XCTAssertEqual(mappingFor(contents: source), ["TestViewController": expected]) 53 | } 54 | 55 | func testViewControllerWithActionInExtension() { 56 | let source = "class TestViewController: UIViewController {}; extension TestViewController { @IBAction func didTapButton(_ sender: UIButton) {} }" 57 | 58 | let didTapButton = Declaration(name: "didTapButton:", line: 1, column: 0) 59 | let expected = Class(outlets: [], actions: [didTapButton], inherited: ["UIViewController"]) 60 | XCTAssertEqual(mappingFor(contents: source), ["TestViewController": expected]) 61 | } 62 | 63 | private func mappingFor(contents: String) -> [String: Class] { 64 | let parser = SwiftParser() 65 | var result: [String: Class] = [:] 66 | do { 67 | try parser.mappingForContents(contents, result: &result) 68 | } catch let error { 69 | XCTFail(error.localizedDescription) 70 | } 71 | return result 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Arkadiusz Holko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :osx, '10.12' 3 | 4 | target 'IBAnalyzer' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | pod 'SourceKittenFramework', '~> 0.19' 9 | pod 'SwiftLint', '~> 0.25.1' 10 | target 'IBAnalyzerTests' do 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SourceKittenFramework (0.19.1): 3 | - SWXMLHash (~> 4.1) 4 | - Yams (~> 0.5.0) 5 | - SwiftLint (0.25.1) 6 | - SWXMLHash (4.5.0) 7 | - Yams (0.5.0) 8 | 9 | DEPENDENCIES: 10 | - SourceKittenFramework (~> 0.19) 11 | - SwiftLint (~> 0.25.1) 12 | 13 | SPEC REPOS: 14 | https://github.com/cocoapods/specs.git: 15 | - SourceKittenFramework 16 | - SwiftLint 17 | - SWXMLHash 18 | - Yams 19 | 20 | SPEC CHECKSUMS: 21 | SourceKittenFramework: ef76be16e76ffa0a64b00c5eb053e87c6770dcdb 22 | SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 23 | SWXMLHash: 5d980b1f12ff0ee2bd9a26df1e01377dc91dfb6e 24 | Yams: 58b13424ca380835c4c797bc775ce6cbb3bc0167 25 | 26 | PODFILE CHECKSUM: e9eb876508bb57d7b03a4c6a6146c2eb1e0051a2 27 | 28 | COCOAPODS: 1.5.3 29 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SourceKittenFramework (0.19.1): 3 | - SWXMLHash (~> 4.1) 4 | - Yams (~> 0.5.0) 5 | - SwiftLint (0.25.1) 6 | - SWXMLHash (4.5.0) 7 | - Yams (0.5.0) 8 | 9 | DEPENDENCIES: 10 | - SourceKittenFramework (~> 0.19) 11 | - SwiftLint (~> 0.25.1) 12 | 13 | SPEC REPOS: 14 | https://github.com/cocoapods/specs.git: 15 | - SourceKittenFramework 16 | - SwiftLint 17 | - SWXMLHash 18 | - Yams 19 | 20 | SPEC CHECKSUMS: 21 | SourceKittenFramework: ef76be16e76ffa0a64b00c5eb053e87c6770dcdb 22 | SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 23 | SWXMLHash: 5d980b1f12ff0ee2bd9a26df1e01377dc91dfb6e 24 | Yams: 58b13424ca380835c4c797bc775ce6cbb3bc0167 25 | 26 | PODFILE CHECKSUM: e9eb876508bb57d7b03a4c6a6146c2eb1e0051a2 27 | 28 | COCOAPODS: 1.5.3 29 | -------------------------------------------------------------------------------- /Pods/Manifest.lock-e: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SourceKittenFramework (0.16.0): 3 | - SWXMLHash (~> 3.0) 4 | - Yams (~> 0.1) 5 | - SwiftLint (0.16.0) 6 | - SWXMLHash (3.0.3) 7 | - Yams (0.1.4) 8 | 9 | DEPENDENCIES: 10 | - SourceKittenFramework (~> 0.16.0) 11 | - SwiftLint (~> 0.16.0) 12 | 13 | SPEC CHECKSUMS: 14 | SourceKittenFramework: 84afd2293a7278ee99a0a1d7dea29f36c9ef3cda 15 | SwiftLint: 90665265ae50b58167c674a11c680bbabe9d6513 16 | SWXMLHash: 80d2529d74891bb2f15305a0b9e08f2a4f229ee7 17 | Yams: 4a4d2b5f0db216fab03c6abc04b7692ceff7cf5f 18 | 19 | PODFILE CHECKSUM: 18620891bf2d6386f04a3125a4e9b431d601c978 20 | 21 | COCOAPODS: 1.1.1 22 | -------------------------------------------------------------------------------- /Pods/SWXMLHash/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 David Mohundro 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 JP Simard. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/ClangTranslationUnit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClangTranslationUnit.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-12. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | #if !os(Linux) 10 | 11 | #if SWIFT_PACKAGE 12 | import Clang_C 13 | #endif 14 | import Foundation 15 | 16 | extension Sequence where Iterator.Element: Hashable { 17 | fileprivate func distinct() -> [Iterator.Element] { 18 | return Array(Set(self)) 19 | } 20 | } 21 | 22 | extension Sequence { 23 | fileprivate func grouped(by transform: (Iterator.Element) -> U) -> [U: [Iterator.Element]] { 24 | return reduce([:]) { dictionary, element in 25 | var dictionary = dictionary 26 | let key = transform(element) 27 | dictionary[key] = (dictionary[key] ?? []) + [element] 28 | return dictionary 29 | } 30 | } 31 | } 32 | 33 | extension Dictionary { 34 | fileprivate init(_ pairs: [Element]) { 35 | self.init() 36 | for (k, v) in pairs { 37 | self[k] = v 38 | } 39 | } 40 | 41 | fileprivate func map(transform: (Value) throws -> (OutValue)) rethrows -> [Key: OutValue] { 42 | return [Key: OutValue](try map { ($0.key, try transform($0.value)) }) 43 | } 44 | } 45 | 46 | /// Represents a group of CXTranslationUnits. 47 | public struct ClangTranslationUnit { 48 | /// Array of CXTranslationUnits. 49 | private let clangTranslationUnits: [CXTranslationUnit] 50 | 51 | public let declarations: [String: [SourceDeclaration]] 52 | 53 | /** 54 | Create a ClangTranslationUnit by passing Objective-C header files and clang compiler arguments. 55 | 56 | - parameter headerFiles: Objective-C header files to document. 57 | - parameter compilerArguments: Clang compiler arguments. 58 | */ 59 | public init(headerFiles: [String], compilerArguments: [String]) { 60 | let cStringCompilerArguments = compilerArguments.map { ($0 as NSString).utf8String } 61 | let clangIndex = ClangIndex() 62 | clangTranslationUnits = headerFiles.map { clangIndex.open(file: $0, args: cStringCompilerArguments) } 63 | declarations = clangTranslationUnits 64 | .flatMap { $0.cursor().flatMap({ SourceDeclaration(cursor: $0, compilerArguments: compilerArguments) }) } 65 | .rejectEmptyDuplicateEnums() 66 | .distinct() 67 | .sorted() 68 | .grouped { $0.location.file } 69 | .map { insertMarks(declarations: $0) } 70 | } 71 | 72 | /** 73 | Failable initializer to create a ClangTranslationUnit by passing Objective-C header files and 74 | `xcodebuild` arguments. Optionally pass in a `path`. 75 | 76 | - parameter headerFiles: Objective-C header files to document. 77 | - parameter xcodeBuildArguments: The arguments necessary pass in to `xcodebuild` to link these header files. 78 | - parameter path: Path to run `xcodebuild` from. Uses current path by default. 79 | */ 80 | public init?(headerFiles: [String], xcodeBuildArguments: [String], inPath path: String = FileManager.default.currentDirectoryPath) { 81 | let xcodeBuildOutput = runXcodeBuild(arguments: xcodeBuildArguments + ["-dry-run"], inPath: path) ?? "" 82 | guard let clangArguments = parseCompilerArguments(xcodebuildOutput: xcodeBuildOutput as NSString, language: .objc, moduleName: nil) else { 83 | fputs("could not parse compiler arguments\n\(xcodeBuildOutput)\n", stderr) 84 | return nil 85 | } 86 | self.init(headerFiles: headerFiles, compilerArguments: clangArguments) 87 | } 88 | } 89 | 90 | // MARK: CustomStringConvertible 91 | 92 | extension ClangTranslationUnit: CustomStringConvertible { 93 | /// A textual JSON representation of `ClangTranslationUnit`. 94 | public var description: String { 95 | return declarationsToJSON(declarations) + "\n" 96 | } 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/CodeCompletionItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeCompletionItem.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 9/4/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | fileprivate extension Dictionary { 12 | mutating func addIfNotNil(_ key: Key, _ value: Value?) { 13 | if let value = value { 14 | self[key] = value 15 | } 16 | } 17 | } 18 | 19 | public struct CodeCompletionItem: CustomStringConvertible { 20 | #if os(Linux) 21 | public typealias NumBytesInt = Int 22 | #else 23 | public typealias NumBytesInt = Int64 24 | #endif 25 | 26 | public let kind: String 27 | public let context: String 28 | public let name: String? 29 | public let descriptionKey: String? 30 | public let sourcetext: String? 31 | public let typeName: String? 32 | public let moduleName: String? 33 | public let docBrief: String? 34 | public let associatedUSRs: String? 35 | public let numBytesToErase: NumBytesInt? 36 | 37 | /// Dictionary representation of CodeCompletionItem. Useful for NSJSONSerialization. 38 | public var dictionaryValue: [String: Any] { 39 | var dict: [String: Any] = ["kind": kind, "context": context] 40 | dict.addIfNotNil("name", name) 41 | dict.addIfNotNil("descriptionKey", descriptionKey) 42 | dict.addIfNotNil("sourcetext", sourcetext) 43 | dict.addIfNotNil("typeName", typeName) 44 | dict.addIfNotNil("moduleName", moduleName) 45 | dict.addIfNotNil("docBrief", docBrief) 46 | dict.addIfNotNil("associatedUSRs", associatedUSRs) 47 | dict.addIfNotNil("numBytesToErase", numBytesToErase) 48 | return dict 49 | } 50 | 51 | public var description: String { 52 | return toJSON(dictionaryValue.bridge()) 53 | } 54 | 55 | public static func parse(response: [String: SourceKitRepresentable]) -> [CodeCompletionItem] { 56 | return (response["key.results"] as! [SourceKitRepresentable]).map { item in 57 | let dict = item as! [String: SourceKitRepresentable] 58 | return CodeCompletionItem(kind: dict["key.kind"] as! String, 59 | context: dict["key.context"] as! String, 60 | name: dict["key.name"] as? String, 61 | descriptionKey: dict["key.description"] as? String, 62 | sourcetext: dict["key.sourcetext"] as? String, 63 | typeName: dict["key.typename"] as? String, 64 | moduleName: dict["key.modulename"] as? String, 65 | docBrief: dict["key.doc.brief"] as? String, 66 | associatedUSRs: dict["key.associated_usrs"] as? String, 67 | numBytesToErase: dict["key.num_bytes_to_erase"] as? NumBytesInt) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Dictionary+Merge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary+Merge.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-08. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /** 10 | Returns a new dictionary by adding the entries of dict2 into dict1, overriding if the key exists. 11 | 12 | - parameter dict1: Dictionary to merge into. 13 | - parameter dict2: Dictionary to merge from (optional). 14 | 15 | - returns: A new dictionary by adding the entries of dict2 into dict1, overriding if the key exists. 16 | */ 17 | internal func merge(_ dict1: [K: V], _ dict2: [K: V]?) -> [K: V] { 18 | var mergedDict = dict1 19 | if let dict2 = dict2 { 20 | for (key, value) in dict2 { 21 | mergedDict[key] = value 22 | } 23 | } 24 | return mergedDict 25 | } 26 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Documentation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Documentation.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 10/27/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | #if !os(Linux) 10 | 11 | #if SWIFT_PACKAGE 12 | import Clang_C 13 | #endif 14 | 15 | public struct Documentation { 16 | public let parameters: [Parameter] 17 | public let returnDiscussion: [Text] 18 | 19 | init(comment: CXComment) { 20 | let comments = (0.. String { 19 | if let array = object as? [Any], array.isEmpty { 20 | return "[\n\n]" 21 | } 22 | do { 23 | let options: JSONSerialization.WritingOptions 24 | #if os(Linux) 25 | options = [.prettyPrinted, .sortedKeys] 26 | #else 27 | if #available(macOS 10.13, *) { 28 | options = [.prettyPrinted, .sortedKeys] 29 | } else { 30 | options = .prettyPrinted 31 | } 32 | #endif 33 | let prettyJSONData = try JSONSerialization.data(withJSONObject: object, options: options) 34 | if let jsonString = String(data: prettyJSONData, encoding: .utf8) { 35 | return jsonString 36 | } 37 | } catch {} 38 | return "" 39 | } 40 | 41 | /** 42 | Convert [String: SourceKitRepresentable] to `NSDictionary`. 43 | 44 | - parameter dictionary: [String: SourceKitRepresentable] to convert. 45 | 46 | - returns: JSON-serializable value. 47 | */ 48 | public func toNSDictionary(_ dictionary: [String: SourceKitRepresentable]) -> NSDictionary { 49 | var anyDictionary = [String: Any]() 50 | for (key, object) in dictionary { 51 | switch object { 52 | case let object as [SourceKitRepresentable]: 53 | anyDictionary[key] = object.map { toNSDictionary($0 as! [String: SourceKitRepresentable]) } 54 | case let object as [[String: SourceKitRepresentable]]: 55 | anyDictionary[key] = object.map { toNSDictionary($0) } 56 | case let object as [String: SourceKitRepresentable]: 57 | anyDictionary[key] = toNSDictionary(object) 58 | case let object as String: 59 | anyDictionary[key] = object 60 | case let object as Int64: 61 | anyDictionary[key] = NSNumber(value: object) 62 | case let object as Bool: 63 | anyDictionary[key] = NSNumber(value: object) 64 | case let object as Any: 65 | anyDictionary[key] = object 66 | default: 67 | fatalError("Should never happen because we've checked all SourceKitRepresentable types") 68 | } 69 | } 70 | return anyDictionary.bridge() 71 | } 72 | 73 | #if !os(Linux) 74 | 75 | public func declarationsToJSON(_ decl: [String: [SourceDeclaration]]) -> String { 76 | let keyValueToDictionary: ((String, [SourceDeclaration])) -> [String: Any] = { [$0.0: toOutputDictionary($0.1)] } 77 | let dictionaries: [[String: Any]] = decl.map(keyValueToDictionary).sorted { $0.keys.first! < $1.keys.first! } 78 | return toJSON(dictionaries) 79 | } 80 | 81 | private func toOutputDictionary(_ decl: SourceDeclaration) -> [String: Any] { 82 | var dict = [String: Any]() 83 | func set(_ key: SwiftDocKey, _ value: Any?) { 84 | if let value = value { 85 | dict[key.rawValue] = value 86 | } 87 | } 88 | func setA(_ key: SwiftDocKey, _ value: [Any]?) { 89 | if let value = value, !value.isEmpty { 90 | dict[key.rawValue] = value 91 | } 92 | } 93 | 94 | set(.kind, decl.type.rawValue) 95 | set(.filePath, decl.location.file) 96 | set(.docFile, decl.location.file) 97 | set(.docLine, Int(decl.location.line)) 98 | set(.docColumn, Int(decl.location.column)) 99 | set(.name, decl.name) 100 | set(.usr, decl.usr) 101 | set(.parsedDeclaration, decl.declaration) 102 | set(.documentationComment, decl.commentBody) 103 | set(.parsedScopeStart, Int(decl.extent.start.line)) 104 | set(.parsedScopeEnd, Int(decl.extent.end.line)) 105 | set(.swiftDeclaration, decl.swiftDeclaration) 106 | set(.swiftName, decl.swiftName) 107 | set(.alwaysDeprecated, decl.availability?.alwaysDeprecated) 108 | set(.alwaysUnavailable, decl.availability?.alwaysUnavailable) 109 | set(.deprecationMessage, decl.availability?.deprecationMessage) 110 | set(.unavailableMessage, decl.availability?.unavailableMessage) 111 | 112 | setA(.docResultDiscussion, decl.documentation?.returnDiscussion.map(toOutputDictionary)) 113 | setA(.docParameters, decl.documentation?.parameters.map(toOutputDictionary)) 114 | setA(.substructure, decl.children.map(toOutputDictionary)) 115 | 116 | if decl.commentBody != nil { 117 | set(.fullXMLDocs, "") 118 | } 119 | 120 | return dict 121 | } 122 | 123 | private func toOutputDictionary(_ decl: [SourceDeclaration]) -> [String: Any] { 124 | return ["key.substructure": decl.map(toOutputDictionary), "key.diagnostic_stage": ""] 125 | } 126 | 127 | private func toOutputDictionary(_ param: Parameter) -> [String: Any] { 128 | return ["name": param.name, "discussion": param.discussion.map(toOutputDictionary)] 129 | } 130 | 131 | private func toOutputDictionary(_ text: Text) -> [String: Any] { 132 | switch text { 133 | case .para(let str, let kind): 134 | return ["kind": kind ?? "", "Para": str] 135 | case .verbatim(let str): 136 | return ["kind": "", "Verbatim": str] 137 | } 138 | } 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Language.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Language.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-03. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /// Language Enum. 10 | public enum Language { 11 | /// Swift. 12 | case swift 13 | /// Objective-C. 14 | case objc 15 | } 16 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/LinuxCompatibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinuxCompatibility.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 8/19/16. 6 | // Copyright © 2016 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if !os(Linux) && !swift(>=4.0) 12 | extension NSTextCheckingResult { 13 | func range(at idx: Int) -> NSRange { 14 | return rangeAt(idx) 15 | } 16 | } 17 | #endif 18 | 19 | extension Array { 20 | public func bridge() -> NSArray { 21 | #if os(Linux) 22 | return NSArray(array: self) 23 | #else 24 | return self as NSArray 25 | #endif 26 | } 27 | } 28 | 29 | extension CharacterSet { 30 | public func bridge() -> NSCharacterSet { 31 | #if os(Linux) 32 | return _bridgeToObjectiveC() 33 | #else 34 | return self as NSCharacterSet 35 | #endif 36 | } 37 | } 38 | 39 | extension Dictionary { 40 | public func bridge() -> NSDictionary { 41 | #if os(Linux) 42 | return NSDictionary(dictionary: self) 43 | #else 44 | return self as NSDictionary 45 | #endif 46 | } 47 | } 48 | 49 | extension NSString { 50 | public func bridge() -> String { 51 | #if os(Linux) 52 | return _bridgeToSwift() 53 | #else 54 | return self as String 55 | #endif 56 | } 57 | } 58 | 59 | extension String { 60 | public func bridge() -> NSString { 61 | #if os(Linux) 62 | return NSString(string: self) 63 | #else 64 | return self as NSString 65 | #endif 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Module.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-07. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Yams 11 | 12 | /// Represents source module to be documented. 13 | public struct Module { 14 | /// Module Name. 15 | public let name: String 16 | /// Compiler arguments required by SourceKit to process the source files in this Module. 17 | public let compilerArguments: [String] 18 | /// Source files to be documented in this Module. 19 | public let sourceFiles: [String] 20 | 21 | /// Documentation for this Module. Typically expensive computed property. 22 | public var docs: [SwiftDocs] { 23 | var fileIndex = 1 24 | let sourceFilesCount = sourceFiles.count 25 | return sourceFiles.flatMap { 26 | let filename = $0.bridge().lastPathComponent 27 | if let file = File(path: $0) { 28 | fputs("Parsing \(filename) (\(fileIndex)/\(sourceFilesCount))\n", stderr) 29 | fileIndex += 1 30 | return SwiftDocs(file: file, arguments: compilerArguments) 31 | } 32 | fputs("Could not parse `\(filename)`. Please open an issue at https://github.com/jpsim/SourceKitten/issues with the file contents.\n", stderr) 33 | return nil 34 | } 35 | } 36 | 37 | public init?(spmName: String) { 38 | let yamlPath = ".build/debug.yaml" 39 | guard let yaml = try? Yams.compose(yaml: String(contentsOfFile: yamlPath, encoding: .utf8)), 40 | let commands = yaml?["commands"]?.mapping?.values else { 41 | fatalError("SPM build manifest does not exist at `\(yamlPath)` or does not match expected format.") 42 | } 43 | guard let moduleCommand = commands.first(where: { $0["module-name"]?.string == spmName }) else { 44 | fputs("Could not find SPM module '\(spmName)'. Here are the modules available:\n", stderr) 45 | let availableModules = commands.flatMap({ $0["module-name"]?.string }) 46 | fputs("\(availableModules.map({ " - " + $0 }).joined(separator: "\n"))\n", stderr) 47 | return nil 48 | } 49 | guard let imports = moduleCommand["import-paths"]?.array(of: String.self), 50 | let otherArguments = moduleCommand["other-args"]?.array(of: String.self), 51 | let sources = moduleCommand["sources"]?.array(of: String.self) else { 52 | fatalError("SPM build manifest does not match expected format.") 53 | } 54 | name = spmName 55 | compilerArguments = { 56 | var arguments = sources 57 | arguments.append(contentsOf: ["-module-name", spmName]) 58 | arguments.append(contentsOf: otherArguments) 59 | arguments.append(contentsOf: ["-I"]) 60 | arguments.append(contentsOf: imports) 61 | return arguments 62 | }() 63 | sourceFiles = sources 64 | } 65 | 66 | /** 67 | Failable initializer to create a Module by the arguments necessary pass in to `xcodebuild` to build it. 68 | Optionally pass in a `moduleName` and `path`. 69 | 70 | - parameter xcodeBuildArguments: The arguments necessary pass in to `xcodebuild` to build this Module. 71 | - parameter name: Module name. Will be parsed from `xcodebuild` output if nil. 72 | - parameter path: Path to run `xcodebuild` from. Uses current path by default. 73 | */ 74 | public init?(xcodeBuildArguments: [String], name: String? = nil, inPath path: String = FileManager.default.currentDirectoryPath) { 75 | let xcodeBuildOutput = runXcodeBuild(arguments: xcodeBuildArguments, inPath: path) ?? "" 76 | guard let arguments = parseCompilerArguments(xcodebuildOutput: xcodeBuildOutput.bridge(), language: .swift, 77 | moduleName: name ?? moduleName(fromArguments: xcodeBuildArguments)) else { 78 | fputs("Could not parse compiler arguments from `xcodebuild` output.\n", stderr) 79 | fputs("Please confirm that `xcodebuild` is building a Swift module.\n", stderr) 80 | let file = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("xcodebuild-\(NSUUID().uuidString).log") 81 | try! xcodeBuildOutput.data(using: .utf8)?.write(to: file) 82 | fputs("Saved `xcodebuild` log file: \(file.path)\n", stderr) 83 | return nil 84 | } 85 | guard let moduleName = moduleName(fromArguments: arguments) else { 86 | fputs("Could not parse module name from compiler arguments.\n", stderr) 87 | return nil 88 | } 89 | self.init(name: moduleName, compilerArguments: arguments) 90 | } 91 | 92 | /** 93 | Initializer to create a Module by name and compiler arguments. 94 | 95 | - parameter name: Module name. 96 | - parameter compilerArguments: Compiler arguments required by SourceKit to process the source files in this Module. 97 | */ 98 | public init(name: String, compilerArguments: [String]) { 99 | self.name = name 100 | self.compilerArguments = compilerArguments 101 | sourceFiles = compilerArguments.filter({ 102 | $0.bridge().isSwiftFile() && $0.isFile 103 | }).map { 104 | return URL(fileURLWithPath: $0).resolvingSymlinksInPath().path 105 | } 106 | } 107 | } 108 | 109 | // MARK: CustomStringConvertible 110 | 111 | extension Module: CustomStringConvertible { 112 | /// A textual representation of `Module`. 113 | public var description: String { 114 | return "Module(name: \(name), compilerArguments: \(compilerArguments), sourceFiles: \(sourceFiles))" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/ObjCDeclarationKind.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObjCDeclarationKind.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 7/15/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | #if !os(Linux) 10 | 11 | #if SWIFT_PACKAGE 12 | import Clang_C 13 | #endif 14 | 15 | /** 16 | Objective-C declaration kinds. 17 | More or less equivalent to `SwiftDeclarationKind`, but with made up values because there's no such 18 | thing as SourceKit for Objective-C. 19 | */ 20 | public enum ObjCDeclarationKind: String { 21 | /// `category`. 22 | case category = "sourcekitten.source.lang.objc.decl.category" 23 | /// `class`. 24 | case `class` = "sourcekitten.source.lang.objc.decl.class" 25 | /// `constant`. 26 | case constant = "sourcekitten.source.lang.objc.decl.constant" 27 | /// `enum`. 28 | case `enum` = "sourcekitten.source.lang.objc.decl.enum" 29 | /// `enumcase`. 30 | case enumcase = "sourcekitten.source.lang.objc.decl.enumcase" 31 | /// `initializer`. 32 | case initializer = "sourcekitten.source.lang.objc.decl.initializer" 33 | /// `method.class`. 34 | case methodClass = "sourcekitten.source.lang.objc.decl.method.class" 35 | /// `method.instance`. 36 | case methodInstance = "sourcekitten.source.lang.objc.decl.method.instance" 37 | /// `property`. 38 | case property = "sourcekitten.source.lang.objc.decl.property" 39 | /// `protocol`. 40 | case `protocol` = "sourcekitten.source.lang.objc.decl.protocol" 41 | /// `typedef`. 42 | case typedef = "sourcekitten.source.lang.objc.decl.typedef" 43 | /// `function`. 44 | case function = "sourcekitten.source.lang.objc.decl.function" 45 | /// `mark`. 46 | case mark = "sourcekitten.source.lang.objc.mark" 47 | /// `struct` 48 | case `struct` = "sourcekitten.source.lang.objc.decl.struct" 49 | /// `field` 50 | case field = "sourcekitten.source.lang.objc.decl.field" 51 | /// `ivar` 52 | case ivar = "sourcekitten.source.lang.objc.decl.ivar" 53 | /// `ModuleImport` 54 | case moduleImport = "sourcekitten.source.lang.objc.module.import" 55 | /// `UnexposedDecl` 56 | case unexposedDecl = "sourcekitten.source.lang.objc.decl.unexposed" 57 | 58 | // swiftlint:disable:next cyclomatic_complexity 59 | public init(_ cursorKind: CXCursorKind) { 60 | switch cursorKind { 61 | case CXCursor_ObjCCategoryDecl: self = .category 62 | case CXCursor_ObjCInterfaceDecl: self = .class 63 | case CXCursor_EnumDecl: self = .enum 64 | case CXCursor_EnumConstantDecl: self = .enumcase 65 | case CXCursor_ObjCClassMethodDecl: self = .methodClass 66 | case CXCursor_ObjCInstanceMethodDecl: self = .methodInstance 67 | case CXCursor_ObjCPropertyDecl: self = .property 68 | case CXCursor_ObjCProtocolDecl: self = .protocol 69 | case CXCursor_TypedefDecl: self = .typedef 70 | case CXCursor_VarDecl: self = .constant 71 | case CXCursor_FunctionDecl: self = .function 72 | case CXCursor_StructDecl: self = .struct 73 | case CXCursor_FieldDecl: self = .field 74 | case CXCursor_ObjCIvarDecl: self = .ivar 75 | case CXCursor_ModuleImportDecl: self = .moduleImport 76 | case CXCursor_UnexposedDecl: self = .unexposedDecl 77 | default: fatalError("Unsupported CXCursorKind: \(clang_getCursorKindSpelling(cursorKind))") 78 | } 79 | } 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/OffsetMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OffsetMap.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-05. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /// Type that maps potentially documented declaration offsets to its closest parent offset. 10 | public typealias OffsetMap = [Int: Int] 11 | 12 | /// File methods to generate and manipulate OffsetMap's. 13 | extension File { 14 | /** 15 | Creates an OffsetMap containing offset locations at which there are declarations that likely 16 | have documentation comments, but haven't been documented by SourceKitten yet. 17 | 18 | - parameter documentedTokenOffsets: Offsets where there are declarations that likely 19 | have documentation comments. 20 | - parameter dictionary: Docs dictionary to check for which offsets are already 21 | documented. 22 | 23 | - returns: OffsetMap containing offset locations at which there are declarations that likely 24 | have documentation comments, but haven't been documented by SourceKitten yet. 25 | */ 26 | public func makeOffsetMap(documentedTokenOffsets: [Int], dictionary: [String: SourceKitRepresentable]) -> OffsetMap { 27 | var offsetMap = OffsetMap() 28 | for offset in documentedTokenOffsets { 29 | offsetMap[offset] = 0 30 | } 31 | offsetMap = mapOffsets(dictionary, offsetMap: offsetMap) 32 | let alreadyDocumentedOffsets = offsetMap.filter({ $0.0 == $0.1 }).map { $0.0 } 33 | for alreadyDocumentedOffset in alreadyDocumentedOffsets { 34 | offsetMap.removeValue(forKey: alreadyDocumentedOffset) 35 | } 36 | return offsetMap 37 | } 38 | 39 | /** 40 | Creates a new OffsetMap that matches all offsets in the offsetMap parameter's keys to its 41 | nearest, currently documented parent offset. 42 | 43 | - parameter dictionary: Already documented dictionary. 44 | - parameter offsetMap: Dictionary mapping potentially documented offsets to its nearest parent 45 | offset. 46 | 47 | - returns: OffsetMap of potentially documented declaration offsets to its nearest parent offset. 48 | */ 49 | private func mapOffsets(_ dictionary: [String: SourceKitRepresentable], offsetMap: OffsetMap) -> OffsetMap { 50 | var offsetMap = offsetMap 51 | if let rangeStart = SwiftDocKey.getNameOffset(dictionary), 52 | let rangeLength = SwiftDocKey.getNameLength(dictionary) { 53 | let bodyLength = SwiftDocKey.getBodyLength(dictionary) ?? 0 54 | let rangeMax = Int(rangeStart + rangeLength + bodyLength) 55 | let rangeStart = Int(rangeStart) 56 | let offsetsInRange = offsetMap.keys.filter { 57 | $0 >= rangeStart && $0 <= rangeMax 58 | } 59 | for offset in offsetsInRange { 60 | offsetMap[offset] = rangeStart 61 | } 62 | } 63 | // Recurse! 64 | if let substructure = SwiftDocKey.getSubstructure(dictionary) { 65 | for subDict in substructure { 66 | offsetMap = mapOffsets(subDict as! [String: SourceKitRepresentable], offsetMap: offsetMap) 67 | } 68 | } 69 | return offsetMap 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Parameter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Parameter.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 10/27/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | #if !os(Linux) 10 | 11 | #if SWIFT_PACKAGE 12 | import Clang_C 13 | #endif 14 | 15 | public struct Parameter { 16 | public let name: String 17 | public let discussion: [Text] 18 | 19 | init(comment: CXComment) { 20 | name = comment.paramName() ?? "" 21 | discussion = comment.paragraph().paragraphToString() 22 | } 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SourceLocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceLocation.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 10/27/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | #if !os(Linux) 10 | 11 | #if SWIFT_PACKAGE 12 | import Clang_C 13 | #endif 14 | import Foundation 15 | 16 | public struct SourceLocation { 17 | public let file: String 18 | public let line: UInt32 19 | public let column: UInt32 20 | public let offset: UInt32 21 | 22 | public func range(toEnd end: SourceLocation) -> NSRange { 23 | return NSRange(location: Int(offset), length: Int(end.offset - offset)) 24 | } 25 | } 26 | 27 | extension SourceLocation { 28 | init(clangLocation: CXSourceLocation) { 29 | var cxfile: CXFile? = nil 30 | var line: UInt32 = 0 31 | var column: UInt32 = 0 32 | var offset: UInt32 = 0 33 | clang_getSpellingLocation(clangLocation, &cxfile, &line, &column, &offset) 34 | self.init(file: clang_getFileName(cxfile).str() ?? "", 35 | line: line, column: column, offset: offset) 36 | } 37 | } 38 | 39 | // MARK: Comparable 40 | 41 | extension SourceLocation: Comparable {} 42 | 43 | public func == (lhs: SourceLocation, rhs: SourceLocation) -> Bool { 44 | return lhs.file.compare(rhs.file) == .orderedSame && 45 | lhs.line == rhs.line && 46 | lhs.column == rhs.column && 47 | lhs.offset == rhs.offset 48 | } 49 | 50 | /// A [strict total order](http://en.wikipedia.org/wiki/Total_order#Strict_total_order) 51 | /// over instances of `Self`. 52 | public func < (lhs: SourceLocation, rhs: SourceLocation) -> Bool { 53 | // Sort by file path. 54 | switch lhs.file.compare(rhs.file) { 55 | case .orderedDescending: 56 | return false 57 | case .orderedAscending: 58 | return true 59 | case .orderedSame: 60 | break 61 | } 62 | 63 | // Then offset. 64 | return lhs.offset < rhs.offset 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/StatementKind.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftStatementKind.swift 3 | // SourceKitten 4 | // 5 | // Created by Denis Lebedev on 03/02/2016. 6 | // Copyright © 2016 SourceKitten. All rights reserved. 7 | // 8 | 9 | // swiftlint:disable identifier_name 10 | 11 | /// Swift declaration kinds. 12 | /// Found in `strings SourceKitService | grep source.lang.swift.stmt.`. 13 | public enum StatementKind: String, SwiftLangSyntax { 14 | /// `brace`. 15 | case brace = "source.lang.swift.stmt.brace" 16 | /// `case`. 17 | case `case` = "source.lang.swift.stmt.case" 18 | /// `for`. 19 | case `for` = "source.lang.swift.stmt.for" 20 | /// `foreach`. 21 | case forEach = "source.lang.swift.stmt.foreach" 22 | /// `guard`. 23 | case `guard` = "source.lang.swift.stmt.guard" 24 | /// `if`. 25 | case `if` = "source.lang.swift.stmt.if" 26 | /// `repeatewhile`. 27 | case repeatWhile = "source.lang.swift.stmt.repeatwhile" 28 | /// `switch`. 29 | case `switch` = "source.lang.swift.stmt.switch" 30 | /// `while`. 31 | case `while` = "source.lang.swift.stmt.while" 32 | } 33 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Structure.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structure.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-06. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Represents the structural information in a Swift source file. 12 | public struct Structure { 13 | /// Structural information as an [String: SourceKitRepresentable]. 14 | public let dictionary: [String: SourceKitRepresentable] 15 | 16 | /** 17 | Create a Structure from a SourceKit `editor.open` response. 18 | 19 | - parameter sourceKitResponse: SourceKit `editor.open` response. 20 | */ 21 | public init(sourceKitResponse: [String: SourceKitRepresentable]) { 22 | var sourceKitResponse = sourceKitResponse 23 | _ = sourceKitResponse.removeValue(forKey: SwiftDocKey.syntaxMap.rawValue) 24 | dictionary = sourceKitResponse 25 | } 26 | 27 | /** 28 | Initialize a Structure by passing in a File. 29 | 30 | - parameter file: File to parse for structural information. 31 | - throws: Request.Error 32 | */ 33 | public init(file: File) throws { 34 | self.init(sourceKitResponse: try Request.editorOpen(file: file).send()) 35 | } 36 | } 37 | 38 | // MARK: CustomStringConvertible 39 | 40 | extension Structure: CustomStringConvertible { 41 | /// A textual JSON representation of `Structure`. 42 | public var description: String { return toJSON(toNSDictionary(dictionary)) } 43 | } 44 | 45 | // MARK: Equatable 46 | 47 | extension Structure: Equatable {} 48 | 49 | /** 50 | Returns true if `lhs` Structure is equal to `rhs` Structure. 51 | 52 | - parameter lhs: Structure to compare to `rhs`. 53 | - parameter rhs: Structure to compare to `lhs`. 54 | 55 | - returns: True if `lhs` Structure is equal to `rhs` Structure. 56 | */ 57 | public func == (lhs: Structure, rhs: Structure) -> Bool { 58 | return lhs.dictionary.isEqualTo(rhs.dictionary) 59 | } 60 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SwiftDeclarationKind.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDeclarationKind.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-05. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /// Swift declaration kinds. 10 | /// Found in `strings SourceKitService | grep source.lang.swift.decl.`. 11 | public enum SwiftDeclarationKind: String, SwiftLangSyntax { 12 | /// `associatedtype`. 13 | case `associatedtype` = "source.lang.swift.decl.associatedtype" 14 | /// `class`. 15 | case `class` = "source.lang.swift.decl.class" 16 | /// `enum`. 17 | case `enum` = "source.lang.swift.decl.enum" 18 | /// `enumcase`. 19 | case enumcase = "source.lang.swift.decl.enumcase" 20 | /// `enumelement`. 21 | case enumelement = "source.lang.swift.decl.enumelement" 22 | /// `extension`. 23 | case `extension` = "source.lang.swift.decl.extension" 24 | /// `extension.class`. 25 | case extensionClass = "source.lang.swift.decl.extension.class" 26 | /// `extension.enum`. 27 | case extensionEnum = "source.lang.swift.decl.extension.enum" 28 | /// `extension.protocol`. 29 | case extensionProtocol = "source.lang.swift.decl.extension.protocol" 30 | /// `extension.struct`. 31 | case extensionStruct = "source.lang.swift.decl.extension.struct" 32 | /// `function.accessor.address`. 33 | case functionAccessorAddress = "source.lang.swift.decl.function.accessor.address" 34 | /// `function.accessor.didset`. 35 | case functionAccessorDidset = "source.lang.swift.decl.function.accessor.didset" 36 | /// `function.accessor.getter`. 37 | case functionAccessorGetter = "source.lang.swift.decl.function.accessor.getter" 38 | /// `function.accessor.mutableaddress`. 39 | case functionAccessorMutableaddress = "source.lang.swift.decl.function.accessor.mutableaddress" 40 | /// `function.accessor.setter`. 41 | case functionAccessorSetter = "source.lang.swift.decl.function.accessor.setter" 42 | /// `function.accessor.willset`. 43 | case functionAccessorWillset = "source.lang.swift.decl.function.accessor.willset" 44 | /// `function.constructor`. 45 | case functionConstructor = "source.lang.swift.decl.function.constructor" 46 | /// `function.destructor`. 47 | case functionDestructor = "source.lang.swift.decl.function.destructor" 48 | /// `function.free`. 49 | case functionFree = "source.lang.swift.decl.function.free" 50 | /// `function.method.class`. 51 | case functionMethodClass = "source.lang.swift.decl.function.method.class" 52 | /// `function.method.instance`. 53 | case functionMethodInstance = "source.lang.swift.decl.function.method.instance" 54 | /// `function.method.static`. 55 | case functionMethodStatic = "source.lang.swift.decl.function.method.static" 56 | /// `function.operator`. 57 | case functionOperator = "source.lang.swift.decl.function.operator" 58 | /// `function.operator.infix`. 59 | case functionOperatorInfix = "source.lang.swift.decl.function.operator.infix" 60 | /// `function.operator.postfix`. 61 | case functionOperatorPostfix = "source.lang.swift.decl.function.operator.postfix" 62 | /// `function.operator.prefix`. 63 | case functionOperatorPrefix = "source.lang.swift.decl.function.operator.prefix" 64 | /// `function.subscript`. 65 | case functionSubscript = "source.lang.swift.decl.function.subscript" 66 | /// `generic_type_param`. 67 | case genericTypeParam = "source.lang.swift.decl.generic_type_param" 68 | /// `module`. 69 | case module = "source.lang.swift.decl.module" 70 | /// `precedencegroup`. 71 | case precedenceGroup = "source.lang.swift.decl.precedencegroup" 72 | /// `protocol`. 73 | case `protocol` = "source.lang.swift.decl.protocol" 74 | /// `struct`. 75 | case `struct` = "source.lang.swift.decl.struct" 76 | /// `typealias`. 77 | case `typealias` = "source.lang.swift.decl.typealias" 78 | /// `var.class`. 79 | case varClass = "source.lang.swift.decl.var.class" 80 | /// `var.global`. 81 | case varGlobal = "source.lang.swift.decl.var.global" 82 | /// `var.instance`. 83 | case varInstance = "source.lang.swift.decl.var.instance" 84 | /// `var.local`. 85 | case varLocal = "source.lang.swift.decl.var.local" 86 | /// `var.parameter`. 87 | case varParameter = "source.lang.swift.decl.var.parameter" 88 | /// `var.static`. 89 | case varStatic = "source.lang.swift.decl.var.static" 90 | } 91 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SwiftDocs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDocs.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-03. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | #if SWIFT_PACKAGE 11 | import SourceKit 12 | #endif 13 | 14 | /// Represents docs for a Swift file. 15 | public struct SwiftDocs { 16 | /// Documented File. 17 | public let file: File 18 | 19 | /// Docs information as an [String: SourceKitRepresentable]. 20 | public let docsDictionary: [String: SourceKitRepresentable] 21 | 22 | /** 23 | Create docs for the specified Swift file and compiler arguments. 24 | 25 | - parameter file: Swift file to document. 26 | - parameter arguments: compiler arguments to pass to SourceKit. 27 | */ 28 | public init?(file: File, arguments: [String]) { 29 | do { 30 | self.init( 31 | file: file, 32 | dictionary: try Request.editorOpen(file: file).send(), 33 | cursorInfoRequest: Request.cursorInfoRequest(filePath: file.path, arguments: arguments) 34 | ) 35 | } catch let error as Request.Error { 36 | fputs(error.description, stderr) 37 | return nil 38 | } catch { 39 | return nil 40 | } 41 | } 42 | 43 | /** 44 | Create docs for the specified Swift file, editor.open SourceKit response and cursor info request. 45 | 46 | - parameter file: Swift file to document. 47 | - parameter dictionary: editor.open response from SourceKit. 48 | - parameter cursorInfoRequest: SourceKit dictionary to use to send cursorinfo request. 49 | */ 50 | public init(file: File, dictionary: [String: SourceKitRepresentable], cursorInfoRequest: sourcekitd_object_t?) { 51 | self.file = file 52 | var dictionary = dictionary 53 | let syntaxMapData = dictionary.removeValue(forKey: SwiftDocKey.syntaxMap.rawValue) as! [SourceKitRepresentable] 54 | let syntaxMap = SyntaxMap(data: syntaxMapData) 55 | dictionary = file.process(dictionary: dictionary, cursorInfoRequest: cursorInfoRequest, syntaxMap: syntaxMap) 56 | if let cursorInfoRequest = cursorInfoRequest { 57 | let documentedTokenOffsets = file.contents.documentedTokenOffsets(syntaxMap: syntaxMap) 58 | dictionary = file.furtherProcess( 59 | dictionary: dictionary, 60 | documentedTokenOffsets: documentedTokenOffsets, 61 | cursorInfoRequest: cursorInfoRequest, 62 | syntaxMap: syntaxMap 63 | ) 64 | } 65 | docsDictionary = file.addDocComments(dictionary: dictionary, syntaxMap: syntaxMap) 66 | } 67 | } 68 | 69 | // MARK: CustomStringConvertible 70 | 71 | extension SwiftDocs: CustomStringConvertible { 72 | /// A textual JSON representation of `SwiftDocs`. 73 | public var description: String { 74 | return toJSON(toNSDictionary([file.path ?? "": docsDictionary])) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SwiftLangSyntax.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol SwiftLangSyntax { 4 | var rawValue: String { get } 5 | } 6 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SyntaxKind.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SyntaxKind.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-03. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /// Syntax kind values. 10 | /// Found in `strings SourceKitService | grep source.lang.swift.syntaxtype.`. 11 | public enum SyntaxKind: String, SwiftLangSyntax { 12 | /// `argument`. 13 | case argument = "source.lang.swift.syntaxtype.argument" 14 | /// `attribute.builtin`. 15 | case attributeBuiltin = "source.lang.swift.syntaxtype.attribute.builtin" 16 | /// `attribute.id`. 17 | case attributeID = "source.lang.swift.syntaxtype.attribute.id" 18 | /// `buildconfig.id`. 19 | case buildconfigID = "source.lang.swift.syntaxtype.buildconfig.id" 20 | /// `buildconfig.keyword`. 21 | case buildconfigKeyword = "source.lang.swift.syntaxtype.buildconfig.keyword" 22 | /// `comment`. 23 | case comment = "source.lang.swift.syntaxtype.comment" 24 | /// `comment.mark`. 25 | case commentMark = "source.lang.swift.syntaxtype.comment.mark" 26 | /// `comment.url`. 27 | case commentURL = "source.lang.swift.syntaxtype.comment.url" 28 | /// `doccomment`. 29 | case docComment = "source.lang.swift.syntaxtype.doccomment" 30 | /// `doccomment.field`. 31 | case docCommentField = "source.lang.swift.syntaxtype.doccomment.field" 32 | /// `identifier`. 33 | case identifier = "source.lang.swift.syntaxtype.identifier" 34 | /// `keyword`. 35 | case keyword = "source.lang.swift.syntaxtype.keyword" 36 | /// `number`. 37 | case number = "source.lang.swift.syntaxtype.number" 38 | /// `objectliteral` 39 | case objectLiteral = "source.lang.swift.syntaxtype.objectliteral" 40 | /// `parameter`. 41 | case parameter = "source.lang.swift.syntaxtype.parameter" 42 | /// `placeholder`. 43 | case placeholder = "source.lang.swift.syntaxtype.placeholder" 44 | /// `string`. 45 | case string = "source.lang.swift.syntaxtype.string" 46 | /// `string_interpolation_anchor`. 47 | case stringInterpolationAnchor = "source.lang.swift.syntaxtype.string_interpolation_anchor" 48 | /// `typeidentifier`. 49 | case typeidentifier = "source.lang.swift.syntaxtype.typeidentifier" 50 | 51 | /// Returns the valid documentation comment syntax kinds. 52 | internal static func docComments() -> [SyntaxKind] { 53 | return [.commentURL, .docComment, .docCommentField] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SyntaxMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SyntaxMap.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-03. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Represents a Swift file's syntax information. 12 | public struct SyntaxMap { 13 | /// Array of SyntaxToken's. 14 | public let tokens: [SyntaxToken] 15 | 16 | /** 17 | Create a SyntaxMap by passing in tokens directly. 18 | 19 | - parameter tokens: Array of SyntaxToken's. 20 | */ 21 | public init(tokens: [SyntaxToken]) { 22 | self.tokens = tokens 23 | } 24 | 25 | /** 26 | Create a SyntaxMap by passing in NSData from a SourceKit `editor.open` response to be parsed. 27 | 28 | - parameter data: NSData from a SourceKit `editor.open` response 29 | */ 30 | public init(data: [SourceKitRepresentable]) { 31 | tokens = data.map { item in 32 | let dict = item as! [String: SourceKitRepresentable] 33 | return SyntaxToken(type: dict["key.kind"] as! String, offset: Int(dict["key.offset"] as! Int64), length: Int(dict["key.length"] as! Int64)) 34 | } 35 | } 36 | 37 | /** 38 | Create a SyntaxMap from a SourceKit `editor.open` response. 39 | 40 | - parameter sourceKitResponse: SourceKit `editor.open` response. 41 | */ 42 | public init(sourceKitResponse: [String: SourceKitRepresentable]) { 43 | self.init(data: SwiftDocKey.getSyntaxMap(sourceKitResponse)!) 44 | } 45 | 46 | /** 47 | Create a SyntaxMap from a File to be parsed. 48 | 49 | - parameter file: File to be parsed. 50 | - throws: Request.Error 51 | */ 52 | public init(file: File) throws { 53 | self.init(sourceKitResponse: try Request.editorOpen(file: file).send()) 54 | } 55 | } 56 | 57 | // MARK: Support for enumerating doc-comment blocks 58 | 59 | extension SyntaxToken { 60 | /// Is this a doc comment? 61 | internal var isDocComment: Bool { 62 | return SyntaxKind.docComments().contains { $0.rawValue == type } 63 | } 64 | } 65 | 66 | extension SyntaxMap { 67 | /// The ranges of documentation comments described by the map, in the order 68 | /// that they occur in the file. 69 | internal var docCommentRanges: [Range] { 70 | let docCommentBlocks = tokens.split { !$0.isDocComment } 71 | return docCommentBlocks.flatMap { ranges in 72 | ranges.first.flatMap { first in 73 | ranges.last.flatMap { last -> Range? in 74 | first.offset..] 89 | /// The most recent file offset requested 90 | private var previousOffset: Int 91 | 92 | /// Create a new doc comment finder from a `SyntaxMap`. 93 | internal init(syntaxMap: SyntaxMap) { 94 | self.ranges = syntaxMap.docCommentRanges 95 | self.previousOffset = -1 96 | } 97 | 98 | /// Get the byte range of the declaration's doc comment, or nil if none. 99 | internal func getRangeForDeclaration(atOffset offset: Int) -> Range? { 100 | guard offset > previousOffset else { return nil } 101 | 102 | let commentsBeforeDecl = ranges.prefix { $0.upperBound < offset } 103 | ranges.replaceSubrange(0.. DocCommentFinder { 111 | return DocCommentFinder(syntaxMap: self) 112 | } 113 | } 114 | 115 | // MARK: CustomStringConvertible 116 | 117 | extension SyntaxMap: CustomStringConvertible { 118 | /// A textual JSON representation of `SyntaxMap`. 119 | public var description: String { 120 | return toJSON(tokens.map { $0.dictionaryValue }) 121 | } 122 | } 123 | 124 | // MARK: Equatable 125 | 126 | extension SyntaxMap: Equatable {} 127 | 128 | /** 129 | Returns true if `lhs` SyntaxMap is equal to `rhs` SyntaxMap. 130 | 131 | - parameter lhs: SyntaxMap to compare to `rhs`. 132 | - parameter rhs: SyntaxMap to compare to `lhs`. 133 | 134 | - returns: True if `lhs` SyntaxMap is equal to `rhs` SyntaxMap. 135 | */ 136 | public func == (lhs: SyntaxMap, rhs: SyntaxMap) -> Bool { 137 | if lhs.tokens.count != rhs.tokens.count { 138 | return false 139 | } 140 | for (index, value) in lhs.tokens.enumerated() where rhs.tokens[index] != value { 141 | return false 142 | } 143 | return true 144 | } 145 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/SyntaxToken.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SyntaxToken.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2015-01-03. 6 | // Copyright (c) 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | /// Represents a single Swift syntax token. 10 | public struct SyntaxToken { 11 | /// Token type. See SyntaxKind. 12 | public let type: String 13 | /// Token offset. 14 | public let offset: Int 15 | /// Token length. 16 | public let length: Int 17 | 18 | /// Dictionary representation of SyntaxToken. Useful for NSJSONSerialization. 19 | public var dictionaryValue: [String: Any] { 20 | return ["type": type, "offset": offset, "length": length] 21 | } 22 | 23 | /** 24 | Create a SyntaxToken by directly passing in its property values. 25 | 26 | - parameter type: Token type. See SyntaxKind. 27 | - parameter offset: Token offset. 28 | - parameter length: Token length. 29 | */ 30 | public init(type: String, offset: Int, length: Int) { 31 | self.type = SyntaxKind(rawValue: type)?.rawValue ?? type 32 | self.offset = offset 33 | self.length = length 34 | } 35 | } 36 | 37 | // MARK: Equatable 38 | 39 | extension SyntaxToken: Equatable {} 40 | 41 | /** 42 | Returns true if `lhs` SyntaxToken is equal to `rhs` SyntaxToken. 43 | 44 | - parameter lhs: SyntaxToken to compare to `rhs`. 45 | - parameter rhs: SyntaxToken to compare to `lhs`. 46 | 47 | - returns: True if `lhs` SyntaxToken is equal to `rhs` SyntaxToken. 48 | */ 49 | public func == (lhs: SyntaxToken, rhs: SyntaxToken) -> Bool { 50 | return (lhs.type == rhs.type) && (lhs.offset == rhs.offset) && (lhs.length == rhs.length) 51 | } 52 | 53 | // MARK: CustomStringConvertible 54 | 55 | extension SyntaxToken: CustomStringConvertible { 56 | /// A textual JSON representation of `SyntaxToken`. 57 | public var description: String { return toJSON(dictionaryValue.bridge()) } 58 | } 59 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Text.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Text.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 10/27/15. 6 | // Copyright © 2015 SourceKitten. All rights reserved. 7 | // 8 | 9 | public enum Text { 10 | case para(String, String?) 11 | case verbatim(String) 12 | } 13 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/Version.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VersionCommand.swift 3 | // SourceKitten 4 | // 5 | // Created by JP Simard on 2017-05-15. 6 | // Copyright (c) 2017 SourceKitten. All rights reserved. 7 | // 8 | 9 | public struct Version { 10 | public let value: String 11 | 12 | public static let current = Version(value: "0.19.1") 13 | } 14 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/clang-c/CXErrorCode.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/CXErrorCode.h - C Index Error Codes --------------*- C -*-===*\ 2 | |* *| 3 | |* The LLVM Compiler Infrastructure *| 4 | |* *| 5 | |* This file is distributed under the University of Illinois Open Source *| 6 | |* License. See LICENSE.TXT for details. *| 7 | |* *| 8 | |*===----------------------------------------------------------------------===*| 9 | |* *| 10 | |* This header provides the CXErrorCode enumerators. *| 11 | |* *| 12 | \*===----------------------------------------------------------------------===*/ 13 | 14 | #ifndef LLVM_CLANG_C_CXERRORCODE_H 15 | #define LLVM_CLANG_C_CXERRORCODE_H 16 | 17 | #import 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * \brief Error codes returned by libclang routines. 25 | * 26 | * Zero (\c CXError_Success) is the only error code indicating success. Other 27 | * error codes, including not yet assigned non-zero values, indicate errors. 28 | */ 29 | enum CXErrorCode { 30 | /** 31 | * \brief No error. 32 | */ 33 | CXError_Success = 0, 34 | 35 | /** 36 | * \brief A generic error code, no further details are available. 37 | * 38 | * Errors of this kind can get their own specific error codes in future 39 | * libclang versions. 40 | */ 41 | CXError_Failure = 1, 42 | 43 | /** 44 | * \brief libclang crashed while performing the requested operation. 45 | */ 46 | CXError_Crashed = 2, 47 | 48 | /** 49 | * \brief The function detected that the arguments violate the function 50 | * contract. 51 | */ 52 | CXError_InvalidArguments = 3, 53 | 54 | /** 55 | * \brief An AST deserialization error has occurred. 56 | */ 57 | CXError_ASTReadError = 4 58 | }; 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/clang-c/CXString.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/CXString.h - C Index strings --------------------*- C -*-===*\ 2 | |* *| 3 | |* The LLVM Compiler Infrastructure *| 4 | |* *| 5 | |* This file is distributed under the University of Illinois Open Source *| 6 | |* License. See LICENSE.TXT for details. *| 7 | |* *| 8 | |*===----------------------------------------------------------------------===*| 9 | |* *| 10 | |* This header provides the interface to C Index strings. *| 11 | |* *| 12 | \*===----------------------------------------------------------------------===*/ 13 | 14 | #ifndef LLVM_CLANG_C_CXSTRING_H 15 | #define LLVM_CLANG_C_CXSTRING_H 16 | 17 | #import 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * \defgroup CINDEX_STRING String manipulation routines 25 | * \ingroup CINDEX 26 | * 27 | * @{ 28 | */ 29 | 30 | /** 31 | * \brief A character string. 32 | * 33 | * The \c CXString type is used to return strings from the interface when 34 | * the ownership of that string might differ from one call to the next. 35 | * Use \c clang_getCString() to retrieve the string data and, once finished 36 | * with the string data, call \c clang_disposeString() to free the string. 37 | */ 38 | typedef struct { 39 | const void *data; 40 | unsigned private_flags; 41 | } CXString; 42 | 43 | /** 44 | * \brief Retrieve the character data associated with the given string. 45 | */ 46 | CINDEX_LINKAGE const char *clang_getCString(CXString string); 47 | 48 | /** 49 | * \brief Free the given string. 50 | */ 51 | CINDEX_LINKAGE void clang_disposeString(CXString string); 52 | 53 | /** 54 | * @} 55 | */ 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/clang-c/Platform.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/Platform.h - C Index platform decls -------------*- C -*-===*\ 2 | |* *| 3 | |* The LLVM Compiler Infrastructure *| 4 | |* *| 5 | |* This file is distributed under the University of Illinois Open Source *| 6 | |* License. See LICENSE.TXT for details. *| 7 | |* *| 8 | |*===----------------------------------------------------------------------===*| 9 | |* *| 10 | |* This header provides platform specific macros (dllimport, deprecated, ...) *| 11 | |* *| 12 | \*===----------------------------------------------------------------------===*/ 13 | 14 | #ifndef LLVM_CLANG_C_PLATFORM_H 15 | #define LLVM_CLANG_C_PLATFORM_H 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /* MSVC DLL import/export. */ 22 | #ifdef _MSC_VER 23 | #ifdef _CINDEX_LIB_ 24 | #define CINDEX_LINKAGE __declspec(dllexport) 25 | #else 26 | #define CINDEX_LINKAGE __declspec(dllimport) 27 | #endif 28 | #else 29 | #define CINDEX_LINKAGE 30 | #endif 31 | 32 | #ifdef __GNUC__ 33 | #define CINDEX_DEPRECATED __attribute__((deprecated)) 34 | #else 35 | #ifdef _MSC_VER 36 | #define CINDEX_DEPRECATED __declspec(deprecated) 37 | #else 38 | #define CINDEX_DEPRECATED 39 | #endif 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/library_wrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // library_wrapper.swift 3 | // sourcekitten 4 | // 5 | // Created by Norio Nomura on 2/20/16. 6 | // Copyright © 2016 SourceKitten. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct DynamicLinkLibrary { 12 | let path: String 13 | let handle: UnsafeMutableRawPointer 14 | 15 | func load(symbol: String) -> T { 16 | if let sym = dlsym(handle, symbol) { 17 | return unsafeBitCast(sym, to: T.self) 18 | } 19 | let errorString = String(validatingUTF8: dlerror()) 20 | fatalError("Finding symbol \(symbol) failed: \(errorString ?? "unknown error")") 21 | } 22 | } 23 | 24 | #if os(Linux) 25 | let toolchainLoader = Loader(searchPaths: [linuxSourceKitLibPath]) 26 | #else 27 | let toolchainLoader = Loader(searchPaths: [ 28 | xcodeDefaultToolchainOverride, 29 | toolchainDir, 30 | xcrunFindPath, 31 | /* 32 | These search paths are used when `xcode-select -p` points to 33 | "Command Line Tools OS X for Xcode", but Xcode.app exists. 34 | */ 35 | applicationsDir?.xcodeDeveloperDir.toolchainDir, 36 | applicationsDir?.xcodeBetaDeveloperDir.toolchainDir, 37 | userApplicationsDir?.xcodeDeveloperDir.toolchainDir, 38 | userApplicationsDir?.xcodeBetaDeveloperDir.toolchainDir 39 | ].flatMap { path in 40 | if let fullPath = path?.usrLibDir, fullPath.isFile { 41 | return fullPath 42 | } 43 | return nil 44 | }) 45 | #endif 46 | 47 | struct Loader { 48 | let searchPaths: [String] 49 | 50 | func load(path: String) -> DynamicLinkLibrary { 51 | let fullPaths = searchPaths.map { $0.appending(pathComponent: path) }.filter { $0.isFile } 52 | 53 | // try all fullPaths that contains target file, 54 | // then try loading with simple path that depends resolving to DYLD 55 | for fullPath in fullPaths + [path] { 56 | if let handle = dlopen(fullPath, RTLD_LAZY) { 57 | return DynamicLinkLibrary(path: path, handle: handle) 58 | } 59 | } 60 | 61 | fatalError("Loading \(path) failed") 62 | } 63 | } 64 | 65 | private func env(_ name: String) -> String? { 66 | return ProcessInfo.processInfo.environment[name] 67 | } 68 | 69 | /// Returns "LINUX_SOURCEKIT_LIB_PATH" environment variable, 70 | /// or "/usr/lib" if unspecified. 71 | internal let linuxSourceKitLibPath = env("LINUX_SOURCEKIT_LIB_PATH") ?? "/usr/lib" 72 | 73 | /// Returns "XCODE_DEFAULT_TOOLCHAIN_OVERRIDE" environment variable 74 | /// 75 | /// `launch-with-toolchain` sets the toolchain path to the 76 | /// "XCODE_DEFAULT_TOOLCHAIN_OVERRIDE" environment variable. 77 | private let xcodeDefaultToolchainOverride = env("XCODE_DEFAULT_TOOLCHAIN_OVERRIDE") 78 | 79 | /// Returns "TOOLCHAIN_DIR" environment variable 80 | /// 81 | /// `Xcode`/`xcodebuild` sets the toolchain path to the 82 | /// "TOOLCHAIN_DIR" environment variable. 83 | private let toolchainDir = env("TOOLCHAIN_DIR") 84 | 85 | /// Returns toolchain directory that parsed from result of `xcrun -find swift` 86 | /// 87 | /// This is affected by "DEVELOPER_DIR", "TOOLCHAINS" environment variables. 88 | private let xcrunFindPath: String? = { 89 | let pathOfXcrun = "/usr/bin/xcrun" 90 | 91 | if !FileManager.default.isExecutableFile(atPath: pathOfXcrun) { 92 | return nil 93 | } 94 | 95 | let task = Process() 96 | task.launchPath = pathOfXcrun 97 | task.arguments = ["-find", "swift"] 98 | 99 | let pipe = Pipe() 100 | task.standardOutput = pipe 101 | task.launch() // if xcode-select does not exist, crash with `NSInvalidArgumentException`. 102 | 103 | let data = pipe.fileHandleForReading.readDataToEndOfFile() 104 | guard let output = String(data: data, encoding: .utf8) else { 105 | return nil 106 | } 107 | 108 | var start = output.startIndex 109 | var end = output.startIndex 110 | var contentsEnd = output.startIndex 111 | output.getLineStart(&start, end: &end, contentsEnd: &contentsEnd, for: start..=4.0) 113 | let xcrunFindSwiftPath = String(output[start.. String { 153 | return URL(fileURLWithPath: self).appendingPathComponent(pathComponent).path 154 | } 155 | 156 | func deleting(lastPathComponents numberOfPathComponents: Int) -> String { 157 | var url = URL(fileURLWithPath: self) 158 | for _ in 0.. (UnsafePointer?) = library.load(symbol: "clang_getCString") 7 | internal let clang_disposeString: @convention(c) (CXString) -> () = library.load(symbol: "clang_disposeString") 8 | #endif 9 | -------------------------------------------------------------------------------- /Pods/SourceKittenFramework/Source/SourceKittenFramework/library_wrapper_Documentation.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | #if SWIFT_PACKAGE 3 | import Clang_C 4 | #endif 5 | private let library = toolchainLoader.load(path: "libclang.dylib") 6 | internal let clang_Cursor_getParsedComment: @convention(c) (CXCursor) -> (CXComment) = library.load(symbol: "clang_Cursor_getParsedComment") 7 | internal let clang_Comment_getKind: @convention(c) (CXComment) -> (CXCommentKind) = library.load(symbol: "clang_Comment_getKind") 8 | internal let clang_Comment_getNumChildren: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_Comment_getNumChildren") 9 | internal let clang_Comment_getChild: @convention(c) (CXComment, UInt32) -> (CXComment) = library.load(symbol: "clang_Comment_getChild") 10 | internal let clang_Comment_isWhitespace: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_Comment_isWhitespace") 11 | internal let clang_InlineContentComment_hasTrailingNewline: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_InlineContentComment_hasTrailingNewline") 12 | internal let clang_TextComment_getText: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_TextComment_getText") 13 | internal let clang_InlineCommandComment_getCommandName: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_InlineCommandComment_getCommandName") 14 | internal let clang_InlineCommandComment_getRenderKind: @convention(c) (CXComment) -> (CXCommentInlineCommandRenderKind) = library.load(symbol: "clang_InlineCommandComment_getRenderKind") 15 | internal let clang_InlineCommandComment_getNumArgs: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_InlineCommandComment_getNumArgs") 16 | internal let clang_InlineCommandComment_getArgText: @convention(c) (CXComment, UInt32) -> (CXString) = library.load(symbol: "clang_InlineCommandComment_getArgText") 17 | internal let clang_HTMLTagComment_getTagName: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_HTMLTagComment_getTagName") 18 | internal let clang_HTMLStartTagComment_isSelfClosing: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_HTMLStartTagComment_isSelfClosing") 19 | internal let clang_HTMLStartTag_getNumAttrs: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_HTMLStartTag_getNumAttrs") 20 | internal let clang_HTMLStartTag_getAttrName: @convention(c) (CXComment, UInt32) -> (CXString) = library.load(symbol: "clang_HTMLStartTag_getAttrName") 21 | internal let clang_HTMLStartTag_getAttrValue: @convention(c) (CXComment, UInt32) -> (CXString) = library.load(symbol: "clang_HTMLStartTag_getAttrValue") 22 | internal let clang_BlockCommandComment_getCommandName: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_BlockCommandComment_getCommandName") 23 | internal let clang_BlockCommandComment_getNumArgs: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_BlockCommandComment_getNumArgs") 24 | internal let clang_BlockCommandComment_getArgText: @convention(c) (CXComment, UInt32) -> (CXString) = library.load(symbol: "clang_BlockCommandComment_getArgText") 25 | internal let clang_BlockCommandComment_getParagraph: @convention(c) (CXComment) -> (CXComment) = library.load(symbol: "clang_BlockCommandComment_getParagraph") 26 | internal let clang_ParamCommandComment_getParamName: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_ParamCommandComment_getParamName") 27 | internal let clang_ParamCommandComment_isParamIndexValid: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_ParamCommandComment_isParamIndexValid") 28 | internal let clang_ParamCommandComment_getParamIndex: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_ParamCommandComment_getParamIndex") 29 | internal let clang_ParamCommandComment_isDirectionExplicit: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_ParamCommandComment_isDirectionExplicit") 30 | internal let clang_ParamCommandComment_getDirection: @convention(c) (CXComment) -> (CXCommentParamPassDirection) = library.load(symbol: "clang_ParamCommandComment_getDirection") 31 | internal let clang_TParamCommandComment_getParamName: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_TParamCommandComment_getParamName") 32 | internal let clang_TParamCommandComment_isParamPositionValid: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_TParamCommandComment_isParamPositionValid") 33 | internal let clang_TParamCommandComment_getDepth: @convention(c) (CXComment) -> (UInt32) = library.load(symbol: "clang_TParamCommandComment_getDepth") 34 | internal let clang_TParamCommandComment_getIndex: @convention(c) (CXComment, UInt32) -> (UInt32) = library.load(symbol: "clang_TParamCommandComment_getIndex") 35 | internal let clang_VerbatimBlockLineComment_getText: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_VerbatimBlockLineComment_getText") 36 | internal let clang_VerbatimLineComment_getText: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_VerbatimLineComment_getText") 37 | internal let clang_HTMLTagComment_getAsString: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_HTMLTagComment_getAsString") 38 | internal let clang_FullComment_getAsHTML: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_FullComment_getAsHTML") 39 | internal let clang_FullComment_getAsXML: @convention(c) (CXComment) -> (CXString) = library.load(symbol: "clang_FullComment_getAsXML") 40 | #endif 41 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## SWXMLHash 5 | 6 | Copyright (c) 2014 David Mohundro 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | 28 | ## SourceKittenFramework 29 | 30 | The MIT License (MIT) 31 | 32 | Copyright (c) 2014 JP Simard. 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all 42 | copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 50 | SOFTWARE. 51 | 52 | 53 | ## SwiftLint 54 | 55 | The MIT License (MIT) 56 | 57 | Copyright (c) 2015 Realm Inc. 58 | 59 | Permission is hereby granted, free of charge, to any person obtaining a copy 60 | of this software and associated documentation files (the "Software"), to deal 61 | in the Software without restriction, including without limitation the rights 62 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 63 | copies of the Software, and to permit persons to whom the Software is 64 | furnished to do so, subject to the following conditions: 65 | 66 | The above copyright notice and this permission notice shall be included in all 67 | copies or substantial portions of the Software. 68 | 69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 75 | SOFTWARE. 76 | 77 | 78 | ## Yams 79 | 80 | The MIT License (MIT) 81 | 82 | Copyright (c) 2016 JP Simard. 83 | 84 | Permission is hereby granted, free of charge, to any person obtaining a copy 85 | of this software and associated documentation files (the "Software"), to deal 86 | in the Software without restriction, including without limitation the rights 87 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 88 | copies of the Software, and to permit persons to whom the Software is 89 | furnished to do so, subject to the following conditions: 90 | 91 | The above copyright notice and this permission notice shall be included in all 92 | copies or substantial portions of the Software. 93 | 94 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 95 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 96 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 97 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 98 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 99 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 100 | SOFTWARE. 101 | 102 | Generated by CocoaPods - https://cocoapods.org 103 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_IBAnalyzer_IBAnalyzerTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_IBAnalyzer_IBAnalyzerTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_IBAnalyzer_IBAnalyzerTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_IBAnalyzer_IBAnalyzerTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash" "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework" "${PODS_CONFIGURATION_BUILD_DIR}/Yams" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash/SWXMLHash.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework/SourceKittenFramework.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Yams/Yams.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "SWXMLHash" -framework "SourceKittenFramework" -framework "Yams" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_IBAnalyzer_IBAnalyzerTests { 2 | umbrella header "Pods-IBAnalyzer-IBAnalyzerTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer-IBAnalyzerTests/Pods-IBAnalyzer-IBAnalyzerTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash" "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework" "${PODS_CONFIGURATION_BUILD_DIR}/Yams" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash/SWXMLHash.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework/SourceKittenFramework.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Yams/Yams.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "SWXMLHash" -framework "SourceKittenFramework" -framework "Yams" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## SWXMLHash 5 | 6 | Copyright (c) 2014 David Mohundro 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | 28 | ## SourceKittenFramework 29 | 30 | The MIT License (MIT) 31 | 32 | Copyright (c) 2014 JP Simard. 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all 42 | copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 50 | SOFTWARE. 51 | 52 | 53 | ## SwiftLint 54 | 55 | The MIT License (MIT) 56 | 57 | Copyright (c) 2015 Realm Inc. 58 | 59 | Permission is hereby granted, free of charge, to any person obtaining a copy 60 | of this software and associated documentation files (the "Software"), to deal 61 | in the Software without restriction, including without limitation the rights 62 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 63 | copies of the Software, and to permit persons to whom the Software is 64 | furnished to do so, subject to the following conditions: 65 | 66 | The above copyright notice and this permission notice shall be included in all 67 | copies or substantial portions of the Software. 68 | 69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 75 | SOFTWARE. 76 | 77 | 78 | ## Yams 79 | 80 | The MIT License (MIT) 81 | 82 | Copyright (c) 2016 JP Simard. 83 | 84 | Permission is hereby granted, free of charge, to any person obtaining a copy 85 | of this software and associated documentation files (the "Software"), to deal 86 | in the Software without restriction, including without limitation the rights 87 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 88 | copies of the Software, and to permit persons to whom the Software is 89 | furnished to do so, subject to the following conditions: 90 | 91 | The above copyright notice and this permission notice shall be included in all 92 | copies or substantial portions of the Software. 93 | 94 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 95 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 96 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 97 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 98 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 99 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 100 | SOFTWARE. 101 | 102 | Generated by CocoaPods - https://cocoapods.org 103 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_IBAnalyzer : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_IBAnalyzer 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_IBAnalyzerVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_IBAnalyzerVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash" "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework" "${PODS_CONFIGURATION_BUILD_DIR}/Yams" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash/SWXMLHash.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework/SourceKittenFramework.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Yams/Yams.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "SWXMLHash" -framework "SourceKittenFramework" -framework "Yams" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_IBAnalyzer { 2 | umbrella header "Pods-IBAnalyzer-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IBAnalyzer/Pods-IBAnalyzer.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash" "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework" "${PODS_CONFIGURATION_BUILD_DIR}/Yams" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash/SWXMLHash.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework/SourceKittenFramework.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Yams/Yams.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "SWXMLHash" -framework "SourceKittenFramework" -framework "Yams" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.5.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/SWXMLHash-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SWXMLHash : NSObject 3 | @end 4 | @implementation PodsDummy_SWXMLHash 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/SWXMLHash-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/SWXMLHash-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SWXMLHashVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SWXMLHashVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/SWXMLHash.modulemap: -------------------------------------------------------------------------------- 1 | framework module SWXMLHash { 2 | umbrella header "SWXMLHash-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SWXMLHash/SWXMLHash.xcconfig: -------------------------------------------------------------------------------- 1 | APPLICATION_EXTENSION_API_ONLY = YES 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SWXMLHash 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | SWIFT_VERSION = 3.0 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.19.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/SourceKittenFramework-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SourceKittenFramework : NSObject 3 | @end 4 | @implementation PodsDummy_SourceKittenFramework 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/SourceKittenFramework-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/SourceKittenFramework-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "BuildSystem.h" 14 | #import "CXCompilationDatabase.h" 15 | #import "CXErrorCode.h" 16 | #import "CXString.h" 17 | #import "Documentation.h" 18 | #import "Index.h" 19 | #import "Platform.h" 20 | #import "sourcekitd.h" 21 | 22 | FOUNDATION_EXPORT double SourceKittenFrameworkVersionNumber; 23 | FOUNDATION_EXPORT const unsigned char SourceKittenFrameworkVersionString[]; 24 | 25 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/SourceKittenFramework.modulemap: -------------------------------------------------------------------------------- 1 | framework module SourceKittenFramework { 2 | umbrella header "SourceKittenFramework-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SourceKittenFramework/SourceKittenFramework.xcconfig: -------------------------------------------------------------------------------- 1 | APPLICATION_EXTENSION_API_ONLY = YES 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SourceKittenFramework 4 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SWXMLHash" "${PODS_CONFIGURATION_BUILD_DIR}/Yams" 5 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 6 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SourceKittenFramework 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.5.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Yams-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Yams : NSObject 3 | @end 4 | @implementation PodsDummy_Yams 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Yams-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Yams-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "CYaml.h" 14 | #import "yaml.h" 15 | #import "yaml_private.h" 16 | #import "Yams.h" 17 | 18 | FOUNDATION_EXPORT double YamsVersionNumber; 19 | FOUNDATION_EXPORT const unsigned char YamsVersionString[]; 20 | 21 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Yams.modulemap: -------------------------------------------------------------------------------- 1 | framework module Yams { 2 | umbrella header "Yams-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Yams/Yams.xcconfig: -------------------------------------------------------------------------------- 1 | APPLICATION_EXTENSION_API_ONLY = YES 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Yams 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Yams 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Pods/Yams/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 JP Simard. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pods/Yams/README.md: -------------------------------------------------------------------------------- 1 | # Yams 2 | 3 | ![Yams](yams.jpg) 4 | 5 | A sweet and swifty [Yaml](http://yaml.org/) parser built on 6 | [libYAML](http://pyyaml.org/wiki/LibYAML). 7 | 8 | [![CircleCI](https://circleci.com/gh/jpsim/Yams.svg?style=svg)](https://circleci.com/gh/jpsim/Yams) 9 | 10 | ## Installation 11 | 12 | Building Yams on macOS requires Xcode 9.x or a Swift 3.2/4.x toolchain with 13 | the Swift Package Manager. 14 | 15 | Building Yams on Linux requires a Swift 4.x compiler and Swift Package Manager 16 | to be installed. 17 | 18 | ### Swift Package Manager 19 | 20 | Add `.package(url: "https://github.com/jpsim/Yams.git", from: "0.5.0")` to your 21 | `Package.swift` file's `dependencies`. 22 | 23 | ### CocoaPods 24 | 25 | Add `pod 'Yams'` to your `Podfile`. 26 | 27 | ### Carthage 28 | 29 | Add `github "jpsim/Yams"` to your `Cartfile`. 30 | 31 | ## License 32 | 33 | Both Yams and libYAML are MIT licensed. 34 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/CYaml/include/CYaml.h: -------------------------------------------------------------------------------- 1 | #include "yaml.h" 2 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/CYaml/src/writer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "yaml_private.h" 3 | 4 | /* 5 | * Declarations. 6 | */ 7 | 8 | static int 9 | yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); 10 | 11 | YAML_DECLARE(int) 12 | yaml_emitter_flush(yaml_emitter_t *emitter); 13 | 14 | /* 15 | * Set the writer error and return 0. 16 | */ 17 | 18 | static int 19 | yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) 20 | { 21 | emitter->error = YAML_WRITER_ERROR; 22 | emitter->problem = problem; 23 | 24 | return 0; 25 | } 26 | 27 | /* 28 | * Flush the output buffer. 29 | */ 30 | 31 | YAML_DECLARE(int) 32 | yaml_emitter_flush(yaml_emitter_t *emitter) 33 | { 34 | int low, high; 35 | 36 | assert(emitter); /* Non-NULL emitter object is expected. */ 37 | assert(emitter->write_handler); /* Write handler must be set. */ 38 | assert(emitter->encoding); /* Output encoding must be set. */ 39 | 40 | emitter->buffer.last = emitter->buffer.pointer; 41 | emitter->buffer.pointer = emitter->buffer.start; 42 | 43 | /* Check if the buffer is empty. */ 44 | 45 | if (emitter->buffer.start == emitter->buffer.last) { 46 | return 1; 47 | } 48 | 49 | /* If the output encoding is UTF-8, we don't need to recode the buffer. */ 50 | 51 | if (emitter->encoding == YAML_UTF8_ENCODING) 52 | { 53 | if (emitter->write_handler(emitter->write_handler_data, 54 | emitter->buffer.start, 55 | emitter->buffer.last - emitter->buffer.start)) { 56 | emitter->buffer.last = emitter->buffer.start; 57 | emitter->buffer.pointer = emitter->buffer.start; 58 | return 1; 59 | } 60 | else { 61 | return yaml_emitter_set_writer_error(emitter, "write error"); 62 | } 63 | } 64 | 65 | /* Recode the buffer into the raw buffer. */ 66 | 67 | low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); 68 | high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); 69 | 70 | while (emitter->buffer.pointer != emitter->buffer.last) 71 | { 72 | unsigned char octet; 73 | unsigned int width; 74 | unsigned int value; 75 | size_t k; 76 | 77 | /* 78 | * See the "reader.c" code for more details on UTF-8 encoding. Note 79 | * that we assume that the buffer contains a valid UTF-8 sequence. 80 | */ 81 | 82 | /* Read the next UTF-8 character. */ 83 | 84 | octet = emitter->buffer.pointer[0]; 85 | 86 | width = (octet & 0x80) == 0x00 ? 1 : 87 | (octet & 0xE0) == 0xC0 ? 2 : 88 | (octet & 0xF0) == 0xE0 ? 3 : 89 | (octet & 0xF8) == 0xF0 ? 4 : 0; 90 | 91 | value = (octet & 0x80) == 0x00 ? octet & 0x7F : 92 | (octet & 0xE0) == 0xC0 ? octet & 0x1F : 93 | (octet & 0xF0) == 0xE0 ? octet & 0x0F : 94 | (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; 95 | 96 | for (k = 1; k < width; k ++) { 97 | octet = emitter->buffer.pointer[k]; 98 | value = (value << 6) + (octet & 0x3F); 99 | } 100 | 101 | emitter->buffer.pointer += width; 102 | 103 | /* Write the character. */ 104 | 105 | if (value < 0x10000) 106 | { 107 | emitter->raw_buffer.last[high] = value >> 8; 108 | emitter->raw_buffer.last[low] = value & 0xFF; 109 | 110 | emitter->raw_buffer.last += 2; 111 | } 112 | else 113 | { 114 | /* Write the character using a surrogate pair (check "reader.c"). */ 115 | 116 | value -= 0x10000; 117 | emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); 118 | emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; 119 | emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); 120 | emitter->raw_buffer.last[low+2] = value & 0xFF; 121 | 122 | emitter->raw_buffer.last += 4; 123 | } 124 | } 125 | 126 | /* Write the raw buffer. */ 127 | 128 | if (emitter->write_handler(emitter->write_handler_data, 129 | emitter->raw_buffer.start, 130 | emitter->raw_buffer.last - emitter->raw_buffer.start)) { 131 | emitter->buffer.last = emitter->buffer.start; 132 | emitter->buffer.pointer = emitter->buffer.start; 133 | emitter->raw_buffer.last = emitter->raw_buffer.start; 134 | emitter->raw_buffer.pointer = emitter->raw_buffer.start; 135 | return 1; 136 | } 137 | else { 138 | return yaml_emitter_set_writer_error(emitter, "write error"); 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Mark.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mark.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 4/11/17. 6 | // Copyright (c) 2017 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Mark { 12 | /// line start from 1 13 | public let line: Int 14 | /// column start from 1. libYAML counts column by unicodeScalars. 15 | public let column: Int 16 | } 17 | 18 | extension Mark: CustomStringConvertible { 19 | public var description: String { return "\(line):\(column)" } 20 | } 21 | 22 | extension Mark { 23 | public func snippet(from yaml: String) -> String { 24 | let contents = yaml.substring(at: line - 1) 25 | let columnIndex = contents.unicodeScalars 26 | .index(contents.unicodeScalars.startIndex, 27 | offsetBy: column - 1, 28 | limitedBy: contents.unicodeScalars.endIndex)? 29 | .samePosition(in: contents.utf16) ?? contents.utf16.endIndex 30 | let columnInUTF16 = contents.utf16.distance(from: contents.utf16.startIndex, to: columnIndex) 31 | return contents.endingWithNewLine + 32 | String(repeating: " ", count: columnInUTF16) + "^" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Node.Mapping.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node.Mapping.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 2/24/17. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Node { 12 | public struct Mapping { 13 | fileprivate var pairs: [Pair] 14 | public var tag: Tag 15 | public var style: Style 16 | public var mark: Mark? 17 | 18 | public enum Style: UInt32 { // swiftlint:disable:this nesting 19 | /// Let the emitter choose the style. 20 | case any 21 | /// The block mapping style. 22 | case block 23 | /// The flow mapping style. 24 | case flow 25 | } 26 | 27 | public init(_ pairs: [(Node, Node)], _ tag: Tag = .implicit, _ style: Style = .any, _ mark: Mark? = nil) { 28 | self.pairs = pairs.map { Pair($0.0, $0.1) } 29 | self.tag = tag 30 | self.style = style 31 | self.mark = mark 32 | } 33 | } 34 | 35 | public var mapping: Mapping? { 36 | get { 37 | if case let .mapping(mapping) = self { 38 | return mapping 39 | } 40 | return nil 41 | } 42 | set { 43 | if let newValue = newValue { 44 | self = .mapping(newValue) 45 | } 46 | } 47 | } 48 | } 49 | 50 | extension Node.Mapping: Comparable { 51 | public static func < (lhs: Node.Mapping, rhs: Node.Mapping) -> Bool { 52 | return lhs.pairs < rhs.pairs 53 | } 54 | } 55 | 56 | extension Node.Mapping: Equatable { 57 | public static func == (lhs: Node.Mapping, rhs: Node.Mapping) -> Bool { 58 | return lhs.pairs == rhs.pairs && lhs.resolvedTag == rhs.resolvedTag 59 | } 60 | } 61 | 62 | extension Node.Mapping: ExpressibleByDictionaryLiteral { 63 | public init(dictionaryLiteral elements: (Node, Node)...) { 64 | self.init(elements) 65 | } 66 | } 67 | 68 | extension Node.Mapping: MutableCollection { 69 | public typealias Element = (key: Node, value: Node) 70 | 71 | // Sequence 72 | public func makeIterator() -> Array.Iterator { 73 | let iterator = pairs.map(Pair.toTuple).makeIterator() 74 | return iterator 75 | } 76 | 77 | // Collection 78 | public typealias Index = Array.Index 79 | 80 | public var startIndex: Int { 81 | return pairs.startIndex 82 | } 83 | 84 | public var endIndex: Int { 85 | return pairs.endIndex 86 | } 87 | 88 | public func index(after index: Int) -> Int { 89 | return pairs.index(after: index) 90 | } 91 | 92 | public subscript(index: Int) -> Element { 93 | get { 94 | return (key: pairs[index].key, value: pairs[index].value) 95 | } 96 | // MutableCollection 97 | set { 98 | pairs[index] = Pair(newValue.key, newValue.value) 99 | } 100 | } 101 | } 102 | 103 | extension Node.Mapping: TagResolvable { 104 | static let defaultTagName = Tag.Name.map 105 | } 106 | 107 | extension Node.Mapping { 108 | public var keys: LazyMapCollection { 109 | return lazy.map { $0.key } 110 | } 111 | 112 | public var values: LazyMapCollection { 113 | return lazy.map { $0.value } 114 | } 115 | 116 | public subscript(string: String) -> Node? { 117 | get { 118 | return self[Node(string)] 119 | } 120 | set { 121 | self[Node(string)] = newValue 122 | } 123 | } 124 | 125 | public subscript(node: Node) -> Node? { 126 | get { 127 | let v = pairs.reversed().first(where: { $0.key == node }) 128 | return v?.value 129 | } 130 | set { 131 | if let newValue = newValue { 132 | if let index = index(forKey: node) { 133 | pairs[index] = Pair(pairs[index].key, newValue) 134 | } else { 135 | pairs.append(Pair(node, newValue)) 136 | } 137 | } else { 138 | if let index = index(forKey: node) { 139 | pairs.remove(at: index) 140 | } 141 | } 142 | } 143 | } 144 | 145 | public func index(forKey key: Node) -> Int? { 146 | return pairs.reversed().index(where: { $0.key == key }).map({ pairs.index(before: $0.base) }) 147 | } 148 | } 149 | 150 | private struct Pair: Comparable, Equatable { 151 | let key: Value 152 | let value: Value 153 | 154 | init(_ key: Value, _ value: Value) { 155 | self.key = key 156 | self.value = value 157 | } 158 | 159 | static func == (lhs: Pair, rhs: Pair) -> Bool { 160 | return lhs.key == rhs.key && lhs.value == rhs.value 161 | } 162 | 163 | static func < (lhs: Pair, rhs: Pair) -> Bool { 164 | return lhs.key < rhs.key 165 | } 166 | 167 | static func toTuple(pair: Pair) -> (key: Value, value: Value) { 168 | return (key: pair.key, value: pair.value) 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Node.Scalar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node.Scalar.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 2/24/17. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Node { 12 | public struct Scalar { 13 | public var string: String { 14 | didSet { 15 | tag = .implicit 16 | } 17 | } 18 | public var tag: Tag 19 | public var style: Style 20 | public var mark: Mark? 21 | 22 | public enum Style: UInt32 { // swiftlint:disable:this nesting 23 | /// Let the emitter choose the style. 24 | case any = 0 25 | /// The plain scalar style. 26 | case plain 27 | 28 | /// The single-quoted scalar style. 29 | case singleQuoted 30 | /// The double-quoted scalar style. 31 | case doubleQuoted 32 | 33 | /// The literal scalar style. 34 | case literal 35 | /// The folded scalar style. 36 | case folded 37 | } 38 | 39 | public init(_ string: String, _ tag: Tag = .implicit, _ style: Style = .any, _ mark: Mark? = nil) { 40 | self.string = string 41 | self.tag = tag 42 | self.style = style 43 | self.mark = mark 44 | } 45 | } 46 | 47 | public var scalar: Scalar? { 48 | get { 49 | if case let .scalar(scalar) = self { 50 | return scalar 51 | } 52 | return nil 53 | } 54 | set { 55 | if let newValue = newValue { 56 | self = .scalar(newValue) 57 | } 58 | } 59 | } 60 | } 61 | 62 | extension Node.Scalar: Comparable { 63 | public static func < (lhs: Node.Scalar, rhs: Node.Scalar) -> Bool { 64 | return lhs.string < rhs.string 65 | } 66 | } 67 | 68 | extension Node.Scalar: Equatable { 69 | public static func == (lhs: Node.Scalar, rhs: Node.Scalar) -> Bool { 70 | return lhs.string == rhs.string && lhs.resolvedTag == rhs.resolvedTag 71 | } 72 | } 73 | 74 | extension Node.Scalar: TagResolvable { 75 | static let defaultTagName = Tag.Name.str 76 | func resolveTag(using resolver: Resolver) -> Tag.Name { 77 | return tag.name == .implicit ? resolver.resolveTag(from: string) : tag.name 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Node.Sequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node.Sequence.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 2/24/17. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Node { 12 | public struct Sequence { 13 | fileprivate var nodes: [Node] 14 | public var tag: Tag 15 | public var style: Style 16 | public var mark: Mark? 17 | 18 | public enum Style: UInt32 { // swiftlint:disable:this nesting 19 | /// Let the emitter choose the style. 20 | case any 21 | /// The block sequence style. 22 | case block 23 | /// The flow sequence style. 24 | case flow 25 | } 26 | 27 | public init(_ nodes: [Node], _ tag: Tag = .implicit, _ style: Style = .any, _ mark: Mark? = nil) { 28 | self.nodes = nodes 29 | self.tag = tag 30 | self.style = style 31 | self.mark = mark 32 | } 33 | } 34 | 35 | public var sequence: Sequence? { 36 | get { 37 | if case let .sequence(sequence) = self { 38 | return sequence 39 | } 40 | return nil 41 | } 42 | set { 43 | if let newValue = newValue { 44 | self = .sequence(newValue) 45 | } 46 | } 47 | } 48 | } 49 | 50 | // MARK: - Node.Sequence 51 | 52 | extension Node.Sequence: Comparable { 53 | public static func < (lhs: Node.Sequence, rhs: Node.Sequence) -> Bool { 54 | return lhs.nodes < rhs.nodes 55 | } 56 | } 57 | 58 | extension Node.Sequence: Equatable { 59 | public static func == (lhs: Node.Sequence, rhs: Node.Sequence) -> Bool { 60 | return lhs.nodes == rhs.nodes && lhs.resolvedTag == rhs.resolvedTag 61 | } 62 | } 63 | 64 | extension Node.Sequence: ExpressibleByArrayLiteral { 65 | public init(arrayLiteral elements: Node...) { 66 | self.init(elements) 67 | } 68 | } 69 | 70 | extension Node.Sequence: MutableCollection { 71 | // Sequence 72 | public func makeIterator() -> Array.Iterator { 73 | return nodes.makeIterator() 74 | } 75 | 76 | // Collection 77 | public typealias Index = Array.Index 78 | 79 | public var startIndex: Index { 80 | return nodes.startIndex 81 | } 82 | 83 | public var endIndex: Index { 84 | return nodes.endIndex 85 | } 86 | 87 | public func index(after index: Index) -> Index { 88 | return nodes.index(after: index) 89 | } 90 | 91 | public subscript(index: Index) -> Node { 92 | get { 93 | return nodes[index] 94 | } 95 | // MutableCollection 96 | set { 97 | nodes[index] = newValue 98 | } 99 | } 100 | 101 | public subscript(bounds: Range) -> Array.SubSequence { 102 | get { 103 | return nodes[bounds] 104 | } 105 | // MutableCollection 106 | set { 107 | nodes[bounds] = newValue 108 | } 109 | } 110 | 111 | public var indices: Array.Indices { 112 | return nodes.indices 113 | } 114 | } 115 | 116 | extension Node.Sequence: RandomAccessCollection { 117 | // BidirectionalCollection 118 | public func index(before index: Index) -> Index { 119 | return nodes.index(before: index) 120 | } 121 | 122 | // RandomAccessCollection 123 | public func index(_ index: Index, offsetBy num: Int) -> Index { 124 | return nodes.index(index, offsetBy: num) 125 | } 126 | 127 | public func distance(from start: Index, to end: Int) -> Index { 128 | return nodes.distance(from: start, to: end) 129 | } 130 | } 131 | 132 | extension Node.Sequence: RangeReplaceableCollection { 133 | public init() { 134 | self.init([]) 135 | } 136 | 137 | public mutating func replaceSubrange(_ subrange: Range, with newElements: C) 138 | where C: Collection, C.Iterator.Element == Node { 139 | nodes.replaceSubrange(subrange, with: newElements) 140 | } 141 | } 142 | 143 | extension Node.Sequence: TagResolvable { 144 | static let defaultTagName = Tag.Name.seq 145 | } 146 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Resolver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Resolver.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 12/15/16. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public final class Resolver { 12 | public struct Rule { 13 | public let tag: Tag.Name 14 | let regexp: NSRegularExpression 15 | public var pattern: String { return regexp.pattern } 16 | 17 | public init(_ tag: Tag.Name, _ pattern: String) throws { 18 | self.tag = tag 19 | self.regexp = try .init(pattern: pattern, options: []) 20 | } 21 | } 22 | 23 | public let rules: [Rule] 24 | 25 | init(_ rules: [Rule] = []) { self.rules = rules } 26 | 27 | public func resolveTag(of node: Node) -> Tag.Name { 28 | switch node { 29 | case let .scalar(scalar): 30 | return resolveTag(of: scalar) 31 | case let .mapping(mapping): 32 | return resolveTag(of: mapping) 33 | case let .sequence(sequence): 34 | return resolveTag(of: sequence) 35 | } 36 | } 37 | 38 | /// Returns a Resolver constructed by appending rule. 39 | public func appending(_ rule: Rule) -> Resolver { 40 | return .init(rules + [rule]) 41 | } 42 | 43 | /// Returns a Resolver constructed by appending pattern for tag. 44 | public func appending(_ tag: Tag.Name, _ pattern: String) throws -> Resolver { 45 | return appending(try Rule(tag, pattern)) 46 | } 47 | 48 | /// Returns a Resolver constructed by replacing rule. 49 | public func replacing(_ rule: Rule) -> Resolver { 50 | return .init(rules.map { $0.tag == rule.tag ? rule : $0 }) 51 | } 52 | 53 | /// Returns a Resolver constructed by replacing pattern for tag. 54 | public func replacing(_ tag: Tag.Name, with pattern: String) throws -> Resolver { 55 | return .init(try rules.map { $0.tag == tag ? try Rule($0.tag, pattern) : $0 }) 56 | } 57 | 58 | /// Returns a Resolver constructed by removing pattern for tag. 59 | public func removing(_ tag: Tag.Name) -> Resolver { 60 | return .init(rules.filter({ $0.tag != tag })) 61 | } 62 | 63 | // MARK: - internal 64 | 65 | func resolveTag(of value: T) -> Tag.Name where T: TagResolvable { 66 | return value.resolveTag(using: self) 67 | } 68 | 69 | func resolveTag(from string: String) -> Tag.Name { 70 | for rule in rules where rule.regexp.matches(in: string) { 71 | return rule.tag 72 | } 73 | return .str 74 | } 75 | } 76 | 77 | extension Resolver { 78 | public static let basic = Resolver() 79 | public static let `default` = Resolver([.bool, .int, .float, .merge, .null, .timestamp, .value]) 80 | } 81 | 82 | extension Resolver.Rule { 83 | // swiftlint:disable:next force_try 84 | public static let bool = try! Resolver.Rule(.bool, """ 85 | ^(?:yes|Yes|YES|no|No|NO\ 86 | |true|True|TRUE|false|False|FALSE\ 87 | |on|On|ON|off|Off|OFF)$ 88 | """) 89 | // swiftlint:disable:next force_try 90 | public static let int = try! Resolver.Rule(.int, """ 91 | ^(?:[-+]?0b[0-1_]+\ 92 | |[-+]?0o?[0-7_]+\ 93 | |[-+]?(?:0|[1-9][0-9_]*)\ 94 | |[-+]?0x[0-9a-fA-F_]+\ 95 | |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$ 96 | """) 97 | // swiftlint:disable:next force_try 98 | public static let float = try! Resolver.Rule(.float, """ 99 | ^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?\ 100 | |\\.[0-9_]+(?:[eE][-+][0-9]+)?\ 101 | |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\ 102 | |[-+]?\\.(?:inf|Inf|INF)\ 103 | |\\.(?:nan|NaN|NAN))$ 104 | """) 105 | // swiftlint:disable:next force_try 106 | public static let merge = try! Resolver.Rule(.merge, "^(?:<<)$") 107 | // swiftlint:disable:next force_try 108 | public static let null = try! Resolver.Rule(.null, """ 109 | ^(?:~\ 110 | |null|Null|NULL\ 111 | |)$ 112 | """) 113 | // swiftlint:disable:next force_try 114 | public static let timestamp = try! Resolver.Rule(.timestamp, """ 115 | ^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\ 116 | |[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?\ 117 | (?:[Tt]|[ \\t]+)[0-9][0-9]?\ 118 | :[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?\ 119 | (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$ 120 | """) 121 | // swiftlint:disable:next force_try 122 | public static let value = try! Resolver.Rule(.value, "^(?:=)$") 123 | } 124 | 125 | func pattern(_ string: String) -> NSRegularExpression { 126 | do { 127 | return try .init(pattern: string, options: []) 128 | } catch { 129 | fatalError("unreachable") 130 | } 131 | } 132 | 133 | extension NSRegularExpression { 134 | fileprivate func matches(in string: String) -> Bool { 135 | let range = NSRange(location: 0, length: string.utf16.count) 136 | if let match = firstMatch(in: string, options: [], range: range) { 137 | return match.range.location != NSNotFound 138 | } 139 | return false 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/String+Yams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Yams.swift 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 12/7/16. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | typealias LineNumberColumnAndContents = (lineNumber: Int, column: Int, contents: String) 13 | 14 | /// line number, column and contents at utf8 offset. 15 | /// 16 | /// - Parameter offset: Int 17 | /// - Returns: lineNumber: line number start from 0, 18 | /// column: utf16 column start from 0, 19 | /// contents: substring of line 20 | func utf8LineNumberColumnAndContents(at offset: Int) -> LineNumberColumnAndContents? { 21 | guard let index = utf8 22 | .index(utf8.startIndex, offsetBy: offset, limitedBy: utf8.endIndex)? 23 | .samePosition(in: self) else { return nil } 24 | return lineNumberColumnAndContents(at: index) 25 | } 26 | 27 | /// line number, column and contents at utf16 offset. 28 | /// 29 | /// - Parameter offset: Int 30 | /// - Returns: lineNumber: line number start from 0, 31 | /// column: utf16 column start from 0, 32 | /// contents: substring of line 33 | func utf16LineNumberColumnAndContents(at offset: Int) -> LineNumberColumnAndContents? { 34 | guard let index = utf16 35 | .index(utf16.startIndex, offsetBy: offset, limitedBy: utf16.endIndex)? 36 | .samePosition(in: self) else { return nil } 37 | return lineNumberColumnAndContents(at: index) 38 | } 39 | 40 | /// line number, column and contents at Index. 41 | /// 42 | /// - Parameter index: String.Index 43 | /// - Returns: lineNumber: line number start from 0, 44 | /// column: utf16 column start from 0, 45 | /// contents: substring of line 46 | func lineNumberColumnAndContents(at index: Index) -> LineNumberColumnAndContents { 47 | assert((startIndex.. String { 72 | var number = 0 73 | var outStartIndex = startIndex, outEndIndex = startIndex, outContentsEndIndex = startIndex 74 | getLineStart(&outStartIndex, end: &outEndIndex, contentsEnd: &outContentsEndIndex, 75 | for: startIndex..(with value: T) -> Tag where T: TagResolvable { 39 | if name == .implicit { 40 | name = resolver.resolveTag(of: value) 41 | } else if name == .nonSpecific { 42 | name = T.defaultTagName 43 | } 44 | return self 45 | } 46 | 47 | // fileprivate 48 | fileprivate let resolver: Resolver 49 | } 50 | 51 | extension Tag: CustomStringConvertible { 52 | public var description: String { 53 | return name.rawValue 54 | } 55 | } 56 | 57 | extension Tag: Hashable { 58 | public var hashValue: Int { 59 | return name.hashValue 60 | } 61 | 62 | public static func == (lhs: Tag, rhs: Tag) -> Bool { 63 | return lhs.name == rhs.name 64 | } 65 | } 66 | 67 | extension Tag.Name: ExpressibleByStringLiteral { 68 | public init(stringLiteral value: String) { 69 | self.rawValue = value 70 | } 71 | 72 | public init(unicodeScalarLiteral value: String) { 73 | self.rawValue = value 74 | } 75 | 76 | public init(extendedGraphemeClusterLiteral value: String) { 77 | self.rawValue = value 78 | } 79 | } 80 | 81 | extension Tag.Name: Hashable { 82 | public var hashValue: Int { 83 | return rawValue.hashValue 84 | } 85 | 86 | public static func == (lhs: Tag.Name, rhs: Tag.Name) -> Bool { 87 | return lhs.rawValue == rhs.rawValue 88 | } 89 | } 90 | 91 | // http://www.yaml.org/spec/1.2/spec.html#Schema 92 | extension Tag.Name { 93 | // Special 94 | /// Tag should be resolved by value. 95 | public static let implicit: Tag.Name = "" 96 | /// Tag should not be resolved by value, and be resolved as .str, .seq or .map. 97 | public static let nonSpecific: Tag.Name = "!" 98 | 99 | // Failsafe Schema 100 | /// "tag:yaml.org,2002:str" 101 | public static let str: Tag.Name = "tag:yaml.org,2002:str" 102 | /// "tag:yaml.org,2002:seq" 103 | public static let seq: Tag.Name = "tag:yaml.org,2002:seq" 104 | /// "tag:yaml.org,2002:map" 105 | public static let map: Tag.Name = "tag:yaml.org,2002:map" 106 | // JSON Schema 107 | /// "tag:yaml.org,2002:bool" 108 | public static let bool: Tag.Name = "tag:yaml.org,2002:bool" 109 | /// "tag:yaml.org,2002:float" 110 | public static let float: Tag.Name = "tag:yaml.org,2002:float" 111 | /// "tag:yaml.org,2002:null" 112 | public static let null: Tag.Name = "tag:yaml.org,2002:null" 113 | /// "tag:yaml.org,2002:int" 114 | public static let int: Tag.Name = "tag:yaml.org,2002:int" 115 | // http://yaml.org/type/index.html 116 | /// "tag:yaml.org,2002:binary" 117 | public static let binary: Tag.Name = "tag:yaml.org,2002:binary" 118 | /// "tag:yaml.org,2002:merge" 119 | public static let merge: Tag.Name = "tag:yaml.org,2002:merge" 120 | /// "tag:yaml.org,2002:omap" 121 | public static let omap: Tag.Name = "tag:yaml.org,2002:omap" 122 | /// "tag:yaml.org,2002:pairs" 123 | public static let pairs: Tag.Name = "tag:yaml.org,2002:pairs" 124 | /// "tag:yaml.org,2002:set". 125 | public static let set: Tag.Name = "tag:yaml.org,2002:set" 126 | /// "tag:yaml.org,2002:timestamp" 127 | public static let timestamp: Tag.Name = "tag:yaml.org,2002:timestamp" 128 | /// "tag:yaml.org,2002:value" 129 | public static let value: Tag.Name = "tag:yaml.org,2002:value" 130 | /// "tag:yaml.org,2002:yaml" We don't support this. 131 | public static let yaml: Tag.Name = "tag:yaml.org,2002:yaml" 132 | } 133 | 134 | protocol TagResolvable { 135 | var tag: Tag { get } 136 | static var defaultTagName: Tag.Name { get } 137 | func resolveTag(using resolver: Resolver) -> Tag.Name 138 | } 139 | 140 | extension TagResolvable { 141 | var resolvedTag: Tag { 142 | return tag.resolved(with: self) 143 | } 144 | 145 | func resolveTag(using resolver: Resolver) -> Tag.Name { 146 | return tag.name == .implicit ? Self.defaultTagName : tag.name 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/YamlError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YamlError.swift 3 | // Yams 4 | // 5 | // Created by JP Simard on 2016-11-19. 6 | // Copyright (c) 2016 Yams. All rights reserved. 7 | // 8 | 9 | #if SWIFT_PACKAGE 10 | import CYaml 11 | #endif 12 | import Foundation 13 | 14 | public enum YamlError: Swift.Error { 15 | // Used in `yaml_emitter_t` and `yaml_parser_t` 16 | /// YAML_NO_ERROR. No error is produced. 17 | case no // swiftlint:disable:this identifier_name 18 | /// YAML_MEMORY_ERROR. Cannot allocate or reallocate a block of memory. 19 | case memory 20 | 21 | // Used in `yaml_parser_t` 22 | /// YAML_READER_ERROR. Cannot read or decode the input stream. 23 | case reader(problem: String, byteOffset: Int, value: Int32, yaml: String) 24 | 25 | // line and column start from 1, column is counted by unicodeScalars 26 | /// YAML_SCANNER_ERROR. Cannot scan the input stream. 27 | case scanner(context: Context?, problem: String, Mark, yaml: String) 28 | /// YAML_PARSER_ERROR. Cannot parse the input stream. 29 | case parser(context: Context?, problem: String, Mark, yaml: String) 30 | /// YAML_COMPOSER_ERROR. Cannot compose a YAML document. 31 | case composer(context: Context?, problem: String, Mark, yaml: String) 32 | 33 | // Used in `yaml_emitter_t` 34 | /// YAML_WRITER_ERROR. Cannot write to the output stream. 35 | case writer(problem: String) 36 | /// YAML_EMITTER_ERROR. Cannot emit a YAML stream. 37 | case emitter(problem: String) 38 | 39 | // Used in `NodeRepresentable` 40 | case representer(problem: String) 41 | 42 | public struct Context: CustomStringConvertible { 43 | public let text: String 44 | public let mark: Mark 45 | public var description: String { 46 | return text + " in line \(mark.line), column \(mark.column)\n" 47 | } 48 | } 49 | } 50 | 51 | extension YamlError { 52 | init(from parser: yaml_parser_t, with yaml: String) { 53 | func context(from parser: yaml_parser_t) -> Context? { 54 | guard let context = parser.context else { return nil } 55 | return Context( 56 | text: String(cString: context), 57 | mark: Mark(line: parser.context_mark.line + 1, column: parser.context_mark.column + 1) 58 | ) 59 | } 60 | 61 | func problemMark(from parser: yaml_parser_t) -> Mark { 62 | return Mark(line: parser.problem_mark.line + 1, column: parser.problem_mark.column + 1) 63 | } 64 | 65 | switch parser.error { 66 | case YAML_MEMORY_ERROR: 67 | self = .memory 68 | case YAML_READER_ERROR: 69 | self = .reader(problem: String(cString: parser.problem), 70 | byteOffset: parser.problem_offset, 71 | value: parser.problem_value, 72 | yaml: yaml) 73 | case YAML_SCANNER_ERROR: 74 | self = .scanner(context: context(from: parser), 75 | problem: String(cString: parser.problem), problemMark(from: parser), 76 | yaml: yaml) 77 | case YAML_PARSER_ERROR: 78 | self = .parser(context: context(from: parser), 79 | problem: String(cString: parser.problem), problemMark(from: parser), 80 | yaml: yaml) 81 | case YAML_COMPOSER_ERROR: 82 | self = .composer(context: context(from: parser), 83 | problem: String(cString: parser.problem), problemMark(from: parser), 84 | yaml: yaml) 85 | default: 86 | fatalError("Parser has unknown error: \(parser.error)!") 87 | } 88 | } 89 | 90 | init(from emitter: yaml_emitter_t) { 91 | switch emitter.error { 92 | case YAML_MEMORY_ERROR: 93 | self = .memory 94 | case YAML_EMITTER_ERROR: 95 | self = .emitter(problem: String(cString: emitter.problem)) 96 | default: 97 | fatalError("Emitter has unknown error: \(emitter.error)!") 98 | } 99 | } 100 | } 101 | 102 | extension YamlError: CustomStringConvertible { 103 | public var description: String { 104 | switch self { 105 | case .no: 106 | return "No error is produced" 107 | case .memory: 108 | return "Memory error" 109 | case let .reader(problem, byteOffset, value, yaml): 110 | guard let (mark, contents) = markAndSnippet(from: yaml, byteOffset) 111 | else { return "\(problem) at byte offset: \(byteOffset), value: \(value)" } 112 | return "\(mark): error: reader: \(problem):\n" + contents.endingWithNewLine 113 | + String(repeating: " ", count: mark.column - 1) + "^" 114 | case let .scanner(context, problem, mark, yaml): 115 | return "\(mark): error: scanner: \(context?.description ?? "")\(problem):\n" + mark.snippet(from: yaml) 116 | case let .parser(context, problem, mark, yaml): 117 | return "\(mark): error: parser: \(context?.description ?? "")\(problem):\n" + mark.snippet(from: yaml) 118 | case let .composer(context, problem, mark, yaml): 119 | return "\(mark): error: composer: \(context?.description ?? "")\(problem):\n" + mark.snippet(from: yaml) 120 | case let .writer(problem), let .emitter(problem), let .representer(problem): 121 | return problem 122 | } 123 | } 124 | } 125 | 126 | extension YamlError { 127 | fileprivate func markAndSnippet(from yaml: String, _ byteOffset: Int) -> (Mark, String)? { 128 | #if USE_UTF8 129 | guard let (line, column, contents) = yaml.utf8LineNumberColumnAndContents(at: byteOffset) 130 | else { return nil } 131 | #else 132 | guard let (line, column, contents) = yaml.utf16LineNumberColumnAndContents(at: byteOffset / 2) 133 | else { return nil } 134 | #endif 135 | return (Mark(line: line + 1, column: column + 1), contents) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Pods/Yams/Sources/Yams/Yams.h: -------------------------------------------------------------------------------- 1 | // 2 | // Yams.h 3 | // Yams 4 | // 5 | // Created by Norio Nomura on 1/25/17. 6 | // Copyright (c) 2017 Yams. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Yams. 12 | FOUNDATION_EXPORT double YamsVersionNumber; 13 | 14 | //! Project version string for Yams. 15 | FOUNDATION_EXPORT const unsigned char YamsVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | #import 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/fastred/IBAnalyzer.svg?branch=master)](https://travis-ci.org/fastred/IBAnalyzer) [![codecov](https://codecov.io/gh/fastred/IBAnalyzer/branch/master/graph/badge.svg)](https://codecov.io/gh/fastred/IBAnalyzer) 2 | 3 | # IBAnalyzer 4 | 5 | Find common xib and storyboard-related problems without running your app or writing unit tests. 6 | 7 | ## Usage 8 | 9 | Pass a path to your project to `ibanalyzer` command line tool. Here's an example output you can expect: 10 | 11 | ``` 12 | $ ./ibanalyzer ~/code/Sample/ 13 | 14 | TwitterViewController doesn't implement a required @IBAction named: loginButtonPressed: 15 | TwitterViewController doesn't implement a required @IBOutlet named: twitterImageView 16 | LoginViewController contains unused @IBAction named: onePasswordButtonTapped: 17 | MessageCell contains unused @IBOutlet named: unreadIndicatorView 18 | MessagesViewController contains unused @IBAction named: infoButtonPressed 19 | ``` 20 | 21 | With IBAnalyzer, you're able to: 22 | 23 | 1. Find unimplemented outlets & actions in classes. Avoid crashes caused by exceptions, like the dreadful: 24 | ``` 25 | *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: ' 26 | [ setValue:forUndefinedKey:]: this 27 | class is not key value coding-compliant for the key twitterImageView.' 28 | ``` 29 | 30 | 2. Find `@IBOutlet`s and `@IBAction`s defined in code but not connected to from nibs. No more: 31 | 32 | Unnecessary action 33 | 34 | and 35 | 36 | Unnecessary outlet 37 | 38 | ## Drawbacks 39 | 40 | This is a new tool, used only on a handful of projects till now. If you encounter any bugs, please create new issues. 41 | 42 | **Doesn't work with Objective-C. Tested on Swift 3.0.** 43 | 44 | ## How It Works 45 | 46 | IBAnalyzer starts by parsing all `.xib,` `.storyboard` and `.swift` files in the provided folder. It then uses this data (wrapped in `AnalyzerConfiguration`) to generate warnings. You can see the source of an analyzer [checking connections between source code and nibs here](https://github.com/fastred/IBAnalyzer/blob/master/IBAnalyzer/Analyzers/ConnectionAnalyzer.swift). 47 | 48 | New warnings can be implemented by adding a new type conforming to the `Analyzer` protocol and initializing it in `main.swift`. Check [issues](https://github.com/fastred/IBAnalyzer/issues) to learn about some ideas for new warnings. 49 | 50 | ## Installation 51 | 52 | ### CocoaPods (Build Phase integration) 53 | 54 | Note: This can significantly slow-down your build times. 55 | 56 | 1. Add `pod 'IBAnalyzer'` to your `Podfile`. 57 | 1. Run `pod repo update` and then `pod install`. 58 | 1. Go to target settings -> Build Phases and add a `New Run Script Phase`. Change its name to something like `IBAnalyzer`. 59 | 1. Use this script to run analysis on all files in your repository (possibly including 3rd party dependencies, like `Pods/`): 60 | 61 | ``` 62 | "${PODS_ROOT}/IBAnalyzer/bin/ibanalyzer" ./ 63 | ``` 64 | 65 | or this one to run analysis only on a single folder: 66 | 67 | ``` 68 | "${PODS_ROOT}/IBAnalyzer/bin/ibanalyzer" FolderName/ 69 | ``` 70 | 71 | ### Binary 72 | 73 | Download the newest prebuilt binary from the [Releases](https://github.com/fastred/IBAnalyzer/releases) tab. Unpack and run using: 74 | 75 | ``` 76 | $ bin/ibanalyzer /path/to/your/project 77 | ``` 78 | 79 | ### From Source 80 | 81 | 1. Clone or download the repo. 82 | 1. Open `IBAnalyzer.xcworkspace` in Xcode 8.2 and build the project (⌘-B). 83 | 1. `$ cd Build/MacOS` 84 | 1. `$ ./ibanalyzer /path/to/your/project` 85 | 86 | ## Attributions 87 | 88 | - [SourceKitten](https://github.com/jpsim/SourceKitten) – IBAnalyzer wouldn't be possible without it 89 | - [SwiftGen](https://github.com/AliSoftware/SwiftGen) – inspiration for `NibParser` 90 | - [Sourcery](https://github.com/krzysztofzablocki/Sourcery) – IBAnalyzer uses pretty much the same `Rakefile` 91 | 92 | ## Author 93 | 94 | Project initially started by [Arek Holko](http://holko.pl) ([@arekholko](https://twitter.com/arekholko) on Twitter). 95 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/rake 2 | ## Based on the code from Sourcery https://github.com/krzysztofzablocki/Sourcery/blob/master/Rakefile 3 | 4 | require 'pathname' 5 | require 'yaml' 6 | require 'json' 7 | require 'net/http' 8 | require 'uri' 9 | 10 | BUILD_DIR = 'build/' 11 | 12 | ## [ Utils ] ################################################################## 13 | 14 | def version_select 15 | # Find all Xcode 8 versions on this computer 16 | xcodes = `mdfind "kMDItemCFBundleIdentifier = 'com.apple.dt.Xcode' && kMDItemVersion = '9.*'"`.chomp.split("\n") 17 | if xcodes.empty? 18 | raise "\n[!!!] You need to have Xcode 9.x to compile IBAnalyzer.\n\n" 19 | end 20 | # Order by version and get the latest one 21 | vers = lambda { |path| `mdls -name kMDItemVersion -raw "#{path}"` } 22 | latest_xcode_version = xcodes.sort { |p1, p2| vers.call(p1) <=> vers.call(p2) }.last 23 | %Q(DEVELOPER_DIR="#{latest_xcode_version}/Contents/Developer" TOOLCHAINS=com.apple.dt.toolchain.XcodeDefault.xctoolchain) 24 | end 25 | 26 | def xcpretty(cmd) 27 | if `which xcpretty` && $?.success? 28 | sh "set -o pipefail && #{cmd} | xcpretty -c" 29 | else 30 | sh cmd 31 | end 32 | end 33 | 34 | def xcrun(cmd) 35 | xcpretty "#{version_select} xcrun #{cmd}" 36 | end 37 | 38 | def print_info(str) 39 | (red,clr) = (`tput colors`.chomp.to_i >= 8) ? %W(\e[33m \e[m) : ["", ""] 40 | puts red, "== #{str.chomp} ==", clr 41 | end 42 | ## [ Tests & Clean ] ########################################################## 43 | 44 | desc "Run the Unit Tests" 45 | task :tests do 46 | print_info "Running Unit Tests" 47 | xcrun %Q(xcodebuild -workspace IBAnalyzer.xcworkspace -scheme IBAnalyzer -sdk macosx test) 48 | end 49 | 50 | desc "Delete the build/ directory" 51 | task :clean do 52 | sh %Q(rm -fr build) 53 | end 54 | 55 | task :build do 56 | print_info "Building project" 57 | xcrun %Q(xcodebuild -workspace IBAnalyzer.xcworkspace -scheme IBAnalyzer -configuration Release -sdk macosx -derivedDataPath #{BUILD_DIR}/tmp/) 58 | sh %Q(rm -fr bin/IBAnalyzer.app) 59 | `mv #{BUILD_DIR}tmp/Build/Products/Release/IBAnalyzer.app bin/` 60 | sh %Q(rm -fr #{BUILD_DIR}tmp/) 61 | end 62 | 63 | ## [ Release ] ########################################################## 64 | 65 | namespace :release do 66 | desc 'Create a new release on GitHub, CocoaPods and Homebrew' 67 | task :new => [:check_versions, :build, :tests, :github, :cocoapods] 68 | 69 | def podspec_version(file = 'IBAnalyzer') 70 | JSON.parse(`bundle exec pod ipc spec #{file}.podspec`)["version"] 71 | end 72 | 73 | def log_result(result, label, error_msg) 74 | if result 75 | puts "#{label.ljust(25)} \u{2705}" 76 | else 77 | puts "#{label.ljust(25)} \u{274C} - #{error_msg}" 78 | end 79 | result 80 | end 81 | 82 | desc 'Check if all versions from the podspecs and CHANGELOG match' 83 | task :check_versions do 84 | results = [] 85 | 86 | # Check if bundler is installed first, as we'll need it for the cocoapods task (and we prefer to fail early) 87 | `which bundler` 88 | results << log_result( $?.success?, 'Bundler installed', 'Please install bundler using `gem install bundler` and run `bundle install` first.') 89 | 90 | # Extract version from IBAnalyzer.podspec 91 | version = podspec_version 92 | puts "#{'IBAnalyzer.podspec'.ljust(25)} \u{1F449} #{version}" 93 | 94 | # Check if entry present in CHANGELOG 95 | changelog_entry = system(%Q{grep -q '^## #{Regexp.quote(version)}$' CHANGELOG.md}) 96 | results << log_result(changelog_entry, "CHANGELOG, Entry added", "Please add an entry for #{version} in CHANGELOG.md") 97 | 98 | changelog_master = system(%q{grep -qi '^## Master' CHANGELOG.md}) 99 | results << log_result(!changelog_master, "CHANGELOG, No master", 'Please remove entry for master in CHANGELOG') 100 | 101 | exit 1 unless results.all? 102 | 103 | print "Release version #{version} [Y/n]? " 104 | exit 2 unless (STDIN.gets.chomp == 'Y') 105 | end 106 | 107 | desc 'Create a zip containing all the prebuilt binaries' 108 | task :zip => [:clean] do 109 | sh %Q(mkdir -p "build") 110 | sh %Q(cp -r bin build/) 111 | `cp LICENSE README.md CHANGELOG.md build` 112 | `cd build; zip -r -X ibanalyzer-#{podspec_version}.zip .` 113 | end 114 | 115 | def post(url, content_type) 116 | uri = URI.parse(url) 117 | req = Net::HTTP::Post.new(uri, initheader = {'Content-Type' => content_type}) 118 | yield req if block_given? 119 | req.basic_auth 'fastred', File.read('.apitoken').chomp 120 | 121 | response = Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == 'https')) do |http| 122 | http.request(req) 123 | end 124 | unless response.code == '201' 125 | puts "Error: #{response.code} - #{response.message}" 126 | puts response.body 127 | exit 3 128 | end 129 | JSON.parse(response.body) 130 | end 131 | 132 | desc 'Upload the zipped binaries to a new GitHub release' 133 | task :github => :zip do 134 | v = podspec_version 135 | 136 | changelog = `sed -n /'^## #{v}$'/,/'^## '/p CHANGELOG.md`.gsub(/^## .*$/,'').strip 137 | print_info "Releasing version #{v} on GitHub" 138 | puts changelog 139 | 140 | json = post('https://api.github.com/repos/fastred/IBAnalyzer/releases', 'application/json') do |req| 141 | req.body = { :tag_name => v, :name => v, :body => changelog, :draft => false, :prerelease => false }.to_json 142 | end 143 | 144 | upload_url = json['upload_url'].gsub(/\{.*\}/,"?name=IBAnalyzer-#{v}.zip") 145 | zipfile = "build/IBAnalyzer-#{v}.zip" 146 | zipsize = File.size(zipfile) 147 | 148 | print_info "Uploading ZIP (#{zipsize} bytes)" 149 | post(upload_url, 'application/zip') do |req| 150 | req.body_stream = File.open(zipfile, 'rb') 151 | req.add_field('Content-Length', zipsize) 152 | req.add_field('Content-Transfer-Encoding', 'binary') 153 | end 154 | end 155 | 156 | desc 'pod trunk push IBAnalyzer to CocoaPods' 157 | task :cocoapods do 158 | print_info "Pushing pod to CocoaPods Trunk" 159 | sh 'bundle exec pod trunk push IBAnalyzer.podspec --allow-warnings' 160 | end 161 | end 162 | -------------------------------------------------------------------------------- /Resources/unnecessary-action@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastred/IBAnalyzer/c368cc8537cd1da842fab05ba17f5afd46964d2c/Resources/unnecessary-action@2x.png -------------------------------------------------------------------------------- /Resources/unnecessary-outlet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastred/IBAnalyzer/c368cc8537cd1da842fab05ba17f5afd46964d2c/Resources/unnecessary-outlet@2x.png -------------------------------------------------------------------------------- /bin/ibanalyzer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file serves just as a link 3 | # Based on: https://github.com/krzysztofzablocki/Sourcery/blob/master/bin/sourcery 4 | 5 | parent_path=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) 6 | 7 | "${parent_path}"/IBAnalyzer.app/Contents/MacOS/IBAnalyzer "$@" 8 | --------------------------------------------------------------------------------