├── .bazelrc ├── .bazelversion ├── .bcr ├── metadata.template.json ├── presubmit.yml └── source.template.json ├── .gitattributes ├── .github └── workflows │ ├── bazel.yml │ ├── jazzy.yml │ ├── pod_lib_lint.yml │ ├── swiftlint.yml │ ├── swiftpm.yml │ └── xcodebuild.yml ├── .gitignore ├── .swiftlint.yml ├── BUILD ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dangerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── MODULE.bazel ├── Makefile ├── Package.resolved ├── Package.swift ├── README.md ├── Releasing.md ├── Source ├── BUILD ├── Clang_C │ ├── Clang_C.c │ ├── Clang_C.modulemap │ └── include │ │ ├── BuildSystem.h │ │ ├── CXCompilationDatabase.h │ │ ├── CXErrorCode.h │ │ ├── CXString.h │ │ ├── Clang_C.h │ │ ├── Documentation.h │ │ ├── Index.h │ │ └── Platform.h ├── SourceKit │ ├── SourceKit.c │ ├── SourceKit.modulemap │ └── include │ │ ├── SourceKit.h │ │ └── sourcekitd.h ├── SourceKittenFramework │ ├── ByteCount.swift │ ├── ByteRange.swift │ ├── Clang+SourceKitten.swift │ ├── ClangTranslationUnit.swift │ ├── CodeCompletionItem.swift │ ├── CursorInfo+Parsing.swift │ ├── Dictionary+Merge.swift │ ├── Documentation.swift │ ├── Exec.swift │ ├── File+Hashable.swift │ ├── File.swift │ ├── JSONOutput.swift │ ├── Language.swift │ ├── LibraryWrapperGenerator.swift │ ├── Line.swift │ ├── LinuxCompatibility.swift │ ├── Module.swift │ ├── ObjCDeclarationKind.swift │ ├── OffsetMap.swift │ ├── Parameter.swift │ ├── Request.swift │ ├── SourceDeclaration.swift │ ├── SourceKitObject.swift │ ├── SourceKittenFramework.h │ ├── SourceLocation.swift │ ├── StatementKind.swift │ ├── String+SourceKitten.swift │ ├── StringView+SourceKitten.swift │ ├── StringView.swift │ ├── Structure.swift │ ├── SwiftDeclarationAttributeKind.swift │ ├── SwiftDeclarationKind.swift │ ├── SwiftDocKey.swift │ ├── SwiftDocs.swift │ ├── SwiftVersion.swift │ ├── SyntaxKind.swift │ ├── SyntaxMap.swift │ ├── SyntaxToken.swift │ ├── Text.swift │ ├── UID.swift │ ├── UIDRepresentable.swift │ ├── UncheckedSendable.swift │ ├── Version.swift │ ├── WindowsError.swift │ ├── Xcode.swift │ ├── XcodeBuildSetting.swift │ ├── library_wrapper.swift │ ├── library_wrapper_Clang_C.swift │ └── library_wrapper_SourceKit.swift └── sourcekitten │ ├── Complete.swift │ ├── Doc.swift │ ├── Errors.swift │ ├── Format.swift │ ├── Index.swift │ ├── ModuleInfo.swift │ ├── Request.swift │ ├── SourceKitten.swift │ ├── Structure.swift │ ├── Syntax.swift │ ├── Version.swift │ └── main.swift ├── SourceKittenFramework.podspec ├── Tests ├── BUILD └── SourceKittenFrameworkTests │ ├── ByteRangeTests.swift │ ├── ClangTranslationUnitTests.swift │ ├── CodeCompletionTests.swift │ ├── CursorInfoParsingTests.swift │ ├── CursorInfoUSRTests.swift │ ├── DocInfoTests.swift │ ├── FileTests.swift │ ├── Fixtures │ ├── Bicycle.json │ ├── Bicycle.swift │ ├── Bicycle@swift-5.9.json │ ├── Bicycle@swift-6.0.json │ ├── BicycleIndex.json │ ├── BicycleIndex@swift-5.9.json │ ├── BicycleIndex@swift-6.0.json │ ├── BicycleSyntax.json │ ├── BicycleUnformatted.swift │ ├── CodeFormatting.h │ ├── CodeFormatting.json │ ├── Commandant.json │ ├── Commandant@swift-5.10.json │ ├── Commandant@swift-5.8.json │ ├── Commandant@swift-5.9.json │ ├── Commandant@swift-6.0.json │ ├── CommandantSPM.json │ ├── CommandantSPM@swift-5.10.json │ ├── CommandantSPM@swift-5.8.json │ ├── CommandantSPM@swift-5.9.json │ ├── CommandantSPM@swift-6.0.json │ ├── CursorInfoUSR.json │ ├── CursorInfoUSR@swift-5.9.json │ ├── CursorInfoUSR@swift-6.0.json │ ├── DocInfo.json │ ├── DocInfo.swift │ ├── Extension.json │ ├── Extension.swift │ ├── Extension@swift-5.9.json │ ├── Extension@swift-6.0.json │ ├── ExternalRef1.swift │ ├── ExternalRef2.swift │ ├── LinuxBicycle.json │ ├── LinuxBicycle@swift-5.6.json │ ├── LinuxBicycle@swift-5.9.json │ ├── LinuxBicycle@swift-6.0.json │ ├── LinuxBicycleIndex.json │ ├── LinuxBicycleIndex@swift-5.6.json │ ├── LinuxBicycleIndex@swift-5.7.json │ ├── LinuxBicycleIndex@swift-5.9.json │ ├── LinuxBicycleIndex@swift-6.0.json │ ├── LinuxCommandantSPM.json │ ├── LinuxCommandantSPM@swift-5.10.json │ ├── LinuxCommandantSPM@swift-5.6.json │ ├── LinuxCommandantSPM@swift-5.8.json │ ├── LinuxCommandantSPM@swift-5.9.json │ ├── LinuxCommandantSPM@swift-6.0.json │ ├── LinuxExtension.json │ ├── LinuxSimpleCodeCompletion.json │ ├── Musician.h │ ├── Musician.json │ ├── Musician@swift-5.2.json │ ├── NonUTF8File.swift │ ├── Realm.json │ ├── Realm │ │ ├── RLMAccessor.h │ │ ├── RLMArray.h │ │ ├── RLMArray_Private.h │ │ ├── RLMCollection.h │ │ ├── RLMConstants.h │ │ ├── RLMDefines.h │ │ ├── RLMListBase.h │ │ ├── RLMMigration.h │ │ ├── RLMMigration_Private.h │ │ ├── RLMObject.h │ │ ├── RLMObjectBase.h │ │ ├── RLMObjectBase_Dynamic.h │ │ ├── RLMObjectSchema.h │ │ ├── RLMObjectSchema_Private.h │ │ ├── RLMObjectStore.h │ │ ├── RLMObject_Private.h │ │ ├── RLMOptionalBase.h │ │ ├── RLMPlatform.h │ │ ├── RLMPrefix.h │ │ ├── RLMProperty.h │ │ ├── RLMProperty_Private.h │ │ ├── RLMRealm.h │ │ ├── RLMRealmConfiguration.h │ │ ├── RLMRealmConfiguration_Private.h │ │ ├── RLMRealm_Dynamic.h │ │ ├── RLMRealm_Private.h │ │ ├── RLMResults.h │ │ ├── RLMResults_Private.h │ │ ├── RLMSchema.h │ │ ├── RLMSchema_Private.h │ │ ├── RLMSwiftBridgingHeader.h │ │ ├── RLMSwiftSupport.h │ │ └── Realm.h │ ├── Realm@swift-5.10.json │ ├── SimpleCodeCompletion.json │ ├── SimpleCodeCompletion@swift-5.10.json │ ├── SimpleCodeCompletion@swift-6.0.json │ ├── Subscript.json │ ├── Subscript.swift │ ├── Subscript@swift-5.9.json │ ├── Subscript@swift-6.0.json │ ├── SuperScript.h │ ├── SuperScript.json │ ├── Union.h │ ├── Union.json │ └── Union@swift-5.9.json │ ├── LibraryWrapperGeneratorTests.swift │ ├── ModuleTests.swift │ ├── OffsetMapTests.swift │ ├── SourceKitObjectTests.swift │ ├── SourceKitStrings+Windows.swift │ ├── SourceKitTests.swift │ ├── StringTests.swift │ ├── StructureTests.swift │ ├── SwiftDocKeyTests.swift │ ├── SwiftDocsTests.swift │ └── SyntaxTests.swift ├── WORKSPACE ├── bazel ├── BUILD ├── SWXMLHash.BUILD └── SwiftArgumentParser.BUILD ├── jazzy.sh └── script ├── Version.swift.template └── get-version /.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_bzlmod 2 | build --macos_minimum_os=12 3 | build --repo_env=CC=clang 4 | test --test_output=errors 5 | test --spawn_strategy=standalone 6 | test --macos_minimum_os=13 7 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 7.0.0 2 | -------------------------------------------------------------------------------- /.bcr/metadata.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://github.com/jpsim/SourceKitten", 3 | "maintainers": [ 4 | { 5 | "email": "jp@jpsim.com", 6 | "github": "jpsim", 7 | "name": "JP Simard" 8 | }, 9 | { 10 | "email": "keithbsmiley@gmail.com", 11 | "github": "keith", 12 | "name": "Keith Smiley" 13 | } 14 | ], 15 | "repository": [ 16 | "github:jpsim/SourceKitten" 17 | ], 18 | "versions": [], 19 | "yanked_versions": {} 20 | } 21 | -------------------------------------------------------------------------------- /.bcr/presubmit.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | verify_targets: 3 | name: Verify build targets 4 | platform: macos 5 | bazel: 7.x 6 | build_targets: 7 | - '@sourcekitten//:sourcekitten' 8 | build_flags: 9 | - "--repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1" 10 | -------------------------------------------------------------------------------- /.bcr/source.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://github.com/jpsim/SourceKitten/archive/refs/tags/{TAG}.tar.gz", 3 | "integrity": "", 4 | "strip_prefix": "SourceKitten-{TAG}" 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Source/Clang_C/* linguist-vendored 2 | Tests/SourceKittenFrameworkTests/Fixtures/* linguist-vendored eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/bazel.yml: -------------------------------------------------------------------------------- 1 | name: Bazel 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | MacOS: 11 | strategy: 12 | matrix: 13 | xcode_version: ['15.3', '15.4', '16.1', '16.2'] 14 | runs-on: macos-14 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: maxim-lobanov/setup-xcode@v1 18 | with: 19 | xcode-version: ${{ matrix.xcode_version }} 20 | - run: bazelisk test //Tests:UnitTests --test_env=PROJECT_ROOT=$(bazelisk info workspace) 21 | - run: bazelisk build sourcekitten 22 | Linux: 23 | strategy: 24 | matrix: 25 | tag: ['5.8-focal', '5.9-focal', '5.10-focal', '6.0-focal'] 26 | runs-on: ubuntu-latest 27 | container: 28 | image: swift:${{ matrix.tag }} 29 | steps: 30 | - uses: actions/checkout@v2 31 | - uses: actions/setup-go@v2 32 | with: 33 | go-version: '^1.13.1' # The Go version to download (if necessary) and use. 34 | - name: Setup Bazel 35 | run: go install github.com/bazelbuild/bazelisk@latest 36 | - name: Build SourceKitten 37 | run: bazelisk build sourcekitten 38 | -------------------------------------------------------------------------------- /.github/workflows/jazzy.yml: -------------------------------------------------------------------------------- 1 | name: Jazzy 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | Jazzy: 11 | runs-on: macos-13 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: ruby/setup-ruby@v1 15 | with: 16 | ruby-version: 2.7 17 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 18 | - run: swift build 19 | - name: Generate documentation json 20 | run: swift run sourcekitten doc --spm --module-name SourceKittenFramework > SourceKittenFramework.json 21 | - name: Run jazzy 22 | run: bundle exec jazzy --clean --sourcekitten-sourcefile SourceKittenFramework.json 23 | - name: Upload Artifact 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: API Docs 27 | path: docs 28 | -------------------------------------------------------------------------------- /.github/workflows/pod_lib_lint.yml: -------------------------------------------------------------------------------- 1 | name: pod lib lint 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | pod_lib_lint: 11 | name: pod lib lint 12 | runs-on: macos-14 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: maxim-lobanov/setup-xcode@v1 16 | with: 17 | xcode-version: 15.3 18 | - run: bundle install --path vendor/bundle 19 | - run: bundle exec pod repo update 20 | - run: bundle exec pod lib lint --verbose 21 | -------------------------------------------------------------------------------- /.github/workflows/swiftlint.yml: -------------------------------------------------------------------------------- 1 | name: SwiftLint 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | SwiftLint: 11 | runs-on: ubuntu-latest 12 | container: 13 | image: ghcr.io/realm/swiftlint:0.58.2 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Run SwiftLint 17 | run: swiftlint --strict 18 | -------------------------------------------------------------------------------- /.github/workflows/swiftpm.yml: -------------------------------------------------------------------------------- 1 | name: SwiftPM 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | Xcode: 11 | strategy: 12 | matrix: 13 | xcode_version: ['15.3', '15.4', '16.1', '16.2'] 14 | runs-on: macos-14 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: maxim-lobanov/setup-xcode@v1 18 | with: 19 | xcode-version: ${{ matrix.xcode_version }} 20 | - run: xcodebuild -version 21 | - run: swift -version 22 | - run: swift test 23 | 24 | Linux: 25 | strategy: 26 | matrix: 27 | tag: ['5.8', '5.9', '5.10', '6.0'] 28 | runs-on: ubuntu-latest 29 | container: 30 | image: swift:${{ matrix.tag }} 31 | steps: 32 | - uses: actions/checkout@v3 33 | - run: swift test --parallel 34 | -------------------------------------------------------------------------------- /.github/workflows/xcodebuild.yml: -------------------------------------------------------------------------------- 1 | name: xcodebuild 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: ['*'] 8 | 9 | jobs: 10 | Xcode: 11 | strategy: 12 | matrix: 13 | xcode_version: ['15.3', '15.4', '16.1', '16.2'] 14 | runs-on: macos-14 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: maxim-lobanov/setup-xcode@v1 18 | with: 19 | xcode-version: ${{ matrix.xcode_version }} 20 | - run: xcodebuild -version 21 | - run: xcodebuild -scheme SourceKitten-Package -parallel-testing-enabled NO test -destination platform=macOS 22 | -------------------------------------------------------------------------------- /.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 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | .DS_Store 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 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 | .swiftpm/ 41 | 42 | # fastlane 43 | # 44 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 45 | # screenshots whenever they are needed. 46 | # For more information about the recommended setup visit: 47 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 48 | 49 | fastlane/report.xml 50 | fastlane/screenshots 51 | 52 | # SourceKitten 53 | 54 | SourceKitten.pkg 55 | SourceKittenFramework.framework.zip 56 | 57 | # Bazel 58 | 59 | bazel-* 60 | /MODULE.bazel.lock 61 | 62 | # vim 63 | .*.sw? 64 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Source 3 | - Tests 4 | excluded: 5 | - Source/SourceKittenFramework/library_wrapper_*.swift 6 | - Tests/SourceKittenFrameworkTests/Fixtures 7 | opt_in_rules: 8 | - array_init 9 | - attributes 10 | - closure_end_indentation 11 | - closure_spacing 12 | - collection_alignment 13 | - contains_over_first_not_nil 14 | - discouraged_optional_boolean 15 | - empty_count 16 | - explicit_init 17 | - first_where 18 | - identical_operands 19 | - joined_default_parameter 20 | - legacy_random 21 | - literal_expression_end_indentation 22 | - lower_acl_than_parent 23 | - modifier_order 24 | - number_separator 25 | - operator_usage_whitespace 26 | - overridden_super_call 27 | - pattern_matching_keywords 28 | - private_outlet 29 | - prohibited_super_call 30 | - redundant_nil_coalescing 31 | - redundant_type_annotation 32 | - sorted_first_last 33 | - sorted_imports 34 | - toggle_bool 35 | - unneeded_parentheses_in_closure_argument 36 | - yoda_condition 37 | disabled_rules: 38 | - force_cast 39 | - force_try 40 | - identifier_name 41 | - switch_case_on_newline 42 | - todo 43 | 44 | line_length: 160 45 | large_tuple: 4 46 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | "swift_binary" 5 | ) 6 | 7 | swift_library( 8 | name = "SourceKittenFramework", 9 | module_name = "SourceKittenFramework", 10 | srcs = ["//Source:SourceKittenFrameworkSources"], 11 | deps = [ 12 | "@sourcekitten_com_github_drmohundro_SWXMLHash//:SWXMLHash", 13 | "@sourcekitten_com_github_jpsim_yams//:Yams", 14 | "//Source:SourceKit", 15 | "//Source:Clang_C" 16 | ], 17 | defines = ["SWIFT_PACKAGE"], 18 | visibility = ["//visibility:public"] 19 | ) 20 | 21 | swift_binary( 22 | name = "sourcekitten", 23 | srcs = ["//Source:SourceKittenLibSources"], 24 | deps = [ 25 | ":SourceKittenFramework", 26 | "@sourcekitten_com_github_apple_swift_argument_parser//:ArgumentParser" 27 | ], 28 | defines = ["SWIFT_PACKAGE"], 29 | visibility = ["//visibility:public"] 30 | ) 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Tracking Changes 2 | 3 | All changes should be made via pull requests on GitHub. 4 | 5 | When issuing a pull request, please add a summary of your changes to 6 | the `CHANGELOG.md` file. 7 | 8 | We follow the same syntax as [CocoaPods' `CHANGELOG.md`](https://github.com/CocoaPods/CocoaPods/blob/master/CHANGELOG.md): 9 | 10 | 1. One Markdown unnumbered list item describing the change. 11 | 2. 2 trailing spaces on the last line describing the change. 12 | 3. A list of Markdown hyperlinks to the change's contributors. One entry 13 | per line. Usually just one. 14 | 4. A list of Markdown hyperlinks to the issues the change addresses. One entry 15 | per line. Usually just one. 16 | 5. All `CHANGELOG.md` content is hard-wrapped at 80 characters. 17 | -------------------------------------------------------------------------------- /Dangerfile: -------------------------------------------------------------------------------- 1 | # Warn when there is a big PR 2 | warn("Big PR") if git.lines_of_code > 500 3 | 4 | # Sometimes its a README fix, or something like that - which isn't relevant for 5 | # including in a CHANGELOG for example 6 | has_app_changes = !git.modified_files.grep(/Source/).empty? 7 | has_test_changes = !git.modified_files.grep(/Tests/).empty? 8 | 9 | # Add a CHANGELOG entry for app changes 10 | if !git.modified_files.include?("CHANGELOG.md") && has_app_changes 11 | fail("Please include a CHANGELOG entry. \nYou can find it at [CHANGELOG.md](https://github.com/jpsim/SourceKitten/blob/main/CHANGELOG.md).") 12 | message "Note, we hard-wrap at 80 chars and use 2 spaces after the last line." 13 | end 14 | 15 | # Non-trivial amounts of app changes without tests 16 | if git.lines_of_code > 50 && has_app_changes && !has_test_changes 17 | warn "This PR may need tests." 18 | end -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cocoapods' 4 | gem "jazzy" 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.1.3.2) 9 | base64 10 | bigdecimal 11 | concurrent-ruby (~> 1.0, >= 1.0.2) 12 | connection_pool (>= 2.2.5) 13 | drb 14 | i18n (>= 1.6, < 2) 15 | minitest (>= 5.1) 16 | mutex_m 17 | tzinfo (~> 2.0) 18 | addressable (2.8.6) 19 | public_suffix (>= 2.0.2, < 6.0) 20 | algoliasearch (1.27.5) 21 | httpclient (~> 2.8, >= 2.8.3) 22 | json (>= 1.5.1) 23 | atomos (0.1.3) 24 | base64 (0.2.0) 25 | bigdecimal (3.1.6) 26 | claide (1.1.0) 27 | cocoapods (1.15.2) 28 | addressable (~> 2.8) 29 | claide (>= 1.0.2, < 2.0) 30 | cocoapods-core (= 1.15.2) 31 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 32 | cocoapods-downloader (>= 2.1, < 3.0) 33 | cocoapods-plugins (>= 1.0.0, < 2.0) 34 | cocoapods-search (>= 1.0.0, < 2.0) 35 | cocoapods-trunk (>= 1.6.0, < 2.0) 36 | cocoapods-try (>= 1.1.0, < 2.0) 37 | colored2 (~> 3.1) 38 | escape (~> 0.0.4) 39 | fourflusher (>= 2.3.0, < 3.0) 40 | gh_inspector (~> 1.0) 41 | molinillo (~> 0.8.0) 42 | nap (~> 1.0) 43 | ruby-macho (>= 2.3.0, < 3.0) 44 | xcodeproj (>= 1.23.0, < 2.0) 45 | cocoapods-core (1.15.2) 46 | activesupport (>= 5.0, < 8) 47 | addressable (~> 2.8) 48 | algoliasearch (~> 1.0) 49 | concurrent-ruby (~> 1.1) 50 | fuzzy_match (~> 2.0.4) 51 | nap (~> 1.0) 52 | netrc (~> 0.11) 53 | public_suffix (~> 4.0) 54 | typhoeus (~> 1.0) 55 | cocoapods-deintegrate (1.0.5) 56 | cocoapods-downloader (2.1) 57 | cocoapods-plugins (1.0.0) 58 | nap 59 | cocoapods-search (1.0.1) 60 | cocoapods-trunk (1.6.0) 61 | nap (>= 0.8, < 2.0) 62 | netrc (~> 0.11) 63 | cocoapods-try (1.2.0) 64 | colored2 (3.1.2) 65 | concurrent-ruby (1.2.3) 66 | connection_pool (2.4.1) 67 | drb (2.2.0) 68 | ruby2_keywords 69 | escape (0.0.4) 70 | ethon (0.16.0) 71 | ffi (>= 1.15.0) 72 | ffi (1.16.3) 73 | fourflusher (2.3.1) 74 | fuzzy_match (2.0.4) 75 | gh_inspector (1.1.3) 76 | httpclient (2.8.3) 77 | i18n (1.14.1) 78 | concurrent-ruby (~> 1.0) 79 | jazzy (0.14.4) 80 | cocoapods (~> 1.5) 81 | mustache (~> 1.1) 82 | open4 (~> 1.3) 83 | redcarpet (~> 3.4) 84 | rexml (~> 3.2) 85 | rouge (>= 2.0.6, < 5.0) 86 | sassc (~> 2.1) 87 | sqlite3 (~> 1.3) 88 | xcinvoke (~> 0.3.0) 89 | json (2.7.1) 90 | liferaft (0.0.6) 91 | mini_portile2 (2.8.5) 92 | minitest (5.22.2) 93 | molinillo (0.8.0) 94 | mustache (1.1.1) 95 | mutex_m (0.2.0) 96 | nanaimo (0.3.0) 97 | nap (1.1.0) 98 | netrc (0.11.0) 99 | nkf (0.2.0) 100 | open4 (1.3.4) 101 | public_suffix (4.0.7) 102 | redcarpet (3.6.0) 103 | rexml (3.3.9) 104 | rouge (4.2.0) 105 | ruby-macho (2.5.1) 106 | ruby2_keywords (0.0.5) 107 | sassc (2.4.0) 108 | ffi (~> 1.9) 109 | sqlite3 (1.7.2) 110 | mini_portile2 (~> 2.8.0) 111 | typhoeus (1.4.1) 112 | ethon (>= 0.9.0) 113 | tzinfo (2.0.6) 114 | concurrent-ruby (~> 1.0) 115 | xcinvoke (0.3.0) 116 | liferaft (~> 0.0.6) 117 | xcodeproj (1.25.0) 118 | CFPropertyList (>= 2.3.3, < 4.0) 119 | atomos (~> 0.1.3) 120 | claide (>= 1.0.2, < 2.0) 121 | colored2 (~> 3.1) 122 | nanaimo (~> 0.3.0) 123 | rexml (>= 3.3.2, < 4.0) 124 | 125 | PLATFORMS 126 | ruby 127 | 128 | DEPENDENCIES 129 | cocoapods 130 | jazzy 131 | 132 | BUNDLED WITH 133 | 2.3.8 134 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "sourcekitten", 3 | version = "0.37.0", 4 | compatibility_level = 1, 5 | ) 6 | 7 | bazel_dep(name = "platforms", version = "0.0.8", dev_dependency = True) 8 | bazel_dep(name = "apple_support", version = "1.11.1", repo_name = "build_bazel_apple_support") 9 | bazel_dep(name = "rules_swift", version = "2.0.0", repo_name = "build_bazel_rules_swift") 10 | bazel_dep(name = "swift_argument_parser", version = "1.3.1.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") 11 | bazel_dep(name = "swxmlhash", version = "7.0.2.1", repo_name = "sourcekitten_com_github_drmohundro_SWXMLHash") 12 | bazel_dep(name = "yams", version = "5.1.3", repo_name = "sourcekitten_com_github_jpsim_yams") 13 | bazel_dep(name = "rules_cc", version = "0.0.2") 14 | 15 | apple_cc_configure = use_extension("@build_bazel_apple_support//crosstool:setup.bzl", "apple_cc_configure_extension") 16 | use_repo(apple_cc_configure, "local_config_apple_cc") 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TEMPORARY_FOLDER?=/tmp/SourceKitten.dst 2 | PREFIX?=/usr/local 3 | BUILD_TOOL?=xcodebuild 4 | 5 | XCODEFLAGS=-workspace 'SourceKitten.xcworkspace' \ 6 | -scheme 'sourcekitten' \ 7 | DSTROOT=$(TEMPORARY_FOLDER) \ 8 | OTHER_LDFLAGS=-Wl,-headerpad_max_install_names 9 | 10 | SWIFT_BUILD_FLAGS=--configuration release 11 | 12 | SOURCEKITTEN_EXECUTABLE=$(shell swift build $(SWIFT_BUILD_FLAGS) --show-bin-path)/sourcekitten 13 | 14 | FRAMEWORKS_FOLDER=$(PREFIX)/Frameworks 15 | BINARIES_FOLDER=$(PREFIX)/bin 16 | 17 | OUTPUT_PACKAGE=SourceKitten.pkg 18 | 19 | SOURCEKITTEN_PLIST=Source/sourcekitten/Info.plist 20 | SOURCEKITTENFRAMEWORK_PLIST=Source/SourceKittenFramework/Info.plist 21 | 22 | VERSION_STRING="$(shell ./script/get-version)" 23 | 24 | .PHONY: all clean install package test uninstall 25 | 26 | all: build 27 | 28 | test: clean_xcode 29 | $(BUILD_TOOL) $(XCODEFLAGS) test 30 | 31 | clean: 32 | rm -f "$(OUTPUT_PACKAGE)" 33 | rm -rf "$(TEMPORARY_FOLDER)" 34 | swift package clean 35 | 36 | clean_xcode: clean 37 | $(BUILD_TOOL) $(XCODEFLAGS) -configuration Test clean 38 | 39 | build: 40 | swift build $(SWIFT_BUILD_FLAGS) 41 | 42 | build_with_disable_sandbox: 43 | swift build --disable-sandbox $(SWIFT_BUILD_FLAGS) 44 | 45 | install: clean build 46 | install -d "$(BINARIES_FOLDER)" 47 | install "$(SOURCEKITTEN_EXECUTABLE)" "$(BINARIES_FOLDER)" 48 | 49 | uninstall: 50 | rm -rf "$(FRAMEWORKS_FOLDER)/SourceKittenFramework.framework" 51 | rm -f "$(BINARIES_FOLDER)/sourcekitten" 52 | 53 | installables: clean build 54 | install -d "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" 55 | install "$(SOURCEKITTEN_EXECUTABLE)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" 56 | 57 | prefix_install: clean build_with_disable_sandbox 58 | install -d "$(PREFIX)/bin/" 59 | install "$(SOURCEKITTEN_EXECUTABLE)" "$(PREFIX)/bin/" 60 | 61 | package: installables 62 | pkgbuild \ 63 | --identifier "com.sourcekitten.SourceKitten" \ 64 | --install-location "/" \ 65 | --root "$(TEMPORARY_FOLDER)" \ 66 | --version "$(VERSION_STRING)" \ 67 | "$(OUTPUT_PACKAGE)" 68 | 69 | release: package 70 | 71 | docker_test: 72 | docker run -v `pwd`:`pwd` -w `pwd` --name sourcekitten --rm swift:5.10-focal swift test --parallel 73 | 74 | docker_htop: 75 | docker run -it --rm --pid=container:sourcekitten terencewestphal/htop || reset 76 | 77 | # http://irace.me/swift-profiling/ 78 | display_compilation_time: 79 | $(BUILD_TOOL) $(XCODEFLAGS) OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" clean build-for-testing | grep -E ^[1-9]{1}[0-9]*.[0-9]+ms | sort -n 80 | 81 | publish: 82 | brew update && brew bump-formula-pr --tag=$(shell git describe --tags) --revision=$(shell git rev-parse HEAD) sourcekitten 83 | pod trunk push --verbose 84 | 85 | update_clang_headers: 86 | rm -rf Source/Clang_C/include 87 | svn export http://llvm.org/svn/llvm-project/cfe/trunk/include/clang-c 88 | mv clang-c Source/Clang_C/include 89 | rm Source/Clang_C/include/module.modulemap 90 | echo '#include "BuildSystem.h"\n#include "CXCompilationDatabase.h"\n#include "CXErrorCode.h"\n#include "CXString.h"\n#include "Documentation.h"\n#include "Index.h"\n#include "Platform.h"' > Source/Clang_C/include/Clang_C.h 91 | sed -i '' "s/^#include \"clang-c\/\(.*\)\"/#include \"\1\"/g" Source/Clang_C/include/* 92 | 93 | update_fixtures: update_fixtures_macos update_fixtures_docker 94 | 95 | update_fixtures_macos: 96 | for identifier in org.swift.50120190418a org.swift.5120190905a ; do \ 97 | swift package reset ; \ 98 | OVERWRITE_FIXTURES=1 xcrun --toolchain $$identifier swift test ; \ 99 | done 100 | 101 | update_fixtures_docker: 102 | for image in swift:5.2 swift:5.3; do \ 103 | swift package reset ; \ 104 | docker run -t -v `pwd`:`pwd` -w `pwd` --rm $$image env OVERWRITE_FIXTURES=1 swift test ; \ 105 | done 106 | 107 | get_version: 108 | @echo $(VERSION_STRING) 109 | 110 | set_version: 111 | $(eval NEW_VERSION := $(filter-out $@,$(MAKECMDGOALS))) 112 | @sed -i '' 's/## Main/## $(NEW_VERSION)/g' CHANGELOG.md 113 | @sed 's/__VERSION__/$(NEW_VERSION)/g' script/Version.swift.template > Source/SourceKittenFramework/Version.swift 114 | @sed -e '3s/.*/ version = "$(NEW_VERSION)",/' -i '' MODULE.bazel 115 | 116 | %: 117 | @: 118 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "swift-argument-parser", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/apple/swift-argument-parser.git", 7 | "state" : { 8 | "revision" : "46989693916f56d1186bd59ac15124caef896560", 9 | "version" : "1.3.1" 10 | } 11 | }, 12 | { 13 | "identity" : "swxmlhash", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/drmohundro/SWXMLHash.git", 16 | "state" : { 17 | "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", 18 | "version" : "7.0.2" 19 | } 20 | }, 21 | { 22 | "identity" : "yams", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/jpsim/Yams.git", 25 | "state" : { 26 | "revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76", 27 | "version" : "5.1.2" 28 | } 29 | } 30 | ], 31 | "version" : 2 32 | } 33 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.7 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "SourceKitten", 6 | platforms: [.macOS(.v12)], 7 | products: [ 8 | .executable(name: "sourcekitten", targets: ["sourcekitten"]), 9 | .library(name: "SourceKittenFramework", targets: ["SourceKittenFramework"]) 10 | ], 11 | dependencies: [ 12 | .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), 13 | .package(url: "https://github.com/drmohundro/SWXMLHash.git", from: "7.0.2"), 14 | .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.5"), 15 | ], 16 | targets: [ 17 | .executableTarget( 18 | name: "sourcekitten", 19 | dependencies: [ 20 | .product(name: "ArgumentParser", package: "swift-argument-parser"), 21 | "SourceKittenFramework", 22 | ] 23 | ), 24 | .target( 25 | name: "Clang_C" 26 | ), 27 | .target( 28 | name: "SourceKit" 29 | ), 30 | .target( 31 | name: "SourceKittenFramework", 32 | dependencies: [ 33 | "Clang_C", 34 | "SourceKit", 35 | .product(name: "SWXMLHash", package: "SWXMLHash"), 36 | .product(name: "Yams", package: "Yams"), 37 | ] 38 | ), 39 | .testTarget( 40 | name: "SourceKittenFrameworkTests", 41 | dependencies: [ 42 | "SourceKittenFramework" 43 | ], 44 | exclude: [ 45 | "Fixtures", 46 | ] 47 | ) 48 | ] 49 | ) 50 | -------------------------------------------------------------------------------- /Releasing.md: -------------------------------------------------------------------------------- 1 | # Releasing SourceKitten 2 | 3 | For SourceKitten contributors, follow these steps to cut a release: 4 | 5 | 1. Update version number: `make set_version 0.6.2` 6 | 2. Come up with a witty feline themed release name. Past names include: 7 | * Objective-Cat 8 | * Cat-astrophic 9 | * SourceClangKitLibKitten 10 | * Grumpy Cat 11 | 3. Commit & push to the `main` branch. 12 | 4. Tag: `git tag -a 0.6.2 -m "0.6.2: Objective-Cat"; git push origin 0.6.2` 13 | 5. Make sure you have the latest stable Xcode version installed and 14 | `xcode-select`ed. 15 | 6. Create the pkg installer: `make release` 16 | 7. Create a GitHub release: https://github.com/jpsim/SourceKitten/releases/new 17 | * Specify the tag you just pushed from the dropdown. 18 | * Set the release title to the new version number & release name. 19 | * Add the changelog section to the release description text box. 20 | * Upload the pkg installer you just built to the GitHub 21 | release binaries. 22 | * Click "Publish release". 23 | 8. Publish to Homebrew and CocoaPods trunk: `make publish` 24 | -------------------------------------------------------------------------------- /Source/BUILD: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift_interop_hint.bzl", "swift_interop_hint") 2 | load("@rules_cc//cc:defs.bzl", "cc_library") 3 | 4 | exports_files(glob(["SourceKittenFramework/**/*.swift"])) 5 | 6 | cc_library( 7 | name = "Clang_CLibrary", 8 | hdrs = glob( 9 | ["Clang_C/**/*.h"], 10 | allow_empty = False, 11 | ), 12 | visibility = ["//visibility:public"], 13 | ) 14 | 15 | cc_library( 16 | name = "Clang_C", 17 | aspect_hints = [":Clang_C_SwiftInterop"], 18 | visibility = ["//visibility:public"], 19 | deps = [":Clang_CLibrary"], 20 | ) 21 | 22 | swift_interop_hint( 23 | name = "Clang_C_SwiftInterop", 24 | module_map = "Clang_C/Clang_C.modulemap", 25 | module_name = "Clang_C", 26 | ) 27 | 28 | cc_library( 29 | name = "SourceKitLibrary", 30 | hdrs = glob( 31 | ["SourceKit/**/*.h"], 32 | allow_empty = False, 33 | ), 34 | visibility = ["//visibility:public"], 35 | ) 36 | 37 | cc_library( 38 | name = "SourceKit", 39 | aspect_hints = [":SourceKit_SwiftInterop"], 40 | visibility = ["//visibility:public"], 41 | deps = [":SourceKitLibrary"], 42 | ) 43 | 44 | swift_interop_hint( 45 | name = "SourceKit_SwiftInterop", 46 | module_map = "SourceKit/SourceKit.modulemap", 47 | module_name = "SourceKit", 48 | ) 49 | 50 | filegroup( 51 | name = "SourceKittenFrameworkSources", 52 | srcs = glob( 53 | ["SourceKittenFramework/**/*.swift"], 54 | allow_empty = False, 55 | ), 56 | visibility = ["//visibility:public"], 57 | ) 58 | 59 | filegroup( 60 | name = "SourceKittenLibSources", 61 | srcs = glob( 62 | ["sourcekitten/**/*.swift"], 63 | allow_empty = False, 64 | ), 65 | visibility = ["//visibility:public"], 66 | ) 67 | -------------------------------------------------------------------------------- /Source/Clang_C/Clang_C.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/SourceKitten/68e9472d9e39360ddb53a76fa8fc9718a336cdd5/Source/Clang_C/Clang_C.c -------------------------------------------------------------------------------- /Source/Clang_C/Clang_C.modulemap: -------------------------------------------------------------------------------- 1 | module Clang_C { 2 | header "include/Clang_C.h" 3 | } 4 | -------------------------------------------------------------------------------- /Source/Clang_C/include/CXErrorCode.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/CXErrorCode.h - C Index Error Codes --------------*- C -*-===*\ 2 | |* *| 3 | |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| 4 | |* Exceptions. *| 5 | |* See https://llvm.org/LICENSE.txt for license information. *| 6 | |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| 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 | #include "Platform.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * 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 | * No error. 32 | */ 33 | CXError_Success = 0, 34 | 35 | /** 36 | * 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 | * libclang crashed while performing the requested operation. 45 | */ 46 | CXError_Crashed = 2, 47 | 48 | /** 49 | * The function detected that the arguments violate the function 50 | * contract. 51 | */ 52 | CXError_InvalidArguments = 3, 53 | 54 | /** 55 | * An AST deserialization error has occurred. 56 | */ 57 | CXError_ASTReadError = 4 58 | }; 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /Source/Clang_C/include/CXString.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/CXString.h - C Index strings --------------------*- C -*-===*\ 2 | |* *| 3 | |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| 4 | |* Exceptions. *| 5 | |* See https://llvm.org/LICENSE.txt for license information. *| 6 | |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| 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 | #include "Platform.h" 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 | * 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 | typedef struct { 44 | CXString *Strings; 45 | unsigned Count; 46 | } CXStringSet; 47 | 48 | /** 49 | * Retrieve the character data associated with the given string. 50 | */ 51 | CINDEX_LINKAGE const char *clang_getCString(CXString string); 52 | 53 | /** 54 | * Free the given string. 55 | */ 56 | CINDEX_LINKAGE void clang_disposeString(CXString string); 57 | 58 | /** 59 | * Free the given string set. 60 | */ 61 | CINDEX_LINKAGE void clang_disposeStringSet(CXStringSet *set); 62 | 63 | /** 64 | * @} 65 | */ 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /Source/Clang_C/include/Clang_C.h: -------------------------------------------------------------------------------- 1 | #include "BuildSystem.h" 2 | #include "CXCompilationDatabase.h" 3 | #include "CXErrorCode.h" 4 | #include "CXString.h" 5 | #include "Documentation.h" 6 | #include "Index.h" 7 | #include "Platform.h" 8 | -------------------------------------------------------------------------------- /Source/Clang_C/include/Platform.h: -------------------------------------------------------------------------------- 1 | /*===-- clang-c/Platform.h - C Index platform decls -------------*- C -*-===*\ 2 | |* *| 3 | |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| 4 | |* Exceptions. *| 5 | |* See https://llvm.org/LICENSE.txt for license information. *| 6 | |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| 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 | -------------------------------------------------------------------------------- /Source/SourceKit/SourceKit.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/SourceKitten/68e9472d9e39360ddb53a76fa8fc9718a336cdd5/Source/SourceKit/SourceKit.c -------------------------------------------------------------------------------- /Source/SourceKit/SourceKit.modulemap: -------------------------------------------------------------------------------- 1 | module SourceKit { 2 | header "include/sourcekitd.h" 3 | } 4 | -------------------------------------------------------------------------------- /Source/SourceKit/include/SourceKit.h: -------------------------------------------------------------------------------- 1 | #include "sourcekitd.h" -------------------------------------------------------------------------------- /Source/SourceKittenFramework/ByteCount.swift: -------------------------------------------------------------------------------- 1 | /// Represents the number of bytes in a string. Could be used to model offsets into a string, or the distance between 2 | /// two locations in a string. 3 | public struct ByteCount: ExpressibleByIntegerLiteral, Hashable { 4 | /// The byte value as an integer. 5 | public var value: Int 6 | 7 | /// Create a byte count by its integer value. 8 | /// 9 | /// - parameter value: Integer value. 10 | public init(integerLiteral value: Int) { 11 | self.value = value 12 | } 13 | 14 | /// Create a byte count by its integer value. 15 | /// 16 | /// - parameter value: Integer value. 17 | public init(_ value: Int) { 18 | self.value = value 19 | } 20 | 21 | /// Create a byte count by its integer value. 22 | /// 23 | /// - parameter value: Integer value. 24 | public init(_ value: Int64) { 25 | self.value = Int(value) 26 | } 27 | } 28 | 29 | extension ByteCount: CustomStringConvertible { 30 | public var description: String { 31 | return value.description 32 | } 33 | } 34 | 35 | extension ByteCount: Comparable { 36 | public static func < (lhs: ByteCount, rhs: ByteCount) -> Bool { 37 | return lhs.value < rhs.value 38 | } 39 | } 40 | 41 | extension ByteCount: AdditiveArithmetic { 42 | public static func - (lhs: ByteCount, rhs: ByteCount) -> ByteCount { 43 | return ByteCount(lhs.value - rhs.value) 44 | } 45 | 46 | public static func -= (lhs: inout ByteCount, rhs: ByteCount) { 47 | lhs.value -= rhs.value 48 | } 49 | 50 | public static func + (lhs: ByteCount, rhs: ByteCount) -> ByteCount { 51 | return ByteCount(lhs.value + rhs.value) 52 | } 53 | 54 | public static func += (lhs: inout ByteCount, rhs: ByteCount) { 55 | lhs.value += rhs.value 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/ByteRange.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Structure that represents a string range in bytes. 4 | public struct ByteRange: Equatable { 5 | /// The starting location of the range. 6 | public let location: ByteCount 7 | 8 | /// The length of the range. 9 | public let length: ByteCount 10 | 11 | /// Creates a byte range from a location and a length. 12 | /// 13 | /// - parameter location: The starting location of the range. 14 | /// - parameter length: The length of the range. 15 | public init(location: ByteCount, length: ByteCount) { 16 | self.location = location 17 | self.length = length 18 | } 19 | 20 | /// The range's upper bound. 21 | public var upperBound: ByteCount { 22 | return location + length 23 | } 24 | 25 | /// The range's lower bound. 26 | public var lowerBound: ByteCount { 27 | return location 28 | } 29 | 30 | public func contains(_ value: ByteCount) -> Bool { 31 | return location <= value && upperBound > value 32 | } 33 | 34 | public func intersects(_ otherRange: ByteRange) -> Bool { 35 | return contains(otherRange.lowerBound) || 36 | contains(otherRange.upperBound - 1) || 37 | otherRange.contains(lowerBound) || 38 | otherRange.contains(upperBound - 1) 39 | } 40 | 41 | public func intersects(_ ranges: [ByteRange]) -> Bool { 42 | return ranges.contains { intersects($0) } 43 | } 44 | 45 | public func union(with otherRange: ByteRange) -> ByteRange { 46 | let maxUpperBound = max(upperBound, otherRange.upperBound) 47 | let minLocation = min(location, otherRange.location) 48 | return ByteRange(location: minLocation, length: maxUpperBound - minLocation) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/ClangTranslationUnit.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | 3 | #if SWIFT_PACKAGE 4 | import Clang_C 5 | #endif 6 | import Foundation 7 | 8 | extension Sequence where Iterator.Element: Hashable { 9 | fileprivate func distinct() -> [Iterator.Element] { 10 | return Array(Set(self)) 11 | } 12 | } 13 | 14 | extension Sequence { 15 | fileprivate func grouped(by transform: (Iterator.Element) -> U) -> [U: [Iterator.Element]] { 16 | return reduce([:]) { dictionary, element in 17 | var dictionary = dictionary 18 | let key = transform(element) 19 | dictionary[key] = (dictionary[key] ?? []) + [element] 20 | return dictionary 21 | } 22 | } 23 | } 24 | 25 | extension Dictionary { 26 | fileprivate init(_ pairs: [Element]) { 27 | self.init() 28 | for (key, value) in pairs { 29 | self[key] = value 30 | } 31 | } 32 | 33 | fileprivate func map(transform: (Value) throws -> (OutValue)) rethrows -> [Key: OutValue] { 34 | return [Key: OutValue](try map { ($0.key, try transform($0.value)) }) 35 | } 36 | } 37 | 38 | /// Represents a group of CXTranslationUnits. 39 | public struct ClangTranslationUnit { 40 | /// Array of CXTranslationUnits. 41 | private let clangTranslationUnits: [CXTranslationUnit] 42 | 43 | public let declarations: [String: [SourceDeclaration]] 44 | 45 | /** 46 | Create a ClangTranslationUnit by passing Objective-C header files and clang compiler arguments. 47 | 48 | - parameter headerFiles: Objective-C header files to document. 49 | - parameter compilerArguments: Clang compiler arguments. 50 | */ 51 | public init(headerFiles: [String], compilerArguments: [String]) { 52 | let cStringCompilerArguments = compilerArguments.map { ($0 as NSString).utf8String } 53 | let clangIndex = ClangIndex() 54 | clangTranslationUnits = headerFiles.map { clangIndex.open(file: $0, args: cStringCompilerArguments) } 55 | declarations = clangTranslationUnits 56 | .flatMap { $0.cursor().compactMap({ SourceDeclaration(cursor: $0, compilerArguments: compilerArguments) }) } 57 | .rejectEmptyDuplicateEnums() 58 | .distinct() 59 | .sorted() 60 | .grouped { $0.location.file } 61 | .map { insertMarks(declarations: $0) } 62 | } 63 | 64 | /** 65 | Failable initializer to create a ClangTranslationUnit by passing Objective-C header files and 66 | `xcodebuild` arguments. Optionally pass in a `path`. 67 | 68 | - parameter headerFiles: Objective-C header files to document. 69 | - parameter xcodeBuildArguments: The arguments necessary pass in to `xcodebuild` to link these header files. 70 | - parameter path: Path to run `xcodebuild` from. Uses current path by default. 71 | */ 72 | public init?(headerFiles: [String], xcodeBuildArguments: [String], inPath path: String = FileManager.default.currentDirectoryPath) { 73 | let xcodeBuildOutput = XcodeBuild.cleanBuild(arguments: xcodeBuildArguments + ["-dry-run"], inPath: path).string ?? "" 74 | guard let clangArguments = parseCompilerArguments(xcodebuildOutput: xcodeBuildOutput, language: .objc, moduleName: nil) else { 75 | fputs("could not parse compiler arguments\n\(xcodeBuildOutput)\n", stderr) 76 | return nil 77 | } 78 | self.init(headerFiles: headerFiles, compilerArguments: clangArguments) 79 | } 80 | } 81 | 82 | // MARK: CustomStringConvertible 83 | 84 | extension ClangTranslationUnit: CustomStringConvertible { 85 | /// A textual JSON representation of `ClangTranslationUnit`. 86 | public var description: String { 87 | return declarationsToJSON(declarations) + "\n" 88 | } 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/CodeCompletionItem.swift: -------------------------------------------------------------------------------- 1 | fileprivate extension Dictionary { 2 | mutating func addIfNotNil(_ key: Key, _ value: Value?) { 3 | if let value = value { 4 | self[key] = value 5 | } 6 | } 7 | } 8 | 9 | public struct CodeCompletionItem: CustomStringConvertible { 10 | public let kind: String 11 | public let context: String 12 | public let name: String? 13 | public let descriptionKey: String? 14 | public let sourcetext: String? 15 | public let typeName: String? 16 | public let moduleName: String? 17 | public let docBrief: String? 18 | public let associatedUSRs: String? 19 | public let numBytesToErase: Int64? 20 | 21 | /// Dictionary representation of CodeCompletionItem. Useful for NSJSONSerialization. 22 | public var dictionaryValue: [String: Any] { 23 | var dict: [String: Any] = ["kind": kind, "context": context] 24 | dict.addIfNotNil("name", name) 25 | dict.addIfNotNil("descriptionKey", descriptionKey) 26 | dict.addIfNotNil("sourcetext", sourcetext) 27 | dict.addIfNotNil("typeName", typeName) 28 | dict.addIfNotNil("moduleName", moduleName) 29 | dict.addIfNotNil("docBrief", docBrief) 30 | dict.addIfNotNil("associatedUSRs", associatedUSRs) 31 | dict.addIfNotNil("numBytesToErase", numBytesToErase) 32 | return dict 33 | } 34 | 35 | public var description: String { 36 | return toJSON(dictionaryValue.bridge()) 37 | } 38 | 39 | public static func parse(response: [String: SourceKitRepresentable]) -> [CodeCompletionItem] { 40 | return (response["key.results"] as! [SourceKitRepresentable]).map { item in 41 | let dict = item as! [String: SourceKitRepresentable] 42 | return CodeCompletionItem(kind: dict["key.kind"] as! String, 43 | context: dict["key.context"] as! String, 44 | name: dict["key.name"] as? String, 45 | descriptionKey: dict["key.description"] as? String, 46 | sourcetext: dict["key.sourcetext"] as? String, 47 | typeName: dict["key.typename"] as? String, 48 | moduleName: dict["key.modulename"] as? String, 49 | docBrief: dict["key.doc.brief"] as? String, 50 | associatedUSRs: dict["key.associated_usrs"] as? String, 51 | numBytesToErase: dict["key.num_bytes_to_erase"] as? Int64) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/CursorInfo+Parsing.swift: -------------------------------------------------------------------------------- 1 | import SWXMLHash 2 | 3 | public extension Dictionary where Key == String, Value == SourceKitRepresentable { 4 | var referencedUSRs: [String] { 5 | if let usr = self["key.usr"] as? String, 6 | let kind = self["key.kind"] as? String, 7 | kind.contains("source.lang.swift.ref") { 8 | if let relatedDecls = self["key.related_decls"] as? [[String: SourceKitRepresentable]] { 9 | return [usr] + relatedDecls.compactMap { ($0["key.annotated_decl"] as? String)?.relatedNameUSR } 10 | } else { 11 | return [usr] 12 | } 13 | } 14 | 15 | return [] 16 | } 17 | } 18 | 19 | private extension String { 20 | var relatedNameUSR: String? { 21 | return XMLHash.parse(self)["RelatedName"].element?.value(ofAttribute: "usr") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Dictionary+Merge.swift: -------------------------------------------------------------------------------- 1 | /** 2 | Returns a new dictionary by adding the entries of dict2 into dict1, overriding if the key exists. 3 | 4 | - parameter dict1: Dictionary to merge into. 5 | - parameter dict2: Dictionary to merge from (optional). 6 | 7 | - returns: A new dictionary by adding the entries of dict2 into dict1, overriding if the key exists. 8 | */ 9 | internal func merge(_ dict1: [K: V], _ dict2: [K: V]?) -> [K: V] { 10 | var mergedDict = dict1 11 | if let dict2 = dict2 { 12 | for (key, value) in dict2 { 13 | mergedDict[key] = value 14 | } 15 | } 16 | return mergedDict 17 | } 18 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Documentation.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | 3 | #if SWIFT_PACKAGE 4 | import Clang_C 5 | #endif 6 | 7 | public struct Documentation { 8 | public let parameters: [Parameter] 9 | public let returnDiscussion: [Text] 10 | 11 | init(comment: CXComment) { 12 | let comments = (0.. Results { 43 | return run(command, arguments, currentDirectory: currentDirectory, stderr: stderr) 44 | } 45 | 46 | /** 47 | Run a command with arguments and return its output and exit status. 48 | 49 | - parameter command: Absolute path of the command to run. 50 | - parameter arguments: Arguments to pass to the command. 51 | - parameter currentDirectory: Current directory for the command. By default 52 | the parent process's current directory. 53 | - parameter stderr: What to do with stderr output from the command. By default 54 | whatever the parent process does. 55 | */ 56 | static func run(_ command: String, 57 | _ arguments: [String] = [], 58 | currentDirectory: String = FileManager.default.currentDirectoryPath, 59 | stderr: Stderr = .inherit) -> Results { 60 | let process = Process() 61 | process.arguments = arguments 62 | 63 | let pipe = Pipe() 64 | process.standardOutput = pipe 65 | 66 | switch stderr { 67 | case .discard: 68 | // FileHandle.nullDevice does not work here, as it consists of an invalid file descriptor, 69 | // causing process.launch() to abort with an EBADF. 70 | process.standardError = FileHandle(forWritingAtPath: "/dev/null")! 71 | case .merge: 72 | process.standardError = pipe 73 | case .inherit: 74 | break 75 | } 76 | 77 | do { 78 | #if canImport(Darwin) && !targetEnvironment(macCatalyst) 79 | if #available(macOS 10.13, *) { 80 | process.executableURL = URL(fileURLWithPath: command) 81 | process.currentDirectoryURL = URL(fileURLWithPath: currentDirectory) 82 | try process.run() 83 | } else { 84 | process.launchPath = command 85 | process.currentDirectoryPath = currentDirectory 86 | process.launch() 87 | } 88 | #else 89 | process.executableURL = URL(fileURLWithPath: command) 90 | process.currentDirectoryURL = URL(fileURLWithPath: currentDirectory) 91 | try process.run() 92 | #endif 93 | } catch { 94 | return Results(terminationStatus: -1, data: Data()) 95 | } 96 | 97 | let file = pipe.fileHandleForReading 98 | let data = file.readDataToEndOfFile() 99 | process.waitUntilExit() 100 | return Results(terminationStatus: process.terminationStatus, data: data) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/File+Hashable.swift: -------------------------------------------------------------------------------- 1 | extension File: Hashable { 2 | public static func == (lhs: File, rhs: File) -> Bool { 3 | switch (lhs.path, rhs.path) { 4 | case let (.some(lhsPath), .some(rhsPath)): 5 | return lhsPath == rhsPath 6 | case (.none, .none): 7 | return lhs.contents == rhs.contents 8 | default: 9 | return false 10 | } 11 | } 12 | 13 | public func hash(into hasher: inout Hasher) { 14 | hasher.combine(path ?? contents) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Language.swift: -------------------------------------------------------------------------------- 1 | /// Language Enum. 2 | public enum Language { 3 | /// Swift. 4 | case swift 5 | /// Objective-C. 6 | case objc 7 | } 8 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Line.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Representation of a single line in a larger String. 4 | public struct Line { 5 | /// origin = 0. 6 | public let index: Int 7 | /// Content. 8 | public let content: String 9 | /// UTF16 based range in entire String. Equivalent to `Range`. 10 | public let range: NSRange 11 | /// Byte based range in entire String. Equivalent to `Range`. 12 | public let byteRange: ByteRange 13 | } 14 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/LinuxCompatibility.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array { 4 | public func bridge() -> NSArray { 5 | return self as NSArray 6 | } 7 | } 8 | 9 | extension CharacterSet { 10 | public func bridge() -> NSCharacterSet { 11 | return self as NSCharacterSet 12 | } 13 | } 14 | 15 | extension Dictionary { 16 | public func bridge() -> NSDictionary { 17 | return self as NSDictionary 18 | } 19 | } 20 | 21 | extension NSString { 22 | public func bridge() -> String { 23 | return self as String 24 | } 25 | } 26 | 27 | extension String { 28 | public func bridge() -> NSString { 29 | return self as NSString 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/ObjCDeclarationKind.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | 3 | #if SWIFT_PACKAGE 4 | import Clang_C 5 | #endif 6 | 7 | /** 8 | Objective-C declaration kinds. 9 | More or less equivalent to `SwiftDeclarationKind`, but with made up values because there's no such 10 | thing as SourceKit for Objective-C. 11 | */ 12 | public enum ObjCDeclarationKind: String { 13 | /// `category`. 14 | case category = "sourcekitten.source.lang.objc.decl.category" 15 | /// `class`. 16 | case `class` = "sourcekitten.source.lang.objc.decl.class" 17 | /// `constant`. 18 | case constant = "sourcekitten.source.lang.objc.decl.constant" 19 | /// `enum`. 20 | case `enum` = "sourcekitten.source.lang.objc.decl.enum" 21 | /// `enumcase`. 22 | case enumcase = "sourcekitten.source.lang.objc.decl.enumcase" 23 | /// `initializer`. 24 | case initializer = "sourcekitten.source.lang.objc.decl.initializer" 25 | /// `method.class`. 26 | case methodClass = "sourcekitten.source.lang.objc.decl.method.class" 27 | /// `method.instance`. 28 | case methodInstance = "sourcekitten.source.lang.objc.decl.method.instance" 29 | /// `property`. 30 | case property = "sourcekitten.source.lang.objc.decl.property" 31 | /// `protocol`. 32 | case `protocol` = "sourcekitten.source.lang.objc.decl.protocol" 33 | /// `typedef`. 34 | case typedef = "sourcekitten.source.lang.objc.decl.typedef" 35 | /// `function`. 36 | case function = "sourcekitten.source.lang.objc.decl.function" 37 | /// `mark`. 38 | case mark = "sourcekitten.source.lang.objc.mark" 39 | /// `struct` 40 | case `struct` = "sourcekitten.source.lang.objc.decl.struct" 41 | /// `union` 42 | case `union` = "sourcekitten.source.lang.objc.decl.union" 43 | /// `field` 44 | case field = "sourcekitten.source.lang.objc.decl.field" 45 | /// `ivar` 46 | case ivar = "sourcekitten.source.lang.objc.decl.ivar" 47 | /// `ModuleImport` 48 | case moduleImport = "sourcekitten.source.lang.objc.module.import" 49 | /// `UnexposedDecl` 50 | case unexposedDecl = "sourcekitten.source.lang.objc.decl.unexposed" 51 | /// `static_assert` 52 | case staticAssert = "sourcekitten.source.lang.objc.decl.static_assert" 53 | 54 | // swiftlint:disable:next cyclomatic_complexity 55 | public init(_ cursorKind: CXCursorKind) { 56 | switch cursorKind { 57 | case CXCursor_ObjCCategoryDecl: self = .category 58 | case CXCursor_ObjCInterfaceDecl: self = .class 59 | case CXCursor_EnumDecl: self = .enum 60 | case CXCursor_EnumConstantDecl: self = .enumcase 61 | case CXCursor_ObjCClassMethodDecl: self = .methodClass 62 | case CXCursor_ObjCInstanceMethodDecl: self = .methodInstance 63 | case CXCursor_ObjCPropertyDecl: self = .property 64 | case CXCursor_ObjCProtocolDecl: self = .protocol 65 | case CXCursor_TypedefDecl: self = .typedef 66 | case CXCursor_VarDecl: self = .constant 67 | case CXCursor_FunctionDecl: self = .function 68 | case CXCursor_StructDecl: self = .struct 69 | case CXCursor_UnionDecl: self = .union 70 | case CXCursor_FieldDecl: self = .field 71 | case CXCursor_ObjCIvarDecl: self = .ivar 72 | case CXCursor_ModuleImportDecl: self = .moduleImport 73 | case CXCursor_UnexposedDecl: self = .unexposedDecl 74 | case CXCursor_ObjCImplementationDecl: self = .class 75 | case CXCursor_ObjCCategoryImplDecl: self = .category 76 | case CXCursor_ObjCDynamicDecl: self = .unexposedDecl 77 | case CXCursor_ObjCSynthesizeDecl: self = .unexposedDecl 78 | case CXCursor_StaticAssert: self = .staticAssert 79 | default: fatalError("Unsupported CXCursorKind: \(clang_getCursorKindSpelling(cursorKind))") 80 | } 81 | } 82 | } 83 | #endif 84 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/OffsetMap.swift: -------------------------------------------------------------------------------- 1 | /// Type that maps potentially documented declaration offsets to its closest parent offset. 2 | public typealias OffsetMap = [ByteCount: ByteCount] 3 | 4 | /// File methods to generate and manipulate OffsetMap's. 5 | extension File { 6 | /** 7 | Creates an OffsetMap containing offset locations at which there are declarations that likely 8 | have documentation comments, but haven't been documented by SourceKitten yet. 9 | 10 | - parameter documentedTokenOffsets: Offsets where there are declarations that likely 11 | have documentation comments. 12 | - parameter dictionary: Docs dictionary to check for which offsets are already 13 | documented. 14 | 15 | - returns: 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 | public func makeOffsetMap(documentedTokenOffsets: [ByteCount], dictionary: [String: SourceKitRepresentable]) -> OffsetMap { 19 | var offsetMap = OffsetMap() 20 | for offset in documentedTokenOffsets { 21 | offsetMap[offset] = 0 22 | } 23 | offsetMap = mapOffsets(dictionary, offsetMap: offsetMap) 24 | let alreadyDocumentedOffsets = offsetMap.filter({ $0.0 == $0.1 }).map { $0.0 } 25 | for alreadyDocumentedOffset in alreadyDocumentedOffsets { 26 | offsetMap.removeValue(forKey: alreadyDocumentedOffset) 27 | } 28 | return offsetMap 29 | } 30 | 31 | /** 32 | Creates a new OffsetMap that matches all offsets in the offsetMap parameter's keys to its 33 | nearest, currently documented parent offset. 34 | 35 | - parameter dictionary: Already documented dictionary. 36 | - parameter offsetMap: Dictionary mapping potentially documented offsets to its nearest parent 37 | offset. 38 | 39 | - returns: OffsetMap of potentially documented declaration offsets to its nearest parent offset. 40 | */ 41 | private func mapOffsets(_ dictionary: [String: SourceKitRepresentable], offsetMap: OffsetMap) -> OffsetMap { 42 | var offsetMap = offsetMap 43 | if let rangeStart = SwiftDocKey.getNameOffset(dictionary), 44 | let rangeLength = SwiftDocKey.getNameLength(dictionary) { 45 | let bodyLength = SwiftDocKey.getBodyLength(dictionary) ?? 0 46 | let rangeMax = rangeStart + rangeLength + bodyLength 47 | let offsetsInRange = offsetMap.keys.filter { 48 | $0 >= rangeStart && $0 <= rangeMax 49 | } 50 | for offset in offsetsInRange { 51 | offsetMap[offset] = rangeStart 52 | } 53 | } 54 | // Recurse! 55 | if let substructure = SwiftDocKey.getSubstructure(dictionary) { 56 | for subDict in substructure { 57 | offsetMap = mapOffsets(subDict, offsetMap: offsetMap) 58 | } 59 | } 60 | return offsetMap 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Parameter.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | 3 | #if SWIFT_PACKAGE 4 | import Clang_C 5 | #endif 6 | 7 | public struct Parameter { 8 | public let name: String 9 | public let discussion: [Text] 10 | 11 | init(comment: CXComment) { 12 | name = comment.paramName() ?? "" 13 | discussion = comment.paragraph().paragraphToString() 14 | } 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SourceKittenFramework.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for SourceKittenFramework. 4 | FOUNDATION_EXPORT double SourceKittenFrameworkVersionNumber; 5 | 6 | //! Project version string for SourceKittenFramework. 7 | FOUNDATION_EXPORT const unsigned char SourceKittenFrameworkVersionString[]; 8 | 9 | // In this header, you should import all the public headers of your framework using statements like #import 10 | 11 | // Ideally this would be in a bridging header, but due to rdar://17633863, we can't have nice things. 12 | // TODO: use clang-c's modulemap instead. 13 | #import 14 | #import 15 | #import 16 | #import 17 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SourceLocation.swift: -------------------------------------------------------------------------------- 1 | #if !os(Linux) 2 | 3 | #if SWIFT_PACKAGE 4 | import Clang_C 5 | #endif 6 | import Foundation 7 | 8 | public struct SourceLocation: Comparable { 9 | public let file: String 10 | public let line: UInt32 11 | public let column: UInt32 12 | public let offset: UInt32 13 | 14 | public func range(toEnd end: SourceLocation) -> ByteRange { 15 | guard end.offset > offset else { 16 | return ByteRange(location: 0, length: 0) 17 | } 18 | return ByteRange(location: ByteCount(Int(offset)), length: ByteCount(Int(end.offset - offset))) 19 | } 20 | 21 | /// A [strict total order](http://en.wikipedia.org/wiki/Total_order#Strict_total_order) 22 | /// over instances of `Self`. 23 | public static func < (lhs: SourceLocation, rhs: SourceLocation) -> Bool { 24 | // Sort by file path. 25 | switch lhs.file.compare(rhs.file) { 26 | case .orderedDescending: 27 | return false 28 | case .orderedAscending: 29 | return true 30 | case .orderedSame: 31 | break 32 | } 33 | 34 | // Then offset. 35 | return lhs.offset < rhs.offset 36 | } 37 | } 38 | 39 | extension SourceLocation { 40 | init(clangLocation: CXSourceLocation) { 41 | var cxfile: CXFile? 42 | var line: UInt32 = 0 43 | var column: UInt32 = 0 44 | var offset: UInt32 = 0 45 | clang_getSpellingLocation(clangLocation, &cxfile, &line, &column, &offset) 46 | self.init(file: clang_getFileName(cxfile).str() ?? "", 47 | line: line, column: column, offset: offset) 48 | } 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/StatementKind.swift: -------------------------------------------------------------------------------- 1 | /// Swift declaration kinds. 2 | /// Found in `strings SourceKitService | grep source.lang.swift.stmt.`. 3 | public enum StatementKind: String { 4 | /// `brace`. 5 | case brace = "source.lang.swift.stmt.brace" 6 | /// `case`. 7 | case `case` = "source.lang.swift.stmt.case" 8 | /// `for`. 9 | case `for` = "source.lang.swift.stmt.for" 10 | /// `foreach`. 11 | case forEach = "source.lang.swift.stmt.foreach" 12 | /// `guard`. 13 | case `guard` = "source.lang.swift.stmt.guard" 14 | /// `if`. 15 | case `if` = "source.lang.swift.stmt.if" 16 | /// `repeatewhile`. 17 | case repeatWhile = "source.lang.swift.stmt.repeatwhile" 18 | /// `switch`. 19 | case `switch` = "source.lang.swift.stmt.switch" 20 | /// `while`. 21 | case `while` = "source.lang.swift.stmt.while" 22 | } 23 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/StringView+SourceKitten.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension StringView { 4 | /** 5 | Returns whether or not the `token` can be documented. Either because it is a 6 | `SyntaxKind.Identifier` or because it is a function treated as a `SyntaxKind.Keyword`: 7 | 8 | - `subscript` 9 | - `init` 10 | - `deinit` 11 | 12 | - parameter token: Token to process. 13 | */ 14 | func isTokenDocumentable(token: SyntaxToken) -> Bool { 15 | if token.type == SyntaxKind.keyword.rawValue { 16 | let keywordFunctions = ["subscript", "init", "deinit"] 17 | return substringWithByteRange(token.range) 18 | .map(keywordFunctions.contains) ?? false 19 | } 20 | return token.type == SyntaxKind.identifier.rawValue 21 | } 22 | 23 | #if !os(Linux) 24 | /// Returns the `#pragma mark`s in the string. 25 | /// Just the content; no leading dashes or leading `#pragma mark`. 26 | func pragmaMarks(filename: String, excludeRanges: [NSRange], limit: NSRange?) -> [SourceDeclaration] { 27 | let regex = try! NSRegularExpression(pattern: "(#pragma\\smark|@name)[ -]*([^\\n]+)", options: []) // Safe to force try 28 | let range: NSRange 29 | if let limit = limit { 30 | range = NSRange(location: limit.location, length: min(utf16View.count - limit.location, limit.length)) 31 | } else { 32 | range = NSRange(location: 0, length: utf16View.count) 33 | } 34 | let matches = regex.matches(in: string, options: [], range: range) 35 | 36 | return matches.compactMap { match in 37 | let markRange = match.range(at: 2) 38 | for excludedRange in excludeRanges where NSIntersectionRange(excludedRange, markRange).length > 0 { 39 | return nil 40 | } 41 | let markString = nsString.substring(with: markRange).trimmingCharacters(in: .whitespaces) 42 | if markString.isEmpty { 43 | return nil 44 | } 45 | guard let markByteRange = self.NSRangeToByteRange(start: markRange.location, length: markRange.length) else { 46 | return nil 47 | } 48 | let location = SourceLocation(file: filename, 49 | line: UInt32(lineRangeWithByteRange(ByteRange(location: markByteRange.location, length: 0))!.start), 50 | column: 1, offset: UInt32(markByteRange.location.value)) 51 | return SourceDeclaration(type: .mark, location: location, extent: (location, location), name: markString, 52 | usr: nil, declaration: nil, documentation: nil, commentBody: nil, children: [], 53 | annotations: nil, swiftDeclaration: nil, swiftName: nil, availability: nil) 54 | } 55 | } 56 | #endif 57 | 58 | /** 59 | Find integer offsets of documented Swift tokens in self. 60 | 61 | - parameter syntaxMap: Syntax Map returned from SourceKit editor.open request. 62 | 63 | - returns: Array of documented token offsets. 64 | */ 65 | func documentedTokenOffsets(syntaxMap: SyntaxMap) -> [ByteCount] { 66 | let documentableOffsets = syntaxMap.tokens.filter(isTokenDocumentable).map { 67 | $0.offset 68 | } 69 | 70 | let regex = try! NSRegularExpression(pattern: "(///.*\\n|\\*/\\n)", options: []) // Safe to force try 71 | let range = NSRange(location: 0, length: string.utf16.count) 72 | let matches = regex.matches(in: string, options: [], range: range) 73 | 74 | return matches.compactMap { match in 75 | return NSRangeToByteRange(match.range) 76 | } 77 | .compactMap { byteRange in 78 | documentableOffsets.first { $0 >= byteRange.location } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Structure.swift: -------------------------------------------------------------------------------- 1 | /// Represents the structural information in a Swift source file. 2 | public struct Structure { 3 | /// Structural information as an [String: SourceKitRepresentable]. 4 | public let dictionary: [String: SourceKitRepresentable] 5 | 6 | /** 7 | Create a Structure from a SourceKit `editor.open` response. 8 | 9 | - parameter sourceKitResponse: SourceKit `editor.open` response. 10 | */ 11 | public init(sourceKitResponse: [String: SourceKitRepresentable]) { 12 | var sourceKitResponse = sourceKitResponse 13 | _ = sourceKitResponse.removeValue(forKey: SwiftDocKey.syntaxMap.rawValue) 14 | dictionary = sourceKitResponse 15 | } 16 | 17 | /** 18 | Initialize a Structure by passing in a File. 19 | 20 | - parameter file: File to parse for structural information. 21 | - throws: Request.Error 22 | */ 23 | public init(file: File) throws { 24 | self.init(sourceKitResponse: try Request.editorOpen(file: file).send()) 25 | } 26 | } 27 | 28 | // MARK: CustomStringConvertible 29 | 30 | extension Structure: CustomStringConvertible { 31 | /// A textual JSON representation of `Structure`. 32 | public var description: String { return toJSON(toNSDictionary(dictionary)) } 33 | } 34 | 35 | // MARK: Equatable 36 | 37 | extension Structure: Equatable {} 38 | 39 | /** 40 | Returns true if `lhs` Structure is equal to `rhs` Structure. 41 | 42 | - parameter lhs: Structure to compare to `rhs`. 43 | - parameter rhs: Structure to compare to `lhs`. 44 | 45 | - returns: True if `lhs` Structure is equal to `rhs` Structure. 46 | */ 47 | public func == (lhs: Structure, rhs: Structure) -> Bool { 48 | return lhs.dictionary.isEqualTo(rhs.dictionary) 49 | } 50 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SwiftDeclarationKind.swift: -------------------------------------------------------------------------------- 1 | /// Swift declaration kinds. 2 | /// Found in `strings SourceKitService | grep source.lang.swift.decl.`. 3 | public enum SwiftDeclarationKind: String, CaseIterable { 4 | /// `associatedtype`. 5 | case `associatedtype` = "source.lang.swift.decl.associatedtype" 6 | /// `class`. 7 | case `class` = "source.lang.swift.decl.class" 8 | /// `enum`. 9 | case `enum` = "source.lang.swift.decl.enum" 10 | /// `enumcase`. 11 | case enumcase = "source.lang.swift.decl.enumcase" 12 | /// `enumelement`. 13 | case enumelement = "source.lang.swift.decl.enumelement" 14 | /// `extension`. 15 | case `extension` = "source.lang.swift.decl.extension" 16 | /// `extension.class`. 17 | case extensionClass = "source.lang.swift.decl.extension.class" 18 | /// `extension.enum`. 19 | case extensionEnum = "source.lang.swift.decl.extension.enum" 20 | /// `extension.protocol`. 21 | case extensionProtocol = "source.lang.swift.decl.extension.protocol" 22 | /// `extension.struct`. 23 | case extensionStruct = "source.lang.swift.decl.extension.struct" 24 | /// `function.accessor.address`. 25 | case functionAccessorAddress = "source.lang.swift.decl.function.accessor.address" 26 | /// `function.accessor.didset`. 27 | case functionAccessorDidset = "source.lang.swift.decl.function.accessor.didset" 28 | /// `function.accessor.getter`. 29 | case functionAccessorGetter = "source.lang.swift.decl.function.accessor.getter" 30 | // `function.accessor.modify` 31 | // @available(swift, introduced: 5.0) 32 | case functionAccessorModify = "source.lang.swift.decl.function.accessor.modify" 33 | /// `function.accessor.mutableaddress`. 34 | case functionAccessorMutableaddress = "source.lang.swift.decl.function.accessor.mutableaddress" 35 | // `function.accessor.read` 36 | // @available(swift, introduced: 5.0) 37 | case functionAccessorRead = "source.lang.swift.decl.function.accessor.read" 38 | /// `function.accessor.setter`. 39 | case functionAccessorSetter = "source.lang.swift.decl.function.accessor.setter" 40 | /// `function.accessor.willset`. 41 | case functionAccessorWillset = "source.lang.swift.decl.function.accessor.willset" 42 | /// `function.constructor`. 43 | case functionConstructor = "source.lang.swift.decl.function.constructor" 44 | /// `function.destructor`. 45 | case functionDestructor = "source.lang.swift.decl.function.destructor" 46 | /// `function.free`. 47 | case functionFree = "source.lang.swift.decl.function.free" 48 | /// `function.method.class`. 49 | case functionMethodClass = "source.lang.swift.decl.function.method.class" 50 | /// `function.method.instance`. 51 | case functionMethodInstance = "source.lang.swift.decl.function.method.instance" 52 | /// `function.method.static`. 53 | case functionMethodStatic = "source.lang.swift.decl.function.method.static" 54 | // `function.operator`. 55 | // @available(swift, obsoleted: 2.2) 56 | case functionOperator = "source.lang.swift.decl.function.operator" 57 | /// `function.operator.infix`. 58 | case functionOperatorInfix = "source.lang.swift.decl.function.operator.infix" 59 | /// `function.operator.postfix`. 60 | case functionOperatorPostfix = "source.lang.swift.decl.function.operator.postfix" 61 | /// `function.operator.prefix`. 62 | case functionOperatorPrefix = "source.lang.swift.decl.function.operator.prefix" 63 | /// `function.subscript`. 64 | case functionSubscript = "source.lang.swift.decl.function.subscript" 65 | /// `generic_type_param`. 66 | case genericTypeParam = "source.lang.swift.decl.generic_type_param" 67 | /// `module`. 68 | case module = "source.lang.swift.decl.module" 69 | /// `opaquetype`. 70 | case opaqueType = "source.lang.swift.decl.opaquetype" 71 | /// `precedencegroup`. 72 | case precedenceGroup = "source.lang.swift.decl.precedencegroup" 73 | /// `protocol`. 74 | case `protocol` = "source.lang.swift.decl.protocol" 75 | /// `struct`. 76 | case `struct` = "source.lang.swift.decl.struct" 77 | /// `typealias`. 78 | case `typealias` = "source.lang.swift.decl.typealias" 79 | /// `var.class`. 80 | case varClass = "source.lang.swift.decl.var.class" 81 | /// `var.global`. 82 | case varGlobal = "source.lang.swift.decl.var.global" 83 | /// `var.instance`. 84 | case varInstance = "source.lang.swift.decl.var.instance" 85 | /// `var.local`. 86 | case varLocal = "source.lang.swift.decl.var.local" 87 | /// `var.parameter`. 88 | case varParameter = "source.lang.swift.decl.var.parameter" 89 | /// `var.static`. 90 | case varStatic = "source.lang.swift.decl.var.static" 91 | /// `actor`. 92 | case actor = "source.lang.swift.decl.actor" 93 | /// `macro` 94 | case macro = "source.lang.swift.decl.macro" 95 | /// `function.accessor.init` 96 | case functionAccessorInit = "source.lang.swift.decl.function.accessor.init" 97 | } 98 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SwiftDocs.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if SWIFT_PACKAGE 4 | import SourceKit 5 | #endif 6 | 7 | #if os(macOS) 8 | import Darwin 9 | #elseif os(Linux) 10 | #if canImport(Glibc) 11 | import Glibc 12 | #elseif canImport(Musl) 13 | import Musl 14 | #endif 15 | #elseif os(Windows) 16 | import ucrt 17 | #else 18 | #error("Unsupported platform") 19 | #endif 20 | 21 | /// Represents docs for a Swift file. 22 | public struct SwiftDocs { 23 | /// Documented File. 24 | public let file: File 25 | 26 | /// Docs information as an [String: SourceKitRepresentable]. 27 | public let docsDictionary: [String: SourceKitRepresentable] 28 | 29 | /** 30 | Create docs for the specified Swift file and compiler arguments. 31 | 32 | - parameter file: Swift file to document. 33 | - parameter arguments: compiler arguments to pass to SourceKit. 34 | */ 35 | public init?(file: File, arguments: [String]) { 36 | do { 37 | self.init( 38 | file: file, 39 | dictionary: try Request.editorOpen(file: file).send(), 40 | cursorInfoRequest: Request.cursorInfoRequest(filePath: file.path, arguments: arguments) 41 | ) 42 | } catch let error as Request.Error { 43 | fputs(error.description, stderr) 44 | return nil 45 | } catch { 46 | return nil 47 | } 48 | } 49 | 50 | /** 51 | Create docs for the specified Swift file, editor.open SourceKit response and cursor info request. 52 | 53 | - parameter file: Swift file to document. 54 | - parameter dictionary: editor.open response from SourceKit. 55 | - parameter cursorInfoRequest: SourceKit dictionary to use to send cursorinfo request. 56 | */ 57 | public init(file: File, dictionary: [String: SourceKitRepresentable], cursorInfoRequest: SourceKitObject?) { 58 | self.file = file 59 | var dictionary = dictionary 60 | let syntaxMapData = dictionary.removeValue(forKey: SwiftDocKey.syntaxMap.rawValue) as! [SourceKitRepresentable] 61 | let syntaxMap = SyntaxMap(data: syntaxMapData) 62 | dictionary = file.process(dictionary: dictionary, cursorInfoRequest: cursorInfoRequest, syntaxMap: syntaxMap) 63 | if let cursorInfoRequest = cursorInfoRequest { 64 | let documentedTokenOffsets = file.stringView.documentedTokenOffsets(syntaxMap: syntaxMap) 65 | dictionary = file.furtherProcess( 66 | dictionary: dictionary, 67 | documentedTokenOffsets: documentedTokenOffsets, 68 | cursorInfoRequest: cursorInfoRequest, 69 | syntaxMap: syntaxMap 70 | ) 71 | } 72 | docsDictionary = file.addDocComments(dictionary: dictionary, syntaxMap: syntaxMap) 73 | } 74 | } 75 | 76 | // MARK: CustomStringConvertible 77 | 78 | extension SwiftDocs: CustomStringConvertible { 79 | /// A textual JSON representation of `SwiftDocs`. 80 | public var description: String { 81 | let source: String 82 | if let path = file.path { 83 | source = URL(fileURLWithPath: path).standardizedFileURL.withUnsafeFileSystemRepresentation { 84 | String(cString: $0!) 85 | } 86 | } else { 87 | source = "" 88 | } 89 | return toJSON(toNSDictionary([source: docsDictionary])) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SwiftVersion.swift: -------------------------------------------------------------------------------- 1 | /// The version triple of the Swift compiler, for example "5.1.3" 2 | struct SwiftVersion: RawRepresentable, Comparable { 3 | typealias RawValue = String 4 | 5 | let rawValue: String 6 | 7 | /// Comparable 8 | static func < (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool { 9 | return lhs.rawValue < rhs.rawValue 10 | } 11 | } 12 | 13 | extension SwiftVersion { 14 | static let beforeFiveDotOne = SwiftVersion(rawValue: "1.0.0") 15 | static let fiveDotOne = SwiftVersion(rawValue: "5.1.0") 16 | 17 | /// The version of the Swift compiler providing SourceKit. Accurate only from 18 | /// compiler version 5.1.0: earlier versions return `.beforeFiveDotOne`. 19 | static let current: SwiftVersion = { 20 | if let result = try? Request.compilerVersion.send(), 21 | let major = result["key.version_major"] as? Int64, 22 | let minor = result["key.version_minor"] as? Int64, 23 | let patch = result["key.version_patch"] as? Int64 { 24 | return SwiftVersion(rawValue: "\(major).\(minor).\(patch)") 25 | } 26 | return .beforeFiveDotOne 27 | }() 28 | } 29 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SyntaxKind.swift: -------------------------------------------------------------------------------- 1 | /// Syntax kind values. 2 | /// Found in `strings SourceKitService | grep source.lang.swift.syntaxtype.`. 3 | public enum SyntaxKind: String, CaseIterable { 4 | /// `argument`. 5 | case argument = "source.lang.swift.syntaxtype.argument" 6 | /// `attribute.builtin`. 7 | case attributeBuiltin = "source.lang.swift.syntaxtype.attribute.builtin" 8 | /// `attribute.id`. 9 | case attributeID = "source.lang.swift.syntaxtype.attribute.id" 10 | /// `buildconfig.id`. 11 | case buildconfigID = "source.lang.swift.syntaxtype.buildconfig.id" 12 | /// `buildconfig.keyword`. 13 | case buildconfigKeyword = "source.lang.swift.syntaxtype.buildconfig.keyword" 14 | /// `comment`. 15 | case comment = "source.lang.swift.syntaxtype.comment" 16 | /// `comment.mark`. 17 | case commentMark = "source.lang.swift.syntaxtype.comment.mark" 18 | /// `comment.url`. 19 | case commentURL = "source.lang.swift.syntaxtype.comment.url" 20 | /// `doccomment`. 21 | case docComment = "source.lang.swift.syntaxtype.doccomment" 22 | /// `doccomment.field`. 23 | case docCommentField = "source.lang.swift.syntaxtype.doccomment.field" 24 | /// `identifier`. 25 | case identifier = "source.lang.swift.syntaxtype.identifier" 26 | /// `keyword`. 27 | case keyword = "source.lang.swift.syntaxtype.keyword" 28 | /// `number`. 29 | case number = "source.lang.swift.syntaxtype.number" 30 | /// `objectliteral` 31 | case objectLiteral = "source.lang.swift.syntaxtype.objectliteral" 32 | /// `parameter`. 33 | case parameter = "source.lang.swift.syntaxtype.parameter" 34 | /// `placeholder`. 35 | case placeholder = "source.lang.swift.syntaxtype.placeholder" 36 | /// `string`. 37 | case string = "source.lang.swift.syntaxtype.string" 38 | /// `string_interpolation_anchor`. 39 | case stringInterpolationAnchor = "source.lang.swift.syntaxtype.string_interpolation_anchor" 40 | /// `typeidentifier`. 41 | case typeidentifier = "source.lang.swift.syntaxtype.typeidentifier" 42 | /// `pounddirective.keyword`. 43 | case poundDirectiveKeyword = "source.lang.swift.syntaxtype.pounddirective.keyword" 44 | /// `operator` 45 | case `operator` = "source.lang.swift.syntaxtype.operator" 46 | 47 | /// Returns the valid documentation comment syntax kinds. 48 | internal static func docComments() -> [SyntaxKind] { 49 | return [.commentURL, .docComment, .docCommentField] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SyntaxMap.swift: -------------------------------------------------------------------------------- 1 | /// Represents a Swift file's syntax information. 2 | public struct SyntaxMap { 3 | /// Array of SyntaxToken's. 4 | public let tokens: [SyntaxToken] 5 | 6 | /** 7 | Create a SyntaxMap by passing in tokens directly. 8 | 9 | - parameter tokens: Array of SyntaxToken's. 10 | */ 11 | public init(tokens: [SyntaxToken]) { 12 | self.tokens = tokens 13 | } 14 | 15 | /** 16 | Create a SyntaxMap by passing in NSData from a SourceKit `editor.open` response to be parsed. 17 | 18 | - parameter data: NSData from a SourceKit `editor.open` response 19 | */ 20 | public init(data: [SourceKitRepresentable]) { 21 | tokens = data.map { item in 22 | let dict = item as! [String: SourceKitRepresentable] 23 | return SyntaxToken(type: dict["key.kind"] as! String, offset: ByteCount(dict["key.offset"] as! Int64), 24 | length: ByteCount(dict["key.length"] as! Int64)) 25 | } 26 | } 27 | 28 | /** 29 | Create a SyntaxMap from a SourceKit `editor.open` response. 30 | 31 | - parameter sourceKitResponse: SourceKit `editor.open` response. 32 | */ 33 | public init(sourceKitResponse: [String: SourceKitRepresentable]) { 34 | self.init(data: SwiftDocKey.getSyntaxMap(sourceKitResponse)!) 35 | } 36 | 37 | /** 38 | Create a SyntaxMap from a File to be parsed. 39 | 40 | - parameter file: File to be parsed. 41 | - throws: Request.Error 42 | */ 43 | public init(file: File) throws { 44 | self.init(sourceKitResponse: try Request.editorOpen(file: file).send()) 45 | } 46 | } 47 | 48 | // MARK: Support for enumerating doc-comment blocks 49 | 50 | extension SyntaxToken { 51 | /// Is this a doc comment? 52 | internal var isDocComment: Bool { 53 | return SyntaxKind.docComments().contains { $0.rawValue == type } 54 | } 55 | } 56 | 57 | extension SyntaxMap { 58 | /// The ranges of documentation comments described by the map, in the order 59 | /// that they occur in the file. 60 | internal var docCommentRanges: [ByteRange] { 61 | let docCommentBlocks = tokens.split { !$0.isDocComment } 62 | return docCommentBlocks.compactMap { ranges in 63 | ranges.first.flatMap { first in 64 | ranges.last.flatMap { last -> ByteRange? in 65 | ByteRange(location: first.offset, length: last.offset + last.length - first.offset) 66 | } 67 | } 68 | } 69 | } 70 | 71 | /** 72 | A tool to distribute doc comments between declarations. 73 | A new instance covers a single complete pass of the file. 74 | The `getRangeForDeclaration(atOffset:)` method should be called with the file's 75 | declaration offsets in order to retrieve the most appropriate doc comment for each. 76 | */ 77 | internal final class DocCommentFinder { 78 | /// Remaining doc comments that have not been assigned or skipped 79 | private var ranges: [ByteRange] 80 | /// The most recent file offset requested 81 | private var previousOffset: ByteCount? 82 | 83 | /// Create a new doc comment finder from a `SyntaxMap`. 84 | internal init(syntaxMap: SyntaxMap) { 85 | self.ranges = syntaxMap.docCommentRanges 86 | self.previousOffset = nil 87 | } 88 | 89 | /// Get the byte range of the declaration's doc comment, or nil if none. 90 | internal func getRangeForDeclaration(atOffset offset: ByteCount) -> ByteRange? { 91 | if let previousOffset = previousOffset { 92 | guard offset > previousOffset else { return nil } 93 | } 94 | 95 | let commentsBeforeDecl = ranges.prefix { $0.upperBound < offset } 96 | ranges.replaceSubrange(0.. DocCommentFinder { 104 | return DocCommentFinder(syntaxMap: self) 105 | } 106 | } 107 | 108 | // MARK: CustomStringConvertible 109 | 110 | extension SyntaxMap: CustomStringConvertible { 111 | /// A textual JSON representation of `SyntaxMap`. 112 | public var description: String { 113 | return toJSON(tokens.map { $0.dictionaryValue }) 114 | } 115 | } 116 | 117 | // MARK: Equatable 118 | 119 | extension SyntaxMap: Equatable {} 120 | 121 | /** 122 | Returns true if `lhs` SyntaxMap is equal to `rhs` SyntaxMap. 123 | 124 | - parameter lhs: SyntaxMap to compare to `rhs`. 125 | - parameter rhs: SyntaxMap to compare to `lhs`. 126 | 127 | - returns: True if `lhs` SyntaxMap is equal to `rhs` SyntaxMap. 128 | */ 129 | public func == (lhs: SyntaxMap, rhs: SyntaxMap) -> Bool { 130 | if lhs.tokens.count != rhs.tokens.count { 131 | return false 132 | } 133 | for (index, value) in lhs.tokens.enumerated() where rhs.tokens[index] != value { 134 | return false 135 | } 136 | return true 137 | } 138 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/SyntaxToken.swift: -------------------------------------------------------------------------------- 1 | /// Represents a single Swift syntax token. 2 | public struct SyntaxToken { 3 | /// Token type. See SyntaxKind. 4 | public let type: String 5 | /// Token offset. 6 | public let offset: ByteCount 7 | /// Token length. 8 | public let length: ByteCount 9 | 10 | /// Dictionary representation of SyntaxToken. Useful for NSJSONSerialization. 11 | public var dictionaryValue: [String: Any] { 12 | return ["type": type, "offset": offset.value, "length": length.value] 13 | } 14 | 15 | /** 16 | Create a SyntaxToken by directly passing in its property values. 17 | 18 | - parameter type: Token type. See SyntaxKind. 19 | - parameter offset: Token offset. 20 | - parameter length: Token length. 21 | */ 22 | public init(type: String, offset: ByteCount, length: ByteCount) { 23 | self.type = SyntaxKind(rawValue: type)?.rawValue ?? type 24 | self.offset = offset 25 | self.length = length 26 | } 27 | 28 | /// Byte range of this token 29 | public var range: ByteRange { 30 | return ByteRange(location: offset, length: length) 31 | } 32 | } 33 | 34 | // MARK: Equatable 35 | 36 | extension SyntaxToken: Equatable {} 37 | 38 | /** 39 | Returns true if `lhs` SyntaxToken is equal to `rhs` SyntaxToken. 40 | 41 | - parameter lhs: SyntaxToken to compare to `rhs`. 42 | - parameter rhs: SyntaxToken to compare to `lhs`. 43 | 44 | - returns: True if `lhs` SyntaxToken is equal to `rhs` SyntaxToken. 45 | */ 46 | public func == (lhs: SyntaxToken, rhs: SyntaxToken) -> Bool { 47 | return (lhs.type == rhs.type) && (lhs.offset == rhs.offset) && (lhs.length == rhs.length) 48 | } 49 | 50 | // MARK: CustomStringConvertible 51 | 52 | extension SyntaxToken: CustomStringConvertible { 53 | /// A textual JSON representation of `SyntaxToken`. 54 | public var description: String { return toJSON(dictionaryValue.bridge()) } 55 | } 56 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Text.swift: -------------------------------------------------------------------------------- 1 | public enum Text { 2 | case para(String, String?) 3 | case verbatim(String) 4 | } 5 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/UID.swift: -------------------------------------------------------------------------------- 1 | #if SWIFT_PACKAGE 2 | import SourceKit 3 | #endif 4 | 5 | /// Swift representation of sourcekitd_uid_t 6 | public struct UID: Hashable { 7 | let sourcekitdUID: sourcekitd_uid_t 8 | init(_ uid: sourcekitd_uid_t) { 9 | self.sourcekitdUID = uid 10 | } 11 | 12 | public init(_ string: String) { 13 | self.init(sourcekitd_uid_get_from_cstr(string)!) 14 | } 15 | 16 | public init(_ rawRepresentable: T) where T: RawRepresentable, T.RawValue == String { 17 | self.init(rawRepresentable.rawValue) 18 | } 19 | 20 | var string: String { 21 | return String(cString: sourcekitd_uid_get_string_ptr(sourcekitdUID)!) 22 | } 23 | } 24 | 25 | extension UID: CustomStringConvertible { 26 | public var description: String { 27 | return string 28 | } 29 | } 30 | 31 | extension UID: ExpressibleByStringLiteral { 32 | public init(stringLiteral value: String) { 33 | self.init(value) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/UIDRepresentable.swift: -------------------------------------------------------------------------------- 1 | public protocol UIDRepresentable { 2 | var uid: UID { get } 3 | } 4 | 5 | extension UID: UIDRepresentable { 6 | public var uid: UID { 7 | return self 8 | } 9 | } 10 | 11 | extension String: UIDRepresentable { 12 | public var uid: UID { 13 | return UID(self) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/UncheckedSendable.swift: -------------------------------------------------------------------------------- 1 | struct UncheckedSendable: @unchecked Sendable { 2 | /// The unchecked value. 3 | var value: Value 4 | 5 | /// Initializes unchecked sendability around a value. 6 | /// 7 | /// - Parameter value: A value to make sendable in an unchecked way. 8 | init(_ value: Value) { 9 | self.value = value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/Version.swift: -------------------------------------------------------------------------------- 1 | public struct Version { 2 | public let value: String 3 | 4 | public static let current = Version(value: "0.37.0") 5 | } 6 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/WindowsError.swift: -------------------------------------------------------------------------------- 1 | #if os(Windows) 2 | import WinSDK 3 | 4 | #if !os(Windows) 5 | // Shims for !windows SourceKit - see LibraryWrapperGeneratorTests.testLibraryWrappersAreUpToDate 6 | private typealias WORD = UInt 7 | private typealias DWORD = WORD 8 | private typealias WCHAR = WORD 9 | private let FORMAT_MESSAGE_ALLOCATE_BUFFER = 0 10 | private let FORMAT_MESSAGE_FROM_SYSTEM = 0 11 | private let FORMAT_MESSAGE_IGNORE_INSERTS = 0 12 | 13 | // swiftlint:disable:next function_parameter_count 14 | private func FormatMessageW(_ a: DWORD, _ b: Int?, _ c: DWORD, _ d: DWORD, _ e: Any?, _ f: Int, _ g: Int?) -> DWORD { 0 } 15 | #endif 16 | 17 | @_transparent 18 | internal func MAKELANGID(_ p: WORD, _ s: WORD) -> DWORD { 19 | return DWORD((s << 10) | p) 20 | } 21 | 22 | struct WindowsError { 23 | let code: DWORD 24 | } 25 | 26 | extension WindowsError: Error { 27 | var localizedDescription: String { 28 | let dwFlags = DWORD(FORMAT_MESSAGE_ALLOCATE_BUFFER) 29 | | DWORD(FORMAT_MESSAGE_FROM_SYSTEM) 30 | | DWORD(FORMAT_MESSAGE_IGNORE_INSERTS) 31 | let dwLanguageId: DWORD = 32 | MAKELANGID(WORD(LANG_NEUTRAL), WORD(SUBLANG_DEFAULT)) 33 | 34 | var buffer: UnsafeMutablePointer? 35 | let dwResult = withUnsafeMutablePointer(to: &buffer) { 36 | $0.withMemoryRebound(to: WCHAR.self, capacity: 2) { 37 | FormatMessageW(dwFlags, nil, code, dwLanguageId, $0, 0, nil) 38 | } 39 | } 40 | guard dwResult > 0, let message = buffer else { return "Unknown error" } 41 | defer { LocalFree(message) } 42 | return String(decodingCString: message, as: UTF16.self) 43 | } 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /Source/SourceKittenFramework/XcodeBuildSetting.swift: -------------------------------------------------------------------------------- 1 | @dynamicMemberLookup 2 | struct XcodeBuildSetting: Codable { 3 | 4 | /// The build settings. 5 | let buildSettings: [String: String] 6 | 7 | subscript(dynamicMember member: String) -> String? { 8 | return buildSettings[member] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Source/sourcekitten/Complete.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SourceKittenFramework 4 | 5 | extension SourceKitten { 6 | struct Complete: ParsableCommand { 7 | static let configuration = CommandConfiguration(abstract: "Generate code completion options") 8 | 9 | @Option(help: "Relative or absolute path of Swift file to parse") 10 | var file = "" 11 | @Option(help: "Swift code text to parse") 12 | var text = "" 13 | @Option(help: "Offset for which to generate code completion options") 14 | var offset = 0 15 | @Option(help: "Read compiler flags from a Swift Package Manager module") 16 | var spmModule = "" 17 | @Flag(help: "Prettify output") 18 | var prettify = false 19 | @Flag(help: "Sort keys in output") 20 | @available(macOS 10.13, *) 21 | var sortKeys = false 22 | @Argument(help: "Compiler arguments to pass to SourceKit") 23 | var compilerargs: [String] 24 | 25 | mutating func run() throws { 26 | let path: String 27 | let contents: String 28 | if !file.isEmpty { 29 | path = file.bridge().absolutePathRepresentation() 30 | guard let file = File(path: path) else { 31 | throw SourceKittenError.readFailed(path: path) 32 | } 33 | contents = file.contents 34 | } else { 35 | path = "\(NSUUID().uuidString).swift" 36 | contents = text 37 | } 38 | 39 | var args: [String] 40 | if spmModule.isEmpty { 41 | args = ["-c", path] + compilerargs 42 | if args.contains("-sdk") { 43 | args.append(contentsOf: ["-sdk", sdkPath()]) 44 | } 45 | } else { 46 | guard let module = Module(spmName: spmModule) else { 47 | throw SourceKittenError.invalidArgument(description: "Bad module name") 48 | } 49 | args = module.compilerArguments 50 | } 51 | 52 | let request = SourceKittenFramework.Request.codeCompletionRequest(file: path, contents: contents, 53 | offset: ByteCount(offset), 54 | arguments: args) 55 | let completionItems = CodeCompletionItem.parse(response: try request.send()) 56 | 57 | var outputOptions: JSONSerialization.WritingOptions = [] 58 | outputOptions.insert(prettify ? .prettyPrinted : []) 59 | if #available(macOS 10.13, *) { 60 | outputOptions.insert(sortKeys ? .sortedKeys : []) 61 | } 62 | print(toJSON(completionItems.map { $0.dictionaryValue.bridge() }, options: outputOptions)) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/sourcekitten/Doc.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SourceKittenFramework 4 | 5 | extension SourceKitten { 6 | struct Doc: ParsableCommand { 7 | static let configuration = CommandConfiguration(abstract: "Print Swift or Objective-C docs as JSON") 8 | 9 | @Flag(help: "Only document one file") 10 | var singleFile = false 11 | @Option(help: "Name of Swift module to document (can't be used with `--single-file`)") 12 | var moduleName = "" 13 | @Flag(help: "Document a Swift Package Manager module") 14 | var spm = false 15 | @Flag(help: "Document Objective-C headers instead of Swift code") 16 | var objc = false 17 | @Argument(help: "Arguments passed to `xcodebuild` or `swift build`") 18 | var arguments: [String] = [] 19 | 20 | mutating func run() throws { 21 | let moduleName = self.moduleName.isEmpty ? nil : self.moduleName 22 | 23 | if spm { 24 | if let docs = Module(spmArguments: arguments, spmName: moduleName)?.docs { 25 | print(docs) 26 | return 27 | } 28 | throw SourceKittenError.docFailed 29 | } else if objc { 30 | #if os(Linux) 31 | fatalError("unsupported") 32 | #else 33 | if arguments.isEmpty { 34 | throw SourceKittenError.invalidArgument( 35 | description: "at least 5 arguments are required when using `--objc`" 36 | ) 37 | } 38 | let translationUnit = ClangTranslationUnit(headerFiles: [arguments[0]], 39 | compilerArguments: Array(arguments.dropFirst(1))) 40 | print(translationUnit) 41 | return 42 | #endif 43 | } else if singleFile { 44 | if arguments.isEmpty { 45 | throw SourceKittenError.invalidArgument( 46 | description: "at least 5 arguments are required when using `--single-file`" 47 | ) 48 | } 49 | let sourcekitdArguments = Array(arguments.dropFirst(1)) 50 | if let file = File(path: arguments[0]), 51 | let docs = SwiftDocs(file: file, arguments: sourcekitdArguments) { 52 | print(docs) 53 | return 54 | } 55 | throw SourceKittenError.readFailed(path: arguments[0]) 56 | } 57 | 58 | let module = Module(xcodeBuildArguments: arguments, name: moduleName) 59 | if let docs = module?.docs { 60 | print(docs) 61 | return 62 | } 63 | throw SourceKittenError.docFailed 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/sourcekitten/Errors.swift: -------------------------------------------------------------------------------- 1 | /// Possible errors within SourceKitten. 2 | enum SourceKittenError: Error, CustomStringConvertible { 3 | /// One or more argument was invalid. 4 | case invalidArgument(description: String) 5 | 6 | /// Failed to read a file at the given path. 7 | case readFailed(path: String) 8 | 9 | /// Failed to generate documentation. 10 | case docFailed 11 | 12 | /// failed with Error 13 | case failed(Swift.Error) 14 | 15 | /// An error message corresponding to this error. 16 | var description: String { 17 | switch self { 18 | case let .invalidArgument(description): 19 | return description 20 | case let .readFailed(path): 21 | return "Failed to read file at '\(path)'" 22 | case .docFailed: 23 | return "Failed to generate documentation" 24 | case let .failed(error): 25 | return error.localizedDescription 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/sourcekitten/Format.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SourceKittenFramework 4 | 5 | extension SourceKitten { 6 | struct Format: ParsableCommand { 7 | static let configuration = CommandConfiguration(abstract: "Format Swift file") 8 | 9 | @Option(help: "Relative or absolute path of Swift file to format") 10 | var file = "" 11 | @Flag(help: "Trim trailing whitespace") 12 | var trimWhitespace = false 13 | @Flag(help: "Use tabs to indent") 14 | var useTabs = false 15 | @Option(help: "Number of spaces to indent") 16 | var indentWidth = 4 17 | 18 | mutating func run() throws { 19 | guard !file.isEmpty else { 20 | throw SourceKittenError.invalidArgument( 21 | description: "file must be set when calling \(Self._commandName)" 22 | ) 23 | } 24 | try File(path: file)? 25 | .format(trimmingTrailingWhitespace: trimWhitespace, 26 | useTabs: useTabs, 27 | indentWidth: indentWidth) 28 | .data(using: .utf8)? 29 | .write(to: URL(fileURLWithPath: file), options: []) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/sourcekitten/Index.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SourceKittenFramework 4 | 5 | extension SourceKitten { 6 | struct Index: ParsableCommand { 7 | static let configuration = CommandConfiguration(abstract: "Index Swift file and print as JSON") 8 | 9 | @Option(help: "Relative or absolute path of Swift file to index") 10 | var file: String = "" 11 | @Argument(help: "Compiler arguments to pass to SourceKit") 12 | var compilerargs: [String] 13 | 14 | mutating func run() throws { 15 | guard !file.isEmpty else { 16 | throw SourceKittenError.invalidArgument( 17 | description: "file must be set when calling \(Self._commandName)" 18 | ) 19 | } 20 | let absoluteFile = file.bridge().absolutePathRepresentation() 21 | let request = SourceKittenFramework.Request.index(file: absoluteFile, arguments: compilerargs) 22 | print(toJSON(toNSDictionary(try request.send()))) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/sourcekitten/ModuleInfo.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SourceKittenFramework 3 | 4 | extension SourceKitten { 5 | struct ModuleInfo: ParsableCommand { 6 | static let configuration = CommandConfiguration( 7 | abstract: "Obtain information about a Swift module and print as JSON" 8 | ) 9 | 10 | @Option(help: "Name of the Swift module") 11 | var module: String = "" 12 | 13 | @Argument(help: "Compiler arguments to pass to SourceKit") 14 | var compilerargs: [String] 15 | 16 | mutating func run() throws { 17 | guard !module.isEmpty else { 18 | throw SourceKittenError.invalidArgument( 19 | description: "module must be set when calling \(Self._commandName)" 20 | ) 21 | } 22 | let request = SourceKittenFramework.Request.moduleInfo(module: module, arguments: compilerargs) 23 | print(toJSON(toNSDictionary(try request.send()))) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/sourcekitten/Request.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SourceKittenFramework 3 | 4 | extension SourceKitten { 5 | struct Request: ParsableCommand { 6 | static let configuration = CommandConfiguration(abstract: "Run a raw SourceKit request") 7 | 8 | @Option(help: "A path to a yaml file, or yaml text to execute") 9 | var yaml: String = "" 10 | 11 | mutating func run() throws { 12 | if self.yaml.isEmpty { 13 | throw SourceKittenError.invalidArgument(description: "yaml file or text must be provided") 14 | } 15 | 16 | let yaml: String 17 | if let file = File(path: self.yaml) { 18 | yaml = file.contents 19 | } else { 20 | yaml = self.yaml 21 | } 22 | 23 | let request = SourceKittenFramework.Request.yamlRequest(yaml: yaml) 24 | print(toJSON(toNSDictionary(try request.send()))) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/sourcekitten/SourceKitten.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | 3 | struct SourceKitten: ParsableCommand { 4 | static let configuration = CommandConfiguration( 5 | commandName: "sourcekitten", 6 | abstract: "An adorable little command line tool for interacting with SourceKit", 7 | version: Version.value, 8 | subcommands: [ 9 | Complete.self, 10 | Doc.self, 11 | Format.self, 12 | Index.self, 13 | ModuleInfo.self, 14 | Request.self, 15 | Structure.self, 16 | Syntax.self, 17 | Version.self 18 | ] 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /Source/sourcekitten/Structure.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SourceKittenFramework 3 | 4 | extension SourceKitten { 5 | struct Structure: ParsableCommand { 6 | static let configuration = CommandConfiguration(abstract: "Print Swift structure information as JSON") 7 | 8 | @Option(help: "Relative or absolute path of Swift file to parse") 9 | var file: String = "" 10 | @Option(help: "Swift code text to parse") 11 | var text: String = "" 12 | 13 | mutating func run() throws { 14 | if !file.isEmpty { 15 | if let file = File(path: file) { 16 | print(try SourceKittenFramework.Structure(file: file)) 17 | return 18 | } 19 | throw SourceKittenError.readFailed(path: file) 20 | } 21 | if !text.isEmpty { 22 | print(try SourceKittenFramework.Structure(file: File(contents: text))) 23 | return 24 | } 25 | throw SourceKittenError.invalidArgument( 26 | description: "either file or text must be set when calling \(Self._commandName)" 27 | ) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/sourcekitten/Syntax.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SourceKittenFramework 3 | 4 | extension SourceKitten { 5 | struct Syntax: ParsableCommand { 6 | static let configuration = CommandConfiguration(abstract: "Print Swift syntax information as JSON") 7 | 8 | @Option(help: "Relative or absolute path of Swift file to parse") 9 | var file: String = "" 10 | @Option(help: "Swift code text to parse") 11 | var text: String = "" 12 | 13 | mutating func run() throws { 14 | if !file.isEmpty { 15 | if let file = File(path: file) { 16 | print(try SyntaxMap(file: file)) 17 | return 18 | } 19 | throw SourceKittenError.readFailed(path: file) 20 | } 21 | print(try SyntaxMap(file: File(contents: text))) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/sourcekitten/Version.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SourceKittenFramework 3 | 4 | extension SourceKitten { 5 | struct Version: ParsableCommand { 6 | static let configuration = CommandConfiguration(abstract: "Display the current version of SourceKitten") 7 | 8 | static var value: String { SourceKittenFramework.Version.current.value } 9 | 10 | mutating func run() throws { 11 | print(Self.value) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/sourcekitten/main.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Dispatch 3 | 4 | #if os(macOS) 5 | import Darwin 6 | #elseif os(Linux) 7 | #if canImport(Glibc) 8 | import Glibc 9 | #elseif canImport(Musl) 10 | import Musl 11 | #endif 12 | #elseif os(Windows) 13 | import ucrt 14 | #else 15 | #error("Unsupported platform") 16 | #endif 17 | 18 | // `sourcekitd_set_notification_handler()` sets the handler to be executed on main thread queue. 19 | // So, we vacate main thread to `dispatchMain()`. 20 | if #available(macOS 10.10, *) { 21 | DispatchQueue.global(qos: .default).async { 22 | SourceKitten.main() 23 | exit(0) 24 | } 25 | dispatchMain() 26 | } else { 27 | SourceKitten.main() 28 | } 29 | -------------------------------------------------------------------------------- /SourceKittenFramework.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SourceKittenFramework' 3 | s.version = `make get_version` 4 | s.summary = 'An adorable little framework for interacting with SourceKit.' 5 | s.homepage = 'https://github.com/jpsim/SourceKitten' 6 | s.source = { git: s.homepage + '.git', tag: s.version } 7 | s.license = { type: 'MIT', file: 'LICENSE' } 8 | s.author = { 'JP Simard' => 'jp@jpsim.com' } 9 | s.platform = :osx, '12' 10 | s.source_files = 'Source/Clang_C/include/*.h', 'Source/SourceKit/include/*.h', 'Source/SourceKittenFramework/*.swift' 11 | s.swift_versions = ['5.3', '5.4', '5.5', '5.6', '5.7'] 12 | s.pod_target_xcconfig = { 'APPLICATION_EXTENSION_API_ONLY' => 'YES' } 13 | s.dependency 'SWXMLHash', '~> 7.0.0' 14 | s.dependency 'Yams', '~> 5.0.0' 15 | end 16 | -------------------------------------------------------------------------------- /Tests/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_test", 4 | ) 5 | 6 | swift_test( 7 | name = "UnitTests", 8 | size = "large", 9 | srcs = glob( 10 | ["SourceKittenFrameworkTests/**/*.swift"], 11 | [ 12 | "SourceKittenFrameworkTests/Fixtures/**/*.*", 13 | ], 14 | allow_empty = False, 15 | ), 16 | data = glob( 17 | ["SourceKittenFrameworkTests/Fixtures/**/*.*"], 18 | allow_empty = False, 19 | ), 20 | module_name = "SourceKittenFrameworkTests", 21 | target_compatible_with = ["@platforms//os:macos"], 22 | deps = [ 23 | "//:SourceKittenFramework", 24 | ], 25 | ) 26 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/ByteRangeTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | class ByteRangeTests: XCTestCase { 5 | 6 | func testZeroLengthRangeContainment() { 7 | let range = ByteRange(location: 10, length: 0) 8 | XCTAssertFalse(range.contains(ByteCount(9))) 9 | XCTAssertFalse(range.contains(ByteCount(10))) 10 | XCTAssertFalse(range.contains(ByteCount(11))) 11 | } 12 | 13 | func testNonZeroLengthRangeContainment() { 14 | let range = ByteRange(location: 10, length: 10) 15 | XCTAssertFalse(range.contains(ByteCount(9))) 16 | 17 | XCTAssertTrue(range.contains(ByteCount(10))) 18 | XCTAssertTrue(range.contains(ByteCount(11))) 19 | XCTAssertTrue(range.contains(ByteCount(19))) 20 | 21 | XCTAssertFalse(range.contains(ByteCount(20))) 22 | } 23 | 24 | func testRangeUnionWithSameRange() { 25 | let range1 = ByteRange(location: 10, length: 10) 26 | let range2 = ByteRange(location: 10, length: 10) 27 | let union = range1.union(with: range2) 28 | XCTAssertEqual(range1, union) 29 | } 30 | 31 | func testRangeUnionWithNonOverlappingRange() { 32 | let range1 = ByteRange(location: 10, length: 1) 33 | let range2 = ByteRange(location: 20, length: 1) 34 | let union = range1.union(with: range2) 35 | XCTAssertEqual(union, ByteRange(location: 10, length: 11)) 36 | } 37 | 38 | func testRangeUnionWithFullyIncludedRange() { 39 | let range1 = ByteRange(location: 10, length: 20) 40 | let range2 = ByteRange(location: 20, length: 1) 41 | let union = range1.union(with: range2) 42 | XCTAssertEqual(union, ByteRange(location: 10, length: 20)) 43 | } 44 | 45 | func testRangeUnionWithOverlapping() { 46 | let range1 = ByteRange(location: 10, length: 5) 47 | let range2 = ByteRange(location: 11, length: 6) 48 | let union = range1.union(with: range2) 49 | XCTAssertEqual(union, ByteRange(location: 10, length: 7)) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/ClangTranslationUnitTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | let testWorkspaceDirectory: String? = { 6 | if let buildWorkspaceRoot: String = ProcessInfo.processInfo.environment["PROJECT_ROOT"] { 7 | return buildWorkspaceRoot + "/Tests/SourceKittenFrameworkTests/Fixtures/" 8 | } 9 | return nil 10 | }() 11 | let fixturesDirectory = testWorkspaceDirectory ?? (URL(fileURLWithPath: #file).deletingLastPathComponent().path + "/Fixtures/") 12 | 13 | #if !os(Linux) 14 | 15 | class ClangTranslationUnitTests: XCTestCase { 16 | 17 | func testParsesObjectiveCHeaderFilesAndXcodebuildArguments() { 18 | let headerFiles = [ 19 | "a.h", 20 | "b.hpp", 21 | "c.hh" 22 | ] 23 | let xcodebuildArguments = [ 24 | "arg1", 25 | "arg2" 26 | ] 27 | let (parsedHeaderFiles, parsedXcodebuildArguments) = parseHeaderFilesAndXcodebuildArguments(sourcekittenArguments: headerFiles + xcodebuildArguments) 28 | XCTAssertEqual(parsedHeaderFiles, headerFiles.map({ $0.bridge().absolutePathRepresentation() }), "Objective-C header files should be parsed") 29 | XCTAssertEqual(parsedXcodebuildArguments, xcodebuildArguments, "xcodebuild arguments should be parsed") 30 | } 31 | 32 | private func compare(clangFixture fixture: String) { 33 | let unit = ClangTranslationUnit(headerFiles: [fixturesDirectory + fixture + ".h"], 34 | compilerArguments: ["-x", "objective-c", "-isysroot", sdkPath(), "-I", fixturesDirectory]) 35 | compareJSONString(withFixtureNamed: (fixture as NSString).lastPathComponent, jsonString: unit) 36 | } 37 | 38 | func testBasicObjectiveCDocs() { 39 | compare(clangFixture: "Musician") 40 | } 41 | 42 | func testUnicodeInObjectiveCDocs() { 43 | compare(clangFixture: "SuperScript") 44 | } 45 | 46 | func testRealmObjectiveCDocs() { 47 | compare(clangFixture: "Realm/Realm") 48 | } 49 | 50 | func testCodeFormattingObjectiveCDocs() { 51 | compare(clangFixture: "CodeFormatting") 52 | } 53 | 54 | func testUnionObjectiveCDocs() { 55 | compare(clangFixture: "Union") 56 | } 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/CodeCompletionTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | class CodeCompletionTests: XCTestCase { 6 | 7 | func testSimpleCodeCompletion() throws { 8 | let file = "\(NSUUID().uuidString).swift" 9 | let completionItems = CodeCompletionItem.parse(response: 10 | try Request.codeCompletionRequest(file: file, contents: "0.", offset: 2, 11 | arguments: ["-c", file, "-sdk", sdkPath()]).send()) 12 | compareJSONString(withFixtureNamed: "SimpleCodeCompletion", 13 | jsonString: completionItems) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/CursorInfoParsingTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | final class CursorInfoParsingTests: XCTestCase { 5 | 6 | func testNoReferencedUSR() { 7 | let cursorInfo: [String: SourceKitRepresentable] = [ 8 | "key.usr": "s:4main5limitL_Sivp", 9 | "key.kind": "source.lang.swift.decl.var.local" 10 | ] 11 | 12 | XCTAssertEqual(cursorInfo.referencedUSRs, []) 13 | } 14 | 15 | func testSingleReferencedUSR() { 16 | let cursorInfo: [String: SourceKitRepresentable] = [ 17 | "key.usr": "s:4main5limitL_Sivp", 18 | "key.kind": "source.lang.swift.ref.var.local" 19 | ] 20 | 21 | XCTAssertEqual(cursorInfo.referencedUSRs, ["s:4main5limitL_Sivp"]) 22 | } 23 | 24 | func testRelatedReferencedUSR() { 25 | let cursorInfo: [String: SourceKitRepresentable] = [ 26 | "key.usr": "s:4main5limitL_Sivp", 27 | "key.kind": "source.lang.swift.ref.var.local", 28 | "key.related_decls": [ 29 | ["key.annotated_decl": "limit"] 30 | ] 31 | ] 32 | 33 | XCTAssertEqual(cursorInfo.referencedUSRs, ["s:4main5limitL_Sivp", "s:4main5limit33_BF49849BA67C991867DA082EF03F5F16LLSivp"]) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/CursorInfoUSRTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | class CursorInfoUSRTests: XCTestCase { 6 | 7 | /// Validates that cursorInfo is parsed correctly. 8 | func testCursorInfoUSRRequest() throws { 9 | let path = fixturesDirectory + "DocInfo.swift" 10 | 11 | let info = toNSDictionary( 12 | try Request.cursorInfoUSR( 13 | file: path, 14 | usr: "s:7DocInfo16DocumentedStructV", 15 | arguments: ["-sdk", sdkPath(), path], 16 | cancelOnSubsequentRequest: false 17 | ).send() 18 | ) 19 | compareJSONString(withFixtureNamed: "CursorInfoUSR", jsonString: toJSON(info)) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/DocInfoTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | class DocInfoTests: XCTestCase { 6 | /// Validates that various doc string formats are parsed correctly. 7 | func testDocInfoRequest() throws { 8 | let swiftFile = File(path: fixturesDirectory + "DocInfo.swift")! 9 | let info = toNSDictionary( 10 | try Request.docInfo(text: swiftFile.contents, arguments: ["-sdk", sdkPath()]).send() 11 | ) 12 | compareJSONString(withFixtureNamed: "DocInfo", jsonString: toJSON(info)) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/FileTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | class FileTests: XCTestCase { 5 | 6 | func testUnreadablePath() { 7 | XCTAssert(File(path: "/dev/wtf") == nil) 8 | } 9 | 10 | func testFormat() throws { 11 | let file = File(path: fixturesDirectory + "BicycleUnformatted.swift") 12 | let formattedFile = try file?.format(trimmingTrailingWhitespace: true, useTabs: false, indentWidth: 4) 13 | XCTAssertEqual(formattedFile!, try String(contentsOfFile: fixturesDirectory + "Bicycle.swift", encoding: .utf8)) 14 | } 15 | 16 | func testLinesRangesWhenUsingLineSeparator() { 17 | let file = File(contents: "// There're two U+2028 invisible characters after the colon:\u{2028}\u{2028}\nclass X {}") 18 | XCTAssertEqual(file.lines.count, 2) 19 | XCTAssertEqual(file.lines.last?.byteRange, ByteRange(location: 67, length: 10)) 20 | } 21 | 22 | func testNonUTF8Files() throws { 23 | let file = File(pathDeferringReading: fixturesDirectory + "NonUTF8File") 24 | XCTAssertEqual(file.contents, "") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Bicycle.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Deprecated extension. 4 | @available(*, deprecated, message: "This is deprecated but should still be documented.") 5 | public extension NSString {} 6 | 7 | /// 🚲 A two-wheeled, human-powered mode of transportation. 8 | public class Bicycle { 9 | /** 10 | Frame and construction style. 11 | 12 | - Road: For streets or trails. 13 | - Touring: For long journeys. 14 | - Cruiser: For casual trips around town. 15 | - Hybrid: For general-purpose transportation. 16 | */ 17 | public enum Style { 18 | case Road, Touring, Cruiser, Hybrid 19 | } 20 | 21 | /** 22 | Mechanism for converting pedal power into motion. 23 | 24 | - Fixed: A single, fixed gear. 25 | - Freewheel: A variable-speed, disengageable gear. 26 | */ 27 | public enum Gearing { 28 | case Fixed 29 | case Freewheel(speeds: Int) 30 | } 31 | 32 | /** 33 | Hardware used for steering. 34 | 35 | - Riser: A casual handlebar. 36 | - Café: An upright handlebar. 37 | - Drop: A classic handlebar. 38 | - Bullhorn: A powerful handlebar. 39 | */ 40 | enum Handlebar { 41 | case Riser, Café, Drop, Bullhorn 42 | } 43 | 44 | /// The style of the bicycle. 45 | let style: Style 46 | 47 | /// The gearing of the bicycle. 48 | let gearing: Gearing 49 | 50 | /// The handlebar of the bicycle. 51 | let handlebar: Handlebar 52 | 53 | /// The size of the frame, in centimeters. 54 | let frameSize: Int 55 | 56 | /// The number of trips travelled by the bicycle. 57 | private(set) var numberOfTrips: Int 58 | 59 | /// The total distance travelled by the bicycle, in meters. 60 | private(set) var distanceTravelled: Double 61 | 62 | /** 63 | Initializes a new bicycle with the provided parts and specifications. 64 | 65 | - parameter style: The style of the bicycle 66 | - parameter gearing: The gearing of the bicycle 67 | - parameter handlebar: The handlebar of the bicycle 68 | - parameter centimeters: The frame size of the bicycle, in centimeters 69 | 70 | - returns: A beautiful, brand-new, custom built just for you. 71 | */ 72 | init(style: Style, gearing: Gearing, handlebar: Handlebar, frameSize centimeters: Int) { 73 | self.style = style 74 | self.gearing = gearing 75 | self.handlebar = handlebar 76 | self.frameSize = centimeters 77 | 78 | numberOfTrips = 0 79 | distanceTravelled = 0 80 | } 81 | 82 | /** 83 | Take a bike out for a spin. 84 | 85 | - parameter meters: The distance to travel in meters. 86 | */ 87 | func travel(distance meters: Double) { 88 | if meters > 0.0 { 89 | distanceTravelled += meters 90 | numberOfTrips += 1 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/BicycleUnformatted.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Deprecated extension. 4 | @available(*, deprecated, message: "This is deprecated but should still be documented.") 5 | public extension NSString {} 6 | 7 | /// 🚲 A two-wheeled, human-powered mode of transportation. 8 | public class Bicycle { 9 | /** 10 | Frame and construction style. 11 | 12 | - Road: For streets or trails. 13 | - Touring: For long journeys. 14 | - Cruiser: For casual trips around town. 15 | - Hybrid: For general-purpose transportation. 16 | */ 17 | public enum Style { 18 | case Road, Touring, Cruiser, Hybrid 19 | } 20 | 21 | /** 22 | Mechanism for converting pedal power into motion. 23 | 24 | - Fixed: A single, fixed gear. 25 | - Freewheel: A variable-speed, disengageable gear. 26 | */ 27 | public enum Gearing { 28 | case Fixed 29 | case Freewheel(speeds: Int) 30 | } 31 | 32 | /** 33 | Hardware used for steering. 34 | 35 | - Riser: A casual handlebar. 36 | - Café: An upright handlebar. 37 | - Drop: A classic handlebar. 38 | - Bullhorn: A powerful handlebar. 39 | */ 40 | enum Handlebar { 41 | case Riser, Café, Drop, Bullhorn 42 | } 43 | 44 | /// The style of the bicycle. 45 | let style: Style 46 | 47 | /// The gearing of the bicycle. 48 | let gearing: Gearing 49 | 50 | /// The handlebar of the bicycle. 51 | let handlebar: Handlebar 52 | 53 | /// The size of the frame, in centimeters. 54 | let frameSize: Int 55 | 56 | /// The number of trips travelled by the bicycle. 57 | private(set) var numberOfTrips: Int 58 | 59 | /// The total distance travelled by the bicycle, in meters. 60 | private(set) var distanceTravelled: Double 61 | 62 | /** 63 | Initializes a new bicycle with the provided parts and specifications. 64 | 65 | - parameter style: The style of the bicycle 66 | - parameter gearing: The gearing of the bicycle 67 | - parameter handlebar: The handlebar of the bicycle 68 | - parameter centimeters: The frame size of the bicycle, in centimeters 69 | 70 | - returns: A beautiful, brand-new, custom built just for you. 71 | */ 72 | init(style: Style, gearing: Gearing, handlebar: Handlebar, frameSize centimeters: Int) { 73 | self.style = style 74 | self.gearing = gearing 75 | self.handlebar = handlebar 76 | self.frameSize = centimeters 77 | 78 | numberOfTrips = 0 79 | distanceTravelled = 0 80 | } 81 | 82 | /** 83 | Take a bike out for a spin. 84 | 85 | - parameter meters: The distance to travel in meters. 86 | */ 87 | func travel(distance meters: Double) { 88 | if meters > 0.0 { 89 | distanceTravelled += meters 90 | numberOfTrips += 1 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/CodeFormatting.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | Tests for miscellaneous code formatting options in header docs. 5 | */ 6 | @interface CodeFormatting : NSObject 7 | 8 | /** 9 | Basic @c CodeFormatting usage, in the middle of a sentence. 10 | */ 11 | - (void)codeWordBasic; 12 | 13 | /** 14 | Tests what happens with code word at the end of a line: @c CodeFormatting 15 | */ 16 | - (void)codeWordEndOfLine; 17 | 18 | /** 19 | Tests a basic code block: 20 | 21 | @code 22 | -[CodeFormatting codeBlockBasic] 23 | @endcode 24 | */ 25 | - (void)codeBlockBasic; 26 | 27 | /** 28 | Tests an inline @code-[CodeFormatting codeBlockBasic]@endcode code block. 29 | 30 | Per Xcode's behavior when formatting Obj-C doc comments, this doesn't actually result in 31 | the code block being _displayed_ inline, but writing it as inline is potentially common enough 32 | to justify testing the results of this format. 33 | */ 34 | - (void)codeBlockInline; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/CursorInfoUSR.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.annotated_decl" : "struct DocumentedStruct<\/Declaration>", 3 | "key.column" : 8, 4 | "key.decl_lang" : "source.lang.swift", 5 | "key.doc.full_as_xml" : "DocumentedStruct<\/Name>s:7DocInfo16DocumentedStructV<\/USR>struct DocumentedStruct<\/Declaration>A documented struct<\/Para><\/Abstract><\/CommentParts><\/Class>", 6 | "key.filepath" : "DocInfo.swift", 7 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> DocumentedStruct<\/decl.name><\/decl.struct>", 8 | "key.kind" : "source.lang.swift.decl.struct", 9 | "key.length" : 16, 10 | "key.line" : 28, 11 | "key.modulename" : "DocInfo", 12 | "key.name" : "DocumentedStruct", 13 | "key.offset" : 416, 14 | "key.typename" : "DocumentedStruct.Type", 15 | "key.typeusr" : "$s7DocInfo16DocumentedStructVmD", 16 | "key.usr" : "s:7DocInfo16DocumentedStructV" 17 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/CursorInfoUSR@swift-5.9.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.annotated_decl" : "struct DocumentedStruct<\/Declaration>", 3 | "key.column" : 8, 4 | "key.decl_lang" : "source.lang.swift", 5 | "key.doc.full_as_xml" : "DocumentedStruct<\/Name>s:7DocInfo16DocumentedStructV<\/USR>struct DocumentedStruct<\/Declaration>A documented struct<\/Para><\/Abstract><\/CommentParts><\/Class>", 6 | "key.filepath" : "DocInfo.swift", 7 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> DocumentedStruct<\/decl.name><\/decl.struct>", 8 | "key.kind" : "source.lang.swift.decl.struct", 9 | "key.length" : 16, 10 | "key.line" : 28, 11 | "key.modulename" : "DocInfo", 12 | "key.name" : "DocumentedStruct", 13 | "key.offset" : 416, 14 | "key.reusingastcontext" : false, 15 | "key.typename" : "DocumentedStruct.Type", 16 | "key.typeusr" : "$s7DocInfo16DocumentedStructVmD", 17 | "key.usr" : "s:7DocInfo16DocumentedStructV" 18 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/CursorInfoUSR@swift-6.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.annotated_decl" : "struct DocumentedStruct<\/Declaration>", 3 | "key.column" : 8, 4 | "key.decl_lang" : "source.lang.swift", 5 | "key.doc_comment" : "A documented struct", 6 | "key.doc.full_as_xml" : "DocumentedStruct<\/Name>s:7DocInfo16DocumentedStructV<\/USR>struct DocumentedStruct<\/Declaration>A documented struct<\/Para><\/Abstract><\/CommentParts><\/Class>", 7 | "key.filepath" : "DocInfo.swift", 8 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> DocumentedStruct<\/decl.name><\/decl.struct>", 9 | "key.kind" : "source.lang.swift.decl.struct", 10 | "key.length" : 16, 11 | "key.line" : 28, 12 | "key.modulename" : "DocInfo", 13 | "key.name" : "DocumentedStruct", 14 | "key.offset" : 416, 15 | "key.reusingastcontext" : false, 16 | "key.typename" : "DocumentedStruct.Type", 17 | "key.typeusr" : "$s7DocInfo16DocumentedStructVmD", 18 | "key.usr" : "s:7DocInfo16DocumentedStructV" 19 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/DocInfo.swift: -------------------------------------------------------------------------------- 1 | 2 | /// Single line commented function 3 | func singleLineCommentedFunc() { 4 | } 5 | 6 | /** 7 | Multiple line 8 | commented function. 9 | */ 10 | func multiLineCommentedFunc() { 11 | } 12 | 13 | func undocumentedFunc() { 14 | } 15 | 16 | // This comment is not a docstring. 17 | func nonDocCommentDocumentedFunc() { 18 | } 19 | 20 | /* This comment is also not a docstring. 21 | but covers multiple lines. 22 | */ 23 | func nonDocCommentMultiLineDocumentedFunc() { 24 | } 25 | 26 | 27 | /// A documented struct 28 | struct DocumentedStruct { 29 | /// A documented variable. 30 | let x: String 31 | 32 | /** 33 | * A documented member func. 34 | */ 35 | fileprivate func documentedMemberFunc() { 36 | } 37 | } 38 | 39 | /// A doc string that refers to nothing. 40 | 41 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Extension.swift: -------------------------------------------------------------------------------- 1 | /// Doc for Base 2 | class Base { 3 | 4 | /// Doc for Base.Index 5 | typealias Index = Int 6 | 7 | /// Doc for Base.f 8 | func f(index: Index) { 9 | } 10 | 11 | /// Doc for Base.Nested 12 | class Nested { 13 | } 14 | } 15 | 16 | extension Base { 17 | 18 | /// Doc for Base.ExtendedIndex 19 | typealias ExtendedIndex = Double 20 | 21 | /// Doc for Base.extendedF 22 | func extendedF(index: ExtendedIndex) { 23 | } 24 | } 25 | 26 | // Tests for extensions of nested types 27 | 28 | extension Base.Nested { 29 | } 30 | 31 | class 🐽 { 32 | struct 🐧 { 33 | } 34 | } 35 | 36 | extension 🐽.🐧 { 37 | } 38 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/ExternalRef1.swift: -------------------------------------------------------------------------------- 1 | func main() { 2 | /// Doc 3 | external() 4 | } 5 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/ExternalRef2.swift: -------------------------------------------------------------------------------- 1 | // 12345678901234567890 2 | // 12345678901234567890 3 | func external() {} 4 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Musician.h: -------------------------------------------------------------------------------- 1 | // 2 | // JAZMusician.h 3 | // JazzyApp 4 | // 5 | 6 | #import 7 | 8 | /** 9 | JAZMusician models, you guessed it... Jazz Musicians! 10 | From Ellington to Marsalis, this class has you covered. 11 | */ 12 | @interface JAZMusician : NSObject 13 | 14 | #pragma mark - Properties 15 | 16 | /// Always returns `YES`. 17 | @property (class, readwrite, nonatomic) BOOL isMusician; 18 | 19 | /** 20 | The name of the musician. i.e. "John Coltrane" 21 | */ 22 | @property (nonatomic, readonly) NSString *name 23 | __attribute__((annotate("This API will eventually be deprecated in favor of fullName."))); 24 | 25 | /** 26 | The full name of the musician. i.e. "John Coltrane" 27 | */ 28 | @property (nonatomic, readonly) NSString *fullName; 29 | 30 | /** 31 | The year the musician was born. i.e. 1926 32 | */ 33 | @property (nonatomic, readonly) NSUInteger birthyear NS_SWIFT_NAME(year); 34 | 35 | /** 36 | Link to an musician's fan page. 37 | */ 38 | @property (nonatomic, readonly) NSURL *musicianURL; 39 | 40 | /** 41 | Direct link to a musician's band page. 42 | */ 43 | @property (nonatomic, readonly) NSURL *musicianBand; 44 | 45 | 46 | #pragma mark - Initializers-hyphenated 47 | 48 | /** 49 | Initialize a JAZMusician. 50 | Don't forget to have a name and a birthyear. 51 | 52 | @warning Jazz can be addicting. 53 | Please be careful out there. 54 | 55 | @param name The name of the musician. 56 | @param birthyear The year the musician was born. 57 | 58 | @return An initialized JAZMusician instance. 59 | */ 60 | - (instancetype)initWithName:(NSString *)name birthyear:(NSUInteger)birthyear NS_SWIFT_NAME(init(name:year:)); 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/NonUTF8File.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/SourceKitten/68e9472d9e39360ddb53a76fa8fc9718a336cdd5/Tests/SourceKittenFrameworkTests/Fixtures/NonUTF8File.swift -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMAccessor.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | #import 22 | 23 | @class RLMObjectSchema, RLMProperty, RLMObjectBase, RLMProperty; 24 | 25 | #ifdef __cplusplus 26 | typedef NSUInteger RLMCreationOptions; 27 | #else 28 | typedef NS_OPTIONS(NSUInteger, RLMCreationOptions); 29 | #endif 30 | 31 | RLM_ASSUME_NONNULL_BEGIN 32 | 33 | // 34 | // Accessors Class Creation/Caching 35 | // 36 | 37 | // get accessor classes for an object class - generates classes if not cached 38 | Class RLMAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema, NSString *prefix); 39 | Class RLMStandaloneAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema); 40 | 41 | // Check if a given class is a generated accessor class 42 | bool RLMIsGeneratedClass(Class cls); 43 | 44 | // 45 | // Dynamic getters/setters 46 | // 47 | FOUNDATION_EXTERN void RLMDynamicValidatedSet(RLMObjectBase *obj, NSString *propName, id __nullable val); 48 | FOUNDATION_EXTERN RLMProperty *RLMValidatedGetProperty(RLMObjectBase *obj, NSString *propName); 49 | FOUNDATION_EXTERN id __nullable RLMDynamicGet(RLMObjectBase *obj, RLMProperty *prop); 50 | 51 | // by property/column 52 | FOUNDATION_EXTERN void RLMDynamicSet(RLMObjectBase *obj, RLMProperty *prop, id val, RLMCreationOptions options); 53 | 54 | // 55 | // Class modification 56 | // 57 | 58 | // Replace className method for the given class 59 | void RLMReplaceClassNameMethod(Class accessorClass, NSString *className); 60 | 61 | // Replace sharedSchema method for the given class 62 | void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema * __nullable schema); 63 | void RLMReplaceSharedSchemaMethodWithBlock(Class accessorClass, RLMObjectSchema *(^method)(Class)); 64 | 65 | RLM_ASSUME_NONNULL_END 66 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMArray_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @interface RLMArray () 22 | - (instancetype)initWithObjectClassName:(NSString *)objectClassName; 23 | - (NSString *)descriptionWithMaxDepth:(NSUInteger)depth; 24 | @end 25 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMDefines.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMObject; 22 | 23 | #ifndef __has_feature 24 | #define __has_feature(x) 0 25 | #endif 26 | 27 | #pragma mark - Generics 28 | 29 | #if __has_extension(objc_generics) 30 | #define RLM_GENERIC_COLLECTION 31 | #define RLM_GENERIC_RETURN 32 | #define RLMObjectArgument RLMObjectType 33 | #else 34 | #define RLM_GENERIC_COLLECTION 35 | #define RLM_GENERIC_RETURN 36 | typedef id RLMObjectType; 37 | typedef RLMObject * RLMObjectArgument; 38 | #endif 39 | 40 | #pragma mark - Nullability 41 | 42 | #if !__has_feature(nullability) 43 | #ifndef __nullable 44 | #define __nullable 45 | #endif 46 | #ifndef __nonnull 47 | #define __nonnull 48 | #endif 49 | #ifndef __null_unspecified 50 | #define __null_unspecified 51 | #endif 52 | #ifndef nullable 53 | #define nullable 54 | #endif 55 | #ifndef nonnull 56 | #define nonnull 57 | #endif 58 | #ifndef null_unspecified 59 | #define null_unspecified 60 | #endif 61 | #endif 62 | 63 | #if defined(NS_ASSUME_NONNULL_BEGIN) && defined(NS_ASSUME_NONNULL_END) 64 | #define RLM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN 65 | #define RLM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END 66 | #else 67 | #define RLM_ASSUME_NONNULL_BEGIN 68 | #define RLM_ASSUME_NONNULL_END 69 | #endif 70 | 71 | #pragma mark - Escaping 72 | 73 | #if __has_attribute(noescape) 74 | # define RLM_NOESCAPE __attribute__((noescape)) 75 | #else 76 | # define RLM_NOESCAPE 77 | #endif 78 | 79 | #pragma mark - Swift Availability 80 | 81 | #if defined(NS_SWIFT_UNAVAILABLE) 82 | # define RLM_SWIFT_UNAVAILABLE(msg) NS_SWIFT_UNAVAILABLE(msg) 83 | #else 84 | # define RLM_SWIFT_UNAVAILABLE(msg) 85 | #endif 86 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMListBase.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMArray; 22 | 23 | // A base class for Swift generic Lists to make it possible to interact with 24 | // them from obj-c 25 | @interface RLMListBase : NSObject 26 | @property (nonatomic, strong) RLMArray *_rlmArray; 27 | 28 | - (instancetype)initWithArray:(RLMArray *)array; 29 | @end 30 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMMigration.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | @class RLMSchema; 25 | @class RLMArray; 26 | @class RLMObject; 27 | 28 | typedef void (^RLMObjectMigrationBlock)(RLMObject * __nullable oldObject, RLMObject * __nullable newObject); 29 | 30 | /** 31 | RLMMigration is the object passed into a user defined RLMMigrationBlock when updating the version 32 | of an RLMRealm instance. 33 | 34 | This object provides access to the RLMSchema current to this migration. 35 | */ 36 | @interface RLMMigration : NSObject 37 | 38 | #pragma mark - Properties 39 | 40 | /** 41 | Get the old RLMSchema for the migration. This is the schema which describes the RLMRealm before the 42 | migration is applied. 43 | */ 44 | @property (nonatomic, readonly) RLMSchema *oldSchema; 45 | 46 | /** 47 | Get the new RLMSchema for the migration. This is the schema which describes the RLMRealm after applying 48 | a migration. 49 | */ 50 | @property (nonatomic, readonly) RLMSchema *newSchema; 51 | 52 | 53 | #pragma mark - Altering Objects during a Migration 54 | 55 | /** 56 | Enumerates objects of a given type in this Realm, providing both the old and new versions of each object. 57 | Objects properties can be accessed using keyed subscripting. 58 | 59 | @param className The name of the RLMObject class to enumerate. 60 | 61 | @warning All objects returned are of a type specific to the current migration and should not be casted 62 | to className. Instead you should access them as RLMObjects and use keyed subscripting to access 63 | properties. 64 | */ 65 | - (void)enumerateObjects:(NSString *)className block:(RLMObjectMigrationBlock)block; 66 | 67 | /** 68 | Create an RLMObject of type `className` in the Realm being migrated. 69 | 70 | @param className The name of the RLMObject class to create. 71 | @param value The value used to populate the created object. This can be any key/value coding compliant 72 | object, or a JSON object such as those returned from the methods in NSJSONSerialization, or 73 | an NSArray with one object for each persisted property. An exception will be 74 | thrown if any required properties are not present and no default is set. 75 | 76 | When passing in an NSArray, all properties must be present, valid and in the same order as the properties defined in the model. 77 | */ 78 | -(RLMObject *)createObject:(NSString *)className withValue:(id)value; 79 | 80 | /** 81 | Delete an object from a Realm during a migration. This can be called within `enumerateObjects:block:`. 82 | 83 | @param object Object to be deleted from the Realm being migrated. 84 | */ 85 | - (void)deleteObject:(RLMObject *)object; 86 | 87 | /** 88 | Deletes the data for the class with the given name. 89 | This deletes all objects of the given class, and if the RLMObject subclass no longer exists in your program, 90 | cleans up any remaining metadata for the class in the Realm file. 91 | 92 | @param name The name of the RLMObject class to delete. 93 | 94 | @return whether there was any data to delete. 95 | */ 96 | - (BOOL)deleteDataForClassName:(NSString *)name; 97 | 98 | @end 99 | 100 | RLM_ASSUME_NONNULL_END 101 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMMigration_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | #import 22 | 23 | typedef void (^RLMObjectBaseMigrationBlock)(RLMObjectBase *oldObject, RLMObjectBase *newObject); 24 | 25 | @interface RLMMigration () 26 | 27 | @property (nonatomic, strong) RLMRealm *oldRealm; 28 | @property (nonatomic, strong) RLMRealm *realm; 29 | 30 | - (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm; 31 | 32 | - (void)execute:(RLMMigrationBlock)block; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObjectBase.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | @class RLMRealm; 25 | @class RLMSchema; 26 | @class RLMObjectSchema; 27 | 28 | @interface RLMObjectBase : NSObject 29 | 30 | @property (nonatomic, readonly, getter = isInvalidated) BOOL invalidated; 31 | 32 | - (instancetype)init; 33 | 34 | + (NSString *)className; 35 | 36 | // Returns whether the class is included in the default set of classes persisted in a Realm. 37 | + (BOOL)shouldIncludeInDefaultSchema; 38 | 39 | @end 40 | 41 | RLM_ASSUME_NONNULL_END 42 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObjectBase_Dynamic.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMObjectSchema, RLMRealm; 22 | 23 | /** 24 | This function is useful only in specialized circumstances, for example, when building components 25 | that integrate with Realm. If you are simply building an app on Realm, it is 26 | recommended to retrieve `realm` via `RLMObject`. 27 | 28 | @param object an RLMObjectBase obtained via a Swift Object or RLMObject 29 | 30 | @return The Realm in which this object is persisted. Returns nil for standalone objects. 31 | */ 32 | FOUNDATION_EXTERN RLMRealm *RLMObjectBaseRealm(RLMObjectBase *object); 33 | 34 | /** 35 | This function is useful only in specialized circumstances, for example, when building components 36 | that integrate with Realm. If you are simply building an app on Realm, it is 37 | recommended to retrieve `objectSchema` via `RLMObject`. 38 | 39 | @param object an RLMObjectBase obtained via a Swift Object or RLMObject 40 | 41 | @return The ObjectSchema which lists the persisted properties for this object. 42 | */ 43 | FOUNDATION_EXTERN RLMObjectSchema *RLMObjectBaseObjectSchema(RLMObjectBase *object); 44 | 45 | /** 46 | This function is useful only in specialized circumstances, for example, when building components 47 | that integrate with Realm. If you are simply building an app on Realm, it is 48 | recommended to retrieve the linking objects via `RLMObject`. 49 | 50 | @param object an RLMObjectBase obtained via a Swift Object or RLMObject 51 | @param className The type of object on which the relationship to query is defined. 52 | @param property The name of the property which defines the relationship. 53 | 54 | @return An NSArray of objects of type `className` which have this object as thier value for the `property` property. 55 | */ 56 | FOUNDATION_EXTERN NSArray *RLMObjectBaseLinkingObjectsOfClass(RLMObjectBase *object, NSString *className, NSString *property); 57 | 58 | /** 59 | This function is useful only in specialized circumstances, for example, when building components 60 | that integrate with Realm. If you are simply building an app on Realm, it is 61 | recommended to retrieve key values via `RLMObject`. 62 | 63 | @warning Will throw `NSUndefinedKeyException` if key is not present on the object 64 | 65 | @param object an RLMObjectBase obtained via a Swift Object or RLMObject 66 | @param key The name of the property 67 | 68 | @return the object for the property requested 69 | */ 70 | FOUNDATION_EXTERN id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key); 71 | 72 | /** 73 | This function is useful only in specialized circumstances, for example, when building components 74 | that integrate with Realm. If you are simply building an app on Realm, it is 75 | recommended to set key values via `RLMObject`. 76 | 77 | @warning Will throw `NSUndefinedKeyException` if key is not present on the object 78 | 79 | @param object an RLMObjectBase obtained via a Swift Object or RLMObject 80 | @param key The name of the property 81 | @param obj The object to set as the value of the key 82 | */ 83 | FOUNDATION_EXTERN void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj); 84 | 85 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObjectSchema.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | @class RLMProperty; 25 | 26 | /** 27 | This class represents Realm model object schemas persisted to Realm in an RLMSchema. 28 | 29 | When using Realm, RLMObjectSchema objects allow performing migrations and 30 | introspecting the database's schema. 31 | 32 | Object schemas map to tables in the core database. 33 | */ 34 | @interface RLMObjectSchema : NSObject 35 | 36 | #pragma mark - Properties 37 | 38 | /** 39 | Array of persisted RLMProperty objects for an object. 40 | 41 | @see RLMProperty 42 | */ 43 | @property (nonatomic, readonly, copy) NSArray *properties; 44 | 45 | /** 46 | The name of the class this schema describes. 47 | */ 48 | @property (nonatomic, readonly) NSString *className; 49 | 50 | /** 51 | The property which is the primary key for this object (if any). 52 | */ 53 | @property (nonatomic, readonly, nullable) RLMProperty *primaryKeyProperty; 54 | 55 | #pragma mark - Methods 56 | 57 | /** 58 | Retrieve an RLMProperty object by name. 59 | 60 | @param propertyName The property's name. 61 | 62 | @return RLMProperty object or nil if there is no property with the given name. 63 | */ 64 | - (nullable RLMProperty *)objectForKeyedSubscript:(id )propertyName; 65 | 66 | /** 67 | Returns YES if equal to objectSchema 68 | */ 69 | - (BOOL)isEqualToObjectSchema:(RLMObjectSchema *)objectSchema; 70 | 71 | @end 72 | 73 | RLM_ASSUME_NONNULL_END 74 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObjectSchema_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | @class RLMRealm; 25 | 26 | // RLMObjectSchema private 27 | @interface RLMObjectSchema () 28 | 29 | // writable redecleration 30 | @property (nonatomic, readwrite, copy) NSArray *properties; 31 | @property (nonatomic, readwrite, assign) bool isSwiftClass; 32 | 33 | // class used for this object schema 34 | @property (nonatomic, readwrite, assign) Class objectClass; 35 | @property (nonatomic, readwrite, assign) Class accessorClass; 36 | @property (nonatomic, readwrite, assign) Class standaloneClass; 37 | 38 | @property (nonatomic, readwrite) RLMProperty *primaryKeyProperty; 39 | 40 | // The Realm retains its object schemas, so they need to not retain the Realm 41 | @property (nonatomic, unsafe_unretained, nullable) RLMRealm *realm; 42 | // returns a cached or new schema for a given object class 43 | + (instancetype)schemaForObjectClass:(Class)objectClass; 44 | 45 | - (void)sortPropertiesByColumn; 46 | 47 | @end 48 | 49 | @interface RLMObjectSchema (Dynamic) 50 | /** 51 | This method is useful only in specialized circumstances, for example, when accessing objects 52 | in a Realm produced externally. If you are simply building an app on Realm, it is not recommened 53 | to use this method as an [RLMObjectSchema](RLMObjectSchema) is generated automatically for every [RLMObject](RLMObject) subclass. 54 | 55 | Initialize an RLMObjectSchema with classname, objectClass, and an array of properties 56 | 57 | @warning This method is useful only in specialized circumstances. 58 | 59 | @param objectClassName The name of the class used to refer to objects of this type. 60 | @param objectClass The objective-c class used when creating instances of this type. 61 | @param properties An array RLMProperty describing the persisted properties for this type. 62 | 63 | @return An initialized instance of RLMObjectSchema. 64 | */ 65 | - (instancetype)initWithClassName:(NSString *)objectClassName objectClass:(Class)objectClass properties:(NSArray *)properties; 66 | @end 67 | 68 | RLM_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObjectStore.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | @class RLMRealm, RLMSchema, RLMObjectSchema, RLMObjectBase, RLMResults, RLMProperty; 26 | 27 | // 28 | // Accessor Creation 29 | // 30 | 31 | // create or get cached accessors for the given schema 32 | void RLMRealmCreateAccessors(RLMSchema *schema); 33 | 34 | // Clear the cache of created accessor classes 35 | void RLMClearAccessorCache(); 36 | 37 | 38 | // 39 | // Options for object creation 40 | // 41 | typedef NS_OPTIONS(NSUInteger, RLMCreationOptions) { 42 | // Normal object creation 43 | RLMCreationOptionsNone = 0, 44 | // If the property is a link or array property, upsert the linked objects 45 | // if they have a primary key, and insert them otherwise. 46 | RLMCreationOptionsCreateOrUpdate = 1 << 0, 47 | // Allow standalone objects to be promoted to persisted objects 48 | // if false objects are copied during object creation 49 | RLMCreationOptionsPromoteStandalone = 1 << 1, 50 | }; 51 | 52 | 53 | // 54 | // Adding, Removing, Getting Objects 55 | // 56 | 57 | // add an object to the given realm 58 | void RLMAddObjectToRealm(RLMObjectBase *object, RLMRealm *realm, bool createOrUpdate); 59 | 60 | // delete an object from its realm 61 | void RLMDeleteObjectFromRealm(RLMObjectBase *object, RLMRealm *realm); 62 | 63 | // deletes all objects from a realm 64 | void RLMDeleteAllObjectsFromRealm(RLMRealm *realm); 65 | 66 | // get objects of a given class 67 | RLMResults *RLMGetObjects(RLMRealm *realm, NSString *objectClassName, NSPredicate *predicate) NS_RETURNS_RETAINED; 68 | 69 | // get an object with the given primary key 70 | id RLMGetObject(RLMRealm *realm, NSString *objectClassName, id key) NS_RETURNS_RETAINED; 71 | 72 | // create object from array or dictionary 73 | RLMObjectBase *RLMCreateObjectInRealmWithValue(RLMRealm *realm, NSString *className, id value, bool createOrUpdate) NS_RETURNS_RETAINED; 74 | 75 | 76 | // 77 | // Accessor Creation 78 | // 79 | 80 | // Create accessors 81 | RLMObjectBase *RLMCreateObjectAccessor(RLMRealm *realm, 82 | RLMObjectSchema *objectSchema, 83 | NSUInteger index) NS_RETURNS_RETAINED; 84 | 85 | // switch List<> properties from being backed by standalone RLMArrays to RLMArrayLinkView 86 | void RLMInitializeSwiftAccessorGenerics(RLMObjectBase *object); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMObject_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | // RLMObject accessor and read/write realm 22 | @interface RLMObjectBase () { 23 | @public 24 | RLMRealm *_realm; 25 | // objectSchema is a cached pointer to an object stored in the RLMSchema 26 | // owned by _realm, so it's guaranteed to stay alive as long as this object 27 | // without retaining it (and retaining it makes iteration slower) 28 | __unsafe_unretained RLMObjectSchema *_objectSchema; 29 | } 30 | 31 | // standalone initializer 32 | - (instancetype)initWithValue:(id)value schema:(RLMSchema *)schema; 33 | 34 | // live accessor initializer 35 | - (instancetype)initWithRealm:(__unsafe_unretained RLMRealm *const)realm 36 | schema:(__unsafe_unretained RLMObjectSchema *const)schema; 37 | 38 | // shared schema for this class 39 | + (RLMObjectSchema *)sharedSchema; 40 | 41 | @end 42 | 43 | @interface RLMDynamicObject : RLMObject 44 | 45 | @end 46 | 47 | // 48 | // Getters and setters for RLMObjectBase ivars for realm and objectSchema 49 | // 50 | FOUNDATION_EXTERN void RLMObjectBaseSetRealm(RLMObjectBase *object, RLMRealm *realm); 51 | FOUNDATION_EXTERN RLMRealm *RLMObjectBaseRealm(RLMObjectBase *object); 52 | FOUNDATION_EXTERN void RLMObjectBaseSetObjectSchema(RLMObjectBase *object, RLMObjectSchema *objectSchema); 53 | FOUNDATION_EXTERN RLMObjectSchema *RLMObjectBaseObjectSchema(RLMObjectBase *object); 54 | 55 | // Get linking objects for an RLMObjectBase 56 | FOUNDATION_EXTERN NSArray *RLMObjectBaseLinkingObjectsOfClass(RLMObjectBase *object, NSString *className, NSString *property); 57 | 58 | // Dynamic access to RLMObjectBase properties 59 | FOUNDATION_EXTERN id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key); 60 | FOUNDATION_EXTERN void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj); 61 | 62 | // Calls valueForKey: and re-raises NSUndefinedKeyExceptions 63 | FOUNDATION_EXTERN id RLMValidatedValueForProperty(id object, NSString *key, NSString *className); 64 | 65 | // Compare two RLObjectBases 66 | FOUNDATION_EXTERN BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2); 67 | 68 | // Get ObjectUil class for objc or swift 69 | FOUNDATION_EXTERN Class RLMObjectUtilClass(BOOL isSwift); 70 | 71 | FOUNDATION_EXTERN const NSUInteger RLMDescriptionMaxDepth; 72 | 73 | @class RLMProperty, RLMArray; 74 | @interface RLMObjectUtil : NSObject 75 | 76 | + (NSArray *)ignoredPropertiesForClass:(Class)cls; 77 | + (NSArray *)indexedPropertiesForClass:(Class)cls; 78 | 79 | + (NSArray *)getGenericListPropertyNames:(id)obj; 80 | + (void)initializeListProperty:(RLMObjectBase *)object property:(RLMProperty *)property array:(RLMArray *)array; 81 | 82 | + (NSDictionary *)getOptionalProperties:(id)obj; 83 | + (NSArray *)requiredPropertiesForClass:(Class)cls; 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMOptionalBase.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | @class RLMObjectBase, RLMProperty; 23 | 24 | @interface RLMOptionalBase : NSProxy 25 | 26 | - (instancetype)init; 27 | 28 | @property (nonatomic, weak) RLMObjectBase *object; 29 | 30 | @property (nonatomic, unsafe_unretained) RLMProperty *property; 31 | 32 | @property (nonatomic) id underlyingValue; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMPlatform.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/SourceKitten/68e9472d9e39360ddb53a76fa8fc9718a336cdd5/Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMPlatform.h -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMPrefix.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #ifdef __OBJC__ 20 | #import 21 | #endif 22 | 23 | #ifdef __cplusplus 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | 30 | #import 31 | #import 32 | #import 33 | #import 34 | #import 35 | #endif 36 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMProperty.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | #import 22 | 23 | RLM_ASSUME_NONNULL_BEGIN 24 | 25 | @protocol RLMInt 26 | @end 27 | @protocol RLMBool 28 | @end 29 | @protocol RLMDouble 30 | @end 31 | @protocol RLMFloat 32 | @end 33 | 34 | @interface NSNumber () 35 | @end 36 | 37 | /** 38 | This class models properties persisted to Realm in an RLMObjectSchema. 39 | 40 | When using Realm, RLMProperty objects allow performing migrations and 41 | introspecting the database's schema. 42 | 43 | These properties map to columns in the core database. 44 | */ 45 | @interface RLMProperty : NSObject 46 | 47 | #pragma mark - Properties 48 | 49 | /** 50 | Property name. 51 | */ 52 | @property (nonatomic, readonly) NSString *name; 53 | 54 | /** 55 | Property type. 56 | 57 | @see RLMPropertyType 58 | */ 59 | @property (nonatomic, readonly) RLMPropertyType type; 60 | 61 | /** 62 | Indicates if this property is indexed. 63 | 64 | @see RLMObject 65 | */ 66 | @property (nonatomic, readonly) BOOL indexed; 67 | 68 | /** 69 | Object class name - specify object types for RLMObject and RLMArray properties. 70 | */ 71 | @property (nonatomic, readonly, copy, nullable) NSString *objectClassName; 72 | 73 | /** 74 | Whether this property is optional. 75 | */ 76 | @property (nonatomic, readonly) BOOL optional; 77 | 78 | #pragma mark - Methods 79 | 80 | /** 81 | Returns YES if property objects are equal. 82 | */ 83 | - (BOOL)isEqualToProperty:(RLMProperty *)property; 84 | 85 | @end 86 | 87 | RLM_ASSUME_NONNULL_END 88 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMProperty_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | #import 22 | 23 | @class RLMObjectBase; 24 | 25 | FOUNDATION_EXTERN BOOL RLMPropertyTypeIsNullable(RLMPropertyType propertyType); 26 | FOUNDATION_EXTERN BOOL RLMPropertyTypeIsNumeric(RLMPropertyType propertyType); 27 | 28 | // private property interface 29 | @interface RLMProperty () 30 | 31 | - (instancetype)initWithName:(NSString *)name 32 | indexed:(BOOL)indexed 33 | property:(objc_property_t)property; 34 | 35 | - (instancetype)initSwiftPropertyWithName:(NSString *)name 36 | indexed:(BOOL)indexed 37 | property:(objc_property_t)property 38 | instance:(RLMObjectBase *)objectInstance; 39 | 40 | - (instancetype)initSwiftListPropertyWithName:(NSString *)name 41 | ivar:(Ivar)ivar 42 | objectClassName:(NSString *)objectClassName; 43 | 44 | - (instancetype)initSwiftOptionalPropertyWithName:(NSString *)name 45 | ivar:(Ivar)ivar 46 | propertyType:(RLMPropertyType)propertyType; 47 | 48 | // private setters 49 | @property (nonatomic, assign) NSUInteger column; 50 | @property (nonatomic, readwrite, assign) RLMPropertyType type; 51 | @property (nonatomic, readwrite) BOOL indexed; 52 | @property (nonatomic, readwrite) BOOL optional; 53 | @property (nonatomic, copy) NSString *objectClassName; 54 | 55 | // private properties 56 | @property (nonatomic, assign) char objcType; 57 | @property (nonatomic, copy) NSString *objcRawType; 58 | @property (nonatomic, assign) BOOL isPrimary; 59 | @property (nonatomic, assign) Ivar swiftIvar; 60 | 61 | // getter and setter names 62 | @property (nonatomic, copy) NSString *getterName; 63 | @property (nonatomic, copy) NSString *setterName; 64 | @property (nonatomic) SEL getterSel; 65 | @property (nonatomic) SEL setterSel; 66 | 67 | @end 68 | 69 | @interface RLMProperty (Dynamic) 70 | /** 71 | This method is useful only in specialized circumstances, for example, in conjunction with 72 | +[RLMObjectSchema initWithClassName:objectClass:properties:]. If you are simply building an 73 | app on Realm, it is not recommened to use this method. 74 | 75 | Initialize an RLMProperty 76 | 77 | @warning This method is useful only in specialized circumstances. 78 | 79 | @param name The property name. 80 | @param type The property type. 81 | @param objectClassName The object type used for Object and Array types. 82 | 83 | @return An initialized instance of RLMProperty. 84 | */ 85 | - (instancetype)initWithName:(NSString *)name 86 | type:(RLMPropertyType)type 87 | objectClassName:(NSString *)objectClassName 88 | indexed:(BOOL)indexed 89 | optional:(BOOL)optional; 90 | @end 91 | 92 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMRealmConfiguration.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An `RLMRealmConfiguration` is used to describe the different options used to 26 | create an `RLMRealm` instance. 27 | */ 28 | @interface RLMRealmConfiguration : NSObject 29 | 30 | #pragma mark - Default Configuration 31 | 32 | /** 33 | Returns the default configuration used to create Realms when no other 34 | configuration is explicitly specified (i.e. `+[RLMRealm defaultRealm]`). 35 | 36 | @return The default Realm configuration. 37 | */ 38 | + (instancetype)defaultConfiguration; 39 | 40 | /** 41 | Sets the default configuration to the given `RLMRealmConfiguration`. 42 | 43 | @param configuration The new default Realm configuration. 44 | */ 45 | + (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration; 46 | 47 | #pragma mark - Properties 48 | 49 | /// The path to the realm file. Mutually exclusive with `inMemoryIdentifier`. 50 | @property (nonatomic, copy, nullable) NSString *path; 51 | 52 | /// A string used to identify a particular in-memory Realm. Mutually exclusive with `path`. 53 | @property (nonatomic, copy, nullable) NSString *inMemoryIdentifier; 54 | 55 | /// 64-byte key to use to encrypt the data. 56 | @property (nonatomic, copy, nullable) NSData *encryptionKey; 57 | 58 | /// Whether the Realm is read-only (must be YES for read-only files). 59 | @property (nonatomic) BOOL readOnly; 60 | 61 | /// The current schema version. 62 | @property (nonatomic) uint64_t schemaVersion; 63 | 64 | /// The block which migrates the Realm to the current version. 65 | @property (nonatomic, copy, nullable) RLMMigrationBlock migrationBlock; 66 | 67 | /// The classes persisted in the Realm. 68 | @property (nonatomic, copy, nullable) NSArray *objectClasses; 69 | 70 | @end 71 | 72 | RLM_ASSUME_NONNULL_END 73 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMRealmConfiguration_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMSchema; 22 | 23 | @interface RLMRealmConfiguration () 24 | 25 | @property (nonatomic, readwrite) bool cache; 26 | @property (nonatomic, readwrite) bool dynamic; 27 | @property (nonatomic, copy) RLMSchema *customSchema; 28 | 29 | // Get the default confiugration without copying it 30 | + (RLMRealmConfiguration *)rawDefaultConfiguration; 31 | 32 | + (void)resetRealmConfigurationState; 33 | @end 34 | 35 | // Get a path in the platform-appropriate documents directory with the given filename 36 | FOUNDATION_EXTERN NSString *RLMRealmPathForFile(NSString *fileName); 37 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMRealm_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMFastEnumerator; 22 | 23 | // Disable syncing files to disk. Cannot be re-enabled. Use only for tests. 24 | FOUNDATION_EXTERN void RLMDisableSyncToDisk(); 25 | 26 | FOUNDATION_EXTERN NSData *RLMRealmValidatedEncryptionKey(NSData *key); 27 | 28 | // RLMRealm private members 29 | @interface RLMRealm () 30 | 31 | @property (nonatomic, readonly) BOOL dynamic; 32 | @property (nonatomic, readwrite) RLMSchema *schema; 33 | 34 | + (void)resetRealmState; 35 | 36 | /** 37 | This method is useful only in specialized circumstances, for example, when opening Realm files 38 | retrieved externally that contain a different schema than defined in your application. 39 | If you are simply building an app on Realm you should consider using: 40 | [defaultRealm]([RLMRealm defaultRealm]) or [realmWithPath:]([RLMRealm realmWithPath:]) 41 | 42 | Obtains an `RLMRealm` instance with persistence to a specific file path with 43 | options. 44 | 45 | @warning This method is useful only in specialized circumstances. 46 | 47 | @param path Path to the file you want the data saved in. 48 | @param key 64-byte key to use to encrypt the data. 49 | @param readonly `BOOL` indicating if this Realm is read-only (must use for read-only files) 50 | @param inMemory `BOOL` indicating if this Realm is in-memory 51 | @param dynamic `BOOL` indicating if this Realm is dynamic 52 | @param customSchema `RLMSchema` object representing the schema for the Realm 53 | @param outError If an error occurs, upon return contains an `NSError` object 54 | that describes the problem. If you are not interested in 55 | possible errors, pass in NULL. 56 | 57 | @return An `RLMRealm` instance. 58 | 59 | @see RLMRealm defaultRealm 60 | @see RLMRealm realmWithPath: 61 | @see RLMRealm realmWithPath:readOnly:error: 62 | @see RLMRealm realmWithPath:encryptionKey:readOnly:error: 63 | */ 64 | + (instancetype)realmWithPath:(NSString *)path 65 | key:(NSData *)key 66 | readOnly:(BOOL)readonly 67 | inMemory:(BOOL)inMemory 68 | dynamic:(BOOL)dynamic 69 | schema:(RLMSchema *)customSchema 70 | error:(NSError **)outError; 71 | 72 | - (void)registerEnumerator:(RLMFastEnumerator *)enumerator; 73 | - (void)unregisterEnumerator:(RLMFastEnumerator *)enumerator; 74 | 75 | - (void)sendNotifications:(NSString *)notification; 76 | - (void)notify; 77 | - (void)verifyThread; 78 | 79 | + (NSString *)writeableTemporaryPathForFile:(NSString *)fileName; 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMResults_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @class RLMObjectSchema; 22 | 23 | @interface RLMResults () 24 | @property (nonatomic, unsafe_unretained) RLMObjectSchema *objectSchema; 25 | @end 26 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMSchema.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | RLM_ASSUME_NONNULL_BEGIN 23 | 24 | @class RLMObjectSchema; 25 | 26 | /** 27 | This class represents the collection of model object schemas persisted to Realm. 28 | 29 | When using Realm, RLMSchema objects allow performing migrations and 30 | introspecting the database's schema. 31 | 32 | Schemas map to collections of tables in the core database. 33 | */ 34 | @interface RLMSchema : NSObject 35 | 36 | #pragma mark - Properties 37 | 38 | /** 39 | An NSArray containing RLMObjectSchema's for all object types in this Realm. Meant 40 | to be used during migrations for dynamic introspection. 41 | 42 | @see RLMObjectSchema 43 | */ 44 | @property (nonatomic, readonly, copy) NSArray *objectSchema; 45 | 46 | #pragma mark - Methods 47 | 48 | /** 49 | Returns an RLMObjectSchema for the given class name in this RLMSchema. 50 | 51 | @param className The object class name. 52 | @return RLMObjectSchema for the given class in this RLMSchema. 53 | 54 | @see RLMObjectSchema 55 | */ 56 | - (nullable RLMObjectSchema *)schemaForClassName:(NSString *)className; 57 | 58 | /** 59 | Look up an RLMObjectSchema for the given class name in this Realm. Throws if there 60 | is no object of type className in this RLMSchema instance. 61 | 62 | @param className The object class name. 63 | @return RLMObjectSchema for the given class in this Realm. 64 | 65 | @see RLMObjectSchema 66 | */ 67 | - (RLMObjectSchema *)objectForKeyedSubscript:(id )className; 68 | 69 | /** 70 | Returns YES if schema are equal 71 | */ 72 | - (BOOL)isEqualToSchema:(RLMSchema *)schema; 73 | 74 | @end 75 | 76 | RLM_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMSchema_Private.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #import 24 | #import 25 | 26 | RLM_ASSUME_NONNULL_BEGIN 27 | 28 | @class RLMRealm; 29 | 30 | // 31 | // RLMSchema private interface 32 | // 33 | @interface RLMSchema () 34 | 35 | /** 36 | Returns an `RLMSchema` containing only the given `RLMObject` subclasses. 37 | 38 | @param classes The classes to be included in the schema. 39 | 40 | @return An `RLMSchema` containing only the given classes. 41 | */ 42 | + (instancetype)schemaWithObjectClasses:(NSArray *)classes; 43 | 44 | @property (nonatomic, readwrite, copy) NSArray *objectSchema; 45 | 46 | // schema based on runtime objects 47 | + (instancetype)sharedSchema; 48 | 49 | // schema based upon all currently registered object classes 50 | + (instancetype)partialSharedSchema; 51 | 52 | // schema based on tables in a Realm 53 | + (instancetype)dynamicSchemaFromRealm:(RLMRealm *)realm; 54 | 55 | // class for string 56 | + (nullable Class)classForString:(NSString *)className; 57 | 58 | // shallow copy for reusing schema properties accross the same Realm on multiple threads 59 | - (instancetype)shallowCopy; 60 | 61 | @end 62 | 63 | RLM_ASSUME_NONNULL_END 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMSwiftBridgingHeader.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | #import 21 | 22 | @interface RLMRealm (Swift) 23 | + (void)resetRealmState; 24 | @end 25 | 26 | @interface RLMArray (Swift) 27 | 28 | - (instancetype)initWithObjectClassName:(NSString *)objectClassName; 29 | 30 | - (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args; 31 | - (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args; 32 | 33 | @end 34 | 35 | @interface RLMResults (Swift) 36 | 37 | - (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args; 38 | - (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args; 39 | 40 | @end 41 | 42 | @interface RLMObjectBase (Swift) 43 | 44 | - (instancetype)initWithRealm:(RLMRealm *)realm schema:(RLMObjectSchema *)schema defaultValues:(BOOL)useDefaults; 45 | 46 | + (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args; 47 | + (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/RLMSwiftSupport.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | @interface RLMSwiftSupport : NSObject 22 | 23 | + (BOOL)isSwiftClassName:(NSString *)className; 24 | + (NSString *)demangleClassName:(NSString *)className; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Realm/Realm.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 Realm Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | //////////////////////////////////////////////////////////////////////////// 18 | 19 | #import 20 | 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Subscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "Subscript.swift" : { 3 | "key.diagnostic_stage" : "source.diagnostic.stage.swift.parse", 4 | "key.length" : 134, 5 | "key.offset" : 0, 6 | "key.substructure" : [ 7 | { 8 | "key.accessibility" : "source.lang.swift.accessibility.internal", 9 | "key.annotated_decl" : "struct VoidStruct<\/Declaration>", 10 | "key.bodylength" : 113, 11 | "key.bodyoffset" : 19, 12 | "key.column" : 8, 13 | "key.decl_lang" : "source.lang.swift", 14 | "key.filepath" : "Subscript.swift", 15 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> VoidStruct<\/decl.name><\/decl.struct>", 16 | "key.kind" : "source.lang.swift.decl.struct", 17 | "key.length" : 133, 18 | "key.line" : 1, 19 | "key.modulename" : "Subscript", 20 | "key.name" : "VoidStruct", 21 | "key.namelength" : 10, 22 | "key.nameoffset" : 7, 23 | "key.offset" : 0, 24 | "key.parsed_declaration" : "struct VoidStruct", 25 | "key.parsed_scope.end" : 7, 26 | "key.parsed_scope.start" : 1, 27 | "key.substructure" : [ 28 | { 29 | "key.accessibility" : "source.lang.swift.accessibility.internal", 30 | "key.annotated_decl" : "subscript(key: String<\/Type>) -> () { get set }<\/Declaration>", 31 | "key.bodylength" : 46, 32 | "key.bodyoffset" : 84, 33 | "key.column" : 5, 34 | "key.decl_lang" : "source.lang.swift", 35 | "key.doc.column" : 5, 36 | "key.doc.comment" : "Returns or sets Void.", 37 | "key.doc.declaration" : "subscript(key: String) -> () { get set }", 38 | "key.doc.file" : "Subscript.swift", 39 | "key.doc.full_as_xml" : "subscript(_:)<\/Name>s:9Subscript10VoidStructVyySScip<\/USR>subscript(key: String) -> () { get set }<\/Declaration>Returns or sets Void.<\/Para><\/Abstract><\/CommentParts><\/Other>", 40 | "key.doc.line" : 3, 41 | "key.doc.name" : "subscript(_:)", 42 | "key.doc.type" : "Other", 43 | "key.doclength" : 26, 44 | "key.docoffset" : 24, 45 | "key.filepath" : "Subscript.swift", 46 | "key.fully_annotated_decl" : "subscript<\/syntaxtype.keyword>(key<\/decl.var.parameter.name>: String<\/ref.struct><\/decl.var.parameter.type><\/decl.var.parameter>) -> ()<\/tuple><\/decl.function.returntype> { get<\/syntaxtype.keyword> set<\/syntaxtype.keyword> }<\/decl.function.subscript>", 47 | "key.kind" : "source.lang.swift.decl.function.subscript", 48 | "key.length" : 77, 49 | "key.line" : 3, 50 | "key.modulename" : "Subscript", 51 | "key.name" : "subscript(_:)", 52 | "key.namelength" : 22, 53 | "key.nameoffset" : 54, 54 | "key.offset" : 54, 55 | "key.parsed_declaration" : "subscript(key: String) -> ()", 56 | "key.parsed_scope.end" : 6, 57 | "key.parsed_scope.start" : 3, 58 | "key.setter_accessibility" : "source.lang.swift.accessibility.internal", 59 | "key.substructure" : [ 60 | 61 | ], 62 | "key.typename" : "(String) -> ()", 63 | "key.typeusr" : "$syySScD", 64 | "key.usr" : "s:9Subscript10VoidStructVyySScip" 65 | } 66 | ], 67 | "key.typename" : "VoidStruct.Type", 68 | "key.typeusr" : "$s9Subscript10VoidStructVmD", 69 | "key.usr" : "s:9Subscript10VoidStructV" 70 | } 71 | ] 72 | } 73 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Subscript.swift: -------------------------------------------------------------------------------- 1 | struct VoidStruct { 2 | /// Returns or sets Void. 3 | subscript(key: String) -> () { 4 | get { return () } 5 | set {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Subscript@swift-5.9.json: -------------------------------------------------------------------------------- 1 | { 2 | "Subscript.swift" : { 3 | "key.diagnostic_stage" : "source.diagnostic.stage.swift.parse", 4 | "key.length" : 134, 5 | "key.offset" : 0, 6 | "key.substructure" : [ 7 | { 8 | "key.accessibility" : "source.lang.swift.accessibility.internal", 9 | "key.annotated_decl" : "struct VoidStruct<\/Declaration>", 10 | "key.bodylength" : 113, 11 | "key.bodyoffset" : 19, 12 | "key.column" : 8, 13 | "key.decl_lang" : "source.lang.swift", 14 | "key.filepath" : "Subscript.swift", 15 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> VoidStruct<\/decl.name><\/decl.struct>", 16 | "key.kind" : "source.lang.swift.decl.struct", 17 | "key.length" : 133, 18 | "key.line" : 1, 19 | "key.modulename" : "Subscript", 20 | "key.name" : "VoidStruct", 21 | "key.namelength" : 10, 22 | "key.nameoffset" : 7, 23 | "key.offset" : 0, 24 | "key.parsed_declaration" : "struct VoidStruct", 25 | "key.parsed_scope.end" : 7, 26 | "key.parsed_scope.start" : 1, 27 | "key.reusingastcontext" : false, 28 | "key.substructure" : [ 29 | { 30 | "key.accessibility" : "source.lang.swift.accessibility.internal", 31 | "key.annotated_decl" : "subscript(key: String<\/Type>) -> () { get set }<\/Declaration>", 32 | "key.bodylength" : 46, 33 | "key.bodyoffset" : 84, 34 | "key.column" : 5, 35 | "key.decl_lang" : "source.lang.swift", 36 | "key.doc.column" : 5, 37 | "key.doc.comment" : "Returns or sets Void.", 38 | "key.doc.declaration" : "subscript(key: String) -> () { get set }", 39 | "key.doc.file" : "Subscript.swift", 40 | "key.doc.full_as_xml" : "subscript(_:)<\/Name>s:9Subscript10VoidStructVyySScip<\/USR>subscript(key: String) -> () { get set }<\/Declaration>Returns or sets Void.<\/Para><\/Abstract><\/CommentParts><\/Other>", 41 | "key.doc.line" : 3, 42 | "key.doc.name" : "subscript(_:)", 43 | "key.doc.type" : "Other", 44 | "key.doclength" : 26, 45 | "key.docoffset" : 24, 46 | "key.filepath" : "Subscript.swift", 47 | "key.fully_annotated_decl" : "subscript<\/syntaxtype.keyword>(key<\/decl.var.parameter.name>: String<\/ref.struct><\/decl.var.parameter.type><\/decl.var.parameter>) -> ()<\/tuple><\/decl.function.returntype> { get<\/syntaxtype.keyword> set<\/syntaxtype.keyword> }<\/decl.function.subscript>", 48 | "key.kind" : "source.lang.swift.decl.function.subscript", 49 | "key.length" : 77, 50 | "key.line" : 3, 51 | "key.modulename" : "Subscript", 52 | "key.name" : "subscript(_:)", 53 | "key.namelength" : 22, 54 | "key.nameoffset" : 54, 55 | "key.offset" : 54, 56 | "key.parsed_declaration" : "subscript(key: String) -> ()", 57 | "key.parsed_scope.end" : 6, 58 | "key.parsed_scope.start" : 3, 59 | "key.reusingastcontext" : false, 60 | "key.setter_accessibility" : "source.lang.swift.accessibility.internal", 61 | "key.substructure" : [ 62 | 63 | ], 64 | "key.typename" : "(String) -> ()", 65 | "key.typeusr" : "$syySScD", 66 | "key.usr" : "s:9Subscript10VoidStructVyySScip" 67 | } 68 | ], 69 | "key.typename" : "VoidStruct.Type", 70 | "key.typeusr" : "$s9Subscript10VoidStructVmD", 71 | "key.usr" : "s:9Subscript10VoidStructV" 72 | } 73 | ] 74 | } 75 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Subscript@swift-6.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "Subscript.swift" : { 3 | "key.diagnostic_stage" : "source.diagnostic.stage.swift.parse", 4 | "key.length" : 134, 5 | "key.offset" : 0, 6 | "key.substructure" : [ 7 | { 8 | "key.accessibility" : "source.lang.swift.accessibility.internal", 9 | "key.annotated_decl" : "struct VoidStruct<\/Declaration>", 10 | "key.bodylength" : 113, 11 | "key.bodyoffset" : 19, 12 | "key.column" : 8, 13 | "key.decl_lang" : "source.lang.swift", 14 | "key.filepath" : "Subscript.swift", 15 | "key.fully_annotated_decl" : "struct<\/syntaxtype.keyword> VoidStruct<\/decl.name><\/decl.struct>", 16 | "key.kind" : "source.lang.swift.decl.struct", 17 | "key.length" : 133, 18 | "key.line" : 1, 19 | "key.modulename" : "Subscript", 20 | "key.name" : "VoidStruct", 21 | "key.namelength" : 10, 22 | "key.nameoffset" : 7, 23 | "key.offset" : 0, 24 | "key.parsed_declaration" : "struct VoidStruct", 25 | "key.parsed_scope.end" : 7, 26 | "key.parsed_scope.start" : 1, 27 | "key.reusingastcontext" : false, 28 | "key.substructure" : [ 29 | { 30 | "key.accessibility" : "source.lang.swift.accessibility.internal", 31 | "key.annotated_decl" : "subscript(key: String<\/Type>) -> () { get set }<\/Declaration>", 32 | "key.bodylength" : 46, 33 | "key.bodyoffset" : 84, 34 | "key.column" : 5, 35 | "key.decl_lang" : "source.lang.swift", 36 | "key.doc_comment" : "Returns or sets Void.", 37 | "key.doc.column" : 5, 38 | "key.doc.comment" : "Returns or sets Void.", 39 | "key.doc.declaration" : "subscript(key: String) -> () { get set }", 40 | "key.doc.file" : "Subscript.swift", 41 | "key.doc.full_as_xml" : "subscript(_:)<\/Name>s:9Subscript10VoidStructVyySScip<\/USR>subscript(key: String) -> () { get set }<\/Declaration>Returns or sets Void.<\/Para><\/Abstract><\/CommentParts><\/Other>", 42 | "key.doc.line" : 3, 43 | "key.doc.name" : "subscript(_:)", 44 | "key.doc.type" : "Other", 45 | "key.doclength" : 26, 46 | "key.docoffset" : 24, 47 | "key.filepath" : "Subscript.swift", 48 | "key.fully_annotated_decl" : "subscript<\/syntaxtype.keyword>(key<\/decl.var.parameter.name>: String<\/ref.struct><\/decl.var.parameter.type><\/decl.var.parameter>) -> ()<\/tuple><\/decl.function.returntype> { get<\/syntaxtype.keyword> set<\/syntaxtype.keyword> }<\/decl.function.subscript>", 49 | "key.kind" : "source.lang.swift.decl.function.subscript", 50 | "key.length" : 77, 51 | "key.line" : 3, 52 | "key.modulename" : "Subscript", 53 | "key.name" : "subscript(_:)", 54 | "key.namelength" : 22, 55 | "key.nameoffset" : 54, 56 | "key.offset" : 54, 57 | "key.parsed_declaration" : "subscript(key: String) -> ()", 58 | "key.parsed_scope.end" : 6, 59 | "key.parsed_scope.start" : 3, 60 | "key.reusingastcontext" : false, 61 | "key.setter_accessibility" : "source.lang.swift.accessibility.internal", 62 | "key.substructure" : [ 63 | 64 | ], 65 | "key.typename" : "(String) -> ()", 66 | "key.typeusr" : "$syySScD", 67 | "key.usr" : "s:9Subscript10VoidStructVyySScip" 68 | } 69 | ], 70 | "key.typename" : "VoidStruct.Type", 71 | "key.typeusr" : "$s9Subscript10VoidStructVmD", 72 | "key.usr" : "s:9Subscript10VoidStructV" 73 | } 74 | ] 75 | } 76 | } -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/SuperScript.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | ᴬ ᴮ ᴰ ᴱ ᴳ ᴴ ᴵ ᴶ ᴷ ᴸ ᴹ ᴺ ᴼ ᴾ ᴿ ᵀ ᵁ ⱽ ᵂ 5 | */ 6 | @interface SuperScript : NSObject 7 | 8 | #pragma mark ᵃ ᵇ ᶜ ᵈ ᵉ ᶠ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ᵛ ʷ ˣ ʸ ᶻ 9 | 10 | /** 11 | ᵝ ᵞ ᵟ ᵋ ᶿ ᶥ ᶹ ᵠ ᵡ 12 | */ 13 | - (IBAction)superSize:(id)sender; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/SuperScript.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "SuperScript.h" : { 4 | "key.diagnostic_stage" : "", 5 | "key.substructure" : [ 6 | { 7 | "key.always_deprecated" : false, 8 | "key.always_unavailable" : false, 9 | "key.deprecation_message" : "", 10 | "key.doc.column" : 12, 11 | "key.doc.comment" : "ᴬ \tᴮ \t\tᴰ \tᴱ \t\tᴳ \tᴴ \tᴵ \tᴶ \tᴷ \tᴸ \tᴹ \tᴺ \tᴼ \tᴾ \t\tᴿ \t\tᵀ \tᵁ \tⱽ \tᵂ", 12 | "key.doc.file" : "SuperScript.h", 13 | "key.doc.full_as_xml" : "", 14 | "key.doc.line" : 6, 15 | "key.filepath" : "SuperScript.h", 16 | "key.kind" : "sourcekitten.source.lang.objc.decl.class", 17 | "key.name" : "SuperScript", 18 | "key.parsed_declaration" : "@interface SuperScript : NSObject", 19 | "key.parsed_scope.end" : 15, 20 | "key.parsed_scope.start" : 6, 21 | "key.substructure" : [ 22 | { 23 | "key.doc.column" : 1, 24 | "key.doc.file" : "SuperScript.h", 25 | "key.doc.line" : 8, 26 | "key.filepath" : "SuperScript.h", 27 | "key.kind" : "sourcekitten.source.lang.objc.mark", 28 | "key.name" : "ᵃ\tᵇ\tᶜ\tᵈ\tᵉ\tᶠ\tᵍ\tʰ\tⁱ\tʲ\tᵏ\tˡ\tᵐ\tⁿ\tᵒ\tᵖ\t\tʳ\tˢ\tᵗ\tᵘ\tᵛ\tʷ\tˣ\tʸ\tᶻ", 29 | "key.parsed_scope.end" : 8, 30 | "key.parsed_scope.start" : 8 31 | }, 32 | { 33 | "key.always_deprecated" : false, 34 | "key.always_unavailable" : false, 35 | "key.deprecation_message" : "", 36 | "key.doc.column" : 13, 37 | "key.doc.comment" : "ᵝ \tᵞ \tᵟ \tᵋ \t\t\tᶿ \tᶥ \t\t\t\t\t\t\t\t\t\t\tᶹ \tᵠ \tᵡ", 38 | "key.doc.file" : "SuperScript.h", 39 | "key.doc.full_as_xml" : "", 40 | "key.doc.line" : 13, 41 | "key.filepath" : "SuperScript.h", 42 | "key.kind" : "sourcekitten.source.lang.objc.decl.method.instance", 43 | "key.name" : "-superSize:", 44 | "key.parsed_declaration" : "- (void)superSize:(id)sender;", 45 | "key.parsed_scope.end" : 13, 46 | "key.parsed_scope.start" : 13, 47 | "key.swift_declaration" : "@IBAction func superSize(_ sender: Any!)", 48 | "key.swift_name" : "superSize(_:)", 49 | "key.unavailable_message" : "", 50 | "key.usr" : "c:objc(cs)SuperScript(im)superSize:" 51 | } 52 | ], 53 | "key.swift_declaration" : "class SuperScript : NSObject", 54 | "key.swift_name" : "SuperScript", 55 | "key.unavailable_message" : "", 56 | "key.usr" : "c:objc(cs)SuperScript" 57 | } 58 | ] 59 | } 60 | } 61 | ] 62 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/Fixtures/Union.h: -------------------------------------------------------------------------------- 1 | typedef union { double a; int b; } VALUE; 2 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/LibraryWrapperGeneratorTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SourceKittenFramework 2 | import XCTest 3 | 4 | final class LibraryWrapperGeneratorTests: XCTestCase { 5 | #if compiler(>=5.4) && os(macOS) 6 | func testLibraryWrappersAreUpToDate() throws { 7 | let sourceKittenFrameworkModule = Module(xcodeBuildArguments: sourcekittenXcodebuildArguments, 8 | name: "SourceKittenFramework", inPath: projectRoot)! 9 | let docsJSON = sourceKittenFrameworkModule.docs.description 10 | 11 | /// If this assert fires and the cause is missing Windows types, then see e.g. https://github.com/jpsim/SourceKitten/pull/828 12 | /// for direction - the idea is to provide 'shim' types to let sourcekit reason about the types and leave this test unchanged. 13 | XCTAssert(docsJSON.range(of: "error type") == nil) 14 | 15 | let jsonArray = try JSONSerialization.jsonObject(with: docsJSON.data(using: .utf8)!, options: []) as? NSArray 16 | XCTAssertNotNil(jsonArray, "JSON should be properly parsed") 17 | for wrapperConfig in LibraryWrapperGenerator.allCases { 18 | let wrapperURL = URL(fileURLWithPath: "\(projectRoot)/\(wrapperConfig.filePath)") 19 | let existingWrapper = try String(contentsOf: wrapperURL) 20 | let generatedWrapper = try wrapperConfig.generate(compilerArguments: sourceKittenFrameworkModule.compilerArguments) 21 | XCTAssertEqual(existingWrapper, generatedWrapper) 22 | let overwrite = false // set this to true to overwrite existing wrappers with the generated ones 23 | if existingWrapper != generatedWrapper && overwrite { 24 | try generatedWrapper.data(using: .utf8)?.write(to: wrapperURL) 25 | } 26 | } 27 | } 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/OffsetMapTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | class OffsetMapTests: XCTestCase { 6 | 7 | func testOffsetMapContainsDeclarationOffsetWithDocCommentButNotAlreadyDocumented() throws { 8 | // Subscripts aren't parsed by SourceKit, so OffsetMap should contain its offset. 9 | let file = File(contents: 10 | "struct VoidStruct {\n/// Returns or sets Void.\nsubscript(key: String) -> () {\n" + 11 | "get { return () }\nset {}\n}\n}" 12 | ) 13 | let documentedTokenOffsets = file.stringView.documentedTokenOffsets(syntaxMap: try SyntaxMap(file: file)) 14 | let response = file.process(dictionary: try Request.editorOpen(file: file).send(), cursorInfoRequest: nil) 15 | let offsetMap = file.makeOffsetMap(documentedTokenOffsets: documentedTokenOffsets, dictionary: response) 16 | XCTAssertEqual(offsetMap, [:], "should generate correct offset map of [(declaration offset): (parent offset)]") 17 | } 18 | 19 | func testOffsetMapDoesntContainAlreadyDocumentedDeclarationOffset() throws { 20 | // Struct declarations are parsed by SourceKit, so OffsetMap shouldn't contain its offset. 21 | let file = File(contents: "/// Doc Comment\nstruct DocumentedStruct {}") 22 | let documentedTokenOffsets = file.stringView.documentedTokenOffsets(syntaxMap: try SyntaxMap(file: file)) 23 | let response = file.process(dictionary: try Request.editorOpen(file: file).send(), cursorInfoRequest: nil) 24 | let offsetMap = file.makeOffsetMap(documentedTokenOffsets: documentedTokenOffsets, dictionary: response) 25 | XCTAssertEqual(offsetMap, [:], "should generate empty offset map") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/SourceKitObjectTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | class SourceKitObjectTests: XCTestCase { 5 | 6 | func testExample() { 7 | let path = #file 8 | let object: SourceKitObject = [ 9 | "key.request": UID("source.request.editor.open"), 10 | "key.name": path, 11 | "key.sourcefile": path 12 | ] 13 | let expected = """ 14 | { 15 | key.request: source.request.editor.open, 16 | key.name: \"\(#file)\", 17 | key.sourcefile: \"\(#file)\" 18 | } 19 | """ 20 | XCTAssertEqual(object.description, expected) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/SwiftDocKeyTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | class SwiftDocKeyTests: XCTestCase { 6 | 7 | func testElements() throws { 8 | let structure = try Structure(file: File(contents: "class Foo: Bar {}")) 9 | let substructures = structure.dictionary[SwiftDocKey.substructure.rawValue] as! [[String: SourceKitRepresentable]] 10 | let elements = (substructures[0][SwiftDocKey.elements.rawValue] as! [[String: SourceKitRepresentable]]).map(toNSDictionary) 11 | let expected: [NSDictionary] = [ 12 | [ 13 | "key.kind": "source.lang.swift.structure.elem.typeref", 14 | "key.offset": 11, 15 | "key.length": 3 16 | ] 17 | ] 18 | XCTAssertEqual(elements, expected) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Tests/SourceKittenFrameworkTests/SyntaxTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import XCTest 4 | 5 | private typealias TokenWrapper = (kind: SyntaxKind, offset: ByteCount, length: ByteCount) 6 | 7 | private func compareSyntax(file: File, expectedTokens: [TokenWrapper]) { 8 | let expectedSyntaxMap = SyntaxMap(tokens: expectedTokens.map { tokenWrapper in 9 | return SyntaxToken(type: tokenWrapper.kind.rawValue, offset: tokenWrapper.offset, length: tokenWrapper.length) 10 | }) 11 | let syntaxMap = try! SyntaxMap(file: file) 12 | XCTAssertEqual(syntaxMap, expectedSyntaxMap, "should generate expected syntax map") 13 | 14 | let syntaxJSONData = syntaxMap.description.data(using: .utf8)! 15 | let jsonArray = try! JSONSerialization.jsonObject(with: syntaxJSONData, options: []) as? [Any] 16 | XCTAssertEqual( 17 | jsonArray!.bridge(), 18 | expectedSyntaxMap.tokens.map({ $0.dictionaryValue.bridge() }).bridge(), 19 | "JSON should match expected syntax" 20 | ) 21 | } 22 | 23 | class SyntaxTests: XCTestCase { 24 | 25 | func testPrintEmptySyntax() throws { 26 | XCTAssertEqual(try SyntaxMap(file: File(contents: "")).description, "[\n\n]", "should print empty syntax") 27 | } 28 | 29 | func testGenerateSameSyntaxMapFileAndContents() throws { 30 | let filepath: String 31 | if let buildWorkspaceRoot = bazelProjectRoot { 32 | filepath = buildWorkspaceRoot + "/Tests/SourceKittenFrameworkTests/SyntaxTests.swift" 33 | } else { 34 | filepath = #file 35 | } 36 | let fileContents = try String(contentsOfFile: filepath, encoding: .utf8) 37 | try XCTAssertEqual(SyntaxMap(file: File(path: filepath)!), 38 | SyntaxMap(file: File(contents: fileContents)), 39 | "should generate the same syntax map for a file as raw text") 40 | } 41 | 42 | func testSubscript() { 43 | compareSyntax(file: File(contents: "struct A { subscript(index: Int) -> () { return () } }"), 44 | expectedTokens: [ 45 | (.keyword, 0, 6), 46 | (.identifier, 7, 1), 47 | (.keyword, 11, 9), 48 | (.identifier, 21, 5), 49 | (.typeidentifier, 28, 3), 50 | (.keyword, 41, 6) 51 | ] 52 | ) 53 | } 54 | 55 | func testSyntaxMapPrintValidJSON() { 56 | compareSyntax(file: File(contents: "import Foundation // Hello World!"), 57 | expectedTokens: [ 58 | (.keyword, 0, 6), 59 | (.identifier, 7, 10), 60 | (.comment, 18, 15) 61 | ] 62 | ) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "sourcekitten") 2 | -------------------------------------------------------------------------------- /bazel/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/SourceKitten/68e9472d9e39360ddb53a76fa8fc9718a336cdd5/bazel/BUILD -------------------------------------------------------------------------------- /bazel/SWXMLHash.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | ) 5 | 6 | swift_library( 7 | name = "SWXMLHash", 8 | srcs = glob(["Source/**/*.swift"]), 9 | module_name = "SWXMLHash", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /bazel/SwiftArgumentParser.BUILD: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") 2 | 3 | swift_library( 4 | name = "ArgumentParserToolInfo", 5 | srcs = glob(["Sources/ArgumentParserToolInfo/**/*.swift"]), 6 | module_name = "ArgumentParserToolInfo", 7 | ) 8 | 9 | swift_library( 10 | name = "ArgumentParser", 11 | srcs = glob(["Sources/ArgumentParser/**/*.swift"]), 12 | module_name = "ArgumentParser", 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | ":ArgumentParserToolInfo", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /jazzy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | jazzy -m SourceKittenFramework \ 4 | -a "JP Simard" \ 5 | -u https://github.com/jpsim/SourceKitten \ 6 | -g https://github.com/jpsim/SourceKitten \ 7 | --github-file-prefix https://github.com/jpsim/SourceKitten/blob/$(make get_version) \ 8 | --module-version $(make get_version) \ 9 | -r http://www.jpsim.com/SourceKitten/ \ 10 | -x -workspace,SourceKitten.xcworkspace,-scheme,SourceKittenFramework \ 11 | -c 12 | -------------------------------------------------------------------------------- /script/Version.swift.template: -------------------------------------------------------------------------------- 1 | public struct Version { 2 | public let value: String 3 | 4 | public static let current = Version(value: "__VERSION__") 5 | } 6 | -------------------------------------------------------------------------------- /script/get-version: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | cat Source/SourceKittenFramework/Version.swift | awk -F '"' '{print $2}' | xargs 6 | --------------------------------------------------------------------------------