├── .bazelignore ├── .bazelrc ├── .bazelversion ├── .dockerignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── test.yml ├── .gitignore ├── .mise.toml ├── .mise └── tasks │ ├── benchmark │ ├── build │ ├── gen-bazel-rules │ ├── lint │ ├── lint-ci │ ├── release │ ├── scan │ ├── scan-linux │ ├── scripts │ ├── Periphery.podspec.template │ ├── Version.swift.template │ ├── artifactbundle_info.json.template │ ├── gen_bazel_rules.rb │ └── release_notes.md.template │ └── write-linux-baseline ├── .swiftformat ├── .swiftlint.yml ├── BUILD.bazel ├── CHANGELOG.md ├── LICENSE.md ├── MODULE.bazel ├── MODULE.bazel.lock ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── BUILD.bazel ├── Configuration │ ├── Configuration.swift │ └── OutputFormat.swift ├── Extensions │ ├── Array+Extension.swift │ ├── Collection+Extension.swift │ ├── FilePath+Extension.swift │ ├── FilePath+Glob.swift │ ├── FilenameMatcher+Extension.swift │ ├── Sequence+Extension.swift │ ├── Set+Extension.swift │ ├── String+Extension.swift │ └── String+Version.swift ├── Frontend │ ├── BazelProjectSetupGuide.swift │ ├── Commands │ │ ├── CheckUpdateCommand.swift │ │ ├── ClearCacheCommand.swift │ │ ├── FrontendCommand.swift │ │ ├── ScanCommand.swift │ │ └── VersionCommand.swift │ ├── CommonSetupGuide.swift │ ├── GuidedSetup.swift │ ├── Logger+Extension.swift │ ├── Project.swift │ ├── SPMProjectSetupGuide.swift │ ├── Scan.swift │ ├── UpdateChecker.swift │ ├── Version.swift │ └── main.swift ├── Indexer │ ├── IndexPipeline.swift │ ├── IndexPlan.swift │ ├── Indexer.swift │ ├── InfoPlistIndexer.swift │ ├── InfoPlistParser.swift │ ├── JobPool.swift │ ├── SourceFileCollector.swift │ ├── SwiftIndexer.swift │ ├── XCDataModelIndexer.swift │ ├── XCDataModelParser.swift │ ├── XCMappingModelIndexer.swift │ ├── XCMappingModelParser.swift │ ├── XibIndexer.swift │ └── XibParser.swift ├── Logger │ └── Logger.swift ├── PeripheryKit │ ├── Results │ │ ├── Baseline.swift │ │ ├── CheckstyleFormatter.swift │ │ ├── CodeClimateFormatter.swift │ │ ├── CsvFormatter.swift │ │ ├── GitHubActionsFormatter.swift │ │ ├── GitHubMarkdownFormatter.swift │ │ ├── JsonFormatter.swift │ │ ├── OutputDeclarationFilter.swift │ │ ├── OutputFormatter.swift │ │ └── XcodeFormatter.swift │ ├── ScanResult.swift │ └── ScanResultBuilder.swift ├── ProjectDrivers │ ├── BazelProjectDriver.swift │ ├── GenericProjectDriver.swift │ ├── ProjectDriver.swift │ ├── SPM.swift │ ├── SPMProjectDriver.swift │ └── XcodeProjectDriver.swift ├── Shared │ ├── Benchmark.swift │ ├── Constants.swift │ ├── PeripheryError.swift │ ├── ProjectKind.swift │ ├── PropertyTypeSanitizer.swift │ ├── SetupGuide.swift │ ├── Shell.swift │ ├── SwiftVersion.swift │ ├── SwiftVersionParser.swift │ └── UnfairLock.swift ├── SourceGraph │ ├── Elements │ │ ├── Accessibility.swift │ │ ├── AssetReference.swift │ │ ├── CommentCommand.swift │ │ ├── Declaration.swift │ │ ├── ImportStatement.swift │ │ ├── Location.swift │ │ ├── ProjectFileKind.swift │ │ ├── Reference.swift │ │ └── SourceFile.swift │ ├── Mutators │ │ ├── AccessibilityCascader.swift │ │ ├── AncestralReferenceEliminator.swift │ │ ├── AssetReferenceRetainer.swift │ │ ├── AssignOnlyPropertyReferenceEliminator.swift │ │ ├── CodablePropertyRetainer.swift │ │ ├── CodingKeyEnumReferenceBuilder.swift │ │ ├── ComplexPropertyAccessorReferenceBuilder.swift │ │ ├── DefaultConstructorReferenceBuilder.swift │ │ ├── DynamicMemberRetainer.swift │ │ ├── EntryPointAttributeRetainer.swift │ │ ├── EnumCaseReferenceBuilder.swift │ │ ├── ExtensionReferenceBuilder.swift │ │ ├── ExternalOverrideRetainer.swift │ │ ├── ExternalTypeProtocolConformanceReferenceRemover.swift │ │ ├── GenericClassAndStructConstructorReferenceBuilder.swift │ │ ├── InterfaceBuilderPropertyRetainer.swift │ │ ├── ObjCAccessibleRetainer.swift │ │ ├── PropertyWrapperRetainer.swift │ │ ├── ProtocolConformanceReferenceBuilder.swift │ │ ├── ProtocolExtensionReferenceBuilder.swift │ │ ├── PubliclyAccessibleRetainer.swift │ │ ├── RedundantExplicitPublicAccessibilityMarker.swift │ │ ├── RedundantProtocolMarker.swift │ │ ├── ResultBuilderRetainer.swift │ │ ├── StringInterpolationAppendInterpolationRetainer.swift │ │ ├── StructImplicitInitializerReferenceBuilder.swift │ │ ├── SwiftTestingRetainer.swift │ │ ├── SwiftUIRetainer.swift │ │ ├── UnusedImportMarker.swift │ │ ├── UnusedParameterRetainer.swift │ │ ├── UsedDeclarationMarker.swift │ │ └── XCTestRetainer.swift │ ├── SourceGraph.swift │ ├── SourceGraphDebugger.swift │ ├── SourceGraphMutator.swift │ ├── SourceGraphMutatorRunner.swift │ └── SynchronizedSourceGraph.swift ├── SyntaxAnalysis │ ├── CommentCommand.swift │ ├── DeclarationSyntaxVisitor.swift │ ├── ImportSyntaxVisitor.swift │ ├── MultiplexingSyntaxVisitor.swift │ ├── SourceLocationBuilder.swift │ ├── TypeSyntaxInspector.swift │ ├── UnusedParameterAnalyzer.swift │ └── UnusedParameterParser.swift └── XcodeSupport │ ├── XcodeProject.swift │ ├── XcodeProjectSetupGuide.swift │ ├── XcodeProjectlike.swift │ ├── XcodeTarget.swift │ ├── XcodeWorkspace.swift │ └── Xcodebuild.swift ├── Tests ├── .swiftlint.yml ├── AccessibilityTests │ ├── AccessibilityProject │ │ ├── .gitignore │ │ ├── Package.swift │ │ ├── Sources │ │ │ ├── ExternalTarget │ │ │ │ └── ExternalProtocol.swift │ │ │ ├── MainTarget │ │ │ │ └── main.swift │ │ │ └── TargetA │ │ │ │ ├── IgnoreAllCommentCommand.swift │ │ │ │ ├── IgnoreCommentCommand.swift │ │ │ │ ├── InternalClassAdoptingPublicProtocol.swift │ │ │ │ ├── InternalProtocolRefiningPublicProtocol.swift │ │ │ │ ├── NotRedundantPublicTestableImportClass.swift │ │ │ │ ├── ProtocolIndirectlyReferencedCrossModuleByExtensionMember.swift │ │ │ │ ├── PublicActor.swift │ │ │ │ ├── PublicAssociatedTypeDefaultType.swift │ │ │ │ ├── PublicClassAdoptingExternalProtocolObjcAccessible.swift │ │ │ │ ├── PublicClassAdoptingInternalProtocol.swift │ │ │ │ ├── PublicClassAdoptingPublicProtocol.swift │ │ │ │ ├── PublicClassInheritingPublicExternalClass.swift │ │ │ │ ├── PublicClassInheritingPublicTypeWithGenericParameter.swift │ │ │ │ ├── PublicComparableOperatorFunction.swift │ │ │ │ ├── PublicDeclarationInInternalParent.swift │ │ │ │ ├── PublicEnumCaseWithParameter.swift │ │ │ │ ├── PublicEnumWithAssociatedValue.swift │ │ │ │ ├── PublicExtensionOnRedundantPublicKind.swift │ │ │ │ ├── PublicInheritedAssociatedType.swift │ │ │ │ ├── PublicInlinableFunction.swift │ │ │ │ ├── PublicProtocolRefiningPublicProtocol.swift │ │ │ │ ├── PublicTypeUsedAsPublicClassGenericParameter.swift │ │ │ │ ├── PublicTypeUsedAsPublicClassGenericRequirement.swift │ │ │ │ ├── PublicTypeUsedAsPublicClassSuperclass.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionGenericParameter.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionGenericRequirement.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionMetatypeParameterWithGenericReturnType.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionParameterDefaultValue.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionParameterType.swift │ │ │ │ ├── PublicTypeUsedAsPublicFunctionReturnType.swift │ │ │ │ ├── PublicTypeUsedAsPublicInitializerParameterType.swift │ │ │ │ ├── PublicTypeUsedAsPublicPropertyInitializer.swift │ │ │ │ ├── PublicTypeUsedAsPublicPropertyType.swift │ │ │ │ ├── PublicTypeUsedAsPublicSubscriptParameterType.swift │ │ │ │ ├── PublicTypeUsedAsPublicSubscriptReturnType.swift │ │ │ │ ├── PublicTypeUsedInPublicClosure.swift │ │ │ │ ├── PublicTypeUsedInPublicFunctionBody.swift │ │ │ │ ├── PublicTypealias.swift │ │ │ │ ├── PublicWrappedProperty.swift │ │ │ │ ├── RedundantPublicTestableImportClass.swift │ │ │ │ └── RedundantPublicType.swift │ │ └── Tests │ │ │ └── TestTarget │ │ │ └── TestableImportTest.swift │ ├── Helper.swift │ └── RedundantPublicAccessibilityTest.swift ├── Fixtures │ ├── Package.swift │ └── Sources │ │ ├── CrossModuleRetentionFixtures │ │ └── testCrossModuleInheritanceWithSameName.swift │ │ ├── CrossModuleRetentionSupportFixtures │ │ └── CrossModuleSuperclass.swift │ │ ├── DeclarationVisitorFixtures │ │ ├── FunctionFixture.swift │ │ ├── ImportFixture.swift │ │ └── PropertyFixture.swift │ │ ├── ExternalModuleFixtures │ │ ├── ExternalAssociatedType.swift │ │ └── ExternalTestCase.swift │ │ ├── ObjcAccessibleRetentionFixtures │ │ ├── testDoesNotRetainMembersOfObjcAnnotatedClass.swift │ │ ├── testDoesNotRetainObjcAnnotatedWithoutOption.swift │ │ ├── testObjcMembersAnnotationRetainsMembers.swift │ │ ├── testRetainsImplicitlyObjcAccessibleClass.swift │ │ ├── testRetainsObjcAnnotatedClass.swift │ │ ├── testRetainsObjcAnnotatedMembers.swift │ │ ├── testRetainsOptionalProtocolMethod.swift │ │ └── testRetainsOptionalProtocolMethodImplementedInSubclass.swift │ │ ├── ObjcAnnotatedRetentionFixtures │ │ ├── testRetainsAnnotatedExtensionDeclarations.swift │ │ ├── testRetainsExtensionDeclarationsOnObjcMembersAnnotatedClass.swift │ │ ├── testRetainsObjcProtocolConformingDeclarations.swift │ │ └── testRetainsObjcProtocolMembers.swift │ │ ├── RetentionFixtures │ │ ├── testAccessibility.swift │ │ ├── testAssignOnlyPropertyAnalysisDoesNotApplyToProtocolProperties.swift │ │ ├── testCircularTypeInheritance.swift │ │ ├── testClassRetainedByUnusedInstanceVariable.swift │ │ ├── testCodingKeyEnum.swift │ │ ├── testCommentCommandOverride.swift │ │ ├── testConformanceToExternalProtocolIsRetained.swift │ │ ├── testConformingProtocolReferencedByNonReferencedClass.swift │ │ ├── testCrossReferencedClasses.swift │ │ ├── testCustomConstructorWithLiteral.swift │ │ ├── testDeeplyNestedClassReferences.swift │ │ ├── testDoesNotRetainDescendantsOfUnusedDeclaration.swift │ │ ├── testDoesNotRetainLazyProperty.swift │ │ ├── testDoesNotRetainProtocolMembersImplementedByExternalType.swift │ │ ├── testDoesNotRetainProtocolMethodInSubclassWithDefaultImplementation.swift │ │ ├── testDoesNotRetainUnusedProtocolMethodWithDefaultImplementation.swift │ │ ├── testEnumCases.swift │ │ ├── testExternalXCTestCaseClass.swift │ │ ├── testFunctionAccessorsRetainReferences.swift │ │ ├── testIdenticallyNamedVarsInStaticAndInstanceScopes.swift │ │ ├── testIgnoreAllComment.swift │ │ ├── testIgnoreComments.swift │ │ ├── testIgnoreUnusedParamInUnusedFunction.swift │ │ ├── testInstanceVarReferencedInClosure.swift │ │ ├── testIsolatedCyclicRootReferences.swift │ │ ├── testMainActorAnnotation.swift │ │ ├── testNestedDeclarations.swift │ │ ├── testNonReferencedClass.swift │ │ ├── testNonReferencedFreeFunction.swift │ │ ├── testNonReferencedMethod.swift │ │ ├── testNonReferencedMethodInClassExtension.swift │ │ ├── testNonReferencedProperty.swift │ │ ├── testOverriddenMethodRetainedBySuper.swift │ │ ├── testPropertyReferencedByComputedValue.swift │ │ ├── testProtocolConformedByStaticMethodOutsideExtension.swift │ │ ├── testProtocolConformingMembersAreRetained.swift │ │ ├── testProtocolImplementInClassAndExtension.swift │ │ ├── testProtocolMethodCalledIndirectlyByProtocolIsRetained.swift │ │ ├── testProtocolMethodsImplementedOnlyInExtension.swift │ │ ├── testProtocolUsedAsExistentialType.swift │ │ ├── testProtocolVarReferencedByProtocolMethodInSameClassIsRedundant.swift │ │ ├── testPublicProtocolMethodImplementedOnlyInExtension.swift │ │ ├── testRedundantProtocolThatInheritsAnyObject.swift │ │ ├── testRedundantProtocolThatInheritsForeignProtocol.swift │ │ ├── testRedundantProtocolThatInheritsOtherProtocols.swift │ │ ├── testRequiredInitInSubclass.swift │ │ ├── testRetainImplicitDeclarations.swift │ │ ├── testRetainOverridingMethod.swift │ │ ├── testRetainPublicMembers.swift │ │ ├── testRetainUnusedProtocolFuncParams.swift │ │ ├── testRetainedProtocolDoesNotRetainImplementationInUnusedClass.swift │ │ ├── testRetainedProtocolDoesNotRetainUnusedClass.swift │ │ ├── testRetainsAssignOnlyPropertyTypes.swift │ │ ├── testRetainsAssociatedTypeTypeAlias.swift │ │ ├── testRetainsCallAsFunction.swift │ │ ├── testRetainsCodableProperties.swift │ │ ├── testRetainsConstructorOfGenericClassAndStruct.swift │ │ ├── testRetainsDefaultConstructor.swift │ │ ├── testRetainsDestructor.swift │ │ ├── testRetainsDynamicMemberLookupSubscript.swift │ │ ├── testRetainsDynamicReplacement.swift │ │ ├── testRetainsEncodableProperties.swift │ │ ├── testRetainsExtendedExternalTypeAlias.swift │ │ ├── testRetainsExtendedProtocolTypeAlias.swift │ │ ├── testRetainsExtendedTypeAlias.swift │ │ ├── testRetainsExternalAssociatedTypeTypeAlias.swift │ │ ├── testRetainsExternalTypeExtension.swift │ │ ├── testRetainsFilesOption.swift │ │ ├── testRetainsForeignProtocolParameters.swift │ │ ├── testRetainsForeignProtocolParametersInSubclass.swift │ │ ├── testRetainsFunctionParametersOnProtocolMembersImplementedByExternalType.swift │ │ ├── testRetainsFunctionParametersOnUnimplementedProtocolMembers.swift │ │ ├── testRetainsGenericProtocolExtensionMembers.swift │ │ ├── testRetainsGenericType.swift │ │ ├── testRetainsInferredAssociatedType.swift │ │ ├── testRetainsInheritedClass.swift │ │ ├── testRetainsInitializerCalledOnTypeAlias.swift │ │ ├── testRetainsMethodDefinedInExtensionOnStandardType.swift │ │ ├── testRetainsNonProtocolMethodDefinedInProtocolExtension.swift │ │ ├── testRetainsOpenClassParameters.swift │ │ ├── testRetainsParamUsedInOverriddenMethod.swift │ │ ├── testRetainsPropertyWrappers.swift │ │ ├── testRetainsProtocolExtension.swift │ │ ├── testRetainsProtocolMethodImplementedInExtension.swift │ │ ├── testRetainsProtocolMethodsImplementedInSuperclasss.swift │ │ ├── testRetainsProtocolParameters.swift │ │ ├── testRetainsProtocolsViaCompositeTypealias.swift │ │ ├── testRetainsPublicEnumCases.swift │ │ ├── testRetainsReferencedMethodViaReceiver.swift │ │ ├── testRetainsResultBuilderMethods.swift │ │ ├── testRetainsSelfReferencedMethodViaReceiver.swift │ │ ├── testRetainsStringInterpolationAppendInterpolation.swift │ │ ├── testRetainsSwiftTestingDeclarations.swift │ │ ├── testRetainsUsedProtocolThatInheritsForeignProtocol.swift │ │ ├── testSelfReferencedClass.swift │ │ ├── testSelfReferencedConstructor.swift │ │ ├── testSelfReferencedProperty.swift │ │ ├── testSelfReferencedRecursiveMethod.swift │ │ ├── testSimpleAssignOnlyPropertyNameConflict.swift │ │ ├── testSimplePropertyAssignedButNeverRead.swift │ │ ├── testSimpleRedundantProtocol.swift │ │ ├── testStaticMemberUsedAsSubscriptKey.swift │ │ ├── testStaticPropertyDeclaredWithCompositeValuesIsNotRetained.swift │ │ ├── testStructImplicitInitializer.swift │ │ ├── testUnusedAssociatedType.swift │ │ ├── testUnusedOverriddenMethod.swift │ │ ├── testUnusedProtocolWithExtension.swift │ │ ├── testUnusedTypealias.swift │ │ └── testXCTestCaseClassesAndMethodsAreRetained.swift │ │ ├── TypeSyntaxInspectorFixtures │ │ └── TypeSyntaxInspectorFixture.swift │ │ ├── UnusedModuleFixtures │ │ └── UnusedModuleDeclaration.swift │ │ └── UnusedParameterFixtures │ │ ├── testBackquote.swift │ │ ├── testBlockParameter.swift │ │ ├── testFatalErrorFunction.swift │ │ ├── testFunctionCallWithNamedParameter.swift │ │ ├── testIBActionAnnotatedFunction.swift │ │ ├── testIgnoreProtocolDeclaration.swift │ │ ├── testIgnoredParameter.swift │ │ ├── testInitializer.swift │ │ ├── testInitializerPosition.swift │ │ ├── testLocalVarDeclaredInBlock.swift │ │ ├── testLocalVariableAssignment.swift │ │ ├── testMultiLineParameterPosition.swift │ │ ├── testNestedFunction.swift │ │ ├── testNestedVariable.swift │ │ ├── testParamForGenericSpecialization.swift │ │ ├── testParameterPosition.swift │ │ ├── testReturn.swift │ │ ├── testShadowed.swift │ │ ├── testShadowedAfterUse.swift │ │ ├── testShadowedByBlockParameter.swift │ │ ├── testSimpleFunctionCall.swift │ │ ├── testSimpleUnused.swift │ │ ├── testStringInterpolation.swift │ │ ├── testSubscriptArgument.swift │ │ ├── testUnavailableFunction.swift │ │ └── testUsedInInitializerCall.swift ├── PeripheryTests │ ├── CrossModuleRetentionTest.swift │ ├── Extensions │ │ ├── FilePathGlobTest.swift │ │ ├── FilePathTest.swift │ │ ├── FilenameMatcherTests.swift │ │ └── String+VersionTest.swift │ ├── ObjcAccessibleRetentionTest.swift │ ├── ObjcAnnotatedRetentionTest.swift │ ├── RetentionTest.swift │ ├── SwiftVersionParserTest.swift │ └── Syntax │ │ ├── FunctionVisitTest.swift │ │ ├── ImportVisitTest.swift │ │ ├── PropertyVisitTest.swift │ │ ├── TypeSyntaxInspectorTest.swift │ │ └── UnusedParameterTest.swift ├── SPMTests │ ├── Helper.swift │ ├── SPMProject │ │ ├── .gitignore │ │ ├── Package.resolved │ │ ├── Package.swift │ │ ├── Sources │ │ │ ├── Frontend │ │ │ │ └── main.swift │ │ │ ├── SPMProjectKit │ │ │ │ ├── Macros.swift │ │ │ │ ├── MockedProtocol.swift │ │ │ │ └── SPMProject.swift │ │ │ └── SPMProjectMacros │ │ │ │ ├── MockMacro.swift │ │ │ │ └── Plugin.swift │ │ └── Tests │ │ │ └── MacroImportTests.swift │ └── SPMProjectTest.swift ├── Shared │ ├── DeclarationDescription.swift │ ├── DeclarationScope.swift │ ├── FixtureSourceGraphTestCase.swift │ ├── Helper.swift │ ├── SPMSourceGraphTestCase.swift │ ├── SourceGraphTestCase.swift │ └── XCTestCase+Extensions.swift └── XcodeTests │ ├── Helper.swift │ ├── ShellMock.swift │ ├── SwiftUIProject │ ├── SwiftUIProject.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── SwiftUIProject.xcscheme │ └── SwiftUIProject │ │ ├── App.swift │ │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ │ ├── ContentView.swift │ │ ├── Info.plist │ │ └── Preview Content │ │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── SwiftUIProjectTest.swift │ ├── UIKitProject │ ├── LocalPackages │ │ └── LocalPackage │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ └── Sources │ │ │ └── LocalPackageTarget │ │ │ ├── LocalPackageUnusedType.swift │ │ │ └── LocalPackageUsedType.swift │ ├── NotificationServiceExtension │ │ ├── Info.plist │ │ └── NotificationService.swift │ ├── Target With Spaces │ │ ├── File With Spaces.swift │ │ └── Info.plist │ ├── UIKitProject.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Scheme With Spaces.xcscheme │ │ │ └── UIKitProject.xcscheme │ ├── UIKitProject │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── CustomEntityMigrationPolicy.swift │ │ ├── EntityValueTransformer.swift │ │ ├── FileInGroupWithoutFolder.xib │ │ ├── Info.plist │ │ ├── Launch Screen.storyboard │ │ ├── Model.xcdatamodeld │ │ │ ├── .xccurrentversion │ │ │ └── Model.xcdatamodel │ │ │ │ └── contents │ │ ├── ModelMapping.xcmappingmodel │ │ │ └── xcmapping.xml │ │ ├── MultiTarget │ │ │ └── MultiTargetStruct.swift │ │ ├── OldModel.xcdatamodeld │ │ │ └── OldModel.xcdatamodel │ │ │ │ └── contents │ │ ├── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ │ └── Contents.json │ │ ├── SceneDelegate.swift │ │ ├── StoryboardViewController.storyboard │ │ ├── StoryboardViewController.swift │ │ ├── XibViewController.swift │ │ ├── XibViewController.xib │ │ ├── XibViewController2.swift │ │ └── XibViewController2Subclass.xib │ ├── UIKitProjectTests │ │ ├── Info.plist │ │ └── UIKitProjectTests.swift │ └── WatchWidget │ │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── WidgetBackground.colorset │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── WatchWidget.intentdefinition │ │ └── WatchWidget.swift │ ├── UIKitProjectTest.swift │ ├── XcodeSourceGraphTestCase.swift │ ├── XcodeTargetTest.swift │ ├── XcodebuildBuildProjectTest.swift │ ├── XcodebuildListOutputs.swift │ └── XcodebuildSchemesTest.swift ├── assets ├── logo.png ├── sponsor-20.svg ├── sponsor.svg ├── sponsors │ ├── emerge-tools-vertical-black.svg │ ├── emerge-tools-vertical-white.svg │ ├── saga-corp-black.svg │ └── saga-corp-white.svg └── xcode-integration │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ └── 5.png ├── baselines ├── bazel.json ├── linux.json └── macos-swift-6.1.json ├── bazel ├── BUILD.bazel ├── dev │ └── BUILD.bazel ├── generated.bzl ├── internal │ ├── BUILD.bazel │ ├── opt.bzl │ └── scan │ │ ├── BUILD.bazel │ │ ├── scan.bzl │ │ └── scan_template.sh └── rules.bzl └── docker └── Dockerfile.linux /.bazelignore: -------------------------------------------------------------------------------- 1 | .build 2 | .git 3 | .mise 4 | .release -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_bzlmod 2 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 8.1.1 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .build/ 3 | .swiftpm/ 4 | .release/ 5 | bazel-* 6 | docker/ 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ileitch 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: needs investigation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Reproduction** 14 | If you are reporting an incorrect result, please provide a sample Xcode or Swift package project that reproduces the issue. 15 | 16 | **Environment** 17 | Copy the output from running: 18 | ``` 19 | periphery version 20 | swift -version 21 | xcodebuild -version 22 | ``` 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.release 2 | /Packages 3 | 4 | # Xcode 5 | .DS_Store 6 | */build/* 7 | *.build/* 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.xccheckout 21 | *.xcscmblueprint 22 | *.gcda 23 | *.gcno 24 | .swiftpm 25 | Tests/Fixtures/.build/ 26 | 27 | # VSCode 28 | .vscode/* 29 | 30 | # Bazel 31 | bazel-* 32 | -------------------------------------------------------------------------------- /.mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | swiftformat = "0.55.5" 3 | swiftlint = "0.59.0" 4 | -------------------------------------------------------------------------------- /.mise/tasks/benchmark: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #USAGE flag "-b --bazel" help="Use binary built by Bazel" 3 | 4 | set -eo pipefail 5 | 6 | cmd="" 7 | 8 | if [ "$usage_bazel" = "true" ]; then 9 | echo "INFO: Using Bazel" 10 | bazel build //:periphery 11 | cmd='bazel-bin/Sources/Frontend_opt scan --config /var/tmp/periphery_bazel/periphery.yml --generic-project-config bazel-bin/external/+generated+periphery_generated/rule/project_config.json' 12 | else 13 | mise r build --arch arm64 14 | cmd='./.build/release/periphery scan --quiet --skip-build' 15 | fi 16 | 17 | echo $cmd 18 | hyperfine --warmup 3 "${cmd}" 19 | -------------------------------------------------------------------------------- /.mise/tasks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #USAGE flag "--arch " help="Build architecture (x86_64, arm64, release)" 3 | 4 | set -eo pipefail 5 | 6 | SWIFT_BUILD_FLAGS="--product periphery --configuration release --disable-sandbox --scratch-path .build" 7 | EXECUTABLE_X86_64="$(swift build ${SWIFT_BUILD_FLAGS} --arch x86_64 --show-bin-path)/periphery" 8 | EXECUTABLE_ARM64="$(swift build ${SWIFT_BUILD_FLAGS} --arch arm64 --show-bin-path)/periphery" 9 | 10 | build_x86_64() { 11 | swift build ${SWIFT_BUILD_FLAGS} --arch x86_64 12 | } 13 | 14 | build_arm64() { 15 | swift build ${SWIFT_BUILD_FLAGS} --arch arm64 16 | } 17 | 18 | if [ "$usage_arch" = "x86_64" ]; then 19 | echo "Building for x86_64" 20 | build_x86_64 21 | echo ${EXECUTABLE_X86_64} 22 | elif [ "$usage_arch" = "arm64" ]; then 23 | echo "Building for arm64" 24 | build_arm64 25 | echo ${EXECUTABLE_ARM64} 26 | elif [ "$usage_arch" = "release" ]; then 27 | echo "Building for release" 28 | build_x86_64 29 | build_arm64 30 | mkdir -p .release 31 | lipo -create -output .release/periphery ${EXECUTABLE_X86_64} ${EXECUTABLE_ARM64} 32 | strip -rSTX .release/periphery 33 | echo "$(realpath .release/periphery)" 34 | else 35 | echo "Invalid architecture. Use --arch where is x86_64, arm64 or release" 36 | exit 1 37 | fi 38 | -------------------------------------------------------------------------------- /.mise/tasks/gen-bazel-rules: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | ruby .mise/tasks/scripts/gen_bazel_rules.rb 6 | -------------------------------------------------------------------------------- /.mise/tasks/lint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | cd $MISE_PROJECT_ROOT 6 | 7 | bazel run //bazel/dev:buildifier.fix 8 | swiftformat . 9 | swiftlint lint --quiet 10 | -------------------------------------------------------------------------------- /.mise/tasks/lint-ci: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | cd $MISE_PROJECT_ROOT 6 | 7 | bazel run //bazel/dev:buildifier.check 8 | swiftformat --quiet --strict . 9 | swiftlint lint --quiet --strict 10 | -------------------------------------------------------------------------------- /.mise/tasks/scan: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | swift build 6 | ./.build/debug/periphery scan "$@" 7 | -------------------------------------------------------------------------------- /.mise/tasks/scan-linux: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export DOCKER_CLI_HINTS=false 6 | docker build -t periphery -f docker/Dockerfile.linux . 7 | docker run --rm -t periphery scan "$@" --baseline baselines/linux.json 8 | -------------------------------------------------------------------------------- /.mise/tasks/scripts/Periphery.podspec.template: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = "Periphery" 3 | spec.version = "__VERSION__" 4 | spec.summary = "A tool to identify unused code in Swift projects." 5 | spec.homepage = "https://github.com/peripheryapp/periphery" 6 | spec.license = { :type => 'MIT', :file => 'LICENSE.md' } 7 | spec.author = { "Ian Leitch" => "ian@leitch.io" } 8 | spec.source = { :http => "#{spec.homepage}/releases/download/#{spec.version}/periphery-#{spec.version}.zip" } 9 | spec.preserve_paths = '*' 10 | end 11 | -------------------------------------------------------------------------------- /.mise/tasks/scripts/Version.swift.template: -------------------------------------------------------------------------------- 1 | let PeripheryVersion = "__VERSION__" 2 | -------------------------------------------------------------------------------- /.mise/tasks/scripts/artifactbundle_info.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0", 3 | "artifacts": { 4 | "periphery": { 5 | "version": "__VERSION__", 6 | "type": "executable", 7 | "variants": [ 8 | { 9 | "path": "periphery-__VERSION__-macos/bin/periphery", 10 | "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] 11 | } 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.mise/tasks/scripts/release_notes.md.template: -------------------------------------------------------------------------------- 1 | ##### Breaking 2 | 3 | - None. 4 | 5 | ##### Enhancements 6 | 7 | - None. 8 | 9 | ##### Bug Fixes 10 | 11 | - None. 12 | -------------------------------------------------------------------------------- /.mise/tasks/write-linux-baseline: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export DOCKER_CLI_HINTS=false 6 | docker build -t periphery -f docker/Dockerfile.linux . 7 | docker run --name periphery_write_linux_baseline -t periphery scan "$@" --write-baseline /linux.json 8 | docker cp periphery_write_linux_baseline:linux.json ./baselines/linux.json 9 | docker rm periphery_write_linux_baseline 10 | -------------------------------------------------------------------------------- /.swiftformat: -------------------------------------------------------------------------------- 1 | --swiftversion 6.0 2 | 3 | --exclude **/.build/ 4 | --exclude Tests/Fixtures/ 5 | --exclude Tests/AccessibilityTests/AccessibilityProject/ 6 | --exclude Tests/XcodeTests/UIKitProject/ 7 | --exclude Tests/XcodeTests/SwiftUIProject/ 8 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: 2 | - "**/.build" 3 | - Tests/Fixtures 4 | - Tests/AccessibilityTests/AccessibilityProject 5 | - Tests/XcodeTests/UIKitProject 6 | - Tests/XcodeTests/SwiftUIProject 7 | 8 | opt_in_rules: 9 | - single_test_class 10 | 11 | disabled_rules: 12 | # Formatting is handled by SwiftFormat 13 | - trailing_comma 14 | - opening_brace 15 | - vertical_parameter_alignment_on_call 16 | - let_var_whitespace 17 | - indentation_width 18 | - attributes 19 | - anonymous_argument_in_multiline_closure 20 | - vertical_whitespace_between_cases 21 | 22 | # Length/size rules 23 | - cyclomatic_complexity 24 | - closure_body_length 25 | - function_body_length 26 | - type_body_length 27 | - file_length 28 | - line_length 29 | - identifier_name 30 | - type_name 31 | - large_tuple 32 | - function_parameter_count 33 | 34 | # Other 35 | - discouraged_optional_collection 36 | - non_optional_string_data_conversion # https://github.com/realm/SwiftLint/issues/5263#issuecomment-2115182747 37 | - balanced_xctest_lifecycle 38 | - todo 39 | - for_where 40 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | alias( 2 | name = "periphery", 3 | actual = "//Sources:Frontend_opt", 4 | visibility = ["//visibility:public"], 5 | ) 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2019 Ian Leitch 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "periphery", 3 | version = "3.1.0", 4 | compatibility_level = 1, 5 | ) 6 | 7 | # Bazel dependencies 8 | bazel_dep(name = "rules_swift", version = "2.8.1") 9 | bazel_dep(name = "rules_apple", version = "3.20.1") 10 | bazel_dep(name = "bazel_skylib", version = "1.7.1") 11 | bazel_dep(name = "apple_support", version = "1.21.1") 12 | bazel_dep(name = "platforms", version = "0.0.11") 13 | 14 | # Swift dependencies 15 | bazel_dep(name = "aexml", version = "4.7.0") 16 | bazel_dep(name = "swift_argument_parser", version = "1.5.0") 17 | bazel_dep(name = "swift-filename-matcher", version = "2.0.0") 18 | bazel_dep(name = "swift-indexstore", version = "0.3.0") 19 | bazel_dep(name = "swift-syntax", version = "601.0.0") 20 | bazel_dep(name = "swift-system", version = "1.4.2") 21 | bazel_dep(name = "pathkit", version = "1.0.1") 22 | bazel_dep(name = "xcodeproj", version = "9.0.0") 23 | bazel_dep(name = "yams", version = "5.3.1") 24 | 25 | # Generated repo 26 | use_repo(use_extension("//bazel:generated.bzl", "generated"), "periphery_generated") 27 | 28 | # Bazel dev dependencies 29 | bazel_dep(name = "buildifier_prebuilt", version = "7.3.1", dev_dependency = True) 30 | -------------------------------------------------------------------------------- /Sources/Configuration/OutputFormat.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum OutputFormat: String, CaseIterable { 4 | case xcode 5 | case csv 6 | case json 7 | case checkstyle 8 | case codeclimate 9 | case githubActions = "github-actions" 10 | case githubMarkdown = "github-markdown" 11 | 12 | public static let `default` = OutputFormat.xcode 13 | 14 | init?(anyValue: Any) { 15 | if let format = anyValue as? OutputFormat { 16 | self = format 17 | return 18 | } 19 | guard let stringValue = anyValue as? String else { return nil } 20 | self.init(rawValue: stringValue) 21 | } 22 | 23 | @inlinable public var supportsAuxiliaryOutput: Bool { 24 | self == .xcode 25 | } 26 | 27 | @inlinable public var supportsColoredOutput: Bool { 28 | self == .xcode 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Extensions/Array+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension Array { 4 | @inlinable 5 | func group(by transform: (Element) -> U) -> [U: [Element]] { 6 | reduce([:]) { dictionary, element in 7 | var dictionary = dictionary 8 | let key = transform(element) 9 | dictionary[key] = (dictionary[key] ?? []) + [element] 10 | return dictionary 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Extensions/Collection+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension Collection { 4 | /// Returns the element at the specified index iff it is within bounds, otherwise nil. 5 | @inlinable 6 | subscript(safe index: Index) -> Element? { 7 | indices.contains(index) ? self[index] : nil 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Extensions/FilenameMatcher+Extension.swift: -------------------------------------------------------------------------------- 1 | import FilenameMatcher 2 | import Foundation 3 | 4 | public extension FilenameMatcher { 5 | @inlinable 6 | init(relativePattern: String, to base: String, caseSensitive: Bool) { 7 | let patternComponents = relativePattern.split(separator: "/", omittingEmptySubsequences: false) 8 | let parentTraversalCount = patternComponents.firstIndex { $0 != ".." } ?? 0 9 | 10 | if parentTraversalCount > base.split(separator: "/").count { 11 | self.init(pattern: "") 12 | return 13 | } 14 | 15 | let baseComponents = base.split(separator: "/", omittingEmptySubsequences: false) 16 | let traversedPattern = patternComponents.dropFirst(parentTraversalCount).joined(separator: "/") 17 | let traversedBaseParts = baseComponents.dropLast(parentTraversalCount) 18 | let traversedBase = traversedBaseParts.joined(separator: "/") 19 | let normalizedBase = traversedBase.hasSuffix("/") ? traversedBase : "\(traversedBase)/" 20 | let shouldPrependPwd = !["/", "*"].contains { relativePattern.hasPrefix($0) } 21 | let pattern = shouldPrependPwd ? "\(normalizedBase)\(traversedPattern)" : traversedPattern 22 | self.init(pattern: pattern, options: caseSensitive ? [.caseSensitive] : []) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Extensions/Sequence+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension Sequence { 4 | @inlinable 5 | func mapFirst(_ transform: (Element) throws -> T?) rethrows -> T? { 6 | for item in self { 7 | if let transformed = try transform(item) { 8 | return transformed 9 | } 10 | } 11 | 12 | return nil 13 | } 14 | 15 | @inlinable 16 | func flatMapSet(_ transform: (Element) throws -> Set) rethrows -> Set { 17 | try reduce(into: .init()) { result, element in 18 | try result.formUnion(transform(element)) 19 | } 20 | } 21 | 22 | @inlinable 23 | func mapSet(_ transform: (Element) throws -> T) rethrows -> Set { 24 | try reduce(into: .init()) { result, element in 25 | try result.insert(transform(element)) 26 | } 27 | } 28 | 29 | @inlinable 30 | func compactMapSet(_ transform: (Element) throws -> T?) rethrows -> Set { 31 | try reduce(into: .init()) { result, element in 32 | if let value = try transform(element) { 33 | result.insert(value) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Extensions/Set+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension Set { 4 | @inlinable 5 | mutating func inserting(_ value: Element) -> Self { 6 | insert(value) 7 | return self 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Extensions/String+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension String { 4 | @inlinable var trimmed: String { 5 | trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 6 | } 7 | 8 | @inlinable 9 | func escapedForXML() -> String { 10 | // & needs to go first, otherwise other replacements will be replaced again 11 | let htmlEscapes = [ 12 | ("&", "&"), 13 | ("\"", """), 14 | ("'", "'"), 15 | (">", ">"), 16 | ("<", "<"), 17 | ] 18 | var newString = self 19 | for (key, value) in htmlEscapes { 20 | newString = newString.replacingOccurrences(of: key, with: value) 21 | } 22 | return newString 23 | } 24 | 25 | // http://www.cse.yorku.ca/~oz/hash.html 26 | @inlinable var djb2: Int { 27 | unicodeScalars 28 | .map(\.value) 29 | .reduce(5381) { ($0 << 5) &+ $0 &+ Int($1) } 30 | } 31 | 32 | @inlinable var djb2Hex: String { 33 | String(format: "%02x", djb2) 34 | } 35 | 36 | @inlinable var withEscapedQuotes: String { 37 | replacingOccurrences(of: "\"", with: "\\\"") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Frontend/BazelProjectSetupGuide.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Logger 3 | import ProjectDrivers 4 | import Shared 5 | import SystemPackage 6 | 7 | final class BazelProjectSetupGuide: SetupGuideHelpers, SetupGuide { 8 | static func detect() -> Self? { 9 | guard BazelProjectDriver.isSupported else { return nil } 10 | return Self() 11 | } 12 | 13 | var projectKindName: String { 14 | "Bazel" 15 | } 16 | 17 | func perform() throws -> ProjectKind { 18 | print(Logger.colorize("\nAdd the following snippet to your MODULE.bazel file:", .bold)) 19 | print(Logger.colorize(""" 20 | bazel_dep(name = "periphery", version = "\(PeripheryVersion)") 21 | use_repo(use_extension("@periphery//bazel:generated.bzl", "generated"), "periphery_generated") 22 | """, .lightGray)) 23 | print(Logger.colorize("\nEnter to continue when ready ", .bold), terminator: "") 24 | _ = readLine() 25 | 26 | return .bazel 27 | } 28 | 29 | var commandLineOptions: [String] { 30 | ["--bazel"] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Frontend/Commands/CheckUpdateCommand.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Configuration 3 | import Foundation 4 | import Logger 5 | 6 | struct CheckUpdateCommand: FrontendCommand { 7 | static let configuration = CommandConfiguration( 8 | commandName: "check-update", 9 | abstract: "Check for available update" 10 | ) 11 | 12 | func run() throws { 13 | let configuration = Configuration() 14 | let logger = Logger(configuration: configuration) 15 | let checker = UpdateChecker(logger: logger, configuration: configuration) 16 | DispatchQueue.global().async { checker.run() } 17 | let latestVersion = try checker.wait().get() 18 | if latestVersion.isVersion(greaterThan: PeripheryVersion) { 19 | logger.info(Logger.colorize("* Update Available", .boldGreen)) 20 | let boldLatestVersion = Logger.colorize(latestVersion, .bold) 21 | let boldLocalVersion = Logger.colorize(PeripheryVersion, .bold) 22 | logger.info("Version \(boldLatestVersion) is now available, you are using version \(boldLocalVersion).") 23 | } else { 24 | let boldLatestVersion = Logger.colorize(latestVersion, .bold) 25 | logger.info("You are using the latest version, \(boldLatestVersion).") 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Frontend/Commands/ClearCacheCommand.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Configuration 3 | import Foundation 4 | import Logger 5 | import Shared 6 | 7 | struct ClearCacheCommand: FrontendCommand { 8 | static let configuration = CommandConfiguration( 9 | commandName: "clear-cache", 10 | abstract: "Clear Periphery's build cache" 11 | ) 12 | 13 | func run() throws { 14 | let configuration = Configuration() 15 | let logger = Logger(configuration: configuration) 16 | let shell = Shell(logger: logger) 17 | try shell.exec(["rm", "-rf", Constants.cachePath().string]) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Frontend/Commands/FrontendCommand.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Logger 3 | 4 | protocol FrontendCommand: ParsableCommand {} 5 | extension FrontendCommand { 6 | static var _errorLabel: String { Logger.colorize("error", .boldRed) } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Frontend/Commands/VersionCommand.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | 4 | struct VersionCommand: FrontendCommand { 5 | static let configuration = CommandConfiguration( 6 | commandName: "version", 7 | abstract: "Display the version of Periphery" 8 | ) 9 | 10 | func run() throws { 11 | print(PeripheryVersion) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Frontend/CommonSetupGuide.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Logger 4 | import Shared 5 | 6 | final class CommonSetupGuide: SetupGuideHelpers { 7 | private let configuration: Configuration 8 | 9 | required init(configuration: Configuration) { 10 | self.configuration = configuration 11 | super.init() 12 | } 13 | 14 | func perform() throws { 15 | print(Logger.colorize("\nAssume all 'public' declarations are in use?", .bold)) 16 | print("Choose 'Yes' if your project is a framework/library without a main application target.") 17 | configuration.retainPublic = selectBoolean() 18 | } 19 | 20 | var commandLineOptions: [String] { 21 | var options: [String] = [] 22 | 23 | if configuration.retainPublic { 24 | options.append("--retain-public") 25 | } 26 | 27 | return options 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Frontend/Logger+Extension.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Logger 3 | 4 | public extension Logger { 5 | @inlinable 6 | convenience init(configuration: Configuration) { 7 | self.init(quiet: configuration.quiet, verbose: configuration.verbose) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Frontend/SPMProjectSetupGuide.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ProjectDrivers 3 | import Shared 4 | import SystemPackage 5 | 6 | final class SPMProjectSetupGuide: SetupGuideHelpers, SetupGuide { 7 | static func detect() -> Self? { 8 | guard SPM.isSupported else { return nil } 9 | return Self() 10 | } 11 | 12 | var projectKindName: String { 13 | "Swift Package" 14 | } 15 | 16 | func perform() throws -> ProjectKind { 17 | .spm 18 | } 19 | 20 | var commandLineOptions: [String] { 21 | [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Frontend/Version.swift: -------------------------------------------------------------------------------- 1 | let PeripheryVersion = "3.1.0" 2 | -------------------------------------------------------------------------------- /Sources/Frontend/main.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import Logger 4 | import Shared 5 | 6 | Logger.configureBuffering() 7 | 8 | struct PeripheryCommand: FrontendCommand { 9 | static let configuration = CommandConfiguration( 10 | commandName: "periphery", 11 | subcommands: [ 12 | ScanCommand.self, 13 | CheckUpdateCommand.self, 14 | ClearCacheCommand.self, 15 | VersionCommand.self, 16 | ] 17 | ) 18 | } 19 | 20 | signal(SIGINT) { _ in 21 | let logger = Logger() 22 | logger.warn( 23 | "Termination can result in a corrupt index. Try the '--clean-build' flag if you get erroneous results such as false-positives and incorrect source file locations.", 24 | newlinePrefix: true // Print a newline after ^C 25 | ) 26 | ShellProcessStore.shared.interruptRunning() 27 | exit(0) 28 | } 29 | 30 | do { 31 | var command = try PeripheryCommand.parseAsRoot() 32 | try command.run() 33 | } catch { 34 | PeripheryCommand.exit(withError: error) 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Indexer/IndexPlan.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceGraph 3 | import SystemPackage 4 | 5 | public struct IndexPlan { 6 | public let sourceFiles: [SourceFile: [IndexUnit]] 7 | public let plistPaths: Set 8 | public let xibPaths: Set 9 | public let xcDataModelPaths: Set 10 | public let xcMappingModelPaths: Set 11 | 12 | public init( 13 | sourceFiles: [SourceFile: [IndexUnit]], 14 | plistPaths: Set = [], 15 | xibPaths: Set = [], 16 | xcDataModelPaths: Set = [], 17 | xcMappingModelPaths: Set = [] 18 | ) { 19 | self.sourceFiles = sourceFiles 20 | self.plistPaths = plistPaths 21 | self.xibPaths = xibPaths 22 | self.xcDataModelPaths = xcDataModelPaths 23 | self.xcMappingModelPaths = xcMappingModelPaths 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Indexer/Indexer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import FilenameMatcher 3 | import Foundation 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | class Indexer { 8 | private let configuration: Configuration 9 | 10 | init(configuration: Configuration) { 11 | self.configuration = configuration 12 | } 13 | 14 | func filterIndexExcluded(from files: Set) -> (included: Set, excluded: Set) { 15 | guard !configuration.indexExclude.isEmpty else { return (files, []) } 16 | 17 | let included = files.filter { !configuration.indexExcludeMatchers.anyMatch(filename: $0.string) } 18 | return (included, files.subtracting(included)) 19 | } 20 | 21 | func isRetained(_ file: SourceFile) -> Bool { 22 | configuration.retainFilesMatchers.anyMatch(filename: file.path.string) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Indexer/InfoPlistIndexer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Logger 3 | import Shared 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | final class InfoPlistIndexer: Indexer { 8 | private let infoPlistFiles: Set 9 | private let graph: SynchronizedSourceGraph 10 | private let logger: ContextualLogger 11 | 12 | required init(infoPlistFiles: Set, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration) { 13 | self.infoPlistFiles = infoPlistFiles 14 | self.graph = graph 15 | self.logger = logger.contextualized(with: "infoplist") 16 | super.init(configuration: configuration) 17 | } 18 | 19 | func perform() throws { 20 | let (includedFiles, excludedFiles) = filterIndexExcluded(from: infoPlistFiles) 21 | excludedFiles.forEach { self.logger.debug("Excluding \($0.string)") } 22 | 23 | try JobPool(jobs: Array(includedFiles)).forEach { [weak self] path in 24 | guard let self else { return } 25 | 26 | let elapsed = try Benchmark.measure { 27 | try InfoPlistParser(path: path) 28 | .parse() 29 | .forEach { self.graph.add($0) } 30 | } 31 | 32 | logger.debug("\(path.string) (\(elapsed)s)") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Indexer/JobPool.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Shared 3 | 4 | struct JobPool { 5 | let jobs: [Job] 6 | 7 | func forEach(_ block: @escaping (Job) throws -> Void) throws { 8 | var error: Error? 9 | 10 | DispatchQueue.concurrentPerform(iterations: jobs.count) { idx in 11 | guard error == nil else { return } 12 | 13 | do { 14 | let job = jobs[idx] 15 | try block(job) 16 | } catch let e { 17 | error = e 18 | } 19 | } 20 | 21 | if let error { 22 | throw error 23 | } 24 | } 25 | 26 | func flatMap(_ block: @escaping (Job) throws -> [Result]) throws -> [Result] { 27 | var error: Error? 28 | var results: [Result] = [] 29 | let lock = UnfairLock() 30 | 31 | DispatchQueue.concurrentPerform(iterations: jobs.count) { idx in 32 | guard error == nil else { return } 33 | 34 | do { 35 | let job = jobs[idx] 36 | let result = try block(job) 37 | 38 | lock.perform { 39 | results.append(contentsOf: result) 40 | } 41 | } catch let e { 42 | error = e 43 | } 44 | } 45 | 46 | if let error { 47 | throw error 48 | } 49 | 50 | return results 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Indexer/XCDataModelIndexer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Logger 3 | import Shared 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | final class XCDataModelIndexer: Indexer { 8 | private let files: Set 9 | private let graph: SynchronizedSourceGraph 10 | private let logger: ContextualLogger 11 | 12 | required init(files: Set, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration) { 13 | self.files = files 14 | self.graph = graph 15 | self.logger = logger.contextualized(with: "xcdatamodel") 16 | super.init(configuration: configuration) 17 | } 18 | 19 | func perform() throws { 20 | let (includedFiles, excludedFiles) = filterIndexExcluded(from: files) 21 | excludedFiles.forEach { self.logger.debug("Excluding \($0.string)") } 22 | 23 | try JobPool(jobs: Array(includedFiles)).forEach { [weak self] path in 24 | guard let self else { return } 25 | 26 | let elapsed = try Benchmark.measure { 27 | try XCDataModelParser(path: path) 28 | .parse() 29 | .forEach { self.graph.add($0) } 30 | } 31 | 32 | logger.debug("\(path.string) (\(elapsed)s)") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Indexer/XCDataModelParser.swift: -------------------------------------------------------------------------------- 1 | import AEXML 2 | import Foundation 3 | import SourceGraph 4 | import SystemPackage 5 | 6 | final class XCDataModelParser { 7 | private let path: FilePath 8 | 9 | required init(path: FilePath) { 10 | self.path = path 11 | } 12 | 13 | func parse() throws -> [AssetReference] { 14 | try FileManager.default.contentsOfDirectory(atPath: path.string).flatMap { subPath -> [AssetReference] in 15 | let modelPath = path.appending(subPath) 16 | guard modelPath.extension == "xcdatamodel" else { return [] } 17 | let contentsPath = modelPath.appending("contents") 18 | guard let data = FileManager.default.contents(atPath: contentsPath.string) else { return [] } 19 | let structure = try AEXMLDocument(xml: data) 20 | return references(from: structure.root).map { 21 | AssetReference(absoluteName: $0, source: .xcDataModel) 22 | } 23 | } 24 | } 25 | 26 | // MARK: - Private 27 | 28 | private func references(from element: AEXMLElement) -> [String] { 29 | var names: [String] = [] 30 | 31 | for child in element.children { 32 | if let name = child.attributes["customClassName"] { 33 | names.append(name) 34 | } 35 | 36 | names += references(from: child) 37 | } 38 | 39 | return names 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Indexer/XCMappingModelIndexer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Logger 3 | import Shared 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | final class XCMappingModelIndexer: Indexer { 8 | private let files: Set 9 | private let graph: SynchronizedSourceGraph 10 | private let logger: ContextualLogger 11 | 12 | required init(files: Set, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration) { 13 | self.files = files 14 | self.graph = graph 15 | self.logger = logger.contextualized(with: "xcmappingmodel") 16 | super.init(configuration: configuration) 17 | } 18 | 19 | func perform() throws { 20 | let (includedFiles, excludedFiles) = filterIndexExcluded(from: files) 21 | excludedFiles.forEach { self.logger.debug("Excluding \($0.string)") } 22 | 23 | try JobPool(jobs: Array(includedFiles)).forEach { [weak self] path in 24 | guard let self else { return } 25 | 26 | let elapsed = try Benchmark.measure { 27 | try XCMappingModelParser(path: path) 28 | .parse() 29 | .forEach { self.graph.add($0) } 30 | } 31 | 32 | logger.debug("\(path.string) (\(elapsed)s)") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Indexer/XCMappingModelParser.swift: -------------------------------------------------------------------------------- 1 | import AEXML 2 | import Foundation 3 | import SourceGraph 4 | import SystemPackage 5 | 6 | final class XCMappingModelParser { 7 | private let path: FilePath 8 | 9 | required init(path: FilePath) { 10 | self.path = path.appending("xcmapping.xml") 11 | } 12 | 13 | func parse() throws -> [AssetReference] { 14 | guard let data = FileManager.default.contents(atPath: path.string) else { return [] } 15 | let structure = try AEXMLDocument(xml: data) 16 | return references(from: structure.root).map { 17 | AssetReference(absoluteName: $0, source: .xcMappingModel) 18 | } 19 | } 20 | 21 | // MARK: - Private 22 | 23 | private func references(from element: AEXMLElement) -> [String] { 24 | var names: [String] = [] 25 | 26 | for child in element.children { 27 | if child.attributes["name"] == "migrationpolicyclassname" { 28 | names.append(child.string) 29 | } 30 | 31 | names += references(from: child) 32 | } 33 | 34 | return names 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Indexer/XibIndexer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Logger 3 | import Shared 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | final class XibIndexer: Indexer { 8 | private let xibFiles: Set 9 | private let graph: SynchronizedSourceGraph 10 | private let logger: ContextualLogger 11 | 12 | required init(xibFiles: Set, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration) { 13 | self.xibFiles = xibFiles 14 | self.graph = graph 15 | self.logger = logger.contextualized(with: "xib") 16 | super.init(configuration: configuration) 17 | } 18 | 19 | func perform() throws { 20 | let (includedFiles, excludedFiles) = filterIndexExcluded(from: xibFiles) 21 | excludedFiles.forEach { self.logger.debug("Excluding \($0.string)") } 22 | 23 | try JobPool(jobs: Array(includedFiles)).forEach { [weak self] xibPath in 24 | guard let self else { return } 25 | 26 | let elapsed = try Benchmark.measure { 27 | try XibParser(path: xibPath) 28 | .parse() 29 | .forEach { self.graph.add($0) } 30 | } 31 | 32 | logger.debug("\(xibPath.string) (\(elapsed)s)") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Indexer/XibParser.swift: -------------------------------------------------------------------------------- 1 | import AEXML 2 | import Foundation 3 | import SourceGraph 4 | import SystemPackage 5 | 6 | final class XibParser { 7 | private let path: FilePath 8 | 9 | required init(path: FilePath) { 10 | self.path = path 11 | } 12 | 13 | func parse() throws -> [AssetReference] { 14 | guard let data = FileManager.default.contents(atPath: path.string) else { return [] } 15 | let structure = try AEXMLDocument(xml: data) 16 | return references(from: structure.root).map { 17 | AssetReference(absoluteName: $0, source: .interfaceBuilder) 18 | } 19 | } 20 | 21 | // MARK: - Private 22 | 23 | private func references(from element: AEXMLElement) -> [String] { 24 | var names: [String] = [] 25 | 26 | for child in element.children { 27 | if let name = child.attributes["customClass"] { 28 | names.append(name) 29 | } 30 | 31 | names += references(from: child) 32 | } 33 | 34 | return names 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/PeripheryKit/Results/Baseline.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A baseline set of declarations that are excluded from results. 4 | public enum Baseline: Codable { 5 | case v1(usrs: [String]) 6 | 7 | public var usrs: Set { 8 | switch self { 9 | case let .v1(usrs): 10 | Set(usrs) 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/PeripheryKit/Results/GitHubActionsFormatter.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | import SourceGraph 5 | import SystemPackage 6 | 7 | final class GitHubActionsFormatter: OutputFormatter { 8 | let configuration: Configuration 9 | lazy var currentFilePath: FilePath = .current 10 | 11 | init(configuration: Configuration) { 12 | self.configuration = configuration 13 | } 14 | 15 | func format(_ results: [ScanResult], colored: Bool) throws -> String? { 16 | guard !results.isEmpty else { return nil } 17 | guard configuration.relativeResults else { throw PeripheryError.usageError("`periphery scan` must be ran with `--relative-results` when using the GitHub Actions formatter") } 18 | 19 | return results.flatMap { result in 20 | describe(result, colored: colored).map { location, description in 21 | prefix(for: location, result: result) + description 22 | } 23 | } 24 | .joined(separator: "\n") 25 | } 26 | 27 | // MARK: - Private 28 | 29 | private func prefix(for location: Location, result: ScanResult) -> String { 30 | let path = outputPath(location) 31 | let lineNum = String(location.line) 32 | let column = location.column 33 | let title = describe(result.annotation) 34 | 35 | return "::warning file=\(path),line=\(lineNum),col=\(column),title=\(title)::" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/PeripheryKit/ScanResult.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceGraph 3 | 4 | public struct ScanResult { 5 | enum Annotation { 6 | case unused 7 | case assignOnlyProperty 8 | case redundantProtocol(references: Set, inherited: Set) 9 | case redundantPublicAccessibility(modules: Set) 10 | } 11 | 12 | let declaration: Declaration 13 | let annotation: Annotation 14 | 15 | public var usrs: Set { 16 | declaration.usrs 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ProjectDrivers/ProjectDriver.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Indexer 3 | import Logger 4 | import SwiftIndexStore 5 | 6 | public protocol ProjectDriver { 7 | func build() throws 8 | func plan(logger: ContextualLogger) throws -> IndexPlan 9 | } 10 | 11 | public extension ProjectDriver { 12 | func build() throws {} 13 | 14 | func plan(logger _: ContextualLogger) throws -> IndexPlan { 15 | IndexPlan(sourceFiles: [:]) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Shared/Benchmark.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Benchmark { 4 | @inlinable 5 | public static func measure(block: () throws -> Void) rethrows -> String { 6 | let start = Date() 7 | try block() 8 | let end = Date() 9 | let elapsed = end.timeIntervalSince(start) 10 | return String(format: "%.03f", elapsed) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Shared/Constants.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | public enum Constants { 5 | public static func cachePath() throws -> FilePath { 6 | let url = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 7 | return FilePath(url.appendingPathComponent("com.github.peripheryapp").path) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Shared/ProjectKind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | public enum ProjectKind { 5 | case xcode(projectPath: FilePath) 6 | case spm 7 | case bazel 8 | case generic(genericProjectConfig: FilePath) 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Shared/PropertyTypeSanitizer.swift: -------------------------------------------------------------------------------- 1 | import Extensions 2 | import Foundation 3 | 4 | public enum PropertyTypeSanitizer { 5 | @inlinable 6 | public static func sanitize(_ type: String) -> String { 7 | type.trimmed.trimmingCharacters(in: .init(["?", "!"])) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Shared/SwiftVersion.swift: -------------------------------------------------------------------------------- 1 | import Extensions 2 | import Foundation 3 | 4 | public struct SwiftVersion { 5 | static let minimumVersion = "5.10" 6 | 7 | public let version: VersionString 8 | public let fullVersion: String 9 | 10 | public init(shell: Shell) { 11 | fullVersion = try! shell.exec(["swift", "-version"]).trimmed // swiftlint:disable:this force_try 12 | version = try! SwiftVersionParser.parse(fullVersion) // swiftlint:disable:this force_try 13 | } 14 | 15 | public func validateVersion() throws { 16 | if version.isVersion(lessThan: Self.minimumVersion) { 17 | throw PeripheryError.swiftVersionUnsupportedError( 18 | version: fullVersion, 19 | minimumVersion: Self.minimumVersion 20 | ) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Shared/SwiftVersionParser.swift: -------------------------------------------------------------------------------- 1 | import Extensions 2 | import Foundation 3 | 4 | enum SwiftVersionParser { 5 | static func parse(_ fullVersion: String) throws -> VersionString { 6 | guard let rawVersion = fullVersion.components(separatedBy: "Swift version").last?.split(separator: " ").first else { 7 | throw PeripheryError.swiftVersionParseError(fullVersion: fullVersion) 8 | } 9 | 10 | let version = rawVersion.split(separator: "-").first ?? rawVersion 11 | return String(version) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Shared/UnfairLock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if canImport(os) 4 | import os 5 | #endif 6 | 7 | public final class UnfairLock { 8 | #if canImport(os) 9 | private var _osAllocatedUnfairLock: Any? 10 | 11 | private var osAllocatedUnfairLock: OSAllocatedUnfairLock { 12 | // swiftlint:disable:next force_cast 13 | _osAllocatedUnfairLock as! OSAllocatedUnfairLock 14 | } 15 | #else 16 | private var _nsLock: Any? 17 | 18 | private var nsLock: NSLock { 19 | // swiftlint:disable:next force_cast 20 | _nsLock as! NSLock 21 | } 22 | #endif 23 | 24 | public init() { 25 | #if canImport(os) 26 | _osAllocatedUnfairLock = OSAllocatedUnfairLock() 27 | #else 28 | _nsLock = NSLock() 29 | #endif 30 | } 31 | 32 | @discardableResult 33 | @inline(__always) 34 | public func perform(_ operation: () throws -> T) rethrows -> T { 35 | #if canImport(os) 36 | osAllocatedUnfairLock.lock() 37 | let value = try operation() 38 | osAllocatedUnfairLock.unlock() 39 | return value 40 | #else 41 | nsLock.lock() 42 | let value = try operation() 43 | nsLock.unlock() 44 | return value 45 | #endif 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/Accessibility.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Accessibility: String { 4 | case `public` 5 | case `internal` 6 | case `private` 7 | case `fileprivate` 8 | case open 9 | } 10 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/AssetReference.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | public struct AssetReference: Hashable { 5 | public init(absoluteName: String, source: ProjectFileKind) { 6 | if let name = absoluteName.split(separator: ".").last { 7 | self.name = String(name) 8 | } else { 9 | name = absoluteName 10 | } 11 | self.source = source 12 | } 13 | 14 | public let name: String 15 | public let source: ProjectFileKind 16 | } 17 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/CommentCommand.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum CommentCommand: CustomStringConvertible, Hashable { 4 | public enum Override: CustomStringConvertible, Hashable { 5 | case location(String, Int, Int) 6 | case kind(String) 7 | 8 | public var description: String { 9 | switch self { 10 | case let .location(path, line, column): 11 | "location=\"\(path):\(line):\(column)\"" 12 | case let .kind(kind): 13 | "kind=\"\(kind)\"" 14 | } 15 | } 16 | } 17 | 18 | case ignore 19 | case ignoreAll 20 | case ignoreParameters([String]) 21 | case override([Override]) 22 | 23 | public var description: String { 24 | switch self { 25 | case .ignore: 26 | return "ignore" 27 | case .ignoreAll: 28 | return "ignore:all" 29 | case let .ignoreParameters(params): 30 | let formattedParams = params.sorted().joined(separator: ",") 31 | return "ignore:parameters \(formattedParams)" 32 | case let .override(overrides): 33 | let formattedOverrides = overrides.map(\.description).joined(separator: " ") 34 | return "override \(formattedOverrides)" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/ImportStatement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ImportStatement { 4 | public let module: String 5 | public let isTestable: Bool 6 | public let isExported: Bool 7 | public let location: Location 8 | public let commentCommands: [CommentCommand] 9 | 10 | public init( 11 | module: String, 12 | isTestable: Bool, 13 | isExported: Bool, 14 | location: Location, 15 | commentCommands: [CommentCommand] 16 | ) { 17 | self.module = module 18 | self.isTestable = isTestable 19 | self.isExported = isExported 20 | self.location = location 21 | self.commentCommands = commentCommands 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/ProjectFileKind.swift: -------------------------------------------------------------------------------- 1 | public enum ProjectFileKind { 2 | case interfaceBuilder 3 | case infoPlist 4 | case xcDataModel 5 | case xcMappingModel 6 | 7 | public var extensions: [String] { 8 | switch self { 9 | case .interfaceBuilder: 10 | ["xib", "storyboard"] 11 | case .infoPlist: 12 | ["plist"] 13 | case .xcDataModel: 14 | ["xcdatamodeld"] 15 | case .xcMappingModel: 16 | ["xcmappingmodel"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Elements/SourceFile.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | public class SourceFile { 5 | public let path: FilePath 6 | public let modules: Set 7 | public var importStatements: [ImportStatement] = [] 8 | public var importsSwiftTesting = false 9 | 10 | public init(path: FilePath, modules: Set) { 11 | self.path = path 12 | self.modules = modules 13 | } 14 | } 15 | 16 | extension SourceFile: Hashable { 17 | public func hash(into hasher: inout Hasher) { 18 | hasher.combine(path) 19 | } 20 | } 21 | 22 | extension SourceFile: Equatable { 23 | public static func == (lhs: SourceFile, rhs: SourceFile) -> Bool { 24 | lhs.path == rhs.path 25 | } 26 | } 27 | 28 | extension SourceFile: Comparable { 29 | public static func < (lhs: SourceFile, rhs: SourceFile) -> Bool { 30 | lhs.path.string < rhs.path.string 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/CodablePropertyRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | final class CodablePropertyRetainer: SourceGraphMutator { 6 | private let graph: SourceGraph 7 | private let configuration: Configuration 8 | 9 | required init(graph: SourceGraph, configuration: Configuration, swiftVersion _: SwiftVersion) { 10 | self.graph = graph 11 | self.configuration = configuration 12 | } 13 | 14 | func mutate() { 15 | if configuration.retainCodableProperties { 16 | for decl in graph.declarations(ofKinds: Declaration.Kind.discreteConformableKinds) { 17 | guard graph.isCodable(decl) else { continue } 18 | 19 | for decl in decl.declarations { 20 | guard decl.kind == .varInstance else { continue } 21 | graph.markRetained(decl) 22 | } 23 | } 24 | } else if configuration.retainEncodableProperties { 25 | for decl in graph.declarations(ofKinds: Declaration.Kind.discreteConformableKinds) { 26 | guard graph.isEncodable(decl) else { continue } 27 | 28 | for decl in decl.declarations { 29 | guard decl.kind == .varInstance else { continue } 30 | graph.markRetained(decl) 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/DynamicMemberRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | final class DynamicMemberRetainer: SourceGraphMutator { 6 | private let graph: SourceGraph 7 | 8 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 9 | self.graph = graph 10 | } 11 | 12 | func mutate() throws { 13 | for decl in graph.declarations(ofKind: .functionSubscript) { 14 | if decl.name == "subscript(dynamicMember:)", decl.parent?.attributes.contains("dynamicMemberLookup") ?? false { 15 | graph.markRetained(decl) 16 | } 17 | } 18 | 19 | for decl in graph.declarations(ofKinds: Declaration.Kind.functionKinds.union(Declaration.Kind.variableKinds)) { 20 | if decl.attributes.contains("_dynamicReplacement") { 21 | graph.markRetained(decl) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/EntryPointAttributeRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | final class EntryPointAttributeRetainer: SourceGraphMutator { 6 | private let graph: SourceGraph 7 | 8 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 9 | self.graph = graph 10 | } 11 | 12 | func mutate() { 13 | graph 14 | .declarations(ofKinds: [.class, .struct, .enum]) 15 | .lazy 16 | .filter { 17 | $0.attributes.contains("NSApplicationMain") || 18 | $0.attributes.contains("UIApplicationMain") || 19 | $0.attributes.contains("main") 20 | } 21 | .forEach { 22 | graph.markRetained($0) 23 | graph.markMainAttributed($0) 24 | 25 | for ancestralDeclaration in $0.ancestralDeclarations { 26 | graph.markRetained(ancestralDeclaration) 27 | } 28 | 29 | if $0.attributes.contains("main") { 30 | // @main requires a static main() function. 31 | $0.declarations 32 | .filter { $0.kind == .functionMethodStatic && $0.name == "main()" } 33 | .forEach { graph.markRetained($0) } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/InterfaceBuilderPropertyRetainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class InterfaceBuilderPropertyRetainer { 4 | private let graph: SourceGraph 5 | private let ibAttributes = ["IBOutlet", "IBAction", "IBInspectable", "IBSegueAction"] 6 | 7 | required init(graph: SourceGraph) { 8 | self.graph = graph 9 | } 10 | 11 | /// Some properties may be declared in extensions on external types, e.g IBInspectable. 12 | func retainPropertiesDeclaredInExtensions() { 13 | let extensions = graph.declarations(ofKind: .extensionClass) 14 | 15 | for extDecl in extensions { 16 | for decl in extDecl.declarations where decl.attributes.contains(where: { ibAttributes.contains($0) }) { 17 | graph.markRetained(decl) 18 | } 19 | } 20 | } 21 | 22 | func retainPropertiesDeclared(in declaration: Declaration) { 23 | let inheritedDeclarations = graph.inheritedDeclarations(of: declaration) 24 | let descendentInheritedDeclarations = inheritedDeclarations.map(\.declarations).joined() 25 | let allDeclarations = declaration.declarations.union(descendentInheritedDeclarations) 26 | 27 | for declaration in allDeclarations where declaration.attributes.contains(where: { ibAttributes.contains($0) }) { 28 | graph.markRetained(declaration) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/PropertyWrapperRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | final class PropertyWrapperRetainer: SourceGraphMutator { 6 | private let graph: SourceGraph 7 | private let specialProperties = ["wrappedValue", "projectedValue"] 8 | 9 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 10 | self.graph = graph 11 | } 12 | 13 | func mutate() { 14 | for decl in graph.declarations(ofKinds: Declaration.Kind.toplevelAttributableKind) where decl.attributes.contains("propertyWrapper") { 15 | decl.declarations 16 | .filter { $0.kind == .varInstance && specialProperties.contains($0.name ?? "") } 17 | .forEach { graph.markRetained($0) } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/PubliclyAccessibleRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | final class PubliclyAccessibleRetainer: SourceGraphMutator { 6 | private let graph: SourceGraph 7 | private let configuration: Configuration 8 | 9 | required init(graph: SourceGraph, configuration: Configuration, swiftVersion _: SwiftVersion) { 10 | self.graph = graph 11 | self.configuration = configuration 12 | } 13 | 14 | func mutate() { 15 | guard configuration.retainPublic else { return } 16 | 17 | let declarations = Declaration.Kind.accessibleKinds.flatMap { 18 | graph.declarations(ofKind: $0) 19 | } 20 | 21 | let publicDeclarations = declarations.filter { $0.accessibility.value == .public || $0.accessibility.value == .open } 22 | 23 | publicDeclarations.forEach { graph.markRetained($0) } 24 | 25 | // Enum cases inherit the accessibility of the enum. 26 | publicDeclarations 27 | .lazy 28 | .filter { $0.kind == .enum } 29 | .flatMap(\.declarations) 30 | .filter { $0.kind == .enumelement } 31 | .forEach { graph.markRetained($0) } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/ResultBuilderRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | /// Retains static methods used by the Result Builder language feature. 6 | final class ResultBuilderRetainer: SourceGraphMutator { 7 | private let graph: SourceGraph 8 | private let resultBuilderMethods = Set([ 9 | "buildExpression(_:)", 10 | "buildOptional(_:)", 11 | "buildEither(first:)", 12 | "buildEither(second:)", 13 | "buildArray(_:)", 14 | "buildBlock(_:)", 15 | "buildFinalResult(_:)", 16 | "buildLimitedAvailability(_:)", 17 | ]) 18 | 19 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 20 | self.graph = graph 21 | } 22 | 23 | func mutate() { 24 | for decl in graph.declarations(ofKinds: Declaration.Kind.toplevelAttributableKind) where decl.attributes.contains("resultBuilder") { 25 | for childDecl in decl.declarations { 26 | if let name = childDecl.name, resultBuilderMethods.contains(name) { 27 | graph.markRetained(childDecl) 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/StringInterpolationAppendInterpolationRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | // https://github.com/apple/swift/issues/56189 6 | // The index store does not contain references to `appendInterpolation` functions from their use in string literals. 7 | final class StringInterpolationAppendInterpolationRetainer: SourceGraphMutator { 8 | private let graph: SourceGraph 9 | 10 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 11 | self.graph = graph 12 | } 13 | 14 | func mutate() { 15 | for declaration in graph.declarations(ofKind: .extensionStruct) { 16 | declaration.declarations.filter { 17 | $0.kind == .functionMethodInstance && 18 | ($0.name ?? "").hasPrefix("appendInterpolation(") 19 | }.forEach { 20 | graph.markRetained($0) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SourceGraph/Mutators/SwiftTestingRetainer.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | /// Retains Swift Testing declarations. 6 | /// https://developer.apple.com/xcode/swift-testing/ 7 | final class SwiftTestingRetainer: SourceGraphMutator { 8 | private let graph: SourceGraph 9 | 10 | required init(graph: SourceGraph, configuration _: Configuration, swiftVersion _: SwiftVersion) { 11 | self.graph = graph 12 | } 13 | 14 | func mutate() { 15 | for decl in graph.declarations(ofKinds: [.class, .struct]) { 16 | guard decl.location.file.importsSwiftTesting else { continue } 17 | 18 | if decl.attributes.contains("Suite") { 19 | graph.markRetained(decl) 20 | } 21 | } 22 | 23 | for decl in graph.declarations(ofKinds: [.functionFree, .functionMethodInstance, .functionMethodClass, .functionMethodStatic]) { 24 | guard decl.location.file.importsSwiftTesting else { continue } 25 | 26 | if decl.attributes.contains("Test") { 27 | graph.markRetained(decl) 28 | 29 | if let parent = decl.parent { 30 | graph.markRetained(parent) 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SourceGraph/SourceGraphMutator.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import Shared 4 | 5 | protocol SourceGraphMutator: AnyObject { 6 | init(graph: SourceGraph, configuration: Configuration, swiftVersion: SwiftVersion) 7 | func mutate() throws 8 | } 9 | -------------------------------------------------------------------------------- /Sources/SyntaxAnalysis/ImportSyntaxVisitor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceGraph 3 | import SwiftSyntax 4 | 5 | public final class ImportSyntaxVisitor: PeripherySyntaxVisitor { 6 | public var importStatements: [ImportStatement] = [] 7 | 8 | private let sourceLocationBuilder: SourceLocationBuilder 9 | 10 | public init(sourceLocationBuilder: SourceLocationBuilder) { 11 | self.sourceLocationBuilder = sourceLocationBuilder 12 | } 13 | 14 | public func visit(_ node: ImportDeclSyntax) { 15 | let parts = node.path.map(\.name.text) 16 | let module = parts.first ?? "" 17 | let attributes = node.attributes.compactMap { 18 | if case let .attribute(attr) = $0 { 19 | attr.attributeName.trimmedDescription 20 | } else { 21 | nil 22 | } 23 | } 24 | let location = sourceLocationBuilder.location(at: node.positionAfterSkippingLeadingTrivia) 25 | let statement = ImportStatement( 26 | module: module, 27 | isTestable: attributes.contains("testable"), 28 | isExported: attributes.contains("_exported") || node.modifiers.contains { $0.name.text == "public" }, 29 | location: location, 30 | commentCommands: CommentCommand.parseCommands(in: node.leadingTrivia.merging(node.trailingTrivia)) 31 | ) 32 | importStatements.append(statement) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SyntaxAnalysis/SourceLocationBuilder.swift: -------------------------------------------------------------------------------- 1 | import SourceGraph 2 | import SwiftSyntax 3 | 4 | public final class SourceLocationBuilder { 5 | private let file: SourceFile 6 | private let locationConverter: SourceLocationConverter 7 | 8 | public init(file: SourceFile, locationConverter: SourceLocationConverter) { 9 | self.file = file 10 | self.locationConverter = locationConverter 11 | } 12 | 13 | public func location(at position: AbsolutePosition) -> Location { 14 | let location = locationConverter.location(for: position) 15 | return Location(file: file, 16 | line: location.line, 17 | column: location.column) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/XcodeSupport/XcodeProjectlike.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | public protocol XcodeProjectlike: AnyObject { 5 | var path: FilePath { get } 6 | var targets: Set { get } 7 | var type: String { get } 8 | var name: String { get } 9 | var sourceRoot: FilePath { get } 10 | 11 | func schemes(additionalArguments: [String]) throws -> Set 12 | } 13 | 14 | public extension XcodeProjectlike { 15 | var name: String { 16 | path.lastComponent?.stem ?? "" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - implicitly_unwrapped_optional 3 | - force_try -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.10 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "AccessibilityProject", 6 | platforms: [.macOS(.v13)], 7 | products: [ 8 | .executable( 9 | name: "app", 10 | targets: ["MainTarget"] 11 | ) 12 | ], 13 | targets: [ 14 | .executableTarget( 15 | name: "MainTarget", 16 | dependencies: ["TargetA"]), 17 | .target( 18 | name: "ExternalTarget", 19 | dependencies: []), 20 | .target( 21 | name: "TargetA", 22 | dependencies: ["ExternalTarget"]), 23 | .testTarget( 24 | name: "TestTarget", 25 | dependencies: ["MainTarget", "TargetA"]) 26 | ] 27 | ) 28 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/ExternalTarget/ExternalProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol ExternalProtocol { 4 | func someExternalProtocolMethod() 5 | } 6 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/IgnoreAllCommentCommand.swift: -------------------------------------------------------------------------------- 1 | // periphery:ignore:all 2 | 3 | import Foundation 4 | 5 | public class IgnoreAllCommentCommand {} 6 | public class IgnoreAllCommentCommandRetainer { 7 | public init() {} 8 | public func retain() { 9 | _ = IgnoreAllCommentCommand() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/IgnoreCommentCommand.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // periphery:ignore 4 | public class IgnoreCommentCommand {} 5 | public class IgnoreCommentCommandRetainer { 6 | public init() {} 7 | public func retain() { 8 | _ = IgnoreCommentCommand() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/InternalClassAdoptingPublicProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol InternalClassAdoptingPublicProtocol_Protocol {} 4 | class InternalClassAdoptingPublicProtocol: InternalClassAdoptingPublicProtocol_Protocol { 5 | public init() {} 6 | } 7 | 8 | public class InternalClassAdoptingPublicProtocolRetainer { 9 | public init() { 10 | let _: InternalClassAdoptingPublicProtocol? = nil 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/InternalProtocolRefiningPublicProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol InternalProtocolRefiningPublicProtocol_Refined {} 4 | protocol InternalProtocolRefiningPublicProtocol: InternalProtocolRefiningPublicProtocol_Refined {} 5 | 6 | public class InternalProtocolRefiningPublicProtocolRetainer { 7 | public init() { 8 | let _: InternalProtocolRefiningPublicProtocol? = nil 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/NotRedundantPublicTestableImportClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class NotRedundantPublicTestableImportClass { 4 | public init() {} 5 | public var testableProperty: String? 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/ProtocolIndirectlyReferencedCrossModuleByExtensionMember.swift: -------------------------------------------------------------------------------- 1 | public protocol ProtocolIndirectlyReferencedCrossModuleByExtensionMember {} 2 | public extension ProtocolIndirectlyReferencedCrossModuleByExtensionMember { 3 | func somePublicFunc() {} 4 | } 5 | public class ProtocolIndirectlyReferencedCrossModuleByExtensionMemberImpl: ProtocolIndirectlyReferencedCrossModuleByExtensionMember { 6 | public init() {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicActor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public actor PublicActor { 4 | public init() { } 5 | public func someFunc() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicAssociatedTypeDefaultType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicInheritedAssociatedTypeDefaultType {} 4 | 5 | public protocol PublicInheritedAssociatedTypeDefaultTypeProtocol { 6 | associatedtype Value = PublicInheritedAssociatedTypeDefaultType 7 | 8 | var items: [Value] { get } 9 | } 10 | 11 | public class PublicInheritedAssociatedTypeDefaultTypeClass: PublicInheritedAssociatedTypeDefaultTypeProtocol { 12 | public init() {} 13 | public let items: [Int] = [] 14 | } 15 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicClassAdoptingExternalProtocolObjcAccessible.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import Foundation 3 | import ExternalTarget 4 | 5 | // Not referenced in MainTarget but retained due to retainObjcAccessible. 6 | @objc public class PublicClassAdoptingExternalProtocolObjcAccessible: NSObject, ExternalProtocol { 7 | public override init() {} 8 | public func someExternalProtocolMethod() {} 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicClassAdoptingInternalProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol PublicClassAdoptingInternalProtocol_Protocol {} 4 | public class PublicClassAdoptingInternalProtocol: PublicClassAdoptingInternalProtocol_Protocol { 5 | public init() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicClassAdoptingPublicProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicClassAdoptingPublicProtocol_Protocol {} 4 | public class PublicClassAdoptingPublicProtocol: PublicClassAdoptingPublicProtocol_Protocol { 5 | public init() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicClassInheritingPublicExternalClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicClassInheritingPublicExternalClass: FileManager { 4 | public override init() {} 5 | } 6 | 7 | public class PublicClassInheritingPublicExternalClassRetainer { 8 | public init() { 9 | let _ = PublicClassInheritingPublicExternalClass() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicClassInheritingPublicTypeWithGenericParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct PublicClassInheritingPublicClassWithGenericParameter_GenericType {} 4 | public class PublicClassInheritingPublicClassWithGenericParameter_Superclass {} 5 | public class PublicClassInheritingPublicClassWithGenericParameter: PublicClassInheritingPublicClassWithGenericParameter_Superclass { 6 | public override init() {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicComparableOperatorFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicComparableOperatorFunction: Comparable {} 4 | 5 | public func < (lhs: PublicComparableOperatorFunction, rhs: PublicComparableOperatorFunction) -> Bool { 6 | true 7 | } 8 | 9 | public func == (lhs: PublicComparableOperatorFunction, rhs: PublicComparableOperatorFunction) -> Bool { 10 | true 11 | } 12 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicDeclarationInInternalParent.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class PublicDeclarationInInternalParent { 4 | public func somePublicFunc() {} 5 | } 6 | 7 | public class PublicDeclarationInInternalParentRetainer { 8 | public init() {} 9 | public func retain() { 10 | PublicDeclarationInInternalParent().somePublicFunc() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicEnumCaseWithParameter.swift: -------------------------------------------------------------------------------- 1 | public class PublicEnumCaseWithParameter_ParameterType {} 2 | public class PublicEnumCaseWithParameter_ParameterType_Outer { 3 | public class Inner {} 4 | } 5 | public enum PublicEnumCaseWithParameter { 6 | case someCase( 7 | param1: PublicEnumCaseWithParameter_ParameterType?, 8 | param2: PublicEnumCaseWithParameter_ParameterType_Outer.Inner? 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicEnumWithAssociatedValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct PublicAssociatedValueA { 4 | public let value: String 5 | 6 | } 7 | public struct PublicAssociatedValueB { 8 | public let value: String 9 | } 10 | 11 | public enum PublicEnumWithAssociatedValue { 12 | case someCase(PublicAssociatedValueA, named: PublicAssociatedValueB) 13 | 14 | public static func getSomeCase() -> Self { 15 | return .someCase(.init(value: ""), named: .init(value: "")) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicExtensionOnRedundantPublicKind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicExtensionOnRedundantPublicKind {} 4 | public extension PublicExtensionOnRedundantPublicKind { 5 | func someFunc() {} 6 | } 7 | 8 | public class PublicExtensionOnRedundantPublicKindRetainer { 9 | public init() {} 10 | public func retain() { 11 | let _ = PublicExtensionOnRedundantPublicKind() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicInheritedAssociatedType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicInheritedAssociatedType {} 4 | 5 | public protocol PublicInheritedAssociatedTypeProtocol { 6 | associatedtype Value: PublicInheritedAssociatedType 7 | 8 | var items: [Value] { get } 9 | } 10 | 11 | public class PublicInheritedAssociatedTypeClass: PublicInheritedAssociatedTypeProtocol { 12 | public init() {} 13 | public let items: [Int] = [] 14 | } 15 | 16 | extension Int: PublicInheritedAssociatedType {} 17 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicInlinableFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class ClassReferencedFromPublicInlinableFunction {} 4 | 5 | @usableFromInline 6 | class ClassReferencedFromPublicInlinableFunction_UsableFromInline {} 7 | 8 | @inlinable 9 | public func inlinableFunction() { 10 | _ = ClassReferencedFromPublicInlinableFunction.self 11 | _ = ClassReferencedFromPublicInlinableFunction_UsableFromInline.self 12 | } 13 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicProtocolRefiningPublicProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicProtocolRefiningPublicProtocol_Refined {} 4 | public protocol PublicProtocolRefiningPublicProtocol: PublicProtocolRefiningPublicProtocol_Refined {} 5 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicClassGenericParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicTypeUsedAsPublicClassGenericParameter_ProtocolA {} 4 | public protocol PublicTypeUsedAsPublicClassGenericParameter_ProtocolB {} 5 | public class PublicTypeUsedAsPublicClassGenericParameter_ConformingClass: PublicTypeUsedAsPublicClassGenericParameter_ProtocolA, PublicTypeUsedAsPublicClassGenericParameter_ProtocolB {} 6 | 7 | public class PublicTypeUsedAsPublicClassGenericParameterRetainer { 8 | public init() {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicClassGenericRequirement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicTypeUsedAsPublicClassGenericRequirement_Protocol {} 4 | public class PublicTypeUsedAsPublicClassGenericRequirement_ConformingClass: PublicTypeUsedAsPublicClassGenericRequirement_Protocol {} 5 | 6 | public class PublicTypeUsedAsPublicClassGenericRequirementRetainer where T: PublicTypeUsedAsPublicClassGenericRequirement_Protocol { 7 | public init() {} 8 | } 9 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicClassSuperclass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicClassInheritingPublicClass_Superclass {} 4 | public class PublicClassInheritingPublicClass: PublicClassInheritingPublicClass_Superclass { 5 | public override init() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicFunctionGenericParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicTypeUsedAsPublicFunctionGenericParameter_ProtocolA {} 4 | public protocol PublicTypeUsedAsPublicFunctionGenericParameter_ProtocolB {} 5 | public class PublicTypeUsedAsPublicFunctionGenericParameter_ConformingClass: PublicTypeUsedAsPublicFunctionGenericParameter_ProtocolA, PublicTypeUsedAsPublicFunctionGenericParameter_ProtocolB {} 6 | 7 | public class PublicTypeUsedAsPublicFunctionGenericParameterRetainer { 8 | public init() {} 9 | public func retain(_ type: T.Type) {} 10 | } 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicFunctionGenericRequirement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol PublicTypeUsedAsPublicFunctionGenericRequirement_Protocol {} 4 | public class PublicTypeUsedAsPublicFunctionGenericRequirement_ConformingClass: PublicTypeUsedAsPublicFunctionGenericRequirement_Protocol {} 5 | 6 | public class PublicTypeUsedAsPublicFunctionGenericRequirementRetainer { 7 | public init() {} 8 | public func retain(_ type: T.Type) where T: PublicTypeUsedAsPublicFunctionGenericRequirement_Protocol {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicFunctionParameterDefaultValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct PublicTypeUsedAsPublicFunctionParameterDefaultValue { 4 | public static let somePublicValue = 1 5 | } 6 | 7 | public class PublicTypeUsedAsPublicFunctionParameterDefaultValueRetainer { 8 | public init() {} 9 | 10 | public func somePublicFunc(value: Int = PublicTypeUsedAsPublicFunctionParameterDefaultValue.somePublicValue) {} 11 | } 12 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicFunctionParameterType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicFunctionParameterType {} 4 | public class PublicTypeUsedAsPublicFunctionParameterTypeClosureArgument {} 5 | public class PublicTypeUsedAsPublicFunctionParameterTypeClosureReturnType {} 6 | 7 | public class PublicTypeUsedAsPublicFunctionParameterTypeRetainer { 8 | public init() {} 9 | public func retain1(type1: PublicTypeUsedAsPublicFunctionParameterType? = nil) {} 10 | public func retain2(type: ((PublicTypeUsedAsPublicFunctionParameterTypeClosureArgument) -> Void)? = nil) {} 11 | public func retain3(type: (() -> PublicTypeUsedAsPublicFunctionParameterTypeClosureReturnType)? = nil) {} 12 | } 13 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicFunctionReturnType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicFunctionReturnType {} 4 | public class PublicTypeUsedAsPublicFunctionReturnTypeClosureArgument {} 5 | public class PublicTypeUsedAsPublicFunctionReturnTypeClosureReturnType {} 6 | 7 | public class PublicTypeUsedAsPublicFunctionReturnTypeRetainer { 8 | public init() {} 9 | public func retain1() -> PublicTypeUsedAsPublicFunctionReturnType { 10 | PublicTypeUsedAsPublicFunctionReturnType() 11 | } 12 | 13 | public func retain2() -> (PublicTypeUsedAsPublicFunctionReturnTypeClosureArgument) -> Void { 14 | let closure: (PublicTypeUsedAsPublicFunctionReturnTypeClosureArgument) -> Void = { _ in } 15 | return closure 16 | } 17 | 18 | public func retain3() -> () -> PublicTypeUsedAsPublicFunctionReturnTypeClosureReturnType { 19 | let closure: () -> PublicTypeUsedAsPublicFunctionReturnTypeClosureReturnType = { 20 | PublicTypeUsedAsPublicFunctionReturnTypeClosureReturnType() 21 | } 22 | return closure 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicInitializerParameterType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicInitializerParameterType {} 4 | 5 | public class PublicTypeUsedAsPublicInitializerParameterTypeRetainer { 6 | public init(_ cls: PublicTypeUsedAsPublicInitializerParameterType? = nil) {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicPropertyInitializer.swift: -------------------------------------------------------------------------------- 1 | public struct PublicTypeUsedAsPublicPropertyInitializer_Simple {} 2 | public struct PublicTypeUsedAsPublicPropertyInitializer_GenericParameter: Hashable {} 3 | 4 | public class PublicTypeUsedAsPublicPropertyInitializer { 5 | public init() {} 6 | 7 | public var retain: [Any] { 8 | [simpleInitializer, genericParameter] 9 | } 10 | 11 | public var simpleInitializer = PublicTypeUsedAsPublicPropertyInitializer_Simple() 12 | public var genericParameter = Set() 13 | } 14 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicPropertyType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicPropertyType1 {} 4 | public class PublicTypeUsedAsPublicPropertyType2 {} 5 | public class PublicTypeUsedAsPublicPropertyType3 {} 6 | public class PublicTypeUsedAsPublicPropertyType4 {} 7 | public class PublicTypeUsedAsPublicPropertyType5 {} 8 | public struct PublicTypeUsedAsPublicPropertyGenericArgumentType: Hashable {} 9 | public class PublicTypeUsedAsPublicPropertyArrayType {} 10 | 11 | public class PublicTypeUsedAsPublicPropertyTypeRetainer { 12 | public init() {} 13 | 14 | public var retain: [Any?] { 15 | [retain1, retain2, retain3, retain4, retain5, retain6, retain7] 16 | } 17 | 18 | public var retain1: PublicTypeUsedAsPublicPropertyType1? 19 | public var retain2: Set? 20 | public var retain3: [PublicTypeUsedAsPublicPropertyArrayType] = [] 21 | public var (retain4, (retain5, retain6)): (PublicTypeUsedAsPublicPropertyType2, (PublicTypeUsedAsPublicPropertyType3, PublicTypeUsedAsPublicPropertyType4)) = (.init(), (.init(), .init())) 22 | public var retain7 = someFunc() 23 | 24 | private static func someFunc() -> PublicTypeUsedAsPublicPropertyType5 { .init() } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicSubscriptParameterType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicSubscriptParameterType {} 4 | 5 | public class PublicTypeUsedAsPublicSubscriptParameterTypeRetainer { 6 | public init() {} 7 | public subscript(_ type: PublicTypeUsedAsPublicSubscriptParameterType? = nil) -> Int { 0 } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedAsPublicSubscriptReturnType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedAsPublicSubscriptReturnType {} 4 | 5 | public class PublicTypeUsedAsPublicSubscriptReturnTypeRetainer { 6 | public init() {} 7 | public subscript(_ idx: Int = 0) -> PublicTypeUsedAsPublicSubscriptReturnType { .init() } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedInPublicClosure.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedInPublicClosureReturnType {} 4 | public class PublicTypeUsedInPublicClosureInputType {} 5 | 6 | public class PublicTypeUsedInPublicClosureRetainer { 7 | public var closure = { (a: PublicTypeUsedInPublicClosureInputType) -> PublicTypeUsedInPublicClosureReturnType in 8 | PublicTypeUsedInPublicClosureReturnType() 9 | } 10 | public init() {} 11 | } 12 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypeUsedInPublicFunctionBody.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PublicTypeUsedInPublicFunctionBody {} 4 | 5 | public class PublicTypeUsedInPublicFunctionBodyRetainer { 6 | public init() {} 7 | public func retain() { 8 | _ = PublicTypeUsedInPublicFunctionBody() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicTypealias.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias PublicTypealiasWithClosureType = (PublicTypealiasStruct) -> Void 4 | public struct PublicTypealiasStruct {} 5 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/PublicWrappedProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @propertyWrapper public struct PublicWrapper { 4 | public var wrappedValue: String 5 | 6 | public init(wrappedValue: String) { 7 | self.wrappedValue = wrappedValue 8 | } 9 | } 10 | 11 | public struct PublicWrappedProperty { 12 | @PublicWrapper public var wrappedProperty: String 13 | 14 | public init() { 15 | wrappedProperty = "" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/RedundantPublicTestableImportClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class RedundantPublicTestableImportClass { 4 | public init() {} 5 | public var testableProperty: String? 6 | } 7 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Sources/TargetA/RedundantPublicType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class RedundantPublicType { 4 | public func redundantPublicFunction() {} 5 | } 6 | 7 | public class RedundantPublicTypeRetainer { 8 | public init() {} 9 | public func retain() { 10 | let type = RedundantPublicType() 11 | type.redundantPublicFunction() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/AccessibilityProject/Tests/TestTarget/TestableImportTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | @testable import TargetA 4 | 5 | class TestableImportTest: XCTestCase { 6 | func testRedundant() { 7 | let cls = RedundantPublicTestableImportClass() 8 | print(cls.testableProperty ?? "") 9 | } 10 | 11 | func testNotRedundant() { 12 | // NotRedundantPublicTestableImportClass is also referenced from MainTarget, and is thus not redundant. 13 | let cls = NotRedundantPublicTestableImportClass() 14 | print(cls.testableProperty ?? "") 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/AccessibilityTests/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | @testable import TestShared 4 | 5 | var AccessibilityProjectPath: FilePath { 6 | ProjectRootPath.appending("Tests/AccessibilityTests/AccessibilityProject") 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/CrossModuleRetentionFixtures/testCrossModuleInheritanceWithSameName.swift: -------------------------------------------------------------------------------- 1 | import CrossModuleRetentionSupportFixtures 2 | 3 | class FixtureClass129: CrossModuleRetentionSupportFixtures.FixtureClass129 {} 4 | 5 | // Explicitly retain CrossModuleRetentionFixtures.FixtureClass129 as we can't use 6 | // --retain-public because it'll also retain CrossModuleRetentionSupportFixtures.FixtureClass129. 7 | // periphery:ignore 8 | class FixtureClass129Retainer { 9 | func retain() { 10 | _ = FixtureClass129.self 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/CrossModuleRetentionSupportFixtures/CrossModuleSuperclass.swift: -------------------------------------------------------------------------------- 1 | open class FixtureClass129 {} 2 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/DeclarationVisitorFixtures/FunctionFixture.swift: -------------------------------------------------------------------------------- 1 | func functionWithSimpleReturnType() -> Bool { 2 | return true 3 | } 4 | 5 | func functionWithTupleReturnType() -> (String, Int) { 6 | return ("", 1) 7 | } 8 | 9 | func functionWithPrefixedReturnType() -> Swift.String { 10 | return "" 11 | } 12 | 13 | func functionWithClosureReturnType() -> (Int) -> String { 14 | let closure: (Int) -> String = { String($0) } 15 | return closure 16 | } 17 | 18 | func functionWithArguments(a: String, b: Int) {} 19 | 20 | func functionWithGenericArgument(_ t: T.Type) where T: RawRepresentable {} 21 | 22 | @available(macOS 10.15.0, *) 23 | func functionWithSomeReturnType() -> some StringProtocol { "" } 24 | 25 | class FixtureClass1 { 26 | init(a: String, b: Int) {} 27 | } 28 | 29 | class FixtureClass2 { 30 | init(_ t: T.Type) where T: RawRepresentable {} 31 | } 32 | 33 | class FixtureClass3 { 34 | subscript(a: Int, b: String) -> Int { 0 } 35 | subscript(_ t: T.Type) -> Int where T: RawRepresentable { 0 } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/DeclarationVisitorFixtures/ImportFixture.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | // periphery:ignore 3 | import CoreFoundation 4 | import Swift // periphery:ignore 5 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/DeclarationVisitorFixtures/PropertyFixture.swift: -------------------------------------------------------------------------------- 1 | class PropertyVisitorTestFixture { 2 | struct CustomType: Hashable { 3 | struct NestedType { 4 | typealias NestedScalar = Int 5 | } 6 | } 7 | 8 | let implicitTypeProperty = "" 9 | let boolProperty: Bool = true 10 | let optionalBoolProperty: Bool? = true 11 | let arrayLiteralProperty: [CustomType] = [] 12 | let optionalArrayLiteralProperty: [CustomType]? = [] 13 | let genericProperty: Set = [] 14 | let tupleProperty: (Int, String) = (1, "2") 15 | let (destructuringPropertyA, destructuringPropertyB): (CustomType, String) = (.init(), "1") 16 | let (destructuringPropertyC, 17 | destructuringPropertyD, 18 | destructuringPropertyE): 19 | (CustomType.NestedType, CustomType.NestedType.NestedScalar, Swift.String) = (.init(), 1, "1") 20 | let (implicitDestructuringPropertyA, implicitDestructuringPropertyB) = (CustomType(), "1") 21 | let multipleBindingPropertyA: Int = 1, multipleBindingPropertyB: String = "" 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ExternalModuleFixtures/ExternalAssociatedType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol ExternalAssociatedType { 4 | associatedtype Value 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ExternalModuleFixtures/ExternalTestCase.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | open class ExternalTestCase: XCTestCase {} 5 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testDoesNotRetainMembersOfObjcAnnotatedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc class FixtureClass24: NSObject { 4 | var someVar: String? 5 | func someMethod() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testDoesNotRetainObjcAnnotatedWithoutOption.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc class FixtureClass23: NSObject {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testObjcMembersAnnotationRetainsMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers class FixtureClass25: NSObject { 4 | var someVar: String? 5 | func someMethod() {} 6 | private func somePrivateMethod() {} // @objcMembers doesn't apply to private methods. 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testRetainsImplicitlyObjcAccessibleClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass126: NSObject {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testRetainsObjcAnnotatedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc class FixtureClass21: NSObject {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testRetainsObjcAnnotatedMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc class FixtureClass22: NSObject { 4 | @objc var someVar: String? 5 | @objc func someMethod() {} 6 | @objc private func somePrivateMethod() {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testRetainsOptionalProtocolMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc protocol FixtureProtocol127 { 4 | @objc optional func optionalFunc() 5 | } 6 | 7 | public class FixtureClass127: FixtureProtocol127 { 8 | public func someFunc() { 9 | let p: FixtureProtocol127? = nil 10 | p?.optionalFunc?() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAccessibleRetentionFixtures/testRetainsOptionalProtocolMethodImplementedInSubclass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class FixtureClass125Base: NSObject, FileManagerDelegate {} 4 | 5 | public class FixtureClass125: FixtureClass125Base { 6 | func fileManager(_ fileManager: FileManager, shouldRemoveItemAtPath path: String) -> Bool { 7 | false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAnnotatedRetentionFixtures/testRetainsAnnotatedExtensionDeclarations.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc class FixtureClass214: NSObject {} 4 | 5 | @objc extension FixtureClass214 { 6 | public func methodInExtension() {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAnnotatedRetentionFixtures/testRetainsExtensionDeclarationsOnObjcMembersAnnotatedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers class FixtureClass217 {} 4 | 5 | extension FixtureClass217 { 6 | func methodInExtension() {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAnnotatedRetentionFixtures/testRetainsObjcProtocolConformingDeclarations.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc protocol FixtureProtocol216 { 4 | func methodInProtocol() 5 | } 6 | 7 | @objc class FixtureClass216: NSObject, FixtureProtocol216 { 8 | func methodInProtocol() {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/ObjcAnnotatedRetentionFixtures/testRetainsObjcProtocolMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc protocol FixtureProtocol215 { 4 | func methodInProtocol() 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testAccessibility.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass31 { 4 | public required init(arg: Int) {} 5 | 6 | open func openFunc() {} 7 | 8 | public class FixtureClass31Inner { 9 | private func privateFunc() {} 10 | } 11 | } 12 | 13 | private class FixtureClass32 { 14 | public var publicVar: String? 15 | } 16 | 17 | class FixtureClass33 {} 18 | 19 | enum Enum1 { 20 | public func publicEnumFunc() {} 21 | } 22 | 23 | public class FixtureClass50 {} 24 | 25 | extension FixtureClass50 { 26 | public func publicMethodInExtension() {} 27 | } 28 | 29 | public extension FixtureClass50 { 30 | static let staticVarInExtension: String? = "" 31 | func methodInPublicExtension() {} 32 | static func staticMethodInPublicExtension() {} 33 | private func privateMethodInPublicExtension() {} 34 | internal func internalMethodInPublicExtension() {} 35 | } 36 | 37 | public extension Array { 38 | func methodInExternalStructTypeExtension() {} 39 | } 40 | 41 | public extension Sequence { // protocol 42 | func methodInExternalProtocolTypeExtension() {} 43 | } 44 | 45 | public extension Notification.Name { 46 | static let CustomNotification = Notification.Name("CustomNotification") 47 | } 48 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testAssignOnlyPropertyAnalysisDoesNotApplyToProtocolProperties.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol124 { 4 | var someProperty: Int? { get set } 5 | } 6 | 7 | class FixtureClass124: FixtureProtocol124 { 8 | var someProperty: Int? 9 | } 10 | 11 | public class FixtureClass124Retainer { 12 | public func retain() { 13 | var cls: FixtureProtocol124 = FixtureClass124() 14 | cls.someProperty = 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testCircularTypeInheritance.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass211 {} 4 | extension FixtureClass211: FixtureProtocol211 {} 5 | protocol FixtureProtocol211: FixtureClass211 {} 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testClassRetainedByUnusedInstanceVariable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass72 {} 4 | 5 | public class FixtureClass71 { 6 | var someVar: FixtureClass72? 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testCommentCommandOverride.swift: -------------------------------------------------------------------------------- 1 | /// periphery:override location="some/other/file.swift:12:34" kind="banana" 2 | public class FixtureClass136 {} 3 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testConformanceToExternalProtocolIsRetained.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass55: Equatable { 4 | public static func == (lhs: FixtureClass55, rhs: FixtureClass55) -> Bool { 5 | return true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testConformingProtocolReferencedByNonReferencedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol1 {} 4 | class FixtureClass6 {} 5 | extension FixtureClass6: FixtureProtocol1 {} 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testCrossReferencedClasses.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass14 { 4 | func someMethod() {} 5 | } 6 | 7 | class FixtureClass15 { 8 | let a: FixtureClass14 9 | 10 | init(a: FixtureClass14) { 11 | self.a = a 12 | } 13 | 14 | func someMethod() { 15 | a.someMethod() 16 | } 17 | } 18 | 19 | class FixtureClass16 { 20 | let b: FixtureClass15 21 | 22 | init(b: FixtureClass15) { 23 | self.b = b 24 | } 25 | 26 | func someMethod() { 27 | b.someMethod() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testCustomConstructorWithLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass108 { 4 | public func someMethod() { 5 | let title = [String](title: "Title").first 6 | print(title ?? "") 7 | } 8 | } 9 | 10 | extension Array where Element == String { 11 | init(title: String) { 12 | self = [title] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDeeplyNestedClassReferences.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass17 { 4 | func someMethod() {} 5 | 6 | class FixtureClass18 { 7 | let a: FixtureClass17 8 | 9 | init(a: FixtureClass17) { 10 | self.a = a 11 | } 12 | 13 | func someMethod() { 14 | a.someMethod() 15 | } 16 | 17 | class FixtureClass19 { 18 | let b: FixtureClass18 19 | 20 | init(b: FixtureClass18) { 21 | self.b = b 22 | } 23 | 24 | func someMethod() { 25 | b.someMethod() 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDoesNotRetainDescendantsOfUnusedDeclaration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Outer retained class just to ensure we're not only checking root declarations. 4 | public class FixtureClass99Outer { 5 | class FixtureClass99 { 6 | var someVar: String = "" 7 | 8 | init() { 9 | someMethod() 10 | } 11 | 12 | func someMethod() { 13 | print(someVar) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDoesNotRetainLazyProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass36 { 4 | private var someVar = "test" 5 | 6 | lazy var someLazyVar: String = { 7 | return someVar 8 | }() 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDoesNotRetainProtocolMembersImplementedByExternalType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol110 { 4 | func sync(execute work: () -> Void) // Implementation provided by DispatchQueue, used 5 | func async(execute item: DispatchWorkItem) // Implementation provided by DispatchQueue, unused 6 | func customImplementedByExtensionUsed() 7 | func customImplementedByExtensionUnused() 8 | } 9 | 10 | extension FixtureProtocol110 { 11 | func customImplementedByExtensionUsed() {} 12 | func customImplementedByExtensionUnused() {} 13 | } 14 | 15 | extension DispatchQueue: FixtureProtocol110 { 16 | func sync(execute item: DispatchWorkItem) {} 17 | func async(execute item: DispatchWorkItem) {} 18 | func customImplementedByExtensionUsed() {} 19 | func customImplementedByExtensionUnused() {} 20 | } 21 | 22 | public class FixtureClass110Retainer { 23 | public func someFunc() { 24 | let queue: FixtureProtocol110 = DispatchQueue(label: "FixtureClass110") 25 | queue.sync {} 26 | queue.customImplementedByExtensionUsed() 27 | DispatchQueue.global().async {} 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDoesNotRetainProtocolMethodInSubclassWithDefaultImplementation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol83: AnyObject { 4 | func protocolMethod() 5 | } 6 | 7 | extension FixtureProtocol83 { 8 | func protocolMethod() {} 9 | } 10 | 11 | class FixtureClass83: FixtureProtocol83 {} 12 | 13 | class FixtureClass84: FixtureClass83 { 14 | func protocolMethod() {} 15 | } 16 | 17 | public class FixtureClass85 { 18 | private let cls: FixtureClass84 19 | weak var delegate: FixtureProtocol83? 20 | 21 | init() { 22 | cls = FixtureClass84() 23 | } 24 | 25 | public func someMethod() { 26 | delegate?.protocolMethod() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testDoesNotRetainUnusedProtocolMethodWithDefaultImplementation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol84 { 4 | func usedMethod() 5 | func unusedMethod() 6 | } 7 | 8 | extension FixtureProtocol84 { 9 | func usedMethod() {} 10 | func unusedMethod() {} 11 | } 12 | 13 | public class FixtureClass86: FixtureProtocol84 { 14 | public func someMethod() { 15 | usedMethod() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testExternalXCTestCaseClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ExternalModuleFixtures 3 | 4 | class FixtureClass217: ExternalTestCase { 5 | func testSomeTestCase() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testFunctionAccessorsRetainReferences.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass63 { 4 | var referencedByGetter: String? 5 | var referencedBySetter: String? 6 | var referencedByDidSet: String? 7 | 8 | public var someVar: String? { 9 | get { 10 | return referencedByGetter 11 | } 12 | set { 13 | referencedBySetter = newValue 14 | } 15 | } 16 | 17 | public var someOtherVar: String? { 18 | didSet { 19 | referencedByDidSet = someOtherVar 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testIdenticallyNamedVarsInStaticAndInstanceScopes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass95 { 4 | private static var someVar: String! 5 | 6 | init() { 7 | FixtureClass95.someVar = "hello" 8 | } 9 | 10 | private var someVar: String! { 11 | return FixtureClass95.someVar 12 | } 13 | 14 | public func testSomething() { 15 | print(someVar ?? "") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testIgnoreAllComment.swift: -------------------------------------------------------------------------------- 1 | // periphery:ignore:all 2 | 3 | import Foundation 4 | 5 | public class Fixture115 { 6 | func someFunc(param: String) {} 7 | } 8 | public class Fixture116 {} 9 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testIgnoreUnusedParamInUnusedFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass105 { 4 | func unused(param: String) {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testInstanceVarReferencedInClosure.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass69 { 4 | private var someVar: String? 5 | 6 | public func someMethod() { 7 | performClosure { [weak self] in 8 | guard let strongSelf = self else { return } 9 | strongSelf.someVar = "test" 10 | } 11 | } 12 | 13 | private func performClosure(block: () -> Void) { 14 | block() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testIsolatedCyclicRootReferences.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass90 { 4 | func someMethod() { 5 | FixtureClass91().someMethod() 6 | } 7 | } 8 | 9 | class FixtureClass91 { 10 | func someMethod() { 11 | FixtureClass90().someMethod() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testMainActorAnnotation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @MainActor class FixtureClass132 { 4 | init(value: Int) {} 5 | let text = "" 6 | } 7 | 8 | public class FixtureClass133 { 9 | @MainActor let main = FixtureClass132(value: 1) 10 | 11 | @MainActor public func retain() { 12 | _ = main.text 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNestedDeclarations.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass102 { 4 | public func perform() { 5 | var nestedVar: Bool { 6 | nested2() 7 | return true 8 | } 9 | 10 | func nestedFunc() { 11 | nested1() 12 | } 13 | 14 | nestedFunc() 15 | print(nestedVar) 16 | } 17 | 18 | func nested1() {} 19 | func nested2() {} 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNonReferencedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass1 {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNonReferencedFreeFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func someFunction() {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNonReferencedMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass2 { 4 | func someMethod() {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNonReferencedMethodInClassExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass4 {} 4 | extension FixtureClass4 { 5 | func someMethod() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testNonReferencedProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass3 { 4 | static var someStaticVar: String? 5 | var someVar: String? 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testOverriddenMethodRetainedBySuper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass82Base { 4 | func someMethod() {} 5 | } 6 | 7 | class FixtureClass82Sub: FixtureClass82Base { 8 | override func someMethod() { 9 | super.someMethod() 10 | } 11 | } 12 | 13 | public class FixtureClass82Retainer { 14 | var cls: FixtureClass82Sub? 15 | 16 | public func retainingMethod() { 17 | cls?.someMethod() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testPropertyReferencedByComputedValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass78 { 4 | public var someVar: String { 5 | someOtherVar 6 | } 7 | 8 | var someOtherVar: String { "" } 9 | var unusedVar: String { "" } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolConformedByStaticMethodOutsideExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass64 { 4 | private let retainer: FixtureClass65 5 | 6 | init() { 7 | retainer = FixtureClass65() 8 | } 9 | } 10 | 11 | class FixtureClass65: Equatable { 12 | } 13 | 14 | func == (lhs: FixtureClass65, rhs: FixtureClass65) -> Bool { 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolImplementInClassAndExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol98 { 4 | func method1() 5 | func method2() 6 | } 7 | 8 | class FixtureClass98 { 9 | func method1() {} 10 | } 11 | 12 | extension FixtureClass98: FixtureProtocol98 { 13 | func method2() {} 14 | } 15 | 16 | public class FixtureClass98Retainer { 17 | public func someMethod() { 18 | let a: FixtureProtocol98 = FixtureClass98() 19 | a.method1() 20 | a.method2() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolMethodCalledIndirectlyByProtocolIsRetained.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol52 { 4 | init() 5 | func protocolMethod() 6 | } 7 | 8 | class FixtureClass52: FixtureProtocol52 { 9 | required init() {} 10 | func protocolMethod() {} 11 | } 12 | 13 | public class FixtureClass53 { 14 | private let things: [FixtureProtocol52.Type] = [FixtureClass52.self] 15 | 16 | init() { 17 | things.forEach { 18 | let cls = $0.init() 19 | cls.protocolMethod() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolMethodsImplementedOnlyInExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol115 { } 4 | 5 | extension FixtureProtocol115 { 6 | func used() { } 7 | func unused() { } 8 | } 9 | 10 | public class FixtureProtocol115Retainer: FixtureProtocol115 { 11 | public func someMethod() { 12 | used() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolUsedAsExistentialType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol119 { 4 | func protocolFunc() 5 | } 6 | 7 | public class FixtureClass119 { 8 | func existentialParameter(param: FixtureProtocol119?) { 9 | print(param ?? "") 10 | } 11 | 12 | public func retainer() { 13 | let value: FixtureProtocol119? = nil 14 | existentialParameter(param: value) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testProtocolVarReferencedByProtocolMethodInSameClassIsRedundant.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol51 { 4 | var protocolVar: String { get } 5 | func protocolMethod() 6 | } 7 | 8 | public class FixtureClass51: FixtureProtocol51 { 9 | var protocolVar: String { 10 | return "hi" 11 | } 12 | 13 | func protocolMethod() { 14 | print(protocolVar) 15 | } 16 | 17 | public func publicMethod() { 18 | protocolMethod() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testPublicProtocolMethodImplementedOnlyInExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FixtureProtocol116 { } 4 | 5 | extension FixtureProtocol116 { 6 | public func used() { } 7 | func unused() { } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRedundantProtocolThatInheritsAnyObject.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol121: AnyObject {} 4 | protocol FixtureProtocol122: Any {} 5 | 6 | public class FixtureClass121: FixtureProtocol121 {} 7 | public class FixtureClass122: FixtureProtocol122 {} 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRedundantProtocolThatInheritsForeignProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol118: Equatable {} 4 | public class FixtureClass118: FixtureProtocol118 { 5 | public static func == (lhs: FixtureClass118, rhs: FixtureClass118) -> Bool { 6 | true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRedundantProtocolThatInheritsOtherProtocols.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol128_Inherited { 4 | func funcA() 5 | } 6 | 7 | protocol FixtureProtocol128: FixtureProtocol128_Inherited { 8 | func funcB() 9 | } 10 | 11 | public class FixtureClass134: FixtureProtocol128 { 12 | func funcA() {} 13 | func funcB() {} 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRequiredInitInSubclass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass77Base { 4 | required init(a: String) {} 5 | required init(b: String) {} 6 | } 7 | 8 | class FixtureClass77: FixtureClass77Base { 9 | required init(c: String) { 10 | super.init(a: "a") 11 | } 12 | 13 | required init(a: String) { 14 | fatalError("init(a:) has not been implemented") 15 | } 16 | 17 | required init(b: String) { 18 | fatalError("init(b:) has not been implemented") 19 | } 20 | } 21 | 22 | public class FixtureClass77Retainer { 23 | let cls1: FixtureClass77 24 | let cls2: FixtureClass77Base 25 | 26 | init() { 27 | cls1 = FixtureClass77(c: "c") 28 | cls2 = FixtureClass77Base(b: "c") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainImplicitDeclarations.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct FixtureStruct2 { 4 | let someVar: String 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainOverridingMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass67 { 4 | func someMethod() {} 5 | 6 | public func retainingMethod() { 7 | someMethod() 8 | } 9 | } 10 | 11 | public class FixtureClass68: FixtureClass67 { 12 | override func someMethod() {} 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainPublicMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass26 { 4 | public func funcPublic() {} 5 | private func funcPrivate() {} 6 | internal func funcInternal() {} 7 | open func funcOpen() {} 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainUnusedProtocolFuncParams.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FixtureProtocol107 { 4 | func myFunc(param: String) 5 | } 6 | 7 | public extension FixtureProtocol107 { 8 | func myFunc(param: String) {} 9 | } 10 | 11 | public class FixtureClass107Class1: FixtureProtocol107 { 12 | public func myFunc(param: String) {} 13 | } 14 | 15 | public class FixtureClass107Class2: FixtureProtocol107 { 16 | public func myFunc(param: String) {} 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainedProtocolDoesNotRetainImplementationInUnusedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol200 { 4 | func protocolFunc() 5 | } 6 | 7 | class FixtureClass200 {} 8 | 9 | class FixtureClass201 {} 10 | 11 | extension FixtureClass200: FixtureProtocol200 { 12 | func protocolFunc() { 13 | print(FixtureClass201.self) 14 | } 15 | } 16 | 17 | public class FixtureClass202 { 18 | public func someFunc() { 19 | // Retain the protocol only 20 | let x: FixtureProtocol200? = nil 21 | x?.protocolFunc() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainedProtocolDoesNotRetainUnusedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FixtureProtocol57 { 4 | func protocolMethod() 5 | } 6 | 7 | class FixtureClass57: FixtureProtocol57 { 8 | func protocolMethod() {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsAssociatedTypeTypeAlias.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol Fixture87State { 4 | associatedtype AssociatedType = Void 5 | } 6 | 7 | struct Fixture87AssociatedType {} 8 | 9 | enum Fixture87MyState: Fixture87State { 10 | typealias AssociatedType = Fixture87AssociatedType 11 | } 12 | 13 | class Fixture87StateMachine { 14 | func someFunction(_ type: T.AssociatedType) {} 15 | } 16 | 17 | public class FixtureClass87Usage { 18 | public func somePublicFunction() { 19 | let sm = Fixture87StateMachine() 20 | sm.someFunction(Fixture87AssociatedType()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsCallAsFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct FixtureStruct1 { 4 | var base: Int 5 | func callAsFunction(_ x: Int) -> Int { 6 | return base + x 7 | } 8 | } 9 | 10 | public struct FixtureStruct1Retainer { 11 | public func retain() { 12 | let add3 = FixtureStruct1(base: 3) 13 | _ = add3(10) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsCodableProperties.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct FixtureStruct14: Codable { 4 | let unused: Int 5 | 6 | init(unused: Int) { 7 | self.unused = unused 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsConstructorOfGenericClassAndStruct.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass61 { 4 | init(someVar: T) {} 5 | } 6 | 7 | struct FixtureStruct61 { 8 | let someVar: T 9 | 10 | init(someVar: T) { 11 | self.someVar = someVar 12 | } 13 | } 14 | 15 | public class FixtureClass62 { 16 | private let classProperty: FixtureClass61 17 | private let structProperty: FixtureStruct61 18 | 19 | public init() { 20 | classProperty = FixtureClass61(someVar: 1) 21 | structProperty = FixtureStruct61(someVar: 1) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsDefaultConstructor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass41 { 4 | init() {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsDestructor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass40 { 4 | deinit {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsDynamicMemberLookupSubscript.swift: -------------------------------------------------------------------------------- 1 | @dynamicMemberLookup 2 | public struct FixtureStruct7 { 3 | subscript(dynamicMember member: String) -> String { 4 | "" 5 | } 6 | 7 | subscript(other: String) -> String { 8 | "" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsDynamicReplacement.swift: -------------------------------------------------------------------------------- 1 | struct FixtureStruct8 { 2 | dynamic static func originalStaticMethod() {} 3 | dynamic func originalMethod() {} 4 | dynamic var originalProperty: Int { 0 } 5 | dynamic subscript(original index: Int) -> Int { 0} 6 | } 7 | 8 | extension FixtureStruct8 { 9 | @_dynamicReplacement(for: originalStaticMethod) 10 | static func replacementStaticMethod() {} 11 | 12 | @_dynamicReplacement(for: originalMethod) 13 | func replacementMethod() {} 14 | 15 | @_dynamicReplacement(for: originalProperty) 16 | var replacementProperty: Int { 0 } 17 | 18 | @_dynamicReplacement(for: subscript(original:)) 19 | subscript(replacement index: Int) -> Int { 0} 20 | } 21 | 22 | public struct FixtureStruct8Retainer { 23 | public func retain() { 24 | _ = FixtureStruct8.originalStaticMethod() 25 | let strct = FixtureStruct8() 26 | strct.originalMethod() 27 | _ = strct.originalProperty 28 | _ = strct[original: 0] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsEncodableProperties.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct FixtureStruct15: Encodable { 4 | let unused: Int 5 | 6 | init(unused: Int) { 7 | self.unused = unused 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsExtendedExternalTypeAlias.swift: -------------------------------------------------------------------------------- 1 | private typealias Fixture215TypeAlias = Int 2 | extension Fixture215TypeAlias { 3 | var someExtensionProperty: Int { 0 } 4 | } 5 | 6 | public class FixtureClass215Retainer { 7 | public func retain() { 8 | _ = 0.someExtensionProperty 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsExtendedProtocolTypeAlias.swift: -------------------------------------------------------------------------------- 1 | public protocol FixtureProtocol216 {} 2 | public class FixtureClass216: FixtureProtocol216 {} 3 | 4 | private typealias Fixture216TypeAlias = FixtureProtocol216 5 | extension Fixture216TypeAlias { 6 | var someExtensionProperty: Int { 0 } 7 | } 8 | 9 | public class FixtureClass216Retainer { 10 | public func retain() { 11 | let cls: FixtureProtocol216 = FixtureClass216() 12 | _ = cls.someExtensionProperty 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsExtendedTypeAlias.swift: -------------------------------------------------------------------------------- 1 | public class FixtureClass214 {} 2 | 3 | private typealias Fixture214TypeAlias = FixtureClass214 4 | extension Fixture214TypeAlias { 5 | var someExtensionProperty: Int { 0 } 6 | } 7 | 8 | public class FixtureClass214Retainer { 9 | public func retain() { 10 | _ = FixtureClass214().someExtensionProperty 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsExternalAssociatedTypeTypeAlias.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ExternalModuleFixtures 3 | 4 | struct Fixture110: ExternalAssociatedType { 5 | typealias Value = Void 6 | } 7 | 8 | public struct Fixture110Retainer { 9 | public func someFunc() { 10 | print(Fixture110.self) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsExternalTypeExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Sequence { 4 | func someMethod() {} 5 | } 6 | 7 | extension Array { 8 | func someMethod() {} 9 | } 10 | 11 | extension NumberFormatter { 12 | func someMethod() {} 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsFilesOption.swift: -------------------------------------------------------------------------------- 1 | class FixtureClass100 {} 2 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsForeignProtocolParameters.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass103: Codable { 4 | public required init(from decoder: Decoder) throws {} 5 | 6 | public func encode(to encoder: Encoder) throws {} 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsForeignProtocolParametersInSubclass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass109: NSCopying { 4 | public func copy(with zone: NSZone?) -> Any { 5 | FixtureClass109() 6 | } 7 | } 8 | 9 | public class FixtureClass109Subclass: FixtureClass109 { 10 | public override func copy(with zone: NSZone?) -> Any { 11 | FixtureClass109Subclass() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsFunctionParametersOnProtocolMembersImplementedByExternalType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol125 { 4 | func object(forKey key: String) -> Any? 5 | } 6 | 7 | extension UserDefaults: FixtureProtocol125 {} 8 | 9 | public class FixtureProtocol125Retainer { 10 | public func retain() { 11 | let defaults: FixtureProtocol125 = UserDefaults.standard 12 | _ = defaults.object(forKey: "") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsFunctionParametersOnUnimplementedProtocolMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol126 { 4 | func unimplementedFunc(param: String) 5 | } 6 | 7 | extension FixtureProtocol126 { 8 | // A default implementation isn't considered a true implementation. 9 | func unimplementedFunc(param: String) {} 10 | } 11 | 12 | public class FixtureProtocol126Retainer { 13 | public func retain() { 14 | let v: FixtureProtocol126? = nil 15 | v?.unimplementedFunc(param: "") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsGenericProtocolExtensionMembers.swift: -------------------------------------------------------------------------------- 1 | public protocol FixtureProtocol38 { 2 | associatedtype Value 3 | } 4 | 5 | public extension FixtureProtocol38 { 6 | func someFunc() {} 7 | } 8 | 9 | public protocol FixtureProtocol39 { 10 | associatedtype Value 11 | associatedtype Value2 12 | } 13 | 14 | public extension FixtureProtocol39 { 15 | func someFunc() {} 16 | } 17 | 18 | public protocol FixtureProtocol40 { 19 | associatedtype Value 20 | associatedtype Value2 21 | } 22 | 23 | public extension FixtureProtocol40 where Value == Int, Value2 == Int { 24 | func someFunc() {} 25 | } 26 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsGenericType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FixtureProtocol37 {} 4 | 5 | public class FixtureClass37 { 6 | public func someFunc(foo: T) { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsInferredAssociatedType.swift: -------------------------------------------------------------------------------- 1 | private struct FixtureStruct120_Collection { 2 | let items: [P.AssociatedType] 3 | } 4 | 5 | private protocol FixtureProtocol120 { 6 | associatedtype AssociatedType 7 | } 8 | 9 | private struct FixtureStruct120: FixtureProtocol120 { 10 | enum AssociatedType: String { 11 | case hello 12 | } 13 | let result = FixtureStruct120_Collection(items: [.hello]) 14 | } 15 | 16 | public class Fixture120Retainer { 17 | public func retain() { 18 | _ = FixtureStruct120().result 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsInheritedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass11 {} 4 | class FixtureClass12: FixtureClass11 {} 5 | 6 | public class FixtureClass13 { 7 | var cls: FixtureClass12? 8 | 9 | public func retainer() { 10 | print(cls ?? "") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsInitializerCalledOnTypeAlias.swift: -------------------------------------------------------------------------------- 1 | class FixtureClass219 { 2 | init(foo: Int) {} 3 | } 4 | 5 | public class FixtureClass219Retainer { 6 | typealias FixtureClass219Aliased = FixtureClass219 7 | 8 | public func retain() { 9 | _ = Self.FixtureClass219Aliased(foo: 1) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsMethodDefinedInExtensionOnStandardType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension String { 4 | var trimmed: String { 5 | return trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 6 | } 7 | } 8 | 9 | public class FixtureClass35 { 10 | public func testSomething() { 11 | print("hello".trimmed) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsNonProtocolMethodDefinedInProtocolExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol66 { 4 | func protocolMethod() 5 | } 6 | 7 | extension FixtureProtocol66 { 8 | func nonProtocolMethod() {} 9 | } 10 | 11 | public class FixtureClass66: FixtureProtocol66 { 12 | func protocolMethod() {} 13 | 14 | public func someMethod() { 15 | nonProtocolMethod() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsOpenClassParameters.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class FixtureClass112 { 4 | open func doSomething(with value: Int) { } 5 | } 6 | 7 | public class FixtureClass112Retainer { 8 | var instance: FixtureClass112? 9 | 10 | public func doSomething() { 11 | instance?.doSomething(with: .random(in: 0...10)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsPropertyWrappers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @propertyWrapper class Fixture111Wrapper { 4 | var projectedValue: Bool = false 5 | 6 | var wrappedValue: String { 7 | didSet { wrappedValue = wrappedValue.capitalized } 8 | } 9 | 10 | init(wrappedValue: String, block: () -> Void) { 11 | self.wrappedValue = wrappedValue.capitalized 12 | } 13 | } 14 | 15 | public class Fixture111 { 16 | @Fixture111Wrapper(block: buildBlock()) 17 | var someVar: String = "" 18 | 19 | static func buildBlock() -> () -> Void { 20 | return {} 21 | } 22 | } 23 | 24 | public class Fixture111Retainer { 25 | public func someFunc() { 26 | print(Fixture111().$someVar) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsProtocolExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FixtureProtocol81 { 4 | func protocolMethod() 5 | } 6 | 7 | extension FixtureProtocol81 { 8 | func protocolMethod() {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsProtocolMethodImplementedInExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol80 { 4 | func protocolMethod() 5 | func protocolMethodWithUnusedDefault() 6 | } 7 | 8 | extension FixtureProtocol80 { 9 | func protocolMethod() {} 10 | func protocolMethodWithUnusedDefault() {} 11 | } 12 | 13 | public class FixtureClass80: FixtureProtocol80 { 14 | func protocolMethodWithUnusedDefault() {} 15 | 16 | public func someMethod() { 17 | protocolMethod() 18 | } 19 | } 20 | 21 | public class FixtureProtocol80Retainer { 22 | var proto: FixtureProtocol80? 23 | 24 | public init() { 25 | proto?.protocolMethodWithUnusedDefault() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsProtocolMethodsImplementedInSuperclasss.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol97 { 4 | var someProtocolVar: Int { get } 5 | func someProtocolMethod1() 6 | func someProtocolMethod2() 7 | func someUnusedProtocolMethod() 8 | } 9 | 10 | class FixtureClass97Base1 { 11 | func someProtocolMethod1() {} 12 | var someProtocolVar: Int = 0 13 | } 14 | 15 | class FixtureClass97Base2: FixtureClass97Base1 { 16 | func someProtocolMethod2() {} 17 | func someUnusedProtocolMethod() {} 18 | } 19 | 20 | class FixtureClass97: FixtureClass97Base2, FixtureProtocol97 {} 21 | 22 | public class FixtureClass97Retainer { 23 | public func someMethod() { 24 | let cls: FixtureProtocol97 = FixtureClass97() 25 | cls.someProtocolMethod1() 26 | cls.someProtocolMethod2() 27 | print(cls.someProtocolVar) 28 | // someUnusedProtocolMethod() not used 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsProtocolsViaCompositeTypealias.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol Fixture200 {} 4 | protocol Fixture201 {} 5 | typealias Fixture202 = Fixture200 & Fixture201 6 | 7 | public struct Fixture203: Fixture202 {} 8 | 9 | public struct Fixture204 { 10 | public func someFunc() { 11 | let x: Fixture202 = Fixture203() 12 | print(x) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsPublicEnumCases.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum FixtureEnum179 { 4 | case someCase 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsReferencedMethodViaReceiver.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass113 { 4 | static func make() -> Self { 5 | return self.init() 6 | } 7 | 8 | required init() {} 9 | } 10 | 11 | public class FixtureClass113Retainer { 12 | let instance = FixtureClass113.make() 13 | 14 | public func retainerFunc() { 15 | print(instance) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsSelfReferencedMethodViaReceiver.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass92 { 4 | func someFunc() {} 5 | 6 | func someOtherFunc() { 7 | let a = FixtureClass92() 8 | a.someFunc() 9 | } 10 | } 11 | 12 | public class FixtureClass92Retainer { 13 | public func someFunc() { 14 | FixtureClass92().someOtherFunc() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsStringInterpolationAppendInterpolation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String.StringInterpolation { 4 | mutating func appendInterpolation(test value: Int) { 5 | appendInterpolation(value) 6 | } 7 | } 8 | 9 | public struct Fixture112 { 10 | public func someFunc() { 11 | print("test: \(test: 1)") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsSwiftTestingDeclarations.swift: -------------------------------------------------------------------------------- 1 | #if canImport(Testing) 2 | import Testing 3 | 4 | @Test func swiftTestingFreeFunction() {} 5 | 6 | class SwiftTestingClass { 7 | @Test("displayName") func instanceMethod() {} 8 | @Test class func classMethod() {} 9 | @Test static func staticMethod() {} 10 | } 11 | 12 | @Suite struct SwiftTestingStructWithSuite { 13 | @Test func instanceMethod() {} 14 | @Test("displayName") static func staticMethod() {} 15 | } 16 | 17 | @Suite("displayName") class SwiftTestingClassWithSuite { 18 | @Test func instanceMethod() {} 19 | @Test("displayName") class func classMethod() {} 20 | @Test static func staticMethod() {} 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testRetainsUsedProtocolThatInheritsForeignProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol96: Comparable { 4 | var usedValue: Int { get } 5 | var unusedValue: Int { get } 6 | } 7 | 8 | extension FixtureProtocol96 { 9 | static func < (lhs: Self, rhs: Self) -> Bool { 10 | return lhs.usedValue <= rhs.usedValue 11 | } 12 | } 13 | 14 | class FixtureClass96: NSObject, FixtureProtocol96 { 15 | var usedValue: Int = 0 16 | var unusedValue: Int = 0 17 | } 18 | 19 | public class FixtureClass96Retainer { 20 | public func sortThings() { 21 | let things = [ 22 | FixtureClass96(), 23 | FixtureClass96() 24 | ] 25 | print(things.sorted()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSelfReferencedClass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass8 { 4 | let a: FixtureClass8 5 | 6 | init(a: FixtureClass8) { 7 | self.a = a 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSelfReferencedConstructor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct FixtureStruct3 { 4 | static let instance = Self(value: 1) 5 | init(value: Int) {} 6 | } 7 | 8 | struct FixtureStruct4 { 9 | init(value: Int) {} 10 | } 11 | 12 | extension FixtureStruct4 { 13 | static func someFunc() { 14 | _ = Self(value: 1) 15 | } 16 | } 17 | 18 | struct FixtureStruct5 { 19 | init(value: Int) {} 20 | } 21 | 22 | public struct FixtureStruct3Retainer { 23 | public func retainer() { 24 | _ = FixtureStruct3.instance 25 | FixtureStruct4.someFunc() 26 | _ = FixtureStruct5.self 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSelfReferencedProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass39 { 4 | let someVar: String 5 | 6 | public init() { 7 | someVar = "Hello" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSelfReferencedRecursiveMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass9 { 4 | var flag = true 5 | 6 | func recursive() { 7 | if flag { 8 | recursive() 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSimpleAssignOnlyPropertyNameConflict.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass131 { 4 | static var someProperty: String? 5 | var someProperty: String 6 | 7 | public init() { 8 | someProperty = "" 9 | Self.someProperty = "" 10 | } 11 | 12 | public func someMethod() { 13 | _ = Self.someProperty 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testSimpleRedundantProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol114 { 4 | func someFunc() 5 | } 6 | 7 | public class FixtureClass114: FixtureProtocol114 { 8 | func someFunc() {} 9 | } 10 | 11 | public class FixtureClass115 {} 12 | 13 | extension FixtureClass115: FixtureProtocol114 { 14 | func someFunc() {} 15 | } 16 | 17 | public struct FixtureStruct116: FixtureProtocol114 { 18 | func someFunc() {} 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testStaticMemberUsedAsSubscriptKey.swift: -------------------------------------------------------------------------------- 1 | enum FixtureEnum128 { 2 | static let someVar = "" 3 | } 4 | 5 | public class FixtureClass128 { 6 | public func someFunc() { 7 | var s: [String: Int] = [:] 8 | s[FixtureEnum128.someVar] = 0 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testStaticPropertyDeclaredWithCompositeValuesIsNotRetained.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass38 { 4 | static let propertyB = ", World" 5 | static let propertyA = "Hello" + propertyB 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testStructImplicitInitializer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct FixtureStruct13_Codable: Codable { 4 | let assignOnly: Int 5 | } 6 | 7 | public struct FixtureStruct13_NotCodable { 8 | let assignOnly: Int 9 | let used: Int 10 | } 11 | 12 | public struct FixtureStruct13Retainer { 13 | public func retain() throws { 14 | let data = "".data(using: .utf8)! 15 | _ = try JSONDecoder().decode(FixtureStruct13_Codable.self, from: data) 16 | _ = FixtureStruct13_NotCodable(assignOnly: 0, used: 0).used 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testUnusedAssociatedType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol Fixture88State { 4 | associatedtype AssociatedType = Void 5 | } 6 | 7 | struct Fixture88AssociatedType {} 8 | 9 | enum Fixture88MyState: Fixture88State { 10 | typealias AssociatedType = Fixture88AssociatedType 11 | } 12 | 13 | class Fixture88StateMachine { 14 | func someFunction() {} 15 | } 16 | 17 | public class FixtureClass88Usage { 18 | public func somePublicFunction() { 19 | let sm = Fixture88StateMachine() 20 | sm.someFunction() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testUnusedOverriddenMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FixtureClass81Base { 4 | func someMethod() {} 5 | } 6 | 7 | class FixtureClass81Sub: FixtureClass81Base { 8 | // Method does not call super.someMethod(), therefore the base method is unused. 9 | override func someMethod() {} 10 | } 11 | 12 | public class FixtureClass81Retainer { 13 | var cls: FixtureClass81Sub? 14 | 15 | public func retainingMethod() { 16 | cls?.someMethod() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testUnusedProtocolWithExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol FixtureProtocol82 { 4 | func protoclMethod() 5 | } 6 | 7 | extension FixtureProtocol82 { 8 | func protoclMethod() {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testUnusedTypealias.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | typealias UnusedAlias = Equatable 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/RetentionFixtures/testXCTestCaseClassesAndMethodsAreRetained.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | class FixtureClass34: XCTestCase { 5 | override static func setUp() { 6 | super.setUp() 7 | } 8 | 9 | override func setUp() { 10 | super.setUp() 11 | } 12 | 13 | func testSomething() {} 14 | func testNotATest(param: Int) {} 15 | } 16 | 17 | class FixtureClass34Subclass: FixtureClass34 { 18 | func testSubclass() {} 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/TypeSyntaxInspectorFixtures/TypeSyntaxInspectorFixture.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | let simpleType: String = "" 4 | var optionalType: String? 5 | let memberType: Swift.String = "" 6 | let tupleType: (String, Int) = ("", 0) 7 | let dictionaryType: [String: Int] = [:] 8 | let arrayType: [String] = [] 9 | func functionSimpleReturnType() -> String { "" } 10 | func functionClosureReturnType() -> (Int) -> String { 11 | let closure: (Int) -> String = { String($0) } 12 | return closure 13 | } 14 | func functionArgumentType(a: String, b: Int) {} 15 | func genericFunction(_ t: T.Type) where T: RawRepresentable {} 16 | @available(macOS 10.15.0, *) 17 | func functionSomeType() -> some StringProtocol { "" } 18 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedModuleFixtures/UnusedModuleDeclaration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct UnusedStruct {} 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testBackquote.swift: -------------------------------------------------------------------------------- 1 | class SyntaxFixture22 { 2 | func myFunc(class: String, func: String) { 3 | print(`class`) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testBlockParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture15 { 4 | func myFunc(block: (String) -> Void) { 5 | block("hello") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testFatalErrorFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass106 { 4 | func myFunc(param: String) { 5 | fatalError() 6 | } 7 | } 8 | 9 | public class FixtureClass106Subclass: FixtureClass106 { 10 | required init?(param: String) { 11 | fatalError("init(coder:) has not been implemented") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testFunctionCallWithNamedParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture5 { 4 | func myFunc(param1: String, param2: String) { 5 | // Check that the label isn't confused as an identifier. 6 | other(param2: param1) 7 | } 8 | 9 | func other(param2: String) { 10 | print(param2) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testIBActionAnnotatedFunction.swift: -------------------------------------------------------------------------------- 1 | class SyntaxFixture21 { 2 | @IBAction func myFunc(param: String) {} 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testIgnoreProtocolDeclaration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol SyntaxFixture11 { 4 | init(param: String) 5 | func myFunc(param: String) 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testIgnoredParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture13 { 4 | func myFunc(_: String) {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testInitializer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture7Base { 4 | init(param: String) {} 5 | } 6 | 7 | class SyntaxFixture7: SyntaxFixture7Base { 8 | required init(param1: String, param2: String) { 9 | super.init(param: param1) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testInitializerPosition.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture20 { 4 | init(someVar: Int = 0) {} 5 | } 6 | 7 | class SyntaxFixture20Generic { 8 | init(type: T.Type) {} 9 | } 10 | 11 | class SyntaxFixture20Optional { 12 | init?(someVar: Int = 0) {} 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testLocalVarDeclaredInBlock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture16 { 4 | func myFunc(param: String) { 5 | myBlockFunc { 6 | let param = "test" 7 | print(param) 8 | } 9 | } 10 | 11 | func myBlockFunc(_ block: () -> Void) { 12 | block() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testLocalVariableAssignment.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture4 { 4 | func myFunc(param1: String, param2: String, param3: String?, param4: String?, param5: String?) { 5 | let _ = param1.description 6 | let _ = param2 7 | if let _ = param3 {} 8 | if let param4 {} 9 | guard let param5 else { return } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testMultiLineParameterPosition.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture12 { 4 | func myFunc(param1: String, 5 | param2: String, 6 | // Some comment. 7 | param3: String, 8 | _ param4: String, 9 | with param5: String, 10 | _ // Another comment. 11 | param6: String 12 | ) {} 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testNestedFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture19 { 4 | func myFunc(param: String) { 5 | func innerFunc() { 6 | print(param) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testNestedVariable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture24 { 4 | func myFunc(param: String) { 5 | var innerProperty: String { param } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testParamForGenericSpecialization.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture18 { 4 | func myFunc(param1: A.Type, param2: B.Type? = nil, param3: C.Type!) {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testParameterPosition.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture23 { 4 | func myFunc(param1: String, with param2: String, _ param3: String) {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testReturn.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture10 { 4 | func myFunc(param: String) -> String { 5 | return param 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testShadowed.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture2 { 4 | func myFunc1(param: String) { 5 | let param = "" 6 | print(param) 7 | } 8 | 9 | func myFunc2(param: String) { 10 | let (other, param) = ("", "") 11 | print(param) 12 | print(other) 13 | } 14 | 15 | func myFunc3(param: String) { 16 | let other = "", param = "" 17 | print(param) 18 | print(other) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testShadowedAfterUse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture6 { 4 | func myFunc(param: String) { 5 | print(param) 6 | let param = "shadowed" 7 | print(param) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testShadowedByBlockParameter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture14 { 4 | func myFunc(param1: String, param2: String, param3: String, param4: String) { 5 | // Shadowed 6 | myBlockFunc1 { param1 in print(param1) } 7 | 8 | // Shadowed 9 | myBlockFunc1 { unused in 10 | myBlockFunc1 { param1 in 11 | print(param1) 12 | } 13 | } 14 | 15 | // Used 16 | myBlockFunc1 { unused in 17 | myBlockFunc1 { unused in 18 | print(param3) 19 | } 20 | } 21 | 22 | // Unused 23 | myBlockFunc2({ param4 in 24 | print(param4) 25 | }, param4) 26 | } 27 | 28 | func myBlockFunc1(_ block: (String) -> Void) {} 29 | func myBlockFunc2(_ block: (String) -> Void, _ param: String) {} 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testSimpleFunctionCall.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture3 { 4 | func myFunc(param: String) { 5 | print(param) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testSimpleUnused.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture1 { 4 | func myFunc(param: String) {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testStringInterpolation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture8 { 4 | func myFunc(param1: String, param2: String, param3: String, param4: String) { 5 | print("\(param1)") 6 | print("\(param2.description)") 7 | print("\(other(param3))") 8 | let x = param4 + "test" 9 | print(x) 10 | } 11 | 12 | func other(_ param: String) { 13 | print(param) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testSubscriptArgument.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture17 { 4 | let array: [Int] = [] 5 | 6 | func myFunc(param: Int) { 7 | print(array[param]) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testUnavailableFunction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FixtureClass135 { 4 | @available(*, unavailable) 5 | func myFunc(param: String) {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Fixtures/Sources/UnusedParameterFixtures/testUsedInInitializerCall.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class SyntaxFixture9Helper { 4 | init(param: String) {} 5 | } 6 | 7 | class SyntaxFixture9 { 8 | func myFunc(param1: String, param2: String) { 9 | print(SyntaxFixture9Helper(param: param1)) 10 | print(SyntaxFixture9Helper(param: param2.description)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/PeripheryTests/CrossModuleRetentionTest.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import SystemPackage 3 | @testable import TestShared 4 | 5 | final class CrossModuleRetentionTest: SPMSourceGraphTestCase { 6 | override static func setUp() { 7 | super.setUp() 8 | 9 | build(projectPath: FixturesProjectPath) 10 | index(configuration: Configuration()) 11 | } 12 | 13 | func testCrossModuleInheritanceWithSameName() { 14 | module("CrossModuleRetentionFixtures") { 15 | self.assertReferenced(.class("FixtureClass129")) 16 | } 17 | 18 | module("CrossModuleRetentionSupportFixtures") { 19 | self.assertReferenced(.class("FixtureClass129")) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/PeripheryTests/Extensions/FilePathTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | import XCTest 4 | 5 | final class FilePathTest: XCTestCase { 6 | func testMakeAbsolute() { 7 | let current = FilePath("/current") 8 | XCTAssertEqual(FilePath.makeAbsolute("/a", relativeTo: current).string, "/a") 9 | XCTAssertEqual(FilePath.makeAbsolute("a", relativeTo: current).string, "/current/a") 10 | XCTAssertEqual(FilePath.makeAbsolute("./a", relativeTo: current).string, "/current/a") 11 | } 12 | 13 | func testRelativeTo() { 14 | XCTAssertEqual(FilePath("/a/b/c").relativeTo(FilePath("/a/b/c")).string, ".") 15 | XCTAssertEqual(FilePath("/a/b/c/d").relativeTo(FilePath("/a/b")).string, "c/d") 16 | XCTAssertEqual(FilePath("/a/b/c/d").relativeTo(FilePath("/a/b/c")).string, "d") 17 | XCTAssertEqual(FilePath("/a/b").relativeTo(FilePath("/a/b/c/d")).string, "../..") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/PeripheryTests/Extensions/String+VersionTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | final class StringVersionTest: XCTestCase { 5 | func testVersion() { 6 | XCTAssertTrue("9.3".isVersion(lessThan: "10.0")) 7 | XCTAssertTrue("9.3.1".isVersion(lessThan: "10.0")) 8 | XCTAssertTrue("9.3.1".isVersion(lessThan: "9.3.2")) 9 | XCTAssertTrue("9.3.3".isVersion(greaterThan: "9.3.2")) 10 | 11 | XCTAssertFalse("9.3.1".isVersion(equalTo: "9.3")) 12 | XCTAssertFalse("9.3".isVersion(equalTo: "10.0")) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/PeripheryTests/SwiftVersionParserTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @testable import Shared 3 | import XCTest 4 | 5 | final class SwiftVersionParserTest: XCTestCase { 6 | func testParse() throws { 7 | let v1 = try SwiftVersionParser.parse("Apple Swift version 5.4 (swiftlang-1205.0.16.12 clang-1205.0.19.6)\nTarget: x86_64-apple-darwin20.2.0") 8 | XCTAssertEqual(v1, "5.4") 9 | 10 | let v2 = try SwiftVersionParser.parse("Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)\nTarget: x86_64-apple-darwin20.2.0") 11 | XCTAssertEqual(v2, "5.3.2") 12 | 13 | let v3 = try SwiftVersionParser.parse("Swift version 5.4-dev (LLVM e2976fe639d1f50, Swift ce587f0a137bf18)\nTarget: x86_64-apple-darwin20.2.0") 14 | XCTAssertEqual(v3, "5.4") 15 | 16 | let v4 = try SwiftVersionParser.parse("swift-driver version: 1.26.5 Apple Swift version 5.5 (swiftlang-1300.0.24.13 clang-1300.0.25.10)\nTarget: x86_64-apple-macosx11.0") 17 | XCTAssertEqual(v4, "5.5") 18 | 19 | let v5 = try SwiftVersionParser.parse("swift-driver version: 1.62.8 Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50)\nTarget: arm64-apple-macosx12.0") 20 | XCTAssertEqual(v5, "5.7") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/SPMTests/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | @testable import TestShared 4 | 5 | var SPMProjectPath: FilePath { 6 | ProjectRootPath.appending("Tests/SPMTests/SPMProject") 7 | } 8 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "cb391f7a83a909d01a33ea32b811335c24badb42ef910696f24d932cf2182ae7", 3 | "pins" : [ 4 | { 5 | "identity" : "swift-syntax", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/swiftlang/swift-syntax", 8 | "state" : { 9 | "revision" : "f99ae8aa18f0cf0d53481901f88a0991dc3bd4a2", 10 | "version" : "601.0.1" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Package.swift: -------------------------------------------------------------------------------- 1 | import CompilerPluginSupport 2 | 3 | // swift-tools-version: 6.0 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SPMProject", 8 | platforms: [.macOS(.v13)], 9 | products: [ 10 | .executable( 11 | name: "frontend", 12 | targets: ["Frontend"] 13 | ), 14 | ], 15 | dependencies: [ 16 | .package(url: "https://github.com/swiftlang/swift-syntax", from: "601.0.1"), 17 | ], 18 | targets: [ 19 | .executableTarget( 20 | name: "Frontend", 21 | dependencies: ["SPMProjectKit"] 22 | ), 23 | .target( 24 | name: "SPMProjectKit", 25 | dependencies: ["SPMProjectMacros"] 26 | ), 27 | .macro( 28 | name: "SPMProjectMacros", 29 | dependencies: [ 30 | .product(name: "SwiftSyntax", package: "swift-syntax"), 31 | .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), 32 | .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), 33 | ] 34 | ), 35 | .testTarget( 36 | name: "Tests", 37 | dependencies: ["SPMProjectKit"] 38 | ), 39 | ] 40 | ) 41 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/Frontend/main.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SPMProjectKit 3 | 4 | func main() { 5 | print(SPMProject().text) 6 | print(PublicCrossModuleReferenced.self) 7 | } 8 | 9 | main() 10 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/SPMProjectKit/Macros.swift: -------------------------------------------------------------------------------- 1 | @attached(peer, names: suffixed(Mock)) 2 | public macro Mock() = #externalMacro(module: "SPMProjectMacros", type: "MockMacro") 3 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/SPMProjectKit/MockedProtocol.swift: -------------------------------------------------------------------------------- 1 | @Mock 2 | protocol MockedProtocol {} 3 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/SPMProjectKit/SPMProject.swift: -------------------------------------------------------------------------------- 1 | public struct SPMProject { 2 | public init() {} 3 | 4 | public var text = "Hello, World!" 5 | } 6 | 7 | public class PublicCrossModuleReferenced {} 8 | public class PublicCrossModuleNotReferenced {} 9 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/SPMProjectMacros/MockMacro.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SwiftOperators 3 | import SwiftSyntax 4 | import SwiftSyntaxMacros 5 | 6 | struct MockMacro: PeerMacro { 7 | public static func expansion( 8 | of _: AttributeSyntax, 9 | providingPeersOf declaration: some DeclSyntaxProtocol, 10 | in _: some MacroExpansionContext 11 | ) throws -> [DeclSyntax] { 12 | guard let protocolDecl = declaration.as(ProtocolDeclSyntax.self) else { return [] } 13 | 14 | let protocolName = protocolDecl.name.text 15 | let mockName = "\(protocolName)Mock" 16 | 17 | let mockClass = DeclSyntax( 18 | ClassDeclSyntax( 19 | modifiers: [DeclModifierSyntax(name: "public")], 20 | name: .identifier(mockName), 21 | inheritanceClause: InheritanceClauseSyntax { 22 | InheritedTypeSyntax(type: TypeSyntax(stringLiteral: protocolName)) 23 | }, 24 | memberBlock: MemberBlockSyntax {} 25 | ) 26 | ) 27 | 28 | return [mockClass] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Sources/SPMProjectMacros/Plugin.swift: -------------------------------------------------------------------------------- 1 | import SwiftCompilerPlugin 2 | import SwiftSyntaxMacros 3 | 4 | @main 5 | struct TestPlugin: CompilerPlugin { 6 | let providingMacros: [Macro.Type] = [ 7 | MockMacro.self, 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProject/Tests/MacroImportTests.swift: -------------------------------------------------------------------------------- 1 | import SPMProjectKit 2 | import XCTest 3 | 4 | class MacroImportTests: XCTestCase { 5 | func testMacro() { 6 | // This is the only reference to SPMProjectKit. 7 | _ = MockedProtocolMock.self 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/SPMTests/SPMProjectTest.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | @testable import TestShared 3 | import XCTest 4 | 5 | final class SPMProjectTest: SPMSourceGraphTestCase { 6 | override static func setUp() { 7 | super.setUp() 8 | 9 | build(projectPath: SPMProjectPath) 10 | index(configuration: Configuration()) 11 | } 12 | 13 | func testMainEntryFile() { 14 | assertReferenced(.functionFree("main()")) 15 | } 16 | 17 | func testCrossModuleReference() { 18 | assertReferenced(.class("PublicCrossModuleReferenced")) 19 | assertNotReferenced(.class("PublicCrossModuleNotReferenced")) 20 | } 21 | 22 | func testMacroImport() { 23 | assertReferenced(.module("SPMProjectKit")) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/Shared/DeclarationScope.swift: -------------------------------------------------------------------------------- 1 | @testable import SourceGraph 2 | 3 | enum DeclarationScope { 4 | case declaration(Declaration) 5 | case module(String) 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Shared/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | 4 | var ProjectRootPath: FilePath { 5 | FilePath(#filePath).appending("../../..").lexicallyNormalized() 6 | } 7 | 8 | var FixturesProjectPath: FilePath { 9 | ProjectRootPath.appending("Tests/Fixtures") 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Shared/SPMSourceGraphTestCase.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import ProjectDrivers 4 | import SystemPackage 5 | 6 | class SPMSourceGraphTestCase: SourceGraphTestCase { 7 | static func build(projectPath: FilePath = ProjectRootPath, configuration: Configuration = .init()) { 8 | projectPath.chdir { 9 | let driver = try! SPMProjectDriver(configuration: configuration, shell: shell, logger: logger) 10 | try! driver.build() 11 | plan = try! driver.plan(logger: logger.contextualized(with: "index")) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Shared/XCTestCase+Extensions.swift: -------------------------------------------------------------------------------- 1 | import SystemPackage 2 | import XCTest 3 | 4 | public extension XCTestCase { 5 | var testFixturePath: FilePath { 6 | #if os(macOS) 7 | let testName = String(name.split(separator: " ").last!).replacingOccurrences(of: "]", with: "") 8 | #else 9 | let testName = String(name.split(separator: ".", maxSplits: 1).last!) 10 | #endif 11 | 12 | let suiteName = String(describing: Self.self).dropLast(4) 13 | return FixturesProjectPath.appending("Sources/\(suiteName)Fixtures/\(testName).swift") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/XcodeTests/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SystemPackage 3 | @testable import TestShared 4 | 5 | var UIKitProjectPath: FilePath { 6 | ProjectRootPath.appending("Tests/XcodeTests/UIKitProject/UIKitProject.xcodeproj") 7 | } 8 | 9 | var SwiftUIProjectPath: FilePath { 10 | ProjectRootPath.appending("Tests/XcodeTests/SwiftUIProject/SwiftUIProject.xcodeproj") 11 | } 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/ShellMock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Logger 3 | import Shared 4 | 5 | class ShellMock: Shell { 6 | var output: String = "" 7 | 8 | convenience init() { 9 | let logger = Logger(quiet: true) 10 | self.init(logger: logger) 11 | } 12 | 13 | override func exec(_: [String]) throws -> String { 14 | output 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject/App.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct SwiftUIProjectApp: App { 5 | @UIApplicationDelegateAdaptor(AppDelegate.self) 6 | var appDelegate 7 | 8 | var body: some Scene { 9 | WindowGroup { 10 | ContentView() 11 | } 12 | } 13 | } 14 | 15 | class AppDelegate: NSObject, UIApplicationDelegate {} 16 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContentView: View { 4 | var body: some View { 5 | Text("Hello, world!") 6 | } 7 | } 8 | 9 | struct ContentView_Previews: PreviewProvider { 10 | static var previews: some View { 11 | ContentView() 12 | } 13 | } 14 | 15 | struct LibraryViewContent: LibraryContentProvider { 16 | var views: [LibraryItem] { 17 | LibraryItem(ContentView()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProject/SwiftUIProject/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/SwiftUIProjectTest.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | @testable import TestShared 3 | 4 | final class SwiftUIProjectTest: XcodeSourceGraphTestCase { 5 | override static func setUp() { 6 | super.setUp() 7 | 8 | let configuration = Configuration() 9 | configuration.schemes = ["SwiftUIProject"] 10 | 11 | build(projectPath: SwiftUIProjectPath, configuration: configuration) 12 | index(configuration: configuration) 13 | } 14 | 15 | func testRetainsMainAppEntryPoint() { 16 | assertReferenced(.struct("SwiftUIProjectApp")) 17 | } 18 | 19 | func testDoesNotRetainPreviewProvider() { 20 | assertNotReferenced(.struct("ContentView_Previews")) 21 | } 22 | 23 | func testRetainsLibraryContentProvider() { 24 | assertReferenced(.struct("LibraryViewContent")) 25 | } 26 | 27 | func testRetainsUIApplicationDelegateAdaptorProperty() { 28 | assertReferenced(.struct("SwiftUIProjectApp")) { 29 | self.assertReferenced(.varInstance("appDelegate")) 30 | } 31 | } 32 | 33 | func testRetainsUIApplicationDelegateAdaptorReferencedType() { 34 | assertReferenced(.class("AppDelegate")) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/LocalPackages/LocalPackage/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/LocalPackages/LocalPackage/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.10 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "LocalPackage", 6 | products: [ 7 | .library( 8 | name: "LocalPackageTarget", 9 | targets: ["LocalPackageTarget"]) 10 | ], 11 | targets: [ 12 | .target( 13 | name: "LocalPackageTarget", 14 | dependencies: []) 15 | ] 16 | ) 17 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/LocalPackages/LocalPackage/Sources/LocalPackageTarget/LocalPackageUnusedType.swift: -------------------------------------------------------------------------------- 1 | public struct LocalPackageUnusedType { 2 | public init() {} 3 | } 4 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/LocalPackages/LocalPackage/Sources/LocalPackageTarget/LocalPackageUsedType.swift: -------------------------------------------------------------------------------- 1 | public struct LocalPackageUsedType { 2 | public init() {} 3 | } 4 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/NotificationServiceExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | NotificationServiceExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.usernotifications.service 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).NotificationService 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/NotificationServiceExtension/NotificationService.swift: -------------------------------------------------------------------------------- 1 | import UserNotifications 2 | 3 | class NotificationService: UNNotificationServiceExtension { 4 | var contentHandler: ((UNNotificationContent) -> Void)? 5 | var bestAttemptContent: UNMutableNotificationContent? 6 | 7 | override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { 8 | print(MultiTargetStruct.usedInExt) 9 | print(MultiTargetStruct.usedInBoth) 10 | 11 | self.contentHandler = contentHandler 12 | bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) 13 | 14 | if let bestAttemptContent = bestAttemptContent { 15 | // Modify the notification content here... 16 | bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" 17 | 18 | contentHandler(bestAttemptContent) 19 | } 20 | } 21 | 22 | override func serviceExtensionTimeWillExpire() { 23 | // Called just before the extension will be terminated by the system. 24 | // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. 25 | if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { 26 | contentHandler(bestAttemptContent) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/Target With Spaces/File With Spaces.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class FileWithSpaces {} 4 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/Target With Spaces/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/CustomEntityMigrationPolicy.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import CoreData 3 | 4 | class CustomEntityMigrationPolicy: NSEntityMigrationPolicy { 5 | override func begin(_ mapping: NSEntityMapping, with manager: NSMigrationManager) throws { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/EntityValueTransformer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | public class EntityValueTransformer: ValueTransformer { 5 | public override func transformedValue(_ value: Any?) -> Any? { 6 | return nil 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/FileInGroupWithoutFolder.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/Model.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | Model.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/Model.xcdatamodeld/Model.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/MultiTarget/MultiTargetStruct.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct MultiTargetStruct { 4 | static let usedInBoth = "" 5 | static let usedInApp = "" 6 | static let usedInExt = "" 7 | static let unused = "" 8 | } 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/OldModel.xcdatamodeld/OldModel.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/StoryboardViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class StoryboardViewController: UIViewController { 4 | @IBOutlet weak var button: UIButton! 5 | @IBAction func click(_ sender: Any) {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/XibViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class XibViewController: UIViewController { 4 | @IBOutlet weak var button: UIButton! 5 | @IBAction func click(_ sender: Any) {} 6 | @IBAction func clickFromSubclass(_ sender: Any) {} 7 | @IBInspectable var controllerProperty: UIColor? 8 | 9 | override func viewDidLoad() { 10 | super.viewDidLoad() 11 | _ = #selector(selectorMethod) 12 | button.addTarget(self, action: #selector(addTargetMethod), for: .touchUpInside) 13 | } 14 | 15 | @objc private func selectorMethod() {} 16 | @objc private func addTargetMethod() {} 17 | } 18 | 19 | class XibView: UIView { 20 | @IBInspectable var viewProperty: UIColor? 21 | } 22 | 23 | extension UIView { 24 | @IBInspectable var customBorderColor: UIColor? { 25 | get { 26 | if let borderColor = layer.borderColor { 27 | return UIColor(cgColor: borderColor) 28 | } 29 | 30 | return nil 31 | } 32 | set { 33 | layer.borderColor = newValue?.cgColor 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProject/XibViewController2.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class XibViewController2Base: UIViewController { 4 | @IBOutlet weak var button: UIButton! 5 | @IBAction func clickFromSubclass(_ sender: Any) {} 6 | } 7 | 8 | class XibViewController2Subclass: XibViewController2Base {} 9 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProjectTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/UIKitProjectTests/UIKitProjectTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIKitProjectTests.swift 3 | // UIKitProjectTests 4 | // 5 | // Created by Ian Leitch on 11/7/20. 6 | // 7 | 8 | import XCTest 9 | 10 | final class UIKitProjectTests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | } 15 | 16 | override func tearDownWithError() throws { 17 | // Put teardown code here. This method is called after the invocation of each test method in the class. 18 | } 19 | 20 | func testExample() throws { 21 | // This is an example of a functional test case. 22 | // Use XCTAssert and related functions to verify your tests produce the correct results. 23 | } 24 | 25 | func testPerformanceExample() throws { 26 | // This is an example of a performance test case. 27 | measure { 28 | // Put the code you want to measure the time of here. 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/WatchWidget/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/WatchWidget/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "watchos", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/WatchWidget/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/WatchWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/UIKitProject/WatchWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/XcodeTests/XcodeSourceGraphTestCase.swift: -------------------------------------------------------------------------------- 1 | import Configuration 2 | import Foundation 3 | import ProjectDrivers 4 | import SystemPackage 5 | @testable import TestShared 6 | 7 | class XcodeSourceGraphTestCase: SourceGraphTestCase { 8 | static func build(projectPath: FilePath, configuration: Configuration) { 9 | projectPath.chdir { 10 | let driver = try! XcodeProjectDriver( 11 | projectPath: projectPath, 12 | configuration: configuration, 13 | shell: shell, 14 | logger: logger 15 | ) 16 | try! driver.build() 17 | plan = try! driver.plan(logger: logger.contextualized(with: "index")) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/XcodeTests/XcodebuildBuildProjectTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Logger 3 | import Shared 4 | @testable import XcodeSupport 5 | import XCTest 6 | 7 | final class XcodebuildBuildProjectTest: XCTestCase { 8 | private var xcodebuild: Xcodebuild! 9 | private var project: XcodeProject! 10 | 11 | override func setUp() { 12 | super.setUp() 13 | 14 | let logger = Logger(quiet: true) 15 | let shell = Shell(logger: logger) 16 | xcodebuild = Xcodebuild(shell: shell, logger: logger) 17 | project = try! XcodeProject(path: UIKitProjectPath, xcodebuild: xcodebuild, shell: shell, logger: logger) 18 | } 19 | 20 | override func tearDown() { 21 | xcodebuild = nil 22 | project = nil 23 | super.tearDown() 24 | } 25 | 26 | func testBuildSchemeWithWhitespace() throws { 27 | let scheme = "Scheme With Spaces" 28 | try xcodebuild.build(project: project, scheme: scheme, allSchemes: [scheme]) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/XcodeTests/XcodebuildSchemesTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Logger 3 | @testable import XcodeSupport 4 | import XCTest 5 | 6 | final class XcodebuildSchemesTest: XCTestCase { 7 | private var shell: ShellMock! 8 | private var xcodebuild: Xcodebuild! 9 | private var project: XcodeProject! 10 | 11 | override func setUp() { 12 | super.setUp() 13 | 14 | shell = ShellMock() 15 | let logger = Logger(quiet: true) 16 | xcodebuild = Xcodebuild(shell: shell, logger: logger) 17 | project = try! XcodeProject(path: UIKitProjectPath, xcodebuild: xcodebuild, shell: shell, logger: logger) 18 | } 19 | 20 | override func tearDown() { 21 | shell = nil 22 | xcodebuild = nil 23 | project = nil 24 | super.tearDown() 25 | } 26 | 27 | func testParseSchemes() { 28 | for output in XcodebuildListOutputs { 29 | shell.output = output 30 | let schemes = try! xcodebuild.schemes(project: project, additionalArguments: []) 31 | XCTAssertEqual(schemes, ["SchemeA", "SchemeB"]) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/logo.png -------------------------------------------------------------------------------- /assets/sponsor-20.svg: -------------------------------------------------------------------------------- 1 | 5 | sponsor logo 6 | 9 | -------------------------------------------------------------------------------- /assets/sponsor.svg: -------------------------------------------------------------------------------- 1 | 5 | sponsor logo 6 | 9 | -------------------------------------------------------------------------------- /assets/xcode-integration/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/xcode-integration/1.png -------------------------------------------------------------------------------- /assets/xcode-integration/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/xcode-integration/2.png -------------------------------------------------------------------------------- /assets/xcode-integration/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/xcode-integration/3.png -------------------------------------------------------------------------------- /assets/xcode-integration/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/xcode-integration/4.png -------------------------------------------------------------------------------- /assets/xcode-integration/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/assets/xcode-integration/5.png -------------------------------------------------------------------------------- /baselines/bazel.json: -------------------------------------------------------------------------------- 1 | {"v1":{"usrs":["s:13Configuration15AbstractSettingP5resetyyF","s:13Configuration7SettingC5resetyyF","s:13ConfigurationAAC13resetMatchersyyF","s:13ConfigurationAAC5resetyyF","s:13SystemPackage8FilePathV10ExtensionsE5chdir7closureyyyKXE_tKF","s:14SyntaxAnalysis21UnusedParameterParserV5parse4file0F9ProtocolsSayAA8FunctionVG11SourceGraph0J4FileC_SbtKFZ","s:14SyntaxAnalysis8FunctionV8fullNameSSvp"]}} -------------------------------------------------------------------------------- /baselines/linux.json: -------------------------------------------------------------------------------- 1 | {"v1":{"usrs":["import-Configuration-Sources\/ProjectDrivers\/XcodeProjectDriver.swift:2:5","import-Indexer-Sources\/ProjectDrivers\/XcodeProjectDriver.swift:4:5","import-Logger-Sources\/ProjectDrivers\/XcodeProjectDriver.swift:5:5","import-Shared-Sources\/ProjectDrivers\/XcodeProjectDriver.swift:6:5","import-SourceGraph-Sources\/ProjectDrivers\/XcodeProjectDriver.swift:7:5","import-TestShared-Tests\/PeripheryTests\/ObjcAccessibleRetentionTest.swift:2:1","import-TestShared-Tests\/PeripheryTests\/ObjcAnnotatedRetentionTest.swift:2:1","s:11SourceGraph15ProjectFileKindO10extensionsSaySSGvp","s:13ConfigurationAAC20_retainFilesMatchers33_99B696DD1FA930EA831ABFF16BC88E61LLSay15FilenameMatcherAEVGSgvp","s:13ConfigurationAAC21_indexExcludeMatchers33_99B696DD1FA930EA831ABFF16BC88E61LLSay15FilenameMatcherAEVGSgvp","s:6Shared14SetupSelectionO","s:6Shared17SetupGuideHelpersC6select8multipleAA0B9SelectionOSaySSG_tF","s:8Frontend13UpdateCheckerC13latestVersion33_996BB8CE205CF54754BD877559C8CCFELLSSSgvp","s:8Frontend13UpdateCheckerC5error33_996BB8CE205CF54754BD877559C8CCFELLs5Error_pSgvp","s:SS10ExtensionsE17withEscapedQuotesSSvp","s:SS10ExtensionsE4djb2Sivp","s:SS10ExtensionsE7djb2HexSSvp","import-Configuration-Tests\/AccessibilityTests\/RedundantPublicAccessibilityTest.swift:1:1"]}} -------------------------------------------------------------------------------- /baselines/macos-swift-6.1.json: -------------------------------------------------------------------------------- 1 | {"v1":{"usrs":["s:13ConfigurationAAC20_retainFilesMatchers33_99B696DD1FA930EA831ABFF16BC88E61LLSay15FilenameMatcherAEVGSgvp","s:13ConfigurationAAC21_indexExcludeMatchers33_99B696DD1FA930EA831ABFF16BC88E61LLSay15FilenameMatcherAEVGSgvp","s:8Frontend13UpdateCheckerC13latestVersion33_996BB8CE205CF54754BD877559C8CCFELLSSSgvp","s:8Frontend13UpdateCheckerC5error33_996BB8CE205CF54754BD877559C8CCFELLs5Error_pSgvp"]}} -------------------------------------------------------------------------------- /bazel/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/bazel/BUILD.bazel -------------------------------------------------------------------------------- /bazel/dev/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@buildifier_prebuilt//:rules.bzl", "buildifier") 2 | 3 | buildifier( 4 | name = "buildifier.fix", 5 | exclude_patterns = [ 6 | "./.git/**/*", 7 | "**/.build/**/*", 8 | ], 9 | lint_mode = "fix", 10 | mode = "fix", 11 | ) 12 | 13 | buildifier( 14 | name = "buildifier.check", 15 | exclude_patterns = [ 16 | "./.git/**/*", 17 | "**/.build/**/*", 18 | ], 19 | lint_mode = "warn", 20 | mode = "check", 21 | ) 22 | -------------------------------------------------------------------------------- /bazel/generated.bzl: -------------------------------------------------------------------------------- 1 | """ 2 | Public generated repo extension. 3 | """ 4 | 5 | def _generated_repo_impl(repository_ctx): 6 | repository_ctx.symlink( 7 | "/var/tmp/periphery_bazel/BUILD.bazel", 8 | "BUILD.bazel", 9 | ) 10 | 11 | generated_repo = repository_rule( 12 | implementation = _generated_repo_impl, 13 | ) 14 | 15 | generated = module_extension(implementation = lambda _: generated_repo(name = "periphery_generated")) 16 | -------------------------------------------------------------------------------- /bazel/internal/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peripheryapp/periphery/63e52c1f0d5a320cd0fcd5f1a710914f273d1915/bazel/internal/BUILD.bazel -------------------------------------------------------------------------------- /bazel/internal/opt.bzl: -------------------------------------------------------------------------------- 1 | """ 2 | Rules for enabling Swift optimizations. 3 | """ 4 | 5 | def _enable_optimizations_impl( 6 | settings, 7 | attr): # @unused 8 | return { 9 | "//command_line_option:compilation_mode": "opt", 10 | "//command_line_option:features": settings["//command_line_option:features"] + [ 11 | "swift.opt_uses_wmo", 12 | "-swift.opt_uses_osize", 13 | ], 14 | } 15 | 16 | _enable_optimizations = transition( 17 | implementation = _enable_optimizations_impl, 18 | inputs = ["//command_line_option:features"], 19 | outputs = ["//command_line_option:compilation_mode", "//command_line_option:features"], 20 | ) 21 | 22 | def _optimized_swift_binary_impl(ctx): 23 | new_exe = ctx.actions.declare_file(ctx.label.name) 24 | ctx.actions.symlink(output = new_exe, target_file = ctx.executable.target) 25 | return [DefaultInfo(executable = new_exe)] 26 | 27 | optimized_swift_binary = rule( 28 | attrs = { 29 | "target": attr.label( 30 | cfg = _enable_optimizations, 31 | mandatory = True, 32 | executable = True, 33 | ), 34 | }, 35 | executable = True, 36 | implementation = _optimized_swift_binary_impl, 37 | ) 38 | -------------------------------------------------------------------------------- /bazel/internal/scan/BUILD.bazel: -------------------------------------------------------------------------------- 1 | exports_files([ 2 | "scan_template.sh", 3 | ]) 4 | -------------------------------------------------------------------------------- /bazel/internal/scan/scan_template.sh: -------------------------------------------------------------------------------- 1 | %periphery_path% scan --config "%config_path%" --generic-project-config "%project_config_path%" 2 | -------------------------------------------------------------------------------- /bazel/rules.bzl: -------------------------------------------------------------------------------- 1 | """ 2 | Periphery public rules. 3 | """ 4 | 5 | load("//bazel/internal/scan:scan.bzl", "force_indexstore", "scan_impl", "scan_inputs_aspect") 6 | 7 | scan = rule( 8 | doc = "Scans the top-level deps and their transitive deps for unused code.", 9 | attrs = { 10 | "deps": attr.label_list( 11 | cfg = force_indexstore, 12 | mandatory = True, 13 | aspects = [scan_inputs_aspect], 14 | doc = "Top-level project targets to scan.", 15 | ), 16 | "config": attr.string(doc = "Path to the periphery.yml configuration file."), 17 | "periphery": attr.label( 18 | doc = "The periphery executable target.", 19 | default = "@periphery//:periphery", 20 | ), 21 | "_template": attr.label( 22 | allow_single_file = True, 23 | default = "@periphery//bazel/internal/scan:scan_template.sh", 24 | ), 25 | }, 26 | outputs = { 27 | "project_config": "project_config.json", 28 | "scan": "scan.sh", 29 | }, 30 | implementation = scan_impl, 31 | executable = True, 32 | ) 33 | -------------------------------------------------------------------------------- /docker/Dockerfile.linux: -------------------------------------------------------------------------------- 1 | FROM swift:latest 2 | WORKDIR /workspace 3 | COPY . /workspace 4 | RUN swift build --product periphery 5 | ENTRYPOINT [".build/debug/periphery"] 6 | --------------------------------------------------------------------------------