[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\njobs:\n  macos:\n    runs-on: macOS-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v1\n      - name: Build\n        run: swift build -v\n      - name: Test\n        run: swift test -v -c release\n"
  },
  {
    "path": ".gitignore",
    "content": "## Xcode projects\n*.xcodeproj\n*.xcworkspace\n\n## Build generated\nbuild/\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n.DS_Store\n*.moved-aside\n*.xccheckout\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n# Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\nPackages/\nPackage.pins\nPackage.resolved\n.build/\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mobile-open-source@uber.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mobile-open-source@uber.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "NOTICE.txt",
    "content": "SwiftMockGen depends on the following libraries:\n\nSwift Package Manager (https://github.com/apple/swift-package-manager)\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.2\nimport PackageDescription\n\nlet package = Package(\n    name: \"SwiftCodeSan\",\n    platforms: [\n        .macOS(.v10_15),\n    ],\n    products: [\n        .executable(name: \"SwiftCodeSan\", targets: [\"SwiftCodeSan\"]),\n        .library(name: \"SwiftCodeSanKit\", targets: [\"SwiftCodeSanKit\"]),\n        ],\n    dependencies: [\n        .package(url: \"https://github.com/apple/swift-argument-parser\", .upToNextMinor(from: \"1.0.2\")),\n        .package(name: \"SwiftSyntax\", url: \"https://github.com/apple/swift-syntax.git\", .branch(\"swift-5.6-RELEASE\"))\n    ],\n    targets: [ \n        .target(\n            name: \"SwiftCodeSan\",\n            dependencies: [\n                \"SwiftCodeSanKit\",\n                .product(name: \"ArgumentParser\", package: \"swift-argument-parser\"),\n                ]),\n        .target(\n            name: \"SwiftCodeSanKit\",\n            dependencies: [\n                .product(name: \"SwiftSyntax\", package: \"SwiftSyntax\"),\n                .product(name: \"SwiftSyntaxParser\", package: \"SwiftSyntax\"),\n            ]\n        ),\n        .testTarget(\n            name: \"SwiftCodeSanTests\",\n            dependencies: [\n                \"SwiftCodeSanKit\",\n            ],\n            path: \"Tests\"\n        )\n    ]\n)\n\n"
  },
  {
    "path": "README.md",
    "content": "# ![](Images/logo.png)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2964/badge)](https://bestpractices.coreinfrastructure.org/projects/2964)\n[![Build Status](https://github.com/uber/SwiftCodeSan/workflows/CI/badge.svg)](https://github.com/uber/SwiftCodeSan/actions)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fuber%2FSwiftCodeSan.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fuber%2FSwiftCodeSan?ref=badge_shield)\n\n# Welcome to SwiftCodeSan\n\n**SwiftCodeSan** is a tool that \"sanitizes\" code written in Swift.  It has support for removing dead code (unreferenced decls) and unused imports, and narrowing access levels (public to internal), which will not only help clean up the codebase but also reduce the build time and the binary size. \n\nIt uses `SwiftSyntax` for parsing and uses concurrency for faster performance.  Unlike other tools, `SwiftCodeSan` does not involve compiling; it handles reference checks directly. This eliminates the need to compile the entire project before running an analysis, which can take a long time for codebases like Uber's (~3M LoC).\n\nMain objectives of `SwiftCodeSan` are accuracy, performance, and ease of use.  It's a lightweight commandline tool, which uses the `SwiftCodeSanKit` framework underneath. It can be used as a standalone tool or integrated into other tools such as a linter.  Try `SwiftCodeSan` and clean up your codebase, and see an improvement in the code quality and the build time.\n\n\n## Motivation\n\nMain objectives of `SwiftCodeSan` are accuracy, performance, flexibility, and ease of use. There aren't many 3rd party tools that perform fast on a large codebase containing, for example, over 3M LoC.  They require building the entire projects on Xcode (for index stores), and take several hours to run analyses. The results contain false postives and negatives. They don't provide support to modify files directly with the results, and lack features such as finding unused imports or redundant access levels.  \n\n`SwiftCodeSan` was built for scalability and performance so running analyses takes a few minutes instead of hours. Since it does not require compiling the codebase, it can also run on code being developed with any IDEs (not just Xcode). It's a lightweight commandline tool, and uses a minimal set of frameworks necessary (see the Used Libraries below) to keep the code lean and efficient. It provides an input option to directly modify files with results, and features other than removing dead code, such as updating access levels and removing unused import statments. \n\n\n## Disclaimer\nThis project may contain unstable APIs which may not be ready for general use. Support and/or new releases may be limited.\n\n\n## System Requirements\n\n* Swift 5.3 or later\n* Xcode 12.0 or later\n* MacOS 10.15.4 or later\n* Support is included for the Swift Package Manager\n\n\n## Build / Install\n\nOption 1: Clone and build \n\n```\n$ git clone https://github.com/uber/SwiftCodeSan.git\n$ cd SwiftCodeSan\n$ swift build -c release\n$ .build/release/SwiftCodeSan -h  // see commandline input options below \n```\n\nInstead of calling the binary `SwiftCodeSan` built in `.build/release`, you can copy the executable into a directory that is part of your `PATH` environment variable and call `SwiftCodeSan`.\n\nOr use Xcode, via following.\n\n```\n$ swift package generate-xcodeproj\n```\n\n## Run\n\n`SwiftCodeSan` is a commandline executable. To run it, pass in a list of the source file directories or file paths of a build target, and the destination filepath for the mock output. To see other arguments to the commandline, run `SwiftCodeSan --help`.\n\n```\n./SwiftCodeSan --files-to-modules [file_to_module_list] --remove-deadcode --in-place\n```\nThe `file_to_module_list` contains a map of source file paths to corresponding module names.  Other input options are `--remove-unused-imports` and `--update-access-levels`.  If `--in-place` is set, files will be modified directly. \n\nUse --help to see the complete list of argument options.\n\n\n## Add SwiftCodeSanKit to your project\n\nOption 1: SPM \n```swift\n\ndependencies: [\n    .package(url: \"https://github.com/uber/SwiftCodeSan.git\", from: \"0.0.1\"),\n],\ntargets: [\n    .target(name: \"MyTarget\", dependencies: [\"SwiftCodeSanKit\"]),\n]\n\n```\n\n\n## Distribution \n\nThe `install-script.sh` will build and package up the `SwiftCodeSan` binary and other necessary resources in the same bundle. \n\n```\n$ ./install-script.sh -h  // see input options \n$ ./install-script.sh -s [source dir] -t SwiftCodeSan -d [destination dir] -o [output filename]\n```\n\nThis will create a tarball for distribution, which contains the `SwiftCodeSan` executable along with a necessary SwiftSyntax parser dylib (lib_InternalSwiftSyntaxParser.dylib). This allows running `SwiftCodeSan` without depending on where the dylib lives. \n\n\n\n\n## Used libraries\n\n[SwiftSyntax](https://github.com/apple/swift-syntax) | \n[SPM](https://github.com/swift-package-manager)\n\n\n## How to contribute to SwiftCodeSan\n\nSee [CONTRIBUTING](CONTRIBUTING.md) for more info.\n\n## Report any issues\n\nIf you run into any problems, please file a git issue. Please include:\n\n* The OS version (e.g. macOS 10.15.6)\n* The Swift version installed on your machine (from `swift --version`)\n* The Xcode version\n* The specific release version of this source code (you can use `git tag` to get a list of all the release versions or `git log` to get a specific commit sha)\n* Any local changes on your machine\n\n\n\n## License\n\nSwiftCodeSan is licensed under Apache License 2.0. See [LICENSE](LICENSE.txt) for more information.\n\n    Copyright (C) 2017 Uber Technologies\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n"
  },
  {
    "path": "Sources/SwiftCodeSan/Executor.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport ArgumentParser\nimport SwiftCodeSanKit\n\nstruct Executor: ParsableCommand {\n    static var configuration = CommandConfiguration(commandName: \"SwiftCodeSan\", abstract: \"SwiftCodeSan: Code Sanitizer for Swift.\")\n\n    private enum Operation: EnumerableFlag {\n        case removeDeadcode\n        case removeUnusedImports\n        case updateAccessLevels\n\n        static func help(for value: Executor.Operation) -> ArgumentHelp? {\n            switch value {\n            case .removeDeadcode:\n                return \"If set, it will remove dead code and generate a report in the logfile. If an --in-place option is set, files will be modified directly.\"\n            case .removeUnusedImports:\n                return \"If set, it will remove unused import statements and generate a report in the logfile. If an --in-place option is set, files will be modified directly.\"\n            case .updateAccessLevels:\n                return \"If set, it will remove unnecessary public or open access levels from decls and generate a report in the logfile. If an --in-place option is set, files will be modified directly.\"\n            }\n        }\n    }\n\n    // MARK: - Private\n    @Option(name: [.long, .customShort(\"v\")],\n            help: \"The logging level to use. Default is set to 0 (info only). Set 1 for verbose, 2 for warning, and 3 for error.\")\n    private var loggingLevel: Int = 0\n    @Option(name: .customLong(\"logfile\"),\n            help: \"Log file path containing the analysis results. If no value is given, it will be saved to a tmp file.\",\n            completion: .file())\n    private var logFilePath: String?\n    @Option(name: [.customLong(\"files-to-modules\"), .short],\n            parsing: .upToNextOption,\n            help: \"File paths each containing a map of source files and corresponding module names.\",\n            completion: .file())\n    private var fileLists: [String] = []\n    @Option(name: .customLong(\"syslib-list\"),\n            parsing: .upToNextOption,\n            help: \"File paths each containing a list of (weak) system frameworks.\",\n            completion: .file())\n    private var syslibLists: [String] = []\n    @Option(name: .customLong(\"test-list\"),\n            parsing: .upToNextOption,\n            help: \"File paths each containing a list of test files.\",\n            completion: .file())\n    private var testFileLists: [String] = []\n    @Option(name: [.long, .short],\n            help: \"The root path. If given, it will be prepended to the source file paths.\",\n            completion: .file())\n    private var root: String?\n    @Option(name: [.long, .customShort(\"j\")],\n            help: \"Maximum number of threads to execute concurrently (default = number of cores on the running machine)\")\n    private var concurrencyLimit: Int?\n\n    @Option(name: [.long, .short],\n            parsing: .upToNextOption,\n            help: \"List of declarations to whitelist (separated by a comma or a space)\",\n            completion: .file())\n    private var whitelistDecls: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations with given prefixes to whitelist (separated by a comma or a space)\",\n            completion: .file())\n    private var whitelistDeclsPrefix: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations with given suffixes to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistDeclsSuffix: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations with given parent types to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistParents: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations in the given modules to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistModules: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations in the modules with given prefixes to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistModulesPrefix: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of declarations in the modules with given suffixes to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistModulesSuffix: [String] = []\n    @Option(name: .long,\n            parsing: .upToNextOption,\n            help: \"List of member declarations with given names to whitelist (separated by a comma or a space).\",\n            completion: .file())\n    private var whitelistMembers: [String] = []\n    @Option(name: [.long, .short],\n            help: \"If set, files modified within the set number of days (leading up to today) will be whitelisted, i.e. all declarations in such files will be whitelisted.\")\n    private var thresholdDays: Int?\n\n    @Flag private var operation: Operation\n    @Option(name: .customLong(\"remove-annotation\"),\n            help: \"If set, it will remove the annotation passed in from decls and generate a report in the logfile. If an --in-place option is set, files will be modified directly. \")\n    private var deleteAnnotation: String?\n    @Flag(name: [.customLong(\"in-place\"), .short],\n          help: \"If set, given source files will be modified with results.\")\n    private var inplace: Bool = false\n    @Flag(name: .customLong(\"in-place-tests\"),\n          help: \"If set, given test files will be modified with results.\")\n    private var inplaceTests: Bool = false\n    @Flag(name: .long,\n          help: \"If set, only top level decls will be parsed/used for analysis.\")\n    private var topDeclsOnly: Bool = false\n\n    private func fullPath(_ path: String) -> String {\n        if path.hasPrefix(\"/\") {\n            return path\n        }\n        if path.hasPrefix(\"~\") {\n            let home = FileManager.default.homeDirectoryForCurrentUser.path\n            return path.replacingOccurrences(of: \"~\", with: home, range: path.range(of: \"~\"))\n        }\n        return FileManager.default.currentDirectoryPath + \"/\" + path\n    }\n\n    mutating func run() throws {\n        minLogLevel = loggingLevel\n\n        var filesToModules = [String: String]()\n        fileLists.forEach { arg in\n            let line = arg.components(separatedBy: \":\")\n            if let key = line.first, let val = line.last {\n                filesToModules[key] = val\n            }\n        }\n        \n        let whitelist = Whitelist(thresholdDays: thresholdDays,\n                                  decls: whitelistDecls,\n                                  declsPrefix: whitelistDeclsPrefix,\n                                  declsSuffix: whitelistDeclsSuffix,\n                                  modules: [whitelistModules, syslibLists].compactMap{$0}.flatMap{$0},\n                                  modulesPrefix: whitelistModulesPrefix,\n                                  modulesSuffix: whitelistModulesSuffix,\n                                  inheritedTypes: whitelistParents,\n                                  members: whitelistMembers)\n\n        execute(with: filesToModules,\n                nil,\n                root,\n                logFilePath,\n                inplace,\n                inplaceTests,\n                topDeclsOnly,\n                concurrencyLimit,\n                whitelist,\n                operation,\n                deleteAnnotation)\n    }\n\n\n\n    private func execute(with filesToModules: [String: String],\n                         _ testfiles: [String]?,\n                         _ root: String?,\n                         _ logfile: String?,\n                         _ inplace: Bool,\n                         _ inplaceTests: Bool,\n                         _ topDeclsOnly: Bool,\n                         _ jobs: Int?,\n                         _ whitelist: Whitelist?,\n                         _ operation: Operation,\n                         _ deleteAnnotation: String?) {\n\n        switch operation {\n        case .removeUnusedImports:\n            removeUnusedImports(fileToModuleMap: filesToModules,\n                                whitelist: whitelist,\n                                topDeclsOnly: topDeclsOnly,\n                                inplace: inplace,\n                                logFilePath: logfile,\n                                concurrencyLimit: jobs)\n        case .removeDeadcode:\n            removeDeadDecls(filesToModules: filesToModules,\n                            whitelist: whitelist,\n                            topDeclsOnly: topDeclsOnly,\n                            inplace: inplace,\n                            testFiles: testfiles,\n                            inplaceTests: inplaceTests,\n                            logFilePath: logfile,\n                            concurrencyLimit: jobs,\n                            onCompletion: {})\n        case .updateAccessLevels:\n            updateAccessLevels(filesToModules: filesToModules,\n                               whitelist: whitelist,\n                               inplace: inplace,\n                               concurrencyLimit: jobs,\n                               onCompletion: {})\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSan/main.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\nimport ArgumentParser\nimport Foundation\n\nfunc main() {\n    let inputs = Array(CommandLine.arguments.dropFirst())\n\n    print(\"Start...\")\n    Executor.main(inputs)\n    print(\"Done.\")\n}\n\nmain()\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/AccessLevelRewriter.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\n\n/**\n Updates access levels in the source code\n */\npublic final class AccessLevelRewriter: SyntaxRewriter {\n    var decls: [DeclMetadata]\n    let path: String\n    let module: String\n    public init(_ path: String, module: String?, decls: [DeclMetadata]) {\n        self.path = path\n        self.module = module ?? \"\"\n        self.decls = decls\n    }\n\n    private func updateModifiers(_ name: String, fullName: String, description: String, declType: DeclType, modifiers: ModifierListSyntax?) -> (ModifierListSyntax, Bool)? {\n        let contains = decls.contains(where: { (d: DeclMetadata) -> Bool in\n            return d.name == name && d.fullName == fullName && d.declDescription == description && d.declType == declType\n        })\n\n        if contains {\n            var isModified = false\n            var list = [DeclModifierSyntax]()\n            if let modifiers = modifiers {\n\n                for modifier in modifiers {\n                    if modifier.name.text == String.public || modifier.name.text == String.open {\n                        let updatedAcl = modifier.name.withKind(.stringLiteral(\"\")).withoutTrailingTrivia()\n                        let updatedModifier = SyntaxFactory.makeDeclModifier(name: updatedAcl, detailLeftParen: modifier.detailLeftParen, detail: modifier.detail, detailRightParen: modifier.detailRightParen)\n                        isModified = true\n                        list.append(updatedModifier)\n                    } else {\n\n                        if isModified, modifier.name.text == String.internal, modifier.detail?.text == \"set\" {\n                            let updatedAcl = modifier.name.withKind(.stringLiteral(\"\")).withoutTrailingTrivia()\n                            let updatedModifier = SyntaxFactory.makeDeclModifier(name: updatedAcl, detailLeftParen: nil, detail: nil, detailRightParen: nil)\n                            list.append(updatedModifier)\n                        } else {\n                            list.append(modifier)\n                        }\n                    }\n                }\n            }\n            return (SyntaxFactory.makeModifierList(list), isModified)\n        }\n        return nil\n    }\n\n    override public func visit(_ node: ExtensionDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: EnumDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: StructDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: ProtocolDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: ClassDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: FunctionDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: SubscriptDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n    \n    override public func visit(_ node: InitializerDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: VariableDeclSyntax) -> DeclSyntax {\n        var mutableNode = node\n        if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n            if isModified {\n                mutableNode.modifiers = updatedModifier\n            }\n            return DeclSyntax(mutableNode)\n        }\n        return super.visit(node)\n    }\n\n    override public func visit(_ node: TypealiasDeclSyntax) -> DeclSyntax {\n           var mutableNode = node\n           if let (updatedModifier, isModified) = updateModifiers(node.name, fullName: node.fullName, description: node.description, declType: node.declType, modifiers: node.modifiers) {\n               if isModified {\n                   mutableNode.modifiers = updatedModifier\n               }\n               return DeclSyntax(mutableNode)\n           }\n           return super.visit(node)\n       }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/DeclMetaTypes.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\n\n/**\nDecl metadata needed for decls in source code being parsed\n*/\n\npublic typealias DeclMap = [String: [DeclMetadata]]\n\npublic enum DeclType {\n    case protocolType, classType, extensionType, structType, enumType\n    case typealiasType, patType\n    case varType, subscriptType, funcType, initType, operatorType, enumCaseType\n    case other\n}\n\nextension DeclType {\n    var isEncloserType: Bool {\n        if self == .protocolType ||\n            self == .classType ||\n            self == .extensionType ||\n            self == .structType ||\n            self == .enumType {\n            return true\n        }\n        return false\n    }\n}\n\npublic final class DeclMetadata: Hashable {\n    let name: String\n    var type: String\n    let fullName: String\n    let declType: DeclType\n    var inheritedTypes: [String]\n    let boundTypes: [String]\n    let boundTypesAL: [String]\n    var members: [DeclMetadata] = []\n\n    let path: String\n    let module: String\n    let imports: [String]\n    var encloser: String\n    var declDescription: String\n    var annotated: Bool = false\n\n    var isOverride: Bool\n    var isExtensionMember: Bool = false\n    var isPublicOrOpen: Bool\n    var shouldExpose: Bool = false\n    var visited: Bool = false\n    var used: Bool = false\n\n    public func hash(into hasher: inout Hasher) {\n        hasher.combine(fullName)\n        hasher.combine(declType)\n        hasher.combine(encloser)\n        hasher.combine(path)\n        hasher.combine(module)\n    }\n\n    public static func == (lhs: DeclMetadata, rhs: DeclMetadata) -> Bool {\n        if lhs.name == rhs.name,\n            lhs.type == rhs.type,\n            lhs.fullName == rhs.fullName,\n            lhs.declType == rhs.declType,\n            lhs.encloser == rhs.encloser,\n            lhs.path == rhs.path,\n            lhs.module == rhs.module {\n            return true\n        }\n        return false\n    }\n\n    public init(path: String,\n                module: String,\n                imports: [String],\n                encloser: String,\n                name: String,\n                type: String, \n                fullName: String,\n                description: String,\n                declType: DeclType,\n                inheritedTypes: [String],\n                boundTypes: [String],\n                boundTypesAL: [String],\n                isPublicOrOpen: Bool,\n                isOverride: Bool,\n                annotated: Bool = false,\n                used: Bool) {\n        self.path = path\n        self.module = module\n        self.imports = imports\n        self.encloser = encloser\n        self.name = name\n        self.type = type\n        self.fullName = fullName\n        self.declDescription = description\n        self.declType = declType\n        self.inheritedTypes = inheritedTypes\n        self.boundTypes = boundTypes\n        self.boundTypesAL = boundTypesAL\n        self.annotated = annotated\n        self.isPublicOrOpen = isPublicOrOpen\n        self.isOverride = isOverride\n    }\n}\n\nstruct AnnotationMetadata {\n    var module: String?\n    var typeAliases: [String: String]?\n    var varTypes: [String: String]?\n}\n\n\npublic struct Whitelist {\n    public let thresholdDays: Int?\n    public let decls: [String]?\n    public let declsPrefix: [String]?\n    public let declsSuffix: [String]?\n    public let modules: [String]?\n    public let modulesPrefix: [String]?\n    public let modulesSuffix: [String]?\n    public let inheritedTypes: [String]?\n    public let members: [String]?\n\n    public init(thresholdDays: Int?,\n                decls: [String]?,\n                 declsPrefix: [String]?,\n                 declsSuffix: [String]?,\n                 modules: [String]?,\n                 modulesPrefix: [String]?,\n                 modulesSuffix: [String]?,\n                 inheritedTypes: [String]?,\n                 members: [String]?) {\n        self.thresholdDays = thresholdDays\n        self.decls = decls\n        self.declsPrefix = declsPrefix\n        self.declsSuffix = declsSuffix\n        self.modules = modules\n        self.modulesPrefix = modulesPrefix\n        self.modulesSuffix = modulesSuffix\n        self.inheritedTypes = inheritedTypes\n        self.members = members\n    }\n\n    func declWhitelisted(name: String, isMember: Bool, module: String?, parents: [String]?, path: String?) -> Bool {\n        if let module = module {\n            if let list = modules, list.contains(module) {\n                return true\n            }\n\n            if let list = modulesPrefix {\n                let moduleHasPrefix = !list.filter{module.hasPrefix($0)}.isEmpty\n                if moduleHasPrefix { return true }\n            }\n\n            if let list = modulesSuffix {\n                let moduleHasSuffix = !list.filter{module.hasSuffix($0)}.isEmpty\n                if moduleHasSuffix { return true }\n            }\n        }\n\n        if let parents = parents, let list = inheritedTypes {\n            let inParentsList = !list.filter{ parents.contains($0) }.isEmpty\n            if inParentsList { return true }\n        }\n\n        if isMember {\n            if let list = members, list.contains(name) { return true }\n        } else {\n            if let list = decls, list.contains(name) { return true }\n            if let list = declsPrefix {\n                let declHasPrefix = !list.filter { name.hasPrefix($0) }.isEmpty\n                if declHasPrefix { return true }\n            }\n\n            if let list = declsSuffix {\n                let declHasSuffix = !list.filter { name.hasSuffix($0) }.isEmpty\n                if declHasSuffix { return true }\n            }\n        }\n\n        return false\n    }\n}\n\n\npublic func flatten(declMap: DeclMap) -> DeclMap {\n    var flatDeclMap = DeclMap()\n\n    for (k, vals) in declMap {\n        for v in vals {\n            if flatDeclMap[k] == nil {\n                flatDeclMap[k] = []\n            }\n\n            if flatDeclMap[k]?.contains(v) ?? false {\n            } else {\n                flatDeclMap[k]?.append(v)\n            }\n\n            for m in v.members {\n                if flatDeclMap[m.name] == nil {\n                    flatDeclMap[m.name] = []\n                }\n                flatDeclMap[m.name]?.append(m)\n            }\n        }\n    }\n    return flatDeclMap\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/DeclRemover.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport Foundation\nimport SwiftSyntax\n\n/**\nRemoves unused decls\n*/\n\npublic final class DeclRemover: SyntaxRewriter {\n    let path: String\n    let decls: [DeclMetadata]\n\n    public init(_ path: String, decls: [DeclMetadata]) {\n        self.path = path\n        self.decls = decls\n    }\n\n    override public func visit(_ node: ExtensionDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankExtensionDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: EnumDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankEnumDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: StructDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankStructDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: ProtocolDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankProtocolDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: ClassDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankClassDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: FunctionDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankFunctionDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: SubscriptDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankSubscriptDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: InitializerDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankInitializerDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: VariableDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankVariableDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: TypealiasDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankTypealiasDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: AssociatedtypeDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankAssociatedtypeDecl())\n        }\n        return super.visit(node)\n    }\n    override public func visit(_ node: EnumCaseDeclSyntax) -> DeclSyntax {\n        if shouldRemove(node.name, fullName: node.fullName, description: node.description, declType: node.declType) {\n            return DeclSyntax(SyntaxFactory.makeBlankEnumCaseDecl())\n        }\n        return super.visit(node)\n    }\n\n    private func shouldRemove(_ name: String, fullName: String, description: String, declType: DeclType) -> Bool {\n        let inList = decls.contains(where: { (d: DeclMetadata) -> Bool in\n            return d.name == name && d.fullName == fullName && d.declDescription == description && d.declType == declType\n        })\n        return inList\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/DeclVisitor.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\n\n/**\nVisit decls in source code being parsed\n*/\n\nfinal class DeclVisitor: SyntaxVisitor {\n    var declMap = DeclMap()\n    let path: String\n    let module: String\n    let topDeclsOnly: Bool\n    let whitelistPath: Bool\n    let whitelist: Whitelist?\n    var importedModules = [String]()\n\n    init(_ path: String,\n         module: String?,\n         topDeclsOnly: Bool,\n         whitelistPath: Bool,\n         whitelist: Whitelist?) {\n        self.whitelist = whitelist\n        self.whitelistPath = whitelistPath\n        self.path = path\n        self.module = module ?? \"\"\n        self.topDeclsOnly = topDeclsOnly\n    }\n\n\n    override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {\n        updateDecl(node, description: node.description, members: topDeclsOnly ? nil : node.members.members)\n        return .skipChildren\n    }\n\n    override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {\n        if node.attributesDescription.contains(String.propertyWrapper) {\n            return .skipChildren\n        }\n\n        updateDecl(node, description: node.description, members: topDeclsOnly ? nil : node.members.members)\n        return .visitChildren\n    }\n    override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {\n        if node.attributesDescription.contains(String.propertyWrapper) {\n            return .skipChildren\n        }\n\n        updateDecl(node, description: node.description, members: topDeclsOnly ? nil : node.members.members)\n        return .skipChildren\n    }\n    override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {\n        updateDecl(node, description: node.description, members: topDeclsOnly ? nil : node.members.members)\n        return .skipChildren\n    }\n    override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {\n        updateDecl(node, description: node.description, members: topDeclsOnly ? nil : node.members.members)\n        return .skipChildren\n    }\n    override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind {\n        importedModules.append(node.path.description.trimmed)\n        return .visitChildren\n    }\n\n    override func visit(_ node: CodeBlockItemSyntax) -> SyntaxVisitorContinueKind {\n        if let item = node.item.as(FunctionDeclSyntax.self) {\n            updateDecl(item, description: item.description, members: nil)\n            return .skipChildren\n        } else if let _ = node.item.as(OperatorDeclSyntax.self) {\n            return .skipChildren\n        } else if let item = node.item.as(VariableDeclSyntax.self) {\n            updateDecl(item, description: item.description, members: nil)\n            return .skipChildren\n        } else if let item = node.item.as(TypealiasDeclSyntax.self) {\n            updateDecl(item, description: item.description, members: nil)\n            return .skipChildren\n        }\n\n        return .visitChildren\n    }\n\n    private func memberDecls(_ decl: DeclSyntax, encloser: String, encloserDeclType: DeclType, encloserWhitelisted: Bool) -> [DeclMetadata] {\n        let mdecls = decl.declMetadatas(path: path, module: module, encloser: encloser, description: decl.description, imports: importedModules)\n\n        for mdecl in mdecls {\n            if encloserDeclType == .extensionType {\n                mdecl.isExtensionMember = true\n            }\n\n            let memberWhitelisted = whitelist?.declWhitelisted(name: mdecl.name, isMember: true, module: nil, parents: nil, path: mdecl.path) ?? false\n            if encloserWhitelisted ||\n                memberWhitelisted ||\n                mdecl.declType == .initType ||\n                mdecl.declType == .subscriptType ||\n                mdecl.declType == .operatorType {\n                if mdecl.isPublicOrOpen {\n                    mdecl.shouldExpose = true\n                }\n                mdecl.used = true\n            }\n        }\n        return mdecls\n    }\n\n    private func updateDecl(_ item: DeclProtocol, description: String, members: MemberDeclListSyntax?) {\n        let decls = item.declMetadatas(path: path, module: module, encloser: \"\", description: description, imports: importedModules)\n\n        for decl in decls {\n            var shouldWhitelist = (decl.declType == .operatorType)\n            if !shouldWhitelist, !decl.name.isEmpty {\n                if let whitelist = whitelist, whitelist.declWhitelisted(name: decl.name, isMember: false, module: module, parents: decl.inheritedTypes, path: decl.path) {\n                    // whitelisted so don't add to declMap\n                    shouldWhitelist = true\n                }\n            }\n\n            if shouldWhitelist {\n                if decl.isPublicOrOpen {\n                    decl.shouldExpose = true\n                }\n                decl.used = true\n            }\n\n            if let members = members {\n                var list = [DeclMetadata]()\n                for m in members {\n                    if let ifconfig = m.decl.as(IfConfigDeclSyntax.self) {\n                        for clause in ifconfig.clauses {\n                            if let clauseMembers = clause.elements.as(MemberDeclListSyntax.self) {\n                                for el in clauseMembers {\n                                    let mdecls = memberDecls(el.decl, encloser: decl.name, encloserDeclType: decl.declType, encloserWhitelisted: shouldWhitelist)\n                                    list.append(contentsOf: mdecls)\n                                }\n                            }\n                        }\n                    } else {\n                        let mdecls = memberDecls(m.decl, encloser: decl.name, encloserDeclType: decl.declType, encloserWhitelisted: shouldWhitelist)\n                        list.append(contentsOf: mdecls)\n                    }\n                }\n                decl.members = list\n            }\n\n            if !decl.name.isEmpty, declMap[decl.name] == nil {\n                declMap[decl.name] = []\n            }\n\n            declMap[decl.name]?.append(decl)\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/ImportRewriter.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\n\n\n/**\nUpdates import statements in source code\n*/\n\npublic final class ImportRewriter: SyntaxRewriter {\n    let unused: [String]\n\n    public init(_ path: String, unusedModules: [String]?) {\n        self.unused = unusedModules ?? []\n    }\n\n    override public func visit(_ node: ImportDeclSyntax) -> DeclSyntax {\n        var remove = false\n        let str = node.path.description.trimmed\n        if unused.contains(str) {\n            remove = true\n        } else {\n            for t in node.path.tokens {\n                if unused.contains(t.text) {\n                    remove = true\n                }\n            }\n        }\n\n        if remove {\n            if let trivia = node.importTok.leadingTrivia {\n                let t = SyntaxFactory.makeUnknown(\"\", leadingTrivia: trivia, trailingTrivia: Trivia(pieces: []))\n                let ret = SyntaxFactory.makeImportDecl(attributes: nil, modifiers: nil, importTok: t, importKind: nil, path: SyntaxFactory.makeAccessPath([]))\n                return DeclSyntax(ret)\n            } else {\n                let ret = SyntaxFactory.makeBlankImportDecl()\n                return DeclSyntax(ret)\n            }\n        }\n\n        return super.visit(node)\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Core/RefChecker.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\n\n/**\nChecks for referenced decls\n*/\n\nfinal class RefChecker: SyntaxVisitor {\n    var imports = [String]()\n    private var declMap = DeclMap()\n    private var path: String\n    private var module: String\n    private var reflist = [String]()\n    var refs: Set<String> {\n        return Set(reflist)\n    }\n    \n    init(_ path: String, module: String, declMap: DeclMap) {\n        self.path = path\n        self.module = module\n        self.declMap = declMap\n    }\n\n    override func visit(_ node: CodeBlockItemSyntax) -> SyntaxVisitorContinueKind {\n        if node.item.is(ExprSyntax.self) || node.item.is(StmtSyntax.self) {\n            reflist.append(contentsOf: node.item.refTypes(with: declMap))\n            return .skipChildren\n        }\n\n        return .visitChildren\n    }\n\n    override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        if node.isOverride {\n            reflist.append(node.name)\n        }\n\n        return .visitChildren\n    }\n\n    override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        if node.isOverride {\n            reflist.append(node.name)\n        }\n        return .visitChildren\n    }\n\n    override func visit(_ node: SubscriptDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n\n    override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        if node.isOverride {\n            reflist.append(node.name)\n        }\n        return .visitChildren\n    }\n\n    override func visit(_ node: EnumCaseDeclSyntax) -> SyntaxVisitorContinueKind {\n         reflist.append(contentsOf: node.refTypes(with: declMap))\n         return .visitChildren\n     }\n\n    override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n    override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n    override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        reflist.append(node.name)\n        return .visitChildren\n    }\n    override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n    override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n\n    override func visit(_ node: TypealiasDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n\n    override func visit(_ node: AssociatedtypeDeclSyntax) -> SyntaxVisitorContinueKind {\n        reflist.append(contentsOf: node.refTypes(with: declMap))\n        return .visitChildren\n    }\n\n    override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind {\n        if node.attributes == nil, node.importKind == nil {\n            let str = node.path.description.trimmed\n            imports.append(str)\n        }\n        return .skipChildren\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/FileParsers/DeclParser.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport SwiftSyntax\nimport SwiftSyntaxParser\n\npublic class DeclParser {\n    \n    public init() {}\n\n    func scanAndMapDecls(fileToModuleMap: [String: String],\n                         topDeclsOnly: Bool,\n                         whitelist: Whitelist?) -> DeclMap {\n        var allDeclMap = DeclMap()\n\n        scanDecls(fileToModuleMap: fileToModuleMap, topDeclsOnly: topDeclsOnly, whitelist: whitelist) { (filepath, subResults) in\n            for (k, decls) in subResults {\n                if allDeclMap[k] == nil {\n                    allDeclMap[k] = []\n                }\n\n                for decl in decls {\n                    if allDeclMap[k]?.contains(decl) ?? false {\n                        // Already added, so do nothing\n                    } else {\n                        allDeclMap[k]?.append(decl)\n                    }\n                }\n            }\n        }\n        return allDeclMap\n    }\n\n    func scanAndMapDecls(fileToModuleMap: [String: String],\n                         topDeclsOnly: Bool) -> DeclMap {\n        return scanAndMapDecls(fileToModuleMap: fileToModuleMap,\n                               topDeclsOnly: topDeclsOnly,\n                               whitelist: nil)\n    }\n\n    func scanDecls(fileToModuleMap: [String: String],\n                   topDeclsOnly: Bool,\n                   completion: @escaping (String, DeclMap) -> ()) {\n        scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in\n            self.visitSrc(path: path,\n                          module: module,\n                          topDeclsOnly: topDeclsOnly,\n                          whitelist: nil,\n                          lock: lock,\n                          completion: completion)\n        }\n    }\n\n    func scanDecls(fileToModuleMap: [String: String],\n                   topDeclsOnly: Bool,\n                   whitelist: Whitelist?,\n                   completion: @escaping (String, DeclMap) -> ()) {\n        scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in\n            self.visitSrc(path: path,\n                          module: module,\n                          topDeclsOnly: topDeclsOnly,\n                          whitelist: whitelist,\n                          lock: lock,\n                          completion: completion)\n        }\n    }\n\n    var wpaths = 0\n    var npaths = 0\n    private func visitSrc(path: String,\n                          module: String?,\n                          topDeclsOnly: Bool,\n                          whitelist: Whitelist?,\n                          lock: NSLock?,\n                          completion: @escaping (String, DeclMap) -> ()) {\n        do {\n            let node = try SyntaxParser.parse(path)\n            let whitelistPath = FileManager.modifiedWithin(whitelist?.thresholdDays, at: path)\n            if whitelistPath {\n                wpaths += 1\n            }\n            npaths += 1\n            let visitor = DeclVisitor(path,\n                                      module: module,\n                                      topDeclsOnly: topDeclsOnly,\n                                      whitelistPath: whitelistPath,\n                                      whitelist: whitelist)\n            visitor.walk(node)\n            \n            lock?.lock()\n            defer {lock?.unlock()}\n            completion(path, visitor.declMap)\n        } catch {\n            fatalError(error.localizedDescription)\n        }\n    }\n\n    func checkRefs(fileToModuleMap: [String: String],\n                   declMap: DeclMap,\n                   completion: @escaping (String, Set<String>, [String]) -> ()) {\n\n        scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in\n            self.referenceSrc(path: path, module: module, declMap: declMap, lock: lock, completion: completion)\n        }\n    }\n\n    private func referenceSrc(path: String,\n                              module: String,\n                              declMap: DeclMap,\n                              lock: NSLock?,\n                              completion: @escaping (String, Set<String>, [String]) -> ()) {\n        do {\n            let node = try SyntaxParser.parse(path)\n            let visitor = RefChecker(path, module: module, declMap: declMap)\n            visitor.walk(node)\n            \n            lock?.lock()\n            completion(path, visitor.refs, visitor.imports)\n            lock?.unlock()\n        } catch {\n            fatalError(error.localizedDescription)\n        }\n    }\n\n    // MARK - input is dirs or filepaths\n\n    func scanDecls(paths: [String],\n                   isDirs: Bool,\n                   topDeclsOnly: Bool,\n                   pathToModules: [String: String],\n                   whitelist: Whitelist?,\n                   completion: @escaping (String, DeclMap) -> ()) {\n        if isDirs {\n            scan(dirs: paths) { (path: String, lock: NSLock?) in\n                self.visitSrc(path: path,\n                              module: pathToModules[path],\n                              topDeclsOnly: topDeclsOnly,\n                              whitelist: whitelist,\n                              lock: lock,\n                              completion: completion)\n            }\n        } else {\n            scan(paths) { (path: String, lock: NSLock?) in\n                self.visitSrc(path: path,\n                              module: pathToModules[path],\n                              topDeclsOnly: topDeclsOnly,\n                              whitelist: whitelist,\n                              lock: lock,\n                              completion: completion)\n            }\n        }\n    }\n\n\n    func checkRefs(paths: [String],\n                   isDirs: Bool,\n                   pathToModules: [String: String],\n                   declMap: DeclMap,\n                   completion: @escaping (String, Set<String>, [String]) -> ()) {\n\n        if isDirs {\n            scan(dirs: paths) { (path: String, lock: NSLock?) in\n                self.referenceSrc(path: path, module: pathToModules[path] ?? \"\", declMap: declMap, lock: lock, completion: completion)\n            }\n        } else {\n            scan(paths) { (path: String, lock: NSLock?) in\n                self.referenceSrc(path: path, module: pathToModules[path] ?? \"\", declMap: declMap, lock: lock, completion: completion)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/FileUpdaters/DeclUpdater.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport Foundation\nimport SwiftSyntax\nimport SwiftSyntaxParser\n\nfinal class DeclUpdater {\n\n    func updateAccessLevels(filesToDecls: [String: [DeclMetadata]],\n                            filesToModules: [String: String],\n                            completion: @escaping (String, String) -> ()) {\n\n        scan(filesToDecls) { (path, decls, lock) in\n            do {\n                let node = try SyntaxParser.parse(path)\n                let rewriter = AccessLevelRewriter(path, module: filesToModules[path], decls: decls)\n                let ret = rewriter.visit(node)\n                lock?.lock()\n                completion(path, ret.description)\n                lock?.unlock()\n            }  catch {\n                fatalError(error.localizedDescription)\n            }\n        }\n    }\n\n    func removeDeadDecls(filesToDecls: [String: [DeclMetadata]],\n                         completion: @escaping (String, String) -> ()) {\n        scan(filesToDecls) { (path, decls, lock) in\n            do {\n                let node = try SyntaxParser.parse(path)\n                let remover = DeclRemover(path, decls: decls)\n                let ret = remover.visit(node)\n\n                lock?.lock()\n                completion(path, ret.description)\n                lock?.unlock()\n            }  catch {\n                fatalError(error.localizedDescription)\n            }\n        }\n    }\n\n    func removeUnusedImports(paths: [String],\n                             isDirs: Bool,\n                             unusedImports: [String: [String]],\n                             completion: @escaping (String, String) -> ()) {\n        if isDirs {\n            scan(dirs: paths) { (path, lock) in\n                self.updateSrcs(path: path, module: \"\", lock: lock, unusedImports: unusedImports, completion: completion)\n            }\n        } else {\n            scan(paths) { (path, lock) in\n                self.updateSrcs(path: path, module: \"\", lock: lock, unusedImports: unusedImports, completion: completion)\n            }\n        }\n    }\n\n    func removeUnusedImports(fileToModuleMap: [String: String],\n                             unusedImports: [String: [String]],\n                             completion: @escaping (String, String) -> ()) {\n        scan(fileToModuleMap) { (path, module, lock) in\n            self.updateSrcs(path: path, module: module, lock: lock, unusedImports: unusedImports, completion: completion)\n        }\n    }\n\n    private func updateSrcs(path: String,\n                            module: String,\n                            lock: NSLock?,\n                            unusedImports: [String: [String]],\n                            completion: @escaping (String, String) -> ()) {\n        do {\n            let node = try SyntaxParser.parse(path)\n            let remover = ImportRewriter(path, unusedModules: unusedImports[path])\n            let ret = remover.visit(node)\n\n            lock?.lock()\n            completion(path, ret.description)\n            lock?.unlock()\n        } catch {\n            fatalError(error.localizedDescription)\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Operations/RemoveDeadDecls.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\npublic func removeDeadDecls(filesToModules: [String: String],\n                            whitelist: Whitelist?,\n                            topDeclsOnly: Bool,\n                            inplace: Bool,\n                            testFiles: [String]?,\n                            inplaceTests: Bool,\n                            logFilePath: String? = nil,\n                            concurrencyLimit: Int? = nil,\n                            onCompletion: @escaping () -> ()) {\n    \n    log(\"Start of removing dead code: topDeclsOnly\", topDeclsOnly)\n    scanConcurrencyLimit = concurrencyLimit\n    let p = DeclParser()\n    var pathToDeclsUpdate = [String: [DeclMetadata]]()\n    \n    log(\"Scan and map top-level decls...\")\n    logTime()\n    let declMap = p.scanAndMapDecls(fileToModuleMap: filesToModules,\n                                    topDeclsOnly: false,\n                                    whitelist: whitelist)\n    logTime()\n    print(\"WWW: \", p.npaths, p.wpaths)\n    \n    log(\"Check references, look up their source modules, and mark used...\")\n    let flatDeclMap = flatten(declMap: declMap)\n    var nref = 0\n    p.checkRefs(fileToModuleMap: filesToModules, declMap: flatDeclMap) { (path, refs, imports) in\n        if let refModule = filesToModules[path] {\n            markUsed(refs, in: refModule, imports: imports, with: flatDeclMap, updateMembers: true)\n        }\n        \n        log(\"#Checked refs\", counter: &nref, interval: 1000, timed: true)\n    }\n    logTime()\n    \n    repeat {\n        log(\"Look up interface members and mark used if any...\")\n        shouldRetry = false\n        markInterfaceMembersUsed(declMap: declMap)\n        logTime()\n    } while shouldRetry\n    var i = flatDeclMap.values.flatMap{$0}.filter{$0.used}.count\n    \n    log(\"Mark bound types used...\")\n    markBoundTypesUsed(declMap: flatDeclMap)\n    resetVisited(declMap: declMap)\n    var j = flatDeclMap.values.flatMap{$0}.filter{$0.used}.count\n    logTime()\n    \n    while i != j {\n        log(\"#Remaining decls to mark used\", j-i, j, i)\n        log(\"Repeat: Look up interface members and mark used if any...\")\n        markInterfaceMembersUsed(declMap: declMap)\n        i = flatDeclMap.values.flatMap{$0}.filter{$0.used}.count\n        logTime()\n        \n        log(\"Repeat: Mark bound types used...\")\n        markBoundTypesUsed(declMap: flatDeclMap)\n        resetVisited(declMap: flatDeclMap)\n        j = flatDeclMap.values.flatMap{$0}.filter{$0.used}.count\n        logTime()\n    }\n    \n    log(\"Filter out used decls...\")\n    for (_, decls) in flatDeclMap {\n        for decl in decls {\n            if !decl.used {\n                if pathToDeclsUpdate[decl.path] == nil {\n                    pathToDeclsUpdate[decl.path] = []\n                }\n                pathToDeclsUpdate[decl.path]?.append(decl)\n            }\n        }\n    }\n    \n    let totalUnused = pathToDeclsUpdate.values.flatMap{$0}.count\n    let totalUsed = flatDeclMap.values.flatMap{$0}.filter{$0.used}.count\n    logTime()\n    log(\"#Total top-level decls: \", declMap.values.flatMap{$0}.count,\n        \"#Total decls\", flatDeclMap.values.flatMap{$0}.count,\n        \"#Decls Unused\", totalUnused,\n        \"#Decls Used\", totalUsed,\n        \"#Files to update\", pathToDeclsUpdate.count)\n    \n    if let logfile = logFilePath {\n        log(\"Save results to\", logfile)\n        \n        let ret = pathToDeclsUpdate.map { arg in\n            let vals = arg.value.map{ ObjectIdentifier($0).debugDescription  + \", \" + $0.fullName + \", \" + $0.encloser }\n            let valStr = vals.joined(separator: \"\\n\")\n            return \"\\(arg.key)\\n--- \\(valStr)\\n\"\n        }.joined(separator: \"\\n\")\n        try? ret.write(toFile: logfile, atomically: true, encoding: .utf8)\n        logTime()\n    }\n    \n    if inplace {\n        log(\"Remove unused decls from files...\", pathToDeclsUpdate.count)\n        let updater = DeclUpdater()\n        updater.removeDeadDecls(filesToDecls: pathToDeclsUpdate) { (path, content) in\n            try? content.write(toFile: path, atomically: true, encoding: .utf8)\n        }\n        logTime()\n    }\n    \n    logTotalElapsed(\"Done\")\n    \n    onCompletion()\n}\n\n\n// MARK - private functions\n\nprivate func markBoundTypesUsed(declMap: DeclMap) {\n    for (k, decls) in declMap {\n        if !k.isEmpty {  // Empty means expr or stmt\n            for decl in decls {\n                if decl.used {\n                    decl.visited = true\n                    markBoundTypesUsed(decl, level: 0, declMap: declMap)\n                }\n            }\n        }\n    }\n}\n\nprivate func markBoundTypesUsed(_ decl: DeclMetadata, level: Int, declMap: DeclMap) {\n    \n    for boundType in decl.boundTypes {\n        if !boundType.isEmpty {\n            var bases: [String]?\n            var leaf: String?\n            if boundType.contains(\".\") {\n                bases = boundType.components(separatedBy: \".\")\n                leaf = bases?.removeLast()\n            }\n            \n            let key = leaf ?? boundType\n            \n            if let boundDecls = declMap[key] {\n                for boundDecl in boundDecls {\n                    if boundDecl.visited, boundDecl.used {\n                        continue\n                    }\n                    boundDecl.visited = true\n                    if decl.module == boundDecl.module || decl.imports.contains(boundDecl.module) {\n                        boundDecl.used = true\n                        markBoundTypesUsed(boundDecl, level: level + 1, declMap: declMap)\n                    }\n                }\n            }\n        }\n    }\n}\n\n\nvar shouldRetry = false\nprivate func markInterfaceMembersUsed(declMap: DeclMap) {\n    var ndecls = 0\n    scan(declMap) { (key, vals, lock) in\n        for cur in vals {\n            var members = [DeclMetadata]()\n            var interfaceMembers = [DeclMetadata]()\n            var userDefinedTypes = [String]()\n            var stdlibTypes = [String]()\n            let level = 0\n            markBoundMembersUsed(key: cur, declMap: declMap, level: level, members: &members, interfaceMembers: &interfaceMembers,  userDefinedTypes: &userDefinedTypes, stdlibTypes: &stdlibTypes)\n            log(\"#Marked used members\", counter: &ndecls, interval: 10000, timed: true)\n        }\n    }\n    \n}\n\nprivate func markBoundMembersUsed(key cur: DeclMetadata,\n                                  declMap: DeclMap,\n                                  level: Int,\n                                  members: inout [DeclMetadata],\n                                  interfaceMembers: inout [DeclMetadata],\n                                  userDefinedTypes: inout [String],\n                                  stdlibTypes: inout [String]) {\n    \n    // First resolve inheritance (loop up protocol conformance, subclassing, and update member ALs)\n    var parents = cur.inheritedTypes\n    let curIsExtension = cur.declType == .extensionType\n    if curIsExtension {\n        parents.append(cur.name)\n    }\n    resolveInheritance(key: cur, inheritedTypes: parents, declMap: declMap, level: level, members: &members, interfaceMembers: &interfaceMembers, userDefinedTypes: &userDefinedTypes, stdlibTypes: &stdlibTypes)\n    \n    let stdTypes = stdlibTypes.filter{!userDefinedTypes.contains($0)}\n    \n    for member in members {\n        let matchingMembers = interfaceMembers.filter {$0.name == member.name}\n        for matched in matchingMembers {\n            if matched.used {\n                member.used = true\n            } else if member.used || member.isOverride {\n                if !matched.used {\n                    matched.used = true\n                    shouldRetry = true\n                }\n            } else if !stdTypes.isEmpty {\n                if !matched.used {\n                    matched.used = true\n                    shouldRetry = true\n                }\n                member.used = true\n            }\n        }\n        \n        if matchingMembers.isEmpty, member.isOverride {\n            // This might be a member overriding stdlib api\n            member.used = true\n        }\n    }\n    \n    // For the following decl types, check bound types and update member ALs.\n    if cur.declType == .extensionType || cur.declType == .enumType {\n        if !cur.used {\n            for m in cur.members {\n                if m.used {\n                    cur.used = true\n                    break\n                }\n            }\n        }\n        \n        if !cur.used {\n            let boundTypes = cur.boundTypes.filter{!cur.inheritedTypes.contains($0)}\n            for boundType in boundTypes {\n                if boundType.isEmpty {\n                    continue\n                }\n                if cur.name != boundType, let _ = declMap[boundType] {\n                    // even if boundtype is used, cur might not be used\n                } else if cur.inheritedTypes.contains(boundType) {\n                    // If parent is not in declMap, assume it's in stdlib.\n                    for member in cur.members {\n                        member.used = true\n                        cur.used = true\n                    }\n                    if cur.used {\n                        break\n                    }\n                }\n            }\n        }\n    }\n}\n\nprivate func resolveInheritance(key cur: DeclMetadata,\n                                inheritedTypes: [String]?,\n                                declMap: DeclMap,\n                                level: Int,\n                                members: inout [DeclMetadata],\n                                interfaceMembers: inout [DeclMetadata],\n                                userDefinedTypes: inout [String],\n                                stdlibTypes: inout [String]) {\n    \n    let parents = inheritedTypes ?? cur.inheritedTypes\n    \n    for parent in parents {\n        if parent.isEmpty {\n            continue\n        }\n        if let parentDecls = declMap[parent] {\n            for parentDecl in parentDecls {\n                if parentDecl.name.isEmpty {\n                    continue\n                }\n                if parentDecl.declType == .protocolType || parentDecl.declType == .classType || parentDecl.declType == .typealiasType {\n                    if parentDecl.declType == .protocolType {\n                        interfaceMembers.append(contentsOf: parentDecl.members)\n                    } else if parentDecl.declType == .classType, cur.declType == .classType {\n                        interfaceMembers.append(contentsOf: parentDecl.members)\n                    }\n                    \n                    userDefinedTypes.append(parentDecl.name)\n                    members.append(contentsOf: cur.members)\n                    \n                    let optionalInitialTypes = parentDecl.declType == .typealiasType ? parentDecl.boundTypes : nil\n                    \n                    resolveInheritance(key: parentDecl, inheritedTypes: optionalInitialTypes, declMap: declMap, level: level+1, members: &members,  interfaceMembers: &interfaceMembers, userDefinedTypes: &userDefinedTypes, stdlibTypes: &stdlibTypes)\n                    \n                } else if parentDecl.declType == .extensionType {\n                    // Parent could be a user defined type or a stdlib type. Add to a list for now and filter out below.\n                    stdlibTypes.append(parentDecl.name)\n                    members.append(contentsOf: cur.members)\n                }\n            }\n        } else {\n            // If parent is not in declMap, assume it's in stdlib.\n            stdlibTypes.append(parent)\n        }\n    }\n    \n    for stdlibType in stdlibTypes {\n        if userDefinedTypes.contains(stdlibType) {\n            continue\n        }\n        \n        interfaceMembers.append(contentsOf: cur.members)\n        members.append(contentsOf: cur.members)\n        break\n    }\n}\n\nprivate func accessMembers(_ bases: [String], _ i: Int, _ refModule: String,  _ imports: [String], declMap: DeclMap) -> Bool {\n    let j = i + 1\n    \n    if j < bases.count {\n        let cur = bases[i]\n        let next = bases[j]\n        if let prefixDecls = declMap[cur] {\n            for prefixDecl in prefixDecls {\n                var list: [DeclMetadata]?\n                \n                if prefixDecl.declType == .funcType ||\n                    prefixDecl.declType == .operatorType ||  // This is handled here but shouldn't be member-accessed\n                    prefixDecl.declType == .varType {\n                    if let typeDecls = declMap[prefixDecl.type] {\n                        for t in typeDecls {\n                            list = t.members.filter{$0.name == next}\n                        }\n                    }\n                    \n                } else {\n                    list = prefixDecl.members.filter{$0.name == next}\n                }\n                \n                if let list = list, !list.isEmpty {\n                    \n                    let accessed = accessMembers(bases, i + 1, refModule, imports, declMap: declMap)\n                    \n                    if accessed, (refModule == prefixDecl.module || imports.contains(prefixDecl.module)) {\n                        for member in list {\n                            member.used = true\n                        }\n                    }\n                    \n                } else {\n                    return false\n                }\n            }\n        }\n    }\n    return true\n}\n\nprivate func markUsed(_ refs: Set<String>, in refModule: String, imports: [String], with declMap: DeclMap, updateMembers: Bool) {\n    // Leaf level node checks\n    for r in refs {\n        var bases: [String]?\n        var leaf: String?\n        \n        if r.contains(\".\") {\n            bases = r.components(separatedBy: \".\")\n        }\n        \n        // First, traverse member access, and update visibility along the way\n        var accessedMembers = false\n        if let bases = bases {\n            accessedMembers = accessMembers(bases, 0, refModule, imports, declMap: declMap)\n        }\n        if accessedMembers {\n            continue\n        }\n        \n        leaf = bases?.removeLast()\n        let refKey = leaf ?? r\n        \n        // If above fails (e.g. encloser type is not found), or non-member access, try following\n        if let refDecls = declMap[refKey] {\n            for refDecl in refDecls {\n                if refModule == refDecl.module || imports.contains(refDecl.module) || refDecl.isOverride {\n                    refDecl.used = true\n                }\n            }\n            \n        }\n    }\n}\n\nprivate func resetVisited(declMap: DeclMap) {\n    for (_, decls) in declMap {\n        for decl in decls {\n            decl.visited = false\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Operations/RemoveUnusedImports.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\npublic func removeUnusedImports(fileToModuleMap: [String: String],\n                                whitelist: Whitelist?,\n                                topDeclsOnly: Bool,\n                                inplace: Bool,\n                                logFilePath: String? = nil,\n                                concurrencyLimit: Int? = nil) {\n    scanConcurrencyLimit = concurrencyLimit\n\n    let p = DeclParser()\n    \n    log(\"Scan all decls and generate a decl map...\")\n    logTime()\n\n    let allDeclMap = p.scanAndMapDecls(fileToModuleMap: fileToModuleMap,\n                                       topDeclsOnly: topDeclsOnly)\n\n    logTime()\n    log(\"#Decls\", allDeclMap.keys.count)\n\n    var unusedImports = [String: [String]]()\n\n    let whitelistModulesBlock = { (module: String) -> Bool in\n        let moduleComps = module.components(separatedBy: \".\").filter {!$0.isEmpty}\n        for comp in moduleComps {\n            if let list = whitelist?.modules, list.contains(comp) {\n                return true\n            }\n            if let list = whitelist?.modulesSuffix {\n                for suffix in list {\n                    if comp.hasSuffix(suffix) {\n                        return true\n                    }\n                }\n            }\n            if let list = whitelist?.modulesPrefix {\n                for prefix in list {\n                    if comp.hasPrefix(prefix) {\n                        return true\n                    }\n                }\n            }\n        }\n        return false\n    }\n\n    log(\"Check referenced decls and compare their source modules against imported modules to filter out unused imports...\")\n    var total = 0\n    p.checkRefs(fileToModuleMap: fileToModuleMap, declMap: allDeclMap) { (filepath, refs, imports) in\n        var usedImportsInFile = [String: Bool]()\n        for i in imports {\n            usedImportsInFile[i] = whitelistModulesBlock(i)\n        }\n        for r in refs {\n            if let refDecls = allDeclMap[r] {\n                for refDecl in refDecls {\n                    let m = refDecl.module\n\n                    if imports.contains(m) {\n                        usedImportsInFile[m] = true\n                    } else {\n                        let refinedImports = imports.filter {$0.contains(\".\")}\n                        for item in refinedImports {\n                            let comps = item.components(separatedBy: \".\")\n                            if comps.contains(m) {\n                                usedImportsInFile[item] = true\n                            }\n                        }\n                    }\n                }\n            } else if imports.contains(r) {\n                // Sometimes a module name can be used in code, e.g. CoreFoundation.Foo\n                usedImportsInFile[r] = true\n            }\n        }\n\n        var unusedListInFile = [String]()\n        for (module, used) in usedImportsInFile {\n            if !used {\n                total += 1\n                unusedListInFile.append(module)\n            }\n        }\n\n        if !unusedListInFile.isEmpty {\n            unusedImports[filepath] = Set(unusedListInFile).compactMap{$0}\n        }\n\n//        log(total, interval: 200)\n    }\n\n    logTime()\n    log(\"#Unused imports\", total)\n\n    if let op = logFilePath {\n        log(\"Save results...\")\n\n        var totalUnused = 0\n        var ret = unusedImports.map { (path, unusedlist) -> String in\n            totalUnused += unusedlist.count\n            return path + \"\\n\" + String(unusedlist.count) + \"\\n\" + unusedlist.joined(separator: \", \")\n        }\n        assert(total == totalUnused)\n        ret.append(\"Total unused: \\(totalUnused)\")\n        let retStr = ret.joined(separator: \"\\n\\n\")\n\n        let declstr = allDeclMap.map{ (k, v) -> String in\n            let t = \"\"\"\n            \\(k):  \\(v.map { $0.path }.joined(separator: \", \"))\n            \"\"\"\n            return t\n        }.joined(separator: \"\\n\")\n\n        try? retStr.write(toFile: op, atomically: true, encoding: .utf8)\n        try? declstr.write(toFile: op+\"-decls\", atomically: true, encoding: .utf8)\n    }\n\n    if inplace {\n        log(\"Remove unused imports from files...\", unusedImports.keys.count)\n        let updater = DeclUpdater()\n        updater.removeUnusedImports(fileToModuleMap: fileToModuleMap,\n                                    unusedImports: unusedImports) { (path, result) in\n                                        try? result.write(toFile: path, atomically: true, encoding: .utf8)\n        }\n    }\n\n    logTime()\n\n    logTotalElapsed(\"Done\")\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Operations/UpdateAccessLevels.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\npublic func updateAccessLevels(filesToModules: [String: String],\n                               whitelist: Whitelist?,\n                               inplace: Bool,\n                               logFilePath: String? = nil,\n                               concurrencyLimit: Int? = nil,\n                               onCompletion: @escaping () -> ()) {\n    \n    scanConcurrencyLimit = concurrencyLimit\n    let p = DeclParser()\n    var pathToDeclsUpdate = [String: [DeclMetadata]]()\n    \n    log(\"Scan and map top-level decls...\")\n    logTime()\n    let declMap = p.scanAndMapDecls(fileToModuleMap: filesToModules,\n                                    topDeclsOnly: false,\n                                    whitelist: whitelist)\n    \n    logTime()\n    \n    log(\"Check references, look up their source modules, and mark visibility...\")\n    p.checkRefs(fileToModuleMap: filesToModules, declMap: declMap) { (path, refs, imports) in\n        if let refModule = filesToModules[path] {\n            markVisiblity(refs, in: refModule, imports: imports, with: declMap, updateMembers: true)\n        }\n    }\n    \n    logTime()\n    \n    log(\"Update ALs (access levels) of top-level decls and their bound types...\")\n    updateBoundTypeALs(declMap: declMap)\n    resetVisited(declMap: declMap)\n    \n    log(\"Update ALs of member decls of interfaces (protocol / base class)...\")\n    updateMemberALs(declMap: declMap)\n    \n    logTime()\n    \n    log(\"Flatten decls, and check references again, for member decls...\")\n    var nref = 0\n    let flatDeclMap = flatten(declMap: declMap)\n    p.checkRefs(fileToModuleMap: filesToModules, declMap: flatDeclMap) { (path, refs, imports) in\n        if let refModule = filesToModules[path] {\n            markVisiblity(refs, in: refModule, imports: imports, with: flatDeclMap, updateMembers: false)\n        }\n        log(counter: &nref, interval: 1000)\n    }\n    log(nref)\n    \n    logTime()\n    \n    log(\"Update ALs of all decls and their bound types...\")\n    updateBoundTypeALs(declMap: flatDeclMap)\n    resetVisited(declMap: flatDeclMap)\n    \n    var i = -1\n    var j = 0\n    \n    while i != j {\n        log(\"If bound types are modified, update their member ALs as well...\")\n        updateMemberALs(declMap: declMap)\n        i = flatDeclMap.values.flatMap{$0}.filter{$0.shouldExpose}.count\n        \n        log(\"Again, update ALs of of all decls and their bound types...\")\n        updateBoundTypeALs(declMap: flatDeclMap)\n        resetVisited(declMap: flatDeclMap)\n        j = flatDeclMap.values.flatMap{$0}.filter{$0.shouldExpose}.count\n        \n        log(\"#Remaining decls to update\", i-j, i, j)\n    }\n    \n    log(\"Save decls to update per files...\")\n    for (_, decls) in flatDeclMap {\n        for decl in decls {\n            if decl.isPublicOrOpen, !decl.shouldExpose {\n                if pathToDeclsUpdate[decl.path] == nil {\n                    pathToDeclsUpdate[decl.path] = []\n                }\n                pathToDeclsUpdate[decl.path]?.append(decl)\n            }\n        }\n    }\n    \n    if let logfile = logFilePath {\n        log(\"Save results to\", logfile)\n        let ret = pathToDeclsUpdate.map {\"\\($0.key): \\($0.value.map{$0.name + \", \" + $0.encloser}.joined(separator: \"\\n\"))\"}.joined(separator: \"\\n\")\n        try? ret.write(toFile: logfile, atomically: true, encoding: .utf8)\n    }\n    \n    if inplace {\n        log(\"Update decl ALs in files...\")\n        let updater  = DeclUpdater()\n        updater.updateAccessLevels(filesToDecls: pathToDeclsUpdate, filesToModules: filesToModules) { (path, content) in\n            try? content.write(toFile: path, atomically: true, encoding: .utf8)\n        }\n    }\n    logTime()\n    \n    let total = pathToDeclsUpdate.values.flatMap{$0}.count\n    log(\"#Total top-level decls: \", declMap.count, \"#Total decls\", flatDeclMap.count, \"#Decls updated\", total, \"#Files updated\", pathToDeclsUpdate.count)\n    logTotalElapsed(\"Done\")\n    \n    onCompletion()\n}\n\n\n// MARK - private functions\n\nprivate func updateBoundTypeALs(declMap: DeclMap) {\n    for (k, decls) in declMap {\n        if !k.isEmpty {  // Empty means expr or stmt\n            for decl in decls {\n                if (decl.isPublicOrOpen && decl.shouldExpose) ||\n                    decl.declType == .extensionType ||\n                    decl.isExtensionMember {\n                    decl.visited = true\n                    updateBoundTypeALs(decl, level: 0, declMap: declMap)\n                }\n            }\n        }\n    }\n}\n\nprivate func updateBoundTypeALs(_ decl: DeclMetadata, level: Int, declMap: DeclMap) {\n    \n    for boundType in decl.boundTypesAL {\n        if !boundType.isEmpty {\n            var bases: [String]?\n            var leaf: String?\n            if boundType.contains(\".\") {\n                bases = boundType.components(separatedBy: \".\")\n                leaf = bases?.removeLast()\n            }\n            \n            let key = leaf ?? boundType\n            \n            if let boundDecls = declMap[key] {\n                for boundDecl in boundDecls {\n                    if boundDecl.visited, boundDecl.shouldExpose {\n                        continue\n                    }\n                    boundDecl.visited = true\n                    if decl.module == boundDecl.module || decl.imports.contains(boundDecl.module) {\n                        boundDecl.shouldExpose = true\n                        updateBoundTypeALs(boundDecl, level: level + 1, declMap: declMap)\n                    }\n                }\n            }\n        }\n    }\n}\n\nprivate func updateMemberALs(declMap: DeclMap) {\n    for (_, vals) in declMap {\n        for cur in vals {\n            var members = [DeclMetadata]()\n            var interfaceMembers = [DeclMetadata]()\n            let level = 0\n            \n            updateBoundMemberALs(key: cur, declMap: declMap, level: level, members: &members, interfaceMembers: &interfaceMembers)\n        }\n    }\n}\n\nprivate func updateBoundMemberALs(key cur: DeclMetadata,\n                                  declMap: DeclMap,\n                                  level: Int,\n                                  members: inout [DeclMetadata],\n                                  interfaceMembers: inout [DeclMetadata]) {\n    \n    // First resolve inheritance (loop up protocol conformance, subclassing, and update member ALs)\n    var parents = cur.inheritedTypes\n    let curIsExtension = cur.declType == .extensionType\n    if curIsExtension {\n        parents.append(cur.name)\n    }\n    resolveInheritance(key: cur, inheritedTypes: parents, declMap: declMap, level: level, members: &members, interfaceMembers: &interfaceMembers)\n    \n    let interfaceMemberNames = interfaceMembers.map{$0.name}\n    for member in members {\n        if interfaceMemberNames.contains(member.name) {\n            if member.isPublicOrOpen || (curIsExtension && cur.isPublicOrOpen) {\n                member.shouldExpose = true\n                \n                // If encloser is extension, it should be also exposed since its member is public/exposed\n                if curIsExtension, !cur.shouldExpose {\n                    cur.shouldExpose = true\n                }\n            }\n        } else if member.isPublicOrOpen, member.isOverride {\n            // This might be a member overriding stdlib api\n            member.shouldExpose = true\n        }\n    }\n    \n    // For the following decl types, check bound types and update member ALs.\n    if cur.declType == .extensionType || cur.declType == .enumType {\n        \n        var visitedCurrent = false\n        let boundTypesAL = cur.boundTypesAL.filter{!cur.inheritedTypes.contains($0)}\n        \n        for boundType in boundTypesAL {\n            if !boundType.isEmpty, cur.name != boundType, let boundTypeVals = declMap[boundType] {\n                for boundDecl in boundTypeVals {\n                    if !visitedCurrent,\n                       boundDecl.isPublicOrOpen,\n                       boundDecl.shouldExpose {\n                        \n                        for member in cur.members {\n                            if member.isPublicOrOpen {\n                                member.shouldExpose = true\n                            }\n                        }\n                        visitedCurrent = true\n                    }\n                }\n            } else if !visitedCurrent, cur.inheritedTypes.contains(boundType) {\n                // If parent is not in declMap, assume it's in stdlib.\n                for member in cur.members {\n                    if member.isPublicOrOpen {\n                        member.shouldExpose = true\n                    }\n                }\n                visitedCurrent = true\n            }\n        }\n        \n        if visitedCurrent, !cur.shouldExpose {\n            cur.shouldExpose = true\n        }\n    }\n}\n\n\nprivate func resolveInheritance(key cur: DeclMetadata,\n                                inheritedTypes: [String]?,\n                                declMap: DeclMap,\n                                level: Int,\n                                members: inout [DeclMetadata],\n                                interfaceMembers: inout [DeclMetadata]) {\n    \n    let parents = inheritedTypes ?? cur.inheritedTypes\n    var stdlibTypes = [String]()\n    var userDefinedTypes = [String]()\n    \n    for parent in parents {\n        if parent.isEmpty {\n            continue\n        }\n        if let parentDecls = declMap[parent] {\n            for parentDecl in parentDecls {\n                if parentDecl.name.isEmpty {\n                    continue\n                }\n                if parentDecl.declType == .protocolType || parentDecl.declType == .classType || parentDecl.declType == .typealiasType {\n                    if parentDecl.isPublicOrOpen, parentDecl.shouldExpose {\n                        if parentDecl.declType == .protocolType {\n                            interfaceMembers.append(contentsOf: parentDecl.members)\n                        } else if parentDecl.declType == .classType, cur.declType == .classType {\n                            interfaceMembers.append(contentsOf: parentDecl.members)\n                        }\n                    }\n                    \n                    userDefinedTypes.append(parentDecl.name)\n                    members.append(contentsOf: cur.members)\n                    \n                    let optionalInitialTypes = parentDecl.declType == .typealiasType ? parentDecl.boundTypesAL : nil\n                    \n                    resolveInheritance(key: parentDecl, inheritedTypes: optionalInitialTypes, declMap: declMap, level: level+1, members: &members,  interfaceMembers: &interfaceMembers)\n                    \n                } else if parentDecl.declType == .extensionType {\n                    // Parent could be a user defined type or a stdlib type. Add to a list for now and filter out below.\n                    stdlibTypes.append(parentDecl.name)\n                }\n            }\n        } else {\n            // If parent is not in declMap, assume it's in stdlib.\n            stdlibTypes.append(parent)\n        }\n    }\n    \n    for stdlibType in stdlibTypes {\n        if userDefinedTypes.contains(stdlibType) {\n            continue\n        }\n        \n        for member in cur.members {\n            if member.isPublicOrOpen {\n                interfaceMembers.append(member)\n                members.append(member)\n            }\n        }\n        break\n    }\n}\n\nprivate func traverseMembers(_ bases: [String], _ i: Int, _ refModule: String,  _ imports: [String], declMap: DeclMap) -> Bool {\n    let j = i + 1\n    \n    if j < bases.count {\n        let cur = bases[i]\n        let next = bases[j]\n        if let prefixDecls = declMap[cur] {\n            for prefixDecl in prefixDecls {\n                var list: [DeclMetadata]?\n                if prefixDecl.declType == .funcType ||\n                    prefixDecl.declType == .operatorType ||  // This is handled here but shouldn't be member-accessed\n                    prefixDecl.declType == .varType {\n                    if let typeDecls = declMap[prefixDecl.type] {\n                        for t in typeDecls {\n                            list = t.members.filter{$0.name == next}\n                        }\n                    }\n                } else {\n                    list = prefixDecl.members.filter{$0.name == next}\n                }\n                \n                if let list = list, !list.isEmpty {\n                    let checked = traverseMembers(bases, i + 1, refModule, imports, declMap: declMap)\n                    if checked, refModule != prefixDecl.module, imports.contains(prefixDecl.module) {\n                        for member in list {\n                            member.shouldExpose = true\n                        }\n                    }\n                    \n                } else {\n                    return false\n                }\n            }\n        }\n    }\n    return true\n}\n\nprivate func markVisiblity(_ refs: Set<String>, in refModule: String, imports: [String], with declMap: DeclMap, updateMembers: Bool) {\n    // Leaf level node checks\n    for r in refs {\n        \n        var bases: [String]?\n        var leaf: String?\n        \n        if r.contains(\".\") {\n            bases = r.components(separatedBy: \".\")\n        }\n        \n        // First, traverse member access, and update visibility along the way\n        var accessedMembers = false\n        if let bases = bases {\n            accessedMembers = traverseMembers(bases, 0, refModule, imports, declMap: declMap)\n        }\n        if accessedMembers {\n            continue\n        }\n        \n        leaf = bases?.removeLast()\n        let refKey = leaf ?? r\n        \n        // If above fails (e.g. encloser type is not found), or non-member access, try following\n        if let refDecls = declMap[refKey] {\n            for refDecl in refDecls {\n                if true ||\n                    refDecl.isPublicOrOpen ||\n                    refDecl.declType == .extensionType ||\n                    refDecl.isExtensionMember {\n                    \n                    // multi modules w/ same decls (foo):\n                    // 1. shadowing: if ref'd, it uses a decl in the same module even if the others are imported.\n                    //      - if foo from another module should be called, it's required to use qualifier X.foo\n                    // 2. if not decl's in the same module as ref, uses corresponding modules, so need to look up imports\n                    // 3. if foo inits are the same for multi-modules:\n                    //     - need qualifier X.foo\n                    if refModule == refDecl.module {\n                        // r is either declared internally\n                        // so r should not be public, so add [decl.path: r] to pathToUpdateDecls\n                    } else {\n                        // look up imports and check decl.module is in the imports, then decl.shouldBePublic = true, so do nothing.\n                        if imports.contains(refDecl.module) {\n                            \n                            if !refDecl.encloser.isEmpty {\n                                // If it has an encloser (part of a class, protocol, etc),\n                                // check if the encloser is in ref'd.\n                                // Encloser type might not be listed, leakdetect.inst.accumulatedLeaksStream\n                                refDecl.shouldExpose = true\n                            } else {\n                                // then r in decl.module should remain public\n                                refDecl.shouldExpose = true\n                            }\n                        } else {\n                            // r must be part of stdlib, handled in updateMemberALs above.\n                        }\n                    }\n                    \n                }\n            }\n        }\n    }\n}\n\n\nprivate func shouldMatchACLForMembers(_ declType: DeclType) -> Bool {\n    return declType == .protocolType ||\n        declType == .extensionType ||\n        declType == .enumType\n}\n\nprivate func resetVisited(declMap: DeclMap) {\n    for (_, decls) in declMap {\n        for decl in decls {\n            decl.visited = false\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Extensions/FileManagerExtensions.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\nextension FileManager {\n\n    static func modifiedWithin(_ delta: Int?, at path: String) -> Bool {\n        if let fileAttrs = try? FileManager.default.attributesOfItem(atPath: path),\n            let modifiedDate = fileAttrs[FileAttributeKey.creationDate] as? Date {\n            let now = Date()\n            let days = Int(floor(modifiedDate.distance(to: now) / 60 / 60 / 24))\n            if let delta = delta, days < delta {\n                return true\n            }\n        }\n        return false\n    }\n}\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Extensions/SequenceExtensions.swift",
    "content": "\n//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\npublic extension Sequence {\n    \n    func compactMap<T>(path: KeyPath<Element, T?>) -> [T] {\n        return compactMap { (element) -> T? in\n            element[keyPath: path]\n        }\n    }\n    func map<T>(path: KeyPath<Element, T>) -> [T] {\n        return map { (element) -> T in\n            element[keyPath: path]\n        }\n    }\n    \n    func filter(path: KeyPath<Element, Bool>) -> [Element] {\n        return filter { (element) -> Bool in\n            element[keyPath: path]\n        }\n    }\n    \n    func sorted<T>(path: KeyPath<Element, T>) -> [Element] where T: Comparable {\n        return sorted { (lhs, rhs) -> Bool in\n            lhs[keyPath: path] < rhs[keyPath: path]\n        }\n    }\n    \n    func sorted<T, U>(path: KeyPath<Element, T>, fallback: KeyPath<Element, U>) -> [Element] where T: Comparable, U: Comparable {\n        return sorted { (lhs, rhs) -> Bool in\n            if lhs[keyPath: path] == rhs[keyPath: path] {\n                return lhs[keyPath: fallback] < rhs[keyPath: fallback]\n            }\n            \n            return lhs[keyPath: path] < rhs[keyPath: path]\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Extensions/StringExtensions.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\nvar alphanumericSet = CharacterSet.alphanumerics\n\nextension String {\n    static public let `final` = \"final\"\n    static let override = \"override\"\n    static let unknownVal = \"Unknown\"\n    static let prefix = \"prefix\"\n    static let `public` = \"public\"\n    static let `open` = \"open\"\n    static let `internal` = \"internal\"\n    static let `required` = \"required\"\n    static let `convenience` = \"convenience\"\n    static let moduleColon = \"module:\"\n    static let typealiasColon = \"typealias:\"\n    static let rxColon = \"rx:\"\n    static let varColon = \"var:\"\n    static let annotationArgDelimiter = \";\"\n    static let transparent = \"@_transparent\"\n    static let propertyWrapper = \"propertyWrapper\"\n    \n    var raw: String {\n        if hasPrefix(\"`\"), hasSuffix(\"`\") {\n            var val = dropFirst()\n            val = val.dropLast()\n            return String(val)\n        }\n        return self\n    }\n    \n    func arguments(with delimiter: String) -> [String: String]? {\n        let argstr = self\n        let args = argstr.components(separatedBy: delimiter)\n        var argsMap = [String: String]()\n        for item in args {\n            let keyVal = item.components(separatedBy: \"=\").map{$0.trimmed}\n            \n            if let k = keyVal.first {\n                if k.contains(\":\") {\n                    break\n                }\n                \n                if let v = keyVal.last {\n                    argsMap[k] = v\n                }\n            }\n        }\n        return !argsMap.isEmpty ? argsMap : nil\n    }\n    \n    public var trimmed: String {\n        return self.trimmingCharacters(in: .whitespaces)\n    }\n    \n    var isAlphanumeric: Bool {\n        let ret = self.unicodeScalars.filter {alphanumericSet.contains($0) || $0 == \"_\"}\n        return !ret.isEmpty\n    }\n    \n    var isPublicOrOpen: Bool {\n        return self == .public || self == .open\n    }\n}\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Extensions/SyntaxExtensions.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport Foundation\nimport SwiftSyntax\n\n\nprotocol DeclProtocol {\n    var type: String { get }\n    var name: String { get }\n    var fullName: String { get }\n    var declType: DeclType { get }\n    var inheritedTypes: [String] { get }\n    func refTypes(with declMap: DeclMap, filterKey: String?) -> [String]\n    var refTypes: [String] { get }\n    var boundTypes: [String] { get }\n    var boundTypesAL: [String] { get } // Bound types for access levels\n    var accessLevel: String { get }\n    var isOverride: Bool { get }\n    var isExprOrStmt: Bool { get }\n    func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata]\n}\n\nextension DeclProtocol {\n    func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata] {\n        if let declSyntax = self as? DeclSyntax, let varSyntax = declSyntax.as(VariableDeclSyntax.self) {\n            return varSyntax.declMetadatas(path: path, module: module, encloser: encloser, description: description, imports: imports)\n        }\n\n        let val = DeclMetadata(path: path,\n                                 module: module,\n                                 imports: imports,\n                                 encloser: encloser,\n                                 name: name,\n                                 type: type,\n                                 fullName: fullName,\n                                 description: description,\n                                 declType: declType,\n                                 inheritedTypes: inheritedTypes,\n                                 boundTypes: boundTypes,\n                                 boundTypesAL: boundTypesAL,\n                                 isPublicOrOpen: accessLevel.isPublicOrOpen,\n                                 isOverride: isOverride,\n                                 used: false)\n          return [val]\n      }\n\n    func refTypes(with declMap: DeclMap, filterKey: String? = nil) -> [String] {\n        return refTypes.filter { declMap[$0] != nil || $0.contains(\".\") || $0.hasSuffix(\"Strings\") || $0.hasSuffix(\"Images\") }\n    }\n\n}\n\nextension Syntax: DeclProtocol {\n\n    var name: String {\n        return \"\"\n    }\n\n    var type: String {\n        return \"\"\n    }\n\n    var fullName: String {\n        return name\n    }\n\n    var accessLevel: String {\n        return \"\"\n    }\n\n    var isOverride: Bool {\n        return false\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    var declType: DeclType {\n        return .other\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n\n    var boundTypes: [String] {\n        return tokens.exprTokenList\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n}\n\nextension DeclSyntax: DeclProtocol {\n    var name: String {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.name\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.name\n        } else {\n            return \"\"\n        }\n    }\n\n    var type: String {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.type\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.type\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.type\n        }\n        return name\n    }\n\n    var fullName: String {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.fullName\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.fullName\n        }\n        return name\n    }\n\n\n    var declType: DeclType {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.declType\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.declType\n        }\n        return .other\n    }\n\n\n    var inheritedTypes: [String] {\n        if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.inheritedTypes\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.inheritedTypes\n        }\n        return []\n    }\n\n    func refTypes(with declMap: DeclMap, filterKey: String?) -> [String] {\n        var list = refTypes\n        if !declMap.isEmpty {\n            list = list.filter{declMap[$0] != nil}\n        }\n        return list\n    }\n\n    var refTypes: [String] {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.refTypes\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.refTypes\n        }\n        return []\n    }\n\n    var boundTypes: [String] {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.boundTypes\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.boundTypes\n        }\n        return []\n    }\n\n    var boundTypesAL: [String] {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.boundTypesAL\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.boundTypesAL\n        }\n        return []\n    }\n\n    var accessLevel: String {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(SubscriptDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(ProtocolDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(ClassDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(ExtensionDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(StructDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(EnumDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(EnumCaseDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(TypealiasDeclSyntax.self) {\n            return d.accessLevel\n        } else if let d = self.as(AssociatedtypeDeclSyntax.self) {\n            return d.accessLevel\n        }\n        return \"\"\n    }\n\n    var isOverride: Bool {\n        if let d = self.as(FunctionDeclSyntax.self) {\n            return d.isOverride\n        } else if let d = self.as(VariableDeclSyntax.self) {\n            return d.isOverride\n        } else if let d = self.as(InitializerDeclSyntax.self) {\n            return d.isOverride\n        }\n        return false\n    }\n\n    var isExprOrStmt: Bool {\n        _syntaxNode.is(StmtSyntax.self) || _syntaxNode.is(ExprSyntax.self)\n    }\n}\n\n\nextension MemberDeclListItemSyntax: DeclProtocol {\n    var refTypes: [String] {\n        return decl.refTypes\n    }\n\n    var declType: DeclType {\n        return decl.declType\n    }\n\n    var inheritedTypes: [String] {\n        return decl.inheritedTypes\n    }\n\n    var boundTypes: [String] {\n        return decl.boundTypes\n    }\n\n    var boundTypesAL: [String] {\n        return decl.boundTypesAL\n    }\n\n    var accessLevel: String {\n        return decl.accessLevel\n    }\n\n    var isOverride: Bool {\n        return decl.isOverride\n    }\n\n    var isExprOrStmt: Bool {\n        return decl.isExprOrStmt\n    }\n\n    var name: String {\n        return decl.name\n    }\n\n    var type: String {\n        return decl.type\n    }\n\n    var fullName: String {\n        return decl.fullName\n    }\n}\n\nextension MemberDeclListSyntax: DeclProtocol {\n\n    var name: String {\n        return \"\"\n    }\n\n    var type: String {\n        return name\n    }\n\n    var fullName: String {\n        return name\n    }\n\n    var declType: DeclType {\n        return .other\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var accessLevel: String {\n        return \"\"\n    }\n\n    var isOverride: Bool {\n        return false\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    var boundTypes: [String] {\n        return self.map { $0.decl.boundTypes }.flatMap{$0}\n    }\n\n    var boundTypesAL: [String] {\n        return self.map { $0.decl.boundTypesAL }.flatMap{$0}\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n\n}\n\nextension ProtocolDeclSyntax: DeclProtocol {\n    var fullName: String {\n        return name\n    }\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var name: String {\n        return identifier.text.raw\n    }\n    \n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return [inheritanceClause?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter{$0 != name}\n    }\n\n    var boundTypes: [String] {\n        return inheritedTypes\n    }\n\n    var boundTypesAL: [String] {\n        return [boundTypes,\n                members.members.boundTypesAL,\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n\n    var declType: DeclType {\n        return .protocolType\n    }\n    \n    var isPrivate: Bool {\n        return self.modifiers?.isPrivate ?? false\n    }\n    \n\n    var attributesDescription: String {\n        self.attributes?.trimmedDescription ?? \"\"\n    }\n    \n    var offset: Int64 {\n        return Int64(self.position.utf8Offset)\n    }\n    \n    func annotationMetadata(with annotation: String) -> AnnotationMetadata? {\n        return leadingTrivia?.annotationMetadata(with: annotation)\n    }\n\n}\n\nextension ClassDeclSyntax: DeclProtocol {\n    var fullName: String {\n        return name\n    }\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    var isOverride: Bool {\n        return false\n    }\n\n    var name: String {\n        return identifier.text.raw\n    }\n    \n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n    \n    var declType: DeclType {\n        return .classType\n    }\n    \n    var boundTypes: [String] {\n        return inheritedTypes\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return [boundTypesAL,\n                members.members.boundTypesAL,\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n\n    var inheritedTypes: [String] {\n        return [genericParameterClause?.genericParameterList.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n                inheritanceClause?.tokens.exprTokenList\n            ].compactMap{$0}.flatMap{$0}.filter{$0 != name}\n    }\n\n    var attributesDescription: String {\n        self.attributes?.trimmedDescription ?? \"\"\n    }\n    \n    var offset: Int64 {\n        return Int64(self.position.utf8Offset)\n    }\n    \n    func annotationMetadata(with annotation: String) -> AnnotationMetadata? {\n        return leadingTrivia?.annotationMetadata(with: annotation)\n    }\n}\n\nextension ExtensionDeclSyntax: DeclProtocol {\n    var fullName: String {\n        return extendedType.description.trimmed + \"_\" + inheritedTypes.joined()\n    }\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var name: String {\n        let str = extendedType.description.trimmed.raw\n        let comps = str.components(separatedBy: \".\")\n        if let last = comps.last, !last.isEmpty {\n            return last\n        }\n        return str\n    }\n\n    var declType: DeclType {\n        return .extensionType\n    }\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return [inheritanceClause?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter{$0 != name}\n    }\n\n    var boundTypes: [String] {\n        var ret = inheritedTypes\n        ret.append(name)\n        return ret\n    }\n\n    var boundTypesAL: [String] {\n        return [boundTypes,\n                members.members.boundTypesAL,\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n\n    func refTypes(with declMap: DeclMap, filterKey: String? = nil) -> [String] {\n        var list = [extendedType.tokens.exprTokenList,\n                    refTypes\n            ].compactMap{$0}.flatMap{$0}\n\n        if !declMap.isEmpty {\n            list = list.filter{declMap[$0] != nil}\n        }\n\n        return list\n    }\n\n}\n\nextension EnumCaseDeclSyntax: DeclProtocol {\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var name: String {\n        let ret = elements.map{$0.identifier.text}.first ?? elements.description\n        return ret.raw\n    }\n\n    var fullName: String {\n        return self.elements.description\n    }\n\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var declType: DeclType {\n        return .enumCaseType\n    }\n\n    var boundTypes: [String] {\n        let list = elements.compactMap{$0.associatedValue?.parameterList.compactMap{$0.type?.tokens.exprTokenList}.flatMap{$0}}.flatMap{$0}\n        return list\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n}\n\nextension EnumDeclSyntax: DeclProtocol {\n    var fullName: String {\n        return name + \"_\" + inheritedTypes.joined()\n    }\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var attributesDescription: String {\n        self.attributes?.description.trimmed ?? \"\"\n    }\n\n    var name: String {\n        return identifier.text.trimmed.raw\n    }\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var declType: DeclType {\n        return .enumType\n    }\n\n    var inheritedTypes: [String] {\n        return [inheritanceClause?.tokens.exprTokenList,\n                genericParameters?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList\n            ].compactMap{$0}.flatMap{$0}.filter{ $0 != name }\n    }\n\n    var boundTypes: [String] {\n        return inheritedTypes\n    }\n\n    var boundTypesAL: [String] {\n        return [boundTypes,\n                members.members.boundTypesAL\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n}\n\nextension StructDeclSyntax: DeclProtocol {\n    var fullName: String {\n        return name + \"_\" + inheritedTypes.joined()\n    }\n    var type: String {\n        return name\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var attributesDescription: String {\n        self.attributes?.description.trimmed ?? \"\"\n    }\n\n    var name: String {\n        return identifier.text.trimmed.raw\n    }\n    var declType: DeclType {\n        return .structType\n    }\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return [inheritanceClause?.tokens.exprTokenList,\n                genericParameterClause?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter{ $0 != name }\n    }\n\n    var boundTypes: [String] {\n        return inheritedTypes\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return [boundTypesAL,\n                members.members.boundTypesAL,\n            ].compactMap{$0}.flatMap{$0}\n    }\n}\n\nextension AssociatedtypeDeclSyntax: DeclProtocol {\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n    var type: String {\n        return name\n    }\n\n    var name: String {\n        return identifier.text.trimmed.raw\n    }\n\n    var fullName: String {\n        return name + \"_\" + boundTypes.joined()\n    }\n\n    var declType: DeclType {\n        return .patType\n    }\n\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return [inheritanceClause?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter{$0 != name}\n    }\n\n    var boundTypes: [String] {\n        return [inheritedTypes,\n                initializer?.value.tokens.exprTokenList.filter{$0 != name}\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n}\n\nextension TypealiasDeclSyntax: DeclProtocol {\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n    var type: String {\n        return name\n    }\n\n    var name: String {\n        return identifier.text.trimmed.raw\n    }\n\n    var fullName: String {\n        return name + \"_\" + boundTypes.joined()\n    }\n\n    var declType: DeclType {\n        return .typealiasType\n    }\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return [genericParameterClause?.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter{$0 != name}\n    }\n\n    var boundTypes: [String] {\n        return [inheritedTypes,\n                initializer?.value.tokens.exprTokenList.filter{$0 != name}\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return boundTypesAL\n    }\n\n}\n\nextension PatternBindingSyntax {\n    var type: String {\n        if let t = typeAnnotation?.type.description.trimmed {\n            return t\n        }\n        if let val = initializer?.value {\n            if let expr = val.as(FunctionCallExprSyntax.self) {\n                return expr.calledExpression.description.trimmed\n            } else if let expr = val.as(ExprSyntax.self) {\n                return expr.description.trimmed\n            }\n        }\n        return .unknownVal\n    }\n\n    func boundTypes(isTransparent: Bool) -> [String] {\n        var list = [String]()\n        if let bound = typeAnnotation?.type.tokens.exprTokenList {\n            list.append(contentsOf: bound)\n        }\n        if let val = initializer?.value {\n            if let expr = val.as(FunctionCallExprSyntax.self) {\n                let exprList = [\n                    expr.calledExpression.tokens.exprTokenList,\n                    expr.argumentList.map{$0.expression.tokens.exprTokenList}.flatMap{$0}\n                    ].flatMap{$0}\n                list.append(contentsOf: exprList)\n            } else if let expr = val.as(ExprSyntax.self) {\n                list.append(contentsOf: expr.tokens.exprTokenList)\n            }\n        }\n\n        if isTransparent {\n            if let bodyTokens = accessor?.tokens.exprTokenList {\n                list.append(contentsOf: bodyTokens)\n            }\n        }\n        return list\n    }\n}\n\nextension VariableDeclSyntax: DeclProtocol {\n    func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata] {\n        var list = [DeclMetadata]()\n\n        for binding in bindings {\n            if let idpattern = binding.pattern.as(IdentifierPatternSyntax.self) {\n                let id = idpattern.identifier.text\n                if id == \"_\" { continue }\n                let ty = binding.type\n                let full = id + \"_\" + ty\n                let bound = binding.boundTypes(isTransparent: isTransparent)\n                let val = DeclMetadata(path: path,\n                                       module: module,\n                                       imports: imports,\n                                       encloser: encloser,\n                                       name: id,\n                                       type: ty,\n                                       fullName: full,\n                                       description: description,\n                                       declType: declType,\n                                       inheritedTypes: inheritedTypes,\n                                       boundTypes: bound,\n                                       boundTypesAL: bound,\n                                       isPublicOrOpen: accessLevel.isPublicOrOpen,\n                                       isOverride: isOverride,\n                                       used: false)\n                list.append(val)\n            } else if let tuple = binding.pattern.as(TuplePatternSyntax.self) {\n                for el in tuple.elements {\n                    if let idpattern = el.pattern.as(IdentifierPatternSyntax.self) {\n                        let id = idpattern.identifier.text\n                        if id == \"_\" { continue }\n\n                        let ty = binding.type\n                        let full = id + \"_\" + ty\n                        let bound = binding.boundTypes(isTransparent: isTransparent)\n                        let val = DeclMetadata(path: path,\n                                               module: module,\n                                               imports: imports,\n                                               encloser: encloser,\n                                               name: id,\n                                               type: ty,\n                                               fullName: full,\n                                               description: description,\n                                               declType: declType,\n                                               inheritedTypes: inheritedTypes,\n                                               boundTypes: bound,\n                                               boundTypesAL: bound,\n                                               isPublicOrOpen: accessLevel.isPublicOrOpen,\n                                               isOverride: isOverride,\n                                               used: false)\n                        list.append(val)\n                    }\n                }\n            }\n        }\n\n        return list\n    }\n\n    var isTransparent: Bool {\n        return attributesDescription.contains(String.transparent)\n    }\n\n    var name: String {\n        let ret = bindings.compactMap { $0.pattern.description.trimmed }.joined().raw\n        return ret\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    var fullName: String {\n        return name + \"_\" + type\n    }\n\n    var declType: DeclType {\n        return .varType\n    }\n\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var isOverride: Bool {\n        return modifiers?.isOverride ?? false\n    }\n\n    var attributesDescription: String {\n        return attributes?.trimmedDescription ?? \"\"\n    }\n\n    var type: String {\n        return bindings.first?.type ?? \"\"\n    }\n\n    var boundTypes: [String] {\n        var list = [String]()\n        for b in bindings {\n            list.append(contentsOf: b.boundTypes(isTransparent: isTransparent))\n        }\n        if let attrs = attributes?.tokens.exprTokenList {\n            list.append(contentsOf: attrs)\n        }\n        return list.filter{$0 != name}\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        let ret = [boundTypesAL,\n                bindings.compactMap{$0.accessor?.tokens.exprTokenList}.flatMap{$0}\n            ].compactMap{$0}.flatMap{$0}\n        return ret\n    }\n}\n\n\nextension FunctionDeclSyntax: DeclProtocol {\n    var name: String {\n        return self.identifier.description.trimmed.raw\n    }\n\n    var type: String {\n        return signature.output?.returnType.description.trimmed ?? \"\"\n    }\n\n    var fullName: String {\n        return name + signature.description.trimmed\n    }\n\n    var declType: DeclType {\n        if self.identifier.tokenKind == .spacedBinaryOperator(self.identifier.text) {\n            return .operatorType\n        }\n        return .funcType\n    }\n\n    var accessLevel: String {\n        return self.modifiers?.acl ?? \"\"\n    }\n\n    var isOverride: Bool {\n        return modifiers?.isOverride ?? false\n    }\n\n    var attributesDescription: String {\n        return attributes?.trimmedDescription ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    var boundTypes: [String] {\n        let genericParamTypes = genericParameterClause?.genericParameterList.tokens.exprTokenList\n        let genericWhereTypes = genericWhereClause?.tokens.exprTokenList\n        let paramTypes = signature.input.parameterList.compactMap{$0.type?.tokens.exprTokenList}.flatMap{$0}\n        let paramVals = signature.input.parameterList.compactMap{$0.defaultArgument?.value.tokens.exprTokenList}.flatMap{$0}\n        let returnTypes = signature.output?.returnType.tokens.exprTokenList\n        let attrs = attributes?.tokens.exprTokenList  // e.g. @FunctionBuilder\n        var list = [genericParamTypes, genericWhereTypes, paramTypes, paramVals, returnTypes, attrs].compactMap{$0}.flatMap{$0}\n        if attributesDescription.contains(String.transparent) {\n            if let bodyTokens = body?.tokens.exprTokenList {\n                list.append(contentsOf: bodyTokens)\n            }\n        }\n        return list.filter{$0 != name}\n    }\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return [boundTypesAL,\n                body?.tokens.exprTokenList\n            ].compactMap{$0}.flatMap{$0}\n    }\n}\n\nextension InitializerDeclSyntax: DeclProtocol {\n    var name: String {\n        return \"init\"\n    }\n    var type: String {\n        return name\n    }\n\n    var fullName: String {\n        return name + \"_\" + parameters.description.trimmed\n    }\n\n    var declType: DeclType {\n        return .initType\n    }\n\n    var isOverride: Bool {\n        return modifiers?.isOverride ?? false\n    }\n\n    var attributesDescription: String {\n        return attributes?.trimmedDescription ?? \"\"\n    }\n\n    var accessLevel: String {\n        return modifiers?.acl ?? \"\"\n    }\n\n    var boundTypes: [String] {\n        let genericParamTypes = genericParameterClause?.genericParameterList.tokens.exprTokenList\n        let genericWhereTypes = genericWhereClause?.tokens.exprTokenList\n\n        var paramList = [String]()\n        for param in parameters.parameterList {\n            if let pval = param.defaultArgument?.value {\n                if let accessed = pval.as(MemberAccessExprSyntax.self), let base = accessed.base {\n                    paramList.append(accessed.description.trimmed)\n                    paramList.append(contentsOf: base.tokens.exprTokenList)\n                } else {\n                    paramList.append(contentsOf: pval.tokens.exprTokenList)\n                }\n            }\n            if let ptypes = param.type?.tokens.exprTokenList {\n                paramList.append(contentsOf: ptypes)\n            }\n        }\n\n        var list = [genericParamTypes, genericWhereTypes, paramList].compactMap{$0}.flatMap{$0}\n\n        // @_transparent on public or @usableFromInline functions require all types in sig and body to be public\n        if attributesDescription.contains(String.transparent) {\n            if let bodyTokens = body?.tokens.exprTokenList {\n                list.append(contentsOf: bodyTokens)\n            }\n        }\n\n        return list.filter{$0 != name}\n    }\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n    var refTypes: [String] {\n        return [boundTypesAL,\n                body?.tokens.exprTokenList\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n\n    func isRequired(with declType: DeclType) -> Bool {\n        if declType == .protocolType {\n            return true\n        } else if declType == .classType {\n            if let modifiers = self.modifiers {\n                \n                if modifiers.isConvenience {\n                    return false\n                }\n                return modifiers.isRequired\n            }\n        }\n        return false\n    }\n}\n\nextension SubscriptDeclSyntax: DeclProtocol {\n\n    var fullName: String {\n        return name + \"_\" + result.returnType.description.trimmed\n    }\n\n    var name: String {\n        return self.subscriptKeyword.text\n    }\n\n    var declType: DeclType {\n        return .subscriptType\n    }\n\n    var accessLevel: String {\n        return modifiers?.acl ?? \"\"\n    }\n\n    var inheritedTypes: [String] {\n        return []\n    }\n\n    var isExprOrStmt: Bool {\n        return false\n    }\n    var isOverride: Bool {\n        return false\n    }\n\n    var type: String {\n        return result.returnType.description.trimmed\n    }\n\n    var boundTypes: [String] {\n        return [result.returnType.tokens.exprTokenList,\n                genericParameterClause?.genericParameterList.tokens.exprTokenList,\n                genericWhereClause?.tokens.exprTokenList,\n                attributes?.tokens.exprTokenList,\n            ].compactMap{$0}.flatMap{$0}.filter {$0 != name }\n    }\n\n    var boundTypesAL: [String] {\n        return boundTypes\n    }\n\n\n    var refTypes: [String] {\n        return [boundTypesAL,\n                accessor?.tokens.exprTokenList\n            ].compactMap{$0}.flatMap{$0}\n    }\n\n}\n\n\n// MARK -\n\nextension AttributeListSyntax {\n    var trimmedDescription: String? {\n        return self.withoutTrivia().description.trimmingCharacters(in: .whitespacesAndNewlines)\n    }\n}\n\nextension ModifierListSyntax {\n    var acl: String {\n        for modifier in self {\n            for token in modifier.tokens {\n                switch token.tokenKind {\n                case .publicKeyword, .internalKeyword, .privateKeyword, .fileprivateKeyword:\n                    return token.text\n                default:\n                    // For some reason openKeyword option is not available in TokenKind so need to address separately\n                    if token.text == String.open {\n                        return token.text\n                    }\n                }\n            }\n        }\n        return \"\"\n    }\n\n    var isStatic: Bool {\n        return self.tokens.filter {$0.tokenKind == .staticKeyword }.count > 0\n    }\n\n    var isRequired: Bool {\n        return self.tokens.filter {$0.text == String.required }.count > 0\n    }\n\n    var isConvenience: Bool {\n        return self.tokens.filter {$0.text == String.convenience }.count > 0\n    }\n\n    var isOverride: Bool {\n        return self.tokens.filter {$0.text == String.override }.count > 0\n    }\n\n    var isFinal: Bool {\n        return self.tokens.filter {$0.text == String.final }.count > 0\n    }\n\n    var isPrivate: Bool {\n        return self.tokens.filter {$0.tokenKind == .privateKeyword || $0.tokenKind == .fileprivateKeyword }.count > 0\n    }\n\n    var isPublic: Bool {\n        return self.tokens.filter {$0.tokenKind == .publicKeyword }.count > 0\n    }\n\n    var isOpen: Bool {\n        return self.tokens.filter {$0.text == String.open }.count > 0\n    }\n}\n\nextension Trivia {\n    // This parses arguments in annotation which can be used to override certain types.\n    //\n    // E.g. given /// @mockable(typealias: T = Any; U = AnyObject), it returns\n    // a dictionary: [T: Any, U: AnyObject] which will be used to override inhertied types\n    // of typealias decls for T and U.\n    private func metadata(with annotation: String, in val: String) -> AnnotationMetadata? {\n        if val.contains(annotation) {\n            let comps = val.components(separatedBy: annotation)\n            var ret = AnnotationMetadata()\n            if var argsStr = comps.last, !argsStr.isEmpty {\n                if argsStr.hasPrefix(\"(\") {\n                    argsStr.removeFirst()\n                }\n                if argsStr.hasSuffix(\")\") {\n                    argsStr.removeLast()\n                }\n                if argsStr.contains(String.typealiasColon), let subStr = argsStr.components(separatedBy: String.typealiasColon).last, !subStr.isEmpty {\n                    ret.typeAliases = subStr.arguments(with: .annotationArgDelimiter)\n                }\n                if argsStr.contains(String.moduleColon), let subStr = argsStr.components(separatedBy: String.moduleColon).last, !subStr.isEmpty {\n                    let val = subStr.arguments(with: .annotationArgDelimiter)\n                    ret.module = val?[.prefix]\n                }\n                if argsStr.contains(String.rxColon), let subStr = argsStr.components(separatedBy: String.rxColon).last, !subStr.isEmpty {\n                    ret.varTypes = subStr.arguments(with: .annotationArgDelimiter)\n                }\n                if argsStr.contains(String.varColon), let subStr = argsStr.components(separatedBy: String.varColon).last, !subStr.isEmpty {\n                    if let val = subStr.arguments(with: .annotationArgDelimiter) {\n                        if ret.varTypes == nil {\n                            ret.varTypes = val\n                        } else {\n                            ret.varTypes?.merge(val, uniquingKeysWith: {$1})\n                        }\n                    }\n                }\n            }\n            return ret\n        }\n        return nil\n    }\n    \n    // Looks up an annotation (e.g. /// @mockable) and its arguments if any.\n    // See metadata(with:, in:) for more info on the annotation arguments.\n    func annotationMetadata(with annotation: String) -> AnnotationMetadata? {\n        guard !annotation.isEmpty else { return nil }\n        var ret: AnnotationMetadata?\n        for i in 0..<count {\n            let trivia = self[i]\n            switch trivia {\n            case .docLineComment(let val):\n                ret = metadata(with: annotation, in: val)\n                if ret != nil {\n                    return ret\n                }\n            case .docBlockComment(let val):\n                ret = metadata(with: annotation, in: val)\n                if ret != nil {\n                    return ret\n                }\n            default:\n                continue\n            }\n        }\n        return nil\n    }\n}\n\n\nextension TokenSyntax {\n    var stringToken: String? {\n        if text == \"self\" || text == \"Self\" || text == \"super\" || text == \"nil\" ||\n            text == \"as\" || text == \"true\" || text == \"false\" || text == \"AnyObject\" || text == \"Any\" {\n            return nil\n        }\n\n        let startsWithLetter = text.first?.isLetter ?? false\n        let validFirstChar = text.first == \"_\" || startsWithLetter\n        if (validFirstChar && (text.isAlphanumeric || text.contains(\"_\"))) ||\n            tokenKind == .spacedBinaryOperator(text) {\n            return text\n        }\n\n        return nil\n    }\n\n    var exprToken: String? {\n        if tokenKind != .stringQuote,\n            tokenKind != .stringSegment(text),\n            tokenKind != .spacedBinaryOperator(text),\n            tokenKind != .initKeyword {\n\n            return stringToken\n        }\n        return nil\n    }\n\n    func filteredToken(with suffix: String) -> String? {\n        if text.hasSuffix(suffix) {\n            return String(text.dropLast(suffix.count))\n        }\n        return nil\n    }\n}\n\nextension TokenSequence {\n    var tokenList: [String] {\n        return self.compactMap { $0.stringToken }\n    }\n\n    var exprTokenList: [String] {\n        return self.compactMap { $0.exprToken }\n    }\n}\n\n\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Extensions/SyntaxParserExtensions.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport Foundation\nimport SwiftSyntax\nimport SwiftSyntaxParser\n\nextension SyntaxParser {\n    public static func parse(_ fileData: Data, path: String,\n                             diagnosticHandler: ((Diagnostic) -> Void)? = nil) throws -> SourceFileSyntax {\n        // Avoid using `String(contentsOf:)` because it creates a wrapped NSString.\n        let source = fileData.withUnsafeBytes { buf in\n            return String(decoding: buf.bindMemory(to: UInt8.self), as: UTF8.self)\n        }\n        return try parse(source: source, filenameForDiagnostics: path,\n                         diagnosticHandler: diagnosticHandler)\n    }\n\n    public static func parse(_ path: String) throws -> SourceFileSyntax {\n        guard let fileData = FileManager.default.contents(atPath: path) else {\n            fatalError(\"Retrieving contents of \\(path) failed\")\n        }\n        return try parse(fileData, path: path)\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Logger.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport os.signpost\n\nfileprivate let perfLog = OSLog(subsystem: \"SwiftCodeSan\", category: \"PointsOfInterest\")\nfileprivate var prevTime: CFAbsoluteTime?\nfileprivate var startTime: CFAbsoluteTime?\n\npublic var minLogLevel = 0\n\n/// Logs status and other messages depending on the level provided\npublic enum LogLevel: Int {\n    case verbose\n    case info\n    case warning\n    case error\n}\n\npublic func logTotalElapsed(_ arg: Any...) {\n    let cur = CFAbsoluteTimeGetCurrent()\n    if let startTime = startTime {\n        print(arg, cur-startTime)\n    } else {\n        print(\"0.00\")\n    }\n}\n\npublic func logTime(_ arg: Any...) {\n    let cur = CFAbsoluteTimeGetCurrent()\n    if let prevTime = prevTime {\n        var str = arg\n        let delta = (cur-prevTime)\n        str.append(\"Took \\(delta)\")\n        print(str)\n    }\n    prevTime = cur\n    if startTime == nil {\n        startTime = cur\n    }\n}\n\npublic func log(_ arg: Int, level: LogLevel = .info, interval: Int) {\n    if arg > 0, arg % interval == 0 {\n        log(arg, level: level)\n    }\n}\n\npublic func log(_ arg: Any..., level: LogLevel = .info, counter: inout Int, interval: Int, timed: Bool = false) {\n    if counter > 0, counter % interval == 0 {\n        log(arg, counter, level: level)\n        if timed {\n            logTime()\n        }\n    }\n    counter += 1\n}\n\npublic func log(_ arg: Any..., level: LogLevel = .info) {\n    guard level.rawValue >= minLogLevel else { return }\n    switch level {\n    case .info, .verbose:\n        print(arg)\n    case .warning:\n        print(\"WARNING: \\(arg)\")\n    case .error:\n        print(\"ERROR: \\(arg)\")\n    }\n}\n\npublic func signpost_begin(name: StaticString) {\n    if minLogLevel == LogLevel.verbose.rawValue {\n        os_signpost(.begin, log: perfLog, name: name)\n    }\n}\n\npublic func signpost_end(name: StaticString) {\n    if minLogLevel == LogLevel.verbose.rawValue {\n        os_signpost(.end, log: perfLog, name: name)\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftCodeSanKit/Utils/Scanner.swift",
    "content": "//\n//  Copyright (c) 2018. Uber Technologies\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\npublic var scanConcurrencyLimit: Int? = nil\n\nfunc semaphore(_ numThreads: Int?) -> DispatchSemaphore? {\n    let limit = concurrencyLimit(numThreads)\n    var sema: DispatchSemaphore?\n    if limit > 1 {\n        sema = DispatchSemaphore(value: limit)\n    }\n    return sema\n}\n\nfunc queue(_ numThreads: Int?) -> DispatchQueue? {\n    var q: DispatchQueue?\n    if concurrencyLimit(numThreads) > 1 {\n        q = DispatchQueue(label: \"SwiftCodeSan-queue\", qos: DispatchQoS.userInteractive, attributes: DispatchQueue.Attributes.concurrent)\n    }\n    return q\n}\n\nfunc concurrencyLimit(_ numThreads: Int?) -> Int {\n    var limit = 1\n    if let n = numThreads {\n        limit = n\n    } else if let n = scanConcurrencyLimit {\n        limit = n\n    }\n    return limit\n}\n\npublic func scan(_ paths: [String],\n                 isDirectory: Bool,\n                 numThreads: Int? = nil,\n                 block: @escaping (_ path: String, _ lock: NSLock?) -> ()) {\n    if isDirectory {\n        scan(dirs: paths, block: block)\n    } else {\n        scan(paths, block: block)\n    }\n}\n\npublic func scan(dirs: [String],\n                 numThreads: Int? = nil,\n                 block: @escaping (_ path: String, _ lock: NSLock?) -> ()) {\n    \n    if let queue = queue(numThreads) {\n        let sema = semaphore(numThreads)\n        let lock = NSLock()\n        scanDirs(dirs) { filePath in\n            _ = sema?.wait(timeout: DispatchTime.distantFuture)\n            queue.async {\n                block(filePath, lock)\n                sema?.signal()\n            }\n        }\n        // Wait for queue to drain\n        queue.sync(flags: .barrier) {}\n    } else {\n        scanDirs(dirs) { filePath in\n            block(filePath, nil)\n        }\n    }\n}\n\npublic func scan<T>(_ elements: [T],\n                    numThreads: Int? = nil,\n                    block: @escaping (T, NSLock?) -> ()) {\n    \n    if let queue = queue(numThreads) {\n        let sema = semaphore(numThreads)\n        let lock = NSLock()\n        for element in elements {\n            _ = sema?.wait(timeout: DispatchTime.distantFuture)\n            queue.async {\n                block(element, lock)\n                sema?.signal()\n            }\n        }\n        queue.sync(flags: .barrier) { }\n    } else {\n        for element in elements {\n            block(element, nil)\n        }\n    }\n}\n\npublic func scan<T, U>(_ elements: [T: U],\n                       numThreads: Int? = nil,\n                       block: @escaping (T, U, NSLock?) -> ()) {\n    \n    if let queue = queue(numThreads) {\n        let sema = semaphore(numThreads)\n        let lock = NSLock()\n        \n        for element in elements {\n            _ = sema?.wait(timeout: DispatchTime.distantFuture)\n            queue.async {\n                block(element.key, element.value, lock)\n                sema?.signal()\n            }\n        }\n        queue.sync(flags: .barrier) { }\n    } else {\n        for element in elements {\n            block(element.key, element.value, nil)\n        }\n    }\n}\n\n\npublic func scanDirs(_ paths: [String], with callBack: (String) -> Void) {\n    for path in paths {\n        scanDir(path, with: callBack)\n    }\n}\n\nfunc scanDir(_ path: String, with callBack: (String) -> Void) {\n    let errorHandler = { (url: URL, error: Error) -> Bool in\n        fatalError(\"Failed to traverse \\(url) with error \\(error).\")\n    }\n    if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path, isDirectory: true), includingPropertiesForKeys: nil, options: [.skipsHiddenFiles], errorHandler: errorHandler) {\n        while let nextObjc = enumerator.nextObject() {\n            if let fileUrl = nextObjc as? URL {\n                callBack(fileUrl.path)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftCodeSanTestCase.swift",
    "content": "import XCTest\nimport SwiftCodeSanKit\n\nclass SwiftCodeSanTestCase: XCTestCase {\n    var srcFilePathsCount = 1\n    var mockFilePathsCount = 1\n    \n    let bundle = Bundle(for: SwiftCodeSanTestCase.self)\n    \n    lazy var dstFilePath: String = {\n        return bundle.bundlePath + \"/Dst.swift\"\n    }()\n    \n    lazy var srcFilePaths: [String] = {\n        var idx = 0\n        var paths = [String]()\n        let prefix = bundle.bundlePath + \"/Src\"\n        let suffix = \".swift\"\n        while idx < srcFilePathsCount {\n            let path = prefix + \"\\(idx)\" + suffix\n            paths.append(path)\n            idx += 1\n        }\n        return paths\n    }()\n    \n    lazy var mockFilePaths: [String] = {\n        var idx = 0\n        var paths = [String]()\n        let prefix = bundle.bundlePath + \"/Mocks\"\n        let suffix = \".swift\"\n        while idx < mockFilePathsCount {\n            let path = prefix + \"\\(idx)\" + suffix\n            paths.append(path)\n            idx += 1\n        }\n        return paths\n    }()\n    \n    override func setUp() {\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n        let created = FileManager.default.createFile(atPath: dstFilePath, contents: nil, attributes: nil)\n        XCTAssert(created)\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        try? FileManager.default.removeItem(atPath: dstFilePath)\n        for srcpath in srcFilePaths {\n            try? FileManager.default.removeItem(atPath: srcpath)\n        }\n    }\n    \n    func verify(srcContent: String, dstContent: String, header: String = \"\", declType: DeclType = .protocolType, useTemplateFunc: Bool = false, testableImports: [String]? = [], concurrencyLimit: Int? = 1) {\n        verify(srcContents: [srcContent], dstContent: dstContent, header: header, declType: declType, useTemplateFunc: useTemplateFunc, testableImports: testableImports, concurrencyLimit: concurrencyLimit)\n    }\n    \n    func verify(srcContents: [String], dstContent: String, header: String, declType: DeclType, useTemplateFunc: Bool, testableImports: [String]?, concurrencyLimit: Int?) {\n        var index = 0\n        srcFilePathsCount = srcContents.count\n        \n        for src in srcContents {\n            if index < srcContents.count {\n                let srcCreated = FileManager.default.createFile(atPath: srcFilePaths[index], contents: src.data(using: .utf8), attributes: nil)\n                index += 1\n                XCTAssert(srcCreated)\n            }\n        }\n        // TODO: Pass in srcfile path - module list\n        removeDeadDecls(filesToModules: [\"test1.swift\": \"test1\"],\n                        whitelist: nil,\n                        topDeclsOnly: true,\n                        inplace: true,\n                        testFiles: [],\n                        inplaceTests: false,\n                        logFilePath: nil,\n                        concurrencyLimit: nil,\n                        onCompletion: {\n                            let output = (try? String(contentsOf: URL(fileURLWithPath: self.dstFilePath), encoding: .utf8)) ?? \"\"\n                            let outputContents = output.components(separatedBy:  .whitespacesAndNewlines).filter{!$0.isEmpty}\n                            XCTAssert(outputContents.count > 0)\n                        })\n    }\n}\n\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test0.swift",
    "content": "#if TESTFILE\nextension Integration {\n    var isUnitTest: Bool {\n        #if TEST\n        if case .test = RunType.current {\n            return !(Handler.isHandlerActive() || runner.sharedInstance.isActive)\n        }\n        #else\n        let x = SomeType().someMethod()\n        return x\n        #endif\n    }\n\n    var workersProviderMock: IntegrationProviderMock { shared { IntegrationProviderMock() } }\n}\n\n\nlet s = SwipeTransitionController()\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test1.swift",
    "content": "#if TESTFILE\nimport Foundation\n\npublic protocol FileHandler {\n\n    func createFile(atPath: String, contents: Data?, attributes: [FileAttributeKey: Any]?) -> Bool\n    func moveItem(at url: URL, to: URL) throws\n\n    func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions) throws -> [URL]\n    func createDirectory(at url: URL, withIntermediateDirectories createIntermediates: Bool, attributes: [FileAttributeKey: Any]?) throws\n    func fileExists(atPath: String) -> Bool\n\n    func createFileHandle(forWritingToURL: URL) throws -> FileHandle\n\n    func read(contentsOf url: URL) throws -> String\n    @discardableResult\n    func write(dictionary: [String: Any], to url: URL, atomically: Bool) -> Bool\n    func write(data: Data, to url: URL, options: Data.WritingOptions) throws\n\n    func read(dictionaryAt url: URL) -> [String: Any]?\n\n    func data(forURL url: URL) -> Data?\n    func isDeletableFile(atURL url: URL) -> Bool\n\n    func removeItem(at URL: URL) throws\n\n    func url(for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask) throws -> URL\n\n    func urls(for directory: FileManager.SearchPathDirectory, in domainMask: FileManager.SearchPathDomainMask) -> [URL]\n    func copyItem(at srcURL: URL, to dstURL: URL) throws\n\n    func setResourceValues(_ values: URLResourceValues, at url: inout URL) throws\n\n}\n\nextension FileManager: FileHandler {\n    public func write(data: Data, to url: URL, options: Data.WritingOptions) throws {\n        try data.write(to: url, options: options)\n    }\n\n    public func createFileHandle(forWritingToURL: URL) throws -> FileHandle {\n        return try FileHandle(forWritingTo: forWritingToURL)\n    }\n\n    public func read(contentsOf url: URL) throws -> String {\n        return try String(contentsOf: url, encoding: String.Encoding.utf8)\n    }\n\n    public func write(dictionary: [String: Any], to url: URL, atomically: Bool) -> Bool {\n        return (dictionary as NSDictionary).write(to: url as URL, atomically: atomically)\n    }\n\n    public func read(dictionaryAt url: URL) -> [String: Any]? {\n        return NSDictionary(contentsOf: url as URL) as? [String: Any]\n    }\n\n    public func data(forURL url: URL) -> Data? {\n        return try? Data(contentsOf: url)\n    }\n\n    public func isDeletableFile(atURL url: URL) -> Bool {\n        return isDeletableFile(atPath: url.path)\n    }\n\n    public func url(for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask) throws -> URL {\n        return try url(for: directory, in: domain, appropriateFor: nil, create: true)\n    }\n\n    public func setResourceValues(_ values: URLResourceValues, at url: inout URL) throws {\n        try url.setResourceValues(values)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test2.swift",
    "content": "//\n//  Copyright © Uber Technologies, Inc. All rights reserved.\n//\n#if TESTFILE\n\nimport Foundation\n\n@_transparent public func testAssert(_ resumable: Bool) {\n    let x = AssertStaticString()\n    print(x)\n    \n    if testAssertionDisabled {\n        return\n    }\n    reassert(message(), file: unsafeBitCast(assertStaticString, to: StaticString.self), function: function, line: line)\n    \n    \n    let handler = AssertionHandlers.assertionFailure\n    print(handler)\n}\n\nclass AssertionHandlers {\n}\n\n\npublic struct AssertStaticString {\n    public init() {}\n    public func check() -> Int {\n        return 5\n    }\n}\n\npublic extension String {\n    func someAssert(_ assertStaticString: AssertStaticString) {\n    }\n}\n\n\npublic typealias AssertionHandler = (String?, data: LogModelMetadata?, line: UInt)\n\n\npublic let testAssertionDisabled: Bool = {\n    return false\n}()\n\npublic func reassert(_ message: String, file: StaticString, function: String, line: UInt) {\n}\n\n\npublic class SynchronizedFoo {\n    \n}\n\npublic protocol KeyValueSubscripting {\n    associatedtype Key\n    associatedtype Value\n    subscript(key: Key) -> Value? { get set }\n}\n\npublic extension SynchronizedFoo: KeyValueSubscripting where T: KeyValueSubscripting {\n    public subscript(key: T.Key) -> T.Value? {\n        get {\n            return read { (collection) -> T.Value? in\n                return collection[key]\n            }\n        }\n        set {\n            write { (collection) -> () in\n                collection[key] = newValue\n            }\n        }\n    }\n\n    public func bar() -> String {\n        return \"bar\"\n    }\n\n}\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test3.swift",
    "content": "#if TESTFILE\n\n\nimport Foundation\n\npublic protocol ProtocolY {\n    func filterBy(uuid: String) -> Int?\n}\npublic protocol ProtocolX: ProtocolY {\n}\n\n\npublic final class FooKlass {\n    public static var sharedInstance = FooKlass()\n\n    func bar(arg: String) -> Int {\n        let (lhs, rhs) = arg\n\n        let ret = Double()\n        ret.listener = lhs\n        return ret\n    }\n}\n\nfinal class ListInteractor {\n    public var x: String = \"\", y: Int, z: Double\n\n    public var (v, w): (String, Int) = (\"\", 0)\n\n    public let\n   application: UIApplicationProtocol,\n   cachedExperiments: CachedExperimenting,\n   deepLinkBuilder: (_ url: URL) -> DetailsDeeplink?,\n   detailsBuilder: DetailsBuildable,\n   listStream: Observable<[DetailsListStreaming]>\n}\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test4.swift",
    "content": "#if TESTFILE\n\n\nimport Foundation\n\npublic enum BarType {\n    case current\n}\n\n\nclass Klass: P {\n    private static var unusedP: SomeType = SomeType()\n\n\n    public init() {\n    }\n\n    func isActive(_ arg: AmbProtocol?) -> Bool {\n        arg?.usedFunc()\n        return true\n    }\n\n    public override func isApplicable(context: SomeContext, with flag: Flag) -> Bool {\n        return flag.isActive\n    }\n\n    func unusedFunc() {\n        print(\"...\")\n    }\n}\n\n\npublic final class OtherKlass {\n    public static var sharedInstance = OtherKlass()\n\n    public var shouldRun: Bool {\n        let (lhs, mhs, rhs) = asdf()\n        print(lhs, rhs)\n\n        return false\n    }\n}\n\npublic protocol Flag {\n}\n\npublic extension Flag {\n    var isActive: Bool {\n        return true\n    }\n\n    var isActiveLong: Bool {\n        return isEnabled(for: \"Exp1\") || isEnabled(for: \"Exp2\")\n    }\n}\n\npublic protocol YProtocol {\n    var unusedY: String { get }\n}\n\npublic extension YProtocol {\n    func usedZ() {\n    }\n}\n\nprotocol UnusedInternal {\n}\n\nextension UnusedInternal {\n    func unusedX() {\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test5.swift",
    "content": "#if TESTFILE\n\nenum State {\n    case eat(SomeFood)\n    case sleep(SomeTime)\n}\n\npublic func toJSON(arg: String) -> JSON {\n    var dict = [String: JSON]()\n\n    switch arg {\n        case .eat(let value):\n            print(value)\n        case .sleep(let value):\n            dict[\"state\"] = value\n    }\n\n    return .dictionary(dict)\n}\n\n\n\npublic typealias T = (String, EventHandler)\npublic typealias EventHandler<StreamingResponse> = (Bool, StreamingResponse?, Error?) -> ()\n\n#if SOME_CONDITION\n\n    public extension String {\n        func withAssertion(_ block: (_ str: StaticString) -> ()) {\n            if let stringData = self.data(using: .utf8, allowLossyConversion: false) {\n                var x = StaticString()\n                x._utf8CodeUnitCount = stringData.count\n                stringData.withUnsafeBytes { rawBufferPointer in\n                    if let rawPtr = rawBufferPointer.baseAddress {\n                        x._startPtrOrData = Int(bitPattern: rawPtr)\n                    }\n                    block(x)\n                }\n            }\n        }\n    }\n\n#endif\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test6.swift",
    "content": "#if TESTFILE\n\nimport Foundation\nimport Test1\n\n\nprivate let error = NSError(domain: TestDomain, code: InvalidData, userInfo: nil)\n\nextension String {\n\n    static func instance(from data: Data) throws -> String {\n        let result = self.init(data: data, encoding: .utf8)\n        if let result = result {\n            return result\n        } else {\n            throw error\n        }\n    }\n}\n\nlet SomeSingleton = SomeSingletonObject()\n\n// This is a comment\n// doc comment\n// asdf\npublic  protocol Bar: P1, P2 {\n}\n\npublic typealias P1 = Cat.P1\n\npublic protocol XAB {\n    subscript(key: Int) -> String? { get }\n}\n\nclass KEY {}\n\nextension KEY: XAB {\n    public subscript(key: Int) -> String? {\n        return nil\n    }\n\n    func bar() {\n\n    }\n\n    var debugDescription: String {\n        return \"this is KEY\"\n    }\n}\n\n\n\npublic protocol ObjectReference {\n\n}\n\npublic protocol P {\n    func iteratedObjects(_ object: Any) -> [ObjectReference]\n}\n\npublic final class SynchronousKeyValueStoreWrapper<Key>: SynchronousKeyValueAssociating where Key: StoredKeying {\n    var base: KeyValueStore<Key>?\n\n\n    public subscript(key: T.Key) -> T.Value? {\n        return nil\n    }\n\n}\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test7.swift",
    "content": "#if TESTFILE\n\nextension Foo {\n    #if DEBUG\n        var baz: Bool {\n            if case .test = RunType.current {\n                return !(Handler.isHandlerActive() || runner.sharedInstance.isActive)\n            }\n            return false\n        }\n\n        var zmock: ZMock { shared { ZMock() } }\n        fileprivate var zvar: Z { shared { Z(with: self) } }\n    #else\n        fileprivate var cat: Z { shared { Z(with: self) } }\n    #endif\n}\n\nimport Test6\n\nlet k = Klass()\n\nclass Klass: P {\n    public func iteratedObjects(_ object: Any) -> [Result] {\n        return []\n    }\n\n    private static var loadedFonts: Synchronized<[String: UIFont]> = Synchronized()\n\n    public init() {\n        testAssert(true)\n    }\n\n    public init(store: KeyValueStore<Key>,\n                storeKey: Key,\n                target: Int,\n                initialHitTargetValue: Bool? = nil) {\n        self.store = store\n        self.storeKey = storeKey\n        self.target = target + 1\n        self.hitTargetSubject = ReplaySubject<Bool>.create(bufferSize: 1)\n\n        queue.async {\n            let count = store.synchronously(operate: { (container: SynchronousKeyValueStoreContainer<Key>?) -> Int? in\n                return container?.item(for: storeKey)\n            })\n            print(count)\n        }\n    }\n}\n\npublic final class KeyValueStore<Key> where Key: StoredKeying {\n    public func synchronously<T>(operations: (SynchronousKeyValueStoreContainer<Key>?) -> T) -> T {\n        let container = SynchronousKeyValueStoreContainer(self)\n        let result = operations(container)\n        container.invalidate()\n        return result\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/Fixtures/test8.swift",
    "content": "#if TESTFILE\n\nimport Test9\nimport Test10\nimport Foundation\n\nclass Foo: ProtocolX {\n    func filterBy(uuid: String) -> Int? {\n        return nil\n    }\n\n    var bar: Bool {\n        let found = FooKlass.sharedInstance.bar(arg)\n        let notFound = ListInteractor.application\n\n        if found, !notFound {\n            return true\n        }\n    }\n\n    var baz: String {\n        if case let .someCase = BarType.current {\n            return !(Klass().isActive() ||\n                Klass().isApplicable() ||\n                OtherKlass.sharedInstance.shouldRun)\n        }\n        return \"\"\n    }\n}\n\nlet foo = Foo()\n\n#endif\n"
  },
  {
    "path": "Tests/TestClasses/SwiftCodeSanTests.swift",
    "content": "import Foundation\n\nclass DCETests: SwiftCodeSanTestCase {\n    \n    func testExample() {\n        // TODO: add a test\n    }\n    \n}\n\n"
  },
  {
    "path": "install-script.sh",
    "content": "#!/bin/bash\n\n# Causes the shell to exit if any subcommand returns a non-zero status\nset -e\n\nshowhelp() {\n    echo \"Description: Builds and installs target specified\nUsage: -s/--source-dir [source dir], -t/--target [name of target to build/install], -d/--destination-dir [destination dir], -o/--output [output file name in tar.gz]\"\n    exit\n}\n\nif [[ $1 == \"\" ]] \nthen\nshowhelp\nfi\n\nrealpath() {\n    [[ $1 = /* ]] && echo \"$1\" || echo \"$PWD\"\n}\n\nwhile [[ $# -gt 0 ]]\ndo\nkey=\"$1\"\n\ncase $key in\n    -s|--source-dir)\n    SRCDIR=$(realpath \"$2\")\n    shift # past argument\n    shift # past value\n    ;;\n    -d|--destination-dir)\n    DESTDIR=$(realpath \"$2\")\n    shift # past argument\n    shift # past value\n    ;;\n    -t|--target)\n    TARGET=\"$2\"\n    shift # past argument\n    shift # past value\n    ;;\n    -o|--output)\n    OUTFILE=\"$2\"\n    shift # past argument\n    shift # past value\n    ;;\n    -h|--help)\n    showhelp\n    ;;\n    *) \n    showhelp\n    ;;\nesac\ndone\n\n\nCUR=$PWD\n\necho \"** Clean/Build...\"\n\necho \"SOURCE DIR = ${SRCDIR}\"\necho \"TARGET = ${TARGET}\"\necho \"DESTINATION DIR = ${DESTDIR}\"\necho \"OUTPUT FILE = ${OUTFILE}\"\n\ncd \"$SRCDIR\"\nrm -rf .build\nswift build -c release \n\ncd .build/release\n\necho \"** Install...\"\ncp \"$(xcode-select -p)\"/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/lib_InternalSwiftSyntaxParser.dylib . \n\ninstall_name_tool -change @rpath/lib_InternalSwiftSyntaxParser.dylib @executable_path/lib_InternalSwiftSyntaxParser.dylib \"$TARGET\"\n\ntar -cvzf \"$OUTFILE\" \"$TARGET\" lib_InternalSwiftSyntaxParser.dylib\n\nmv \"$OUTFILE\" \"$DESTDIR\"\n\ncd \"$CUR\"\n\necho \"** Output file is at $DESTDIR/$OUTFILE\"\necho \"** Done.\"\n"
  }
]